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.
This commit is contained in:
parent
302e43f256
commit
9337fcbf77
@ -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 rtwn_softc *);
|
||||
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, desc, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user