aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorAndriy Voskoboinyk <avos@FreeBSD.org>2016-11-06 18:11:19 +0000
committerAndriy Voskoboinyk <avos@FreeBSD.org>2016-11-06 18:11:19 +0000
commit519e6c0fc222192a1862c66b66a78a9b8a983e73 (patch)
tree7f250728a57d107bc3f6a5e97c075954af1d2449 /sys/dev
parent1acd7ad907c388d72ce6bf1da9e4473ccfd16a01 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/rtwn/pci/rtwn_pci_attach.c124
1 files changed, 94 insertions, 30 deletions
diff --git a/sys/dev/rtwn/pci/rtwn_pci_attach.c b/sys/dev/rtwn/pci/rtwn_pci_attach.c
index e48ae8141291..4db4427a5f89 100644
--- a/sys/dev/rtwn/pci/rtwn_pci_attach.c
+++ b/sys/dev/rtwn/pci/rtwn_pci_attach.c
@@ -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];
-
- 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;
+ struct rtwn_tx_data *data = &ring->tx_data[i];
+ void *desc = (uint8_t *)ring->desc + sc->txdesc_len * i;
- rtwn_pci_copy_tx_desc(pc, tx_desc, NULL);
+ rtwn_pci_copy_tx_desc(pc, 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