Date: Sun, 6 Nov 2016 18:11:19 +0000 (UTC) From: Andriy Voskoboinyk <avos@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308381 - head/sys/dev/rtwn/pci Message-ID: <201611061811.uA6IBJO4095149@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: avos Date: Sun Nov 6 18:11:19 2016 New Revision: 308381 URL: https://svnweb.freebsd.org/changeset/base/308381 Log: rtwn: fix Tx ring cleanup. Do not try to clear stale Tx descriptor entries when there are some running vaps; just free node references - rtwn_pci_tx_done() will free mbufs without creating holes in the Tx descriptor space. Also, reset only 2 first entries in the beacon ring - other will not be used anyway. Tested with RTL8188CE, STA + STA mode. Modified: head/sys/dev/rtwn/pci/rtwn_pci_attach.c Modified: head/sys/dev/rtwn/pci/rtwn_pci_attach.c ============================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_attach.c Sun Nov 6 17:24:16 2016 (r308380) +++ head/sys/dev/rtwn/pci/rtwn_pci_attach.c Sun Nov 6 18:11:19 2016 (r308381) @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_var.h> +#include <dev/rtwn/if_rtwnreg.h> #include <dev/rtwn/if_rtwnvar.h> #include <dev/rtwn/if_rtwn_nop.h> #include <dev/rtwn/if_rtwn_debug.h> @@ -75,6 +76,8 @@ static int rtwn_pci_alloc_rx_list(struct static void rtwn_pci_reset_rx_list(struct rtwn_softc *); static void rtwn_pci_free_rx_list(struct rtwn_softc *); static int rtwn_pci_alloc_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *, int); +static void rtwn_pci_reset_beacon_ring(struct rtwn_softc *, int); static void rtwn_pci_reset_tx_list(struct rtwn_softc *, struct ieee80211vap *, int); static void rtwn_pci_free_tx_list(struct rtwn_softc *, int); @@ -312,48 +315,109 @@ fail: } static void -rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, - int qid) +rtwn_pci_reset_tx_ring_stopped(struct rtwn_softc *sc, int qid) { - struct rtwn_vap *uvp = RTWN_VAP(vap); struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); - struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; - int i, id; - - id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + int i; for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { - struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + struct rtwn_tx_data *data = &ring->tx_data[i]; + void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i; - if (vap == NULL || (tx_data->ni == NULL && - (tx_data->id == id || id == RTWN_VAP_ID_INVALID)) || - (tx_data->ni != NULL && tx_data->ni->ni_vap == vap)) { - void *tx_desc = - (uint8_t *)tx_ring->desc + sc->txdesc_len * i; - - rtwn_pci_copy_tx_desc(pc, tx_desc, NULL); - - if (tx_data->m != NULL) { - bus_dmamap_sync(tx_ring->data_dmat, - tx_data->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->data_dmat, - tx_data->map); - m_freem(tx_data->m); - tx_data->m = NULL; - } - if (tx_data->ni != NULL) { - ieee80211_free_node(tx_data->ni); - tx_data->ni = NULL; - } + rtwn_pci_copy_tx_desc(pc, desc, NULL); + + if (data->m != NULL) { + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + m_freem(data->m); + data->m = NULL; + } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; } } - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTWRITE); sc->qfullmsk &= ~(1 << qid); - tx_ring->queued = 0; - tx_ring->last = tx_ring->cur = 0; + ring->queued = 0; + ring->last = ring->cur = 0; +} + +/* + * Clear entry 0 (or 1) in the beacon queue (other are not used). + */ +static void +rtwn_pci_reset_beacon_ring(struct rtwn_softc *sc, int id) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE]; + struct rtwn_tx_data *data = &ring->tx_data[id]; + struct rtwn_tx_desc_common *txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + id * sc->txdesc_len); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + if (txd->flags0 & RTWN_FLAGS0_OWN) { + /* Clear OWN bit. */ + txd->flags0 &= ~RTWN_FLAGS0_OWN; + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Unload mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + } +} + +/* + * Drop stale entries from Tx ring before the vap will be deleted. + * In case if vap is NULL just free everything and reset cur / last pointers. + */ +static void +rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, + int qid) +{ + int i; + + if (vap == NULL) { + if (qid != RTWN_PCI_BEACON_QUEUE) { + /* + * Device was stopped; just clear all entries. + */ + rtwn_pci_reset_tx_ring_stopped(sc, qid); + } else { + for (i = 0; i < RTWN_PORT_COUNT; i++) + rtwn_pci_reset_beacon_ring(sc, i); + } + } else if (qid == RTWN_PCI_BEACON_QUEUE && + (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS)) { + struct rtwn_vap *uvp = RTWN_VAP(vap); + + rtwn_pci_reset_beacon_ring(sc, uvp->id); + } else { + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *data = &ring->tx_data[i]; + if (data->ni != NULL && data->ni->ni_vap == vap) { + /* + * NB: if some vap is still running + * rtwn_pci_tx_done() will free the mbuf; + * otherwise, rtwn_stop() will reset all rings + * after device shutdown. + */ + ieee80211_free_node(data->ni); + data->ni = NULL; + } + } + } } static void
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611061811.uA6IBJO4095149>