Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Jul 2012 09:30:38 +0000 (UTC)
From:      Bernhard Schmidt <bschmidt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r237917 - stable/9/sys/dev/iwn
Message-ID:  <201207010930.q619UcKb080436@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bschmidt
Date: Sun Jul  1 09:30:37 2012
New Revision: 237917
URL: http://svn.freebsd.org/changeset/base/237917

Log:
  MFC BA/DELBA fixes:
  - r234321:
    Use the M_AMPDU_MPDU flag to determine when to manually set the seqno and
    use a BA queue.
  - r235686:
    Discard frames after a DELBA which where queued during an active BA
    session.
  - r235687:
    remove unused vap variable
  - r237647:
    Fix a TX aggregation issue, if after the last compressed BA notification
    the TX queue is empty, there won't be a TX done notification, effectly
    resulting in an mbuf leak. The correct way to handle this is to free
    up mbufs on both BA and TX done notifications up to the last sent seqno.
  - r237649 (1):
    We need to defer passing the DELBA request to the firmware until the aggr
    queue is empty or the firmware will go nuts.
  
  PR:		kern/167806 (1)

Modified:
  stable/9/sys/dev/iwn/if_iwn.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/iwn/if_iwn.c
==============================================================================
--- stable/9/sys/dev/iwn/if_iwn.c	Sun Jul  1 09:17:55 2012	(r237916)
+++ stable/9/sys/dev/iwn/if_iwn.c	Sun Jul  1 09:30:37 2012	(r237917)
@@ -2432,23 +2432,66 @@ static void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
     struct iwn_rx_data *data)
 {
+	struct iwn_ops *ops = &sc->ops;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct iwn_node *wn;
 	struct ieee80211_node *ni;
 	struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1);
 	struct iwn_tx_ring *txq;
+	struct iwn_tx_data *txdata;
 	struct ieee80211_tx_ampdu *tap;
+	struct mbuf *m;
 	uint64_t bitmap;
+	uint16_t ssn;
 	uint8_t tid;
-	int ackfailcnt = 0, i, shift;
+	int ackfailcnt = 0, i, lastidx, qid, *res, shift;
 
 	bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
-	txq = &sc->txq[le16toh(ba->qid)];
-	tap = sc->qid2tap[le16toh(ba->qid)];
+	qid = le16toh(ba->qid);
+	txq = &sc->txq[ba->qid];
+	tap = sc->qid2tap[ba->qid];
 	tid = WME_AC_TO_TID(tap->txa_ac);
-	ni = tap->txa_ni;
-	wn = (void *)ni;
+	wn = (void *)tap->txa_ni;
+
+	res = NULL;
+	ssn = 0;
+	if (!IEEE80211_AMPDU_RUNNING(tap)) {
+		res = tap->txa_private;
+		ssn = tap->txa_start & 0xfff;
+	}
+
+	for (lastidx = le16toh(ba->ssn) & 0xff; txq->read != lastidx;) {
+		txdata = &txq->data[txq->read];
+
+		/* Unmap and free mbuf. */
+		bus_dmamap_sync(txq->data_dmat, txdata->map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(txq->data_dmat, txdata->map);
+		m = txdata->m, txdata->m = NULL;
+		ni = txdata->ni, txdata->ni = NULL;
+
+		KASSERT(ni != NULL, ("no node"));
+		KASSERT(m != NULL, ("no mbuf"));
+
+		if (m->m_flags & M_TXCB)
+			ieee80211_process_callback(ni, m, 1);
+
+		m_freem(m);
+		ieee80211_free_node(ni);
+
+		txq->queued--;
+		txq->read = (txq->read + 1) % IWN_TX_RING_COUNT;
+	}
+
+	if (txq->queued == 0 && res != NULL) {
+		iwn_nic_lock(sc);
+		ops->ampdu_tx_stop(sc, qid, tid, ssn);
+		iwn_nic_unlock(sc);
+		sc->qid2tap[qid] = NULL;
+		free(res, M_DEVBUF);
+		return;
+	}
 
 	if (wn->agg[tid].bitmap == 0)
 		return;
@@ -2460,6 +2503,7 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 	if (wn->agg[tid].nframes > (64 - shift))
 		return;
 
+	ni = tap->txa_ni;
 	bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap;
 	for (i = 0; bitmap; i++) {
 		if ((bitmap & 1) == 0) {
@@ -2759,19 +2803,20 @@ static void
 iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
     void *stat)
 {
+	struct iwn_ops *ops = &sc->ops;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct iwn_tx_ring *ring = &sc->txq[qid];
 	struct iwn_tx_data *data;
 	struct mbuf *m;
 	struct iwn_node *wn;
 	struct ieee80211_node *ni;
-	struct ieee80211vap *vap;
 	struct ieee80211_tx_ampdu *tap;
 	uint64_t bitmap;
 	uint32_t *status = stat;
 	uint16_t *aggstatus = stat;
+	uint16_t ssn;
 	uint8_t tid;
-	int bit, i, lastidx, seqno, shift, start;
+	int bit, i, lastidx, *res, seqno, shift, start;
 
 #ifdef NOT_YET
 	if (nframes == 1) {
@@ -2804,27 +2849,32 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 		bitmap |= 1ULL << bit;
 	}
 	tap = sc->qid2tap[qid];
-	if (tap != NULL) {
-		tid = WME_AC_TO_TID(tap->txa_ac);
-		wn = (void *)tap->txa_ni;
-		wn->agg[tid].bitmap = bitmap;
-		wn->agg[tid].startidx = start;
-		wn->agg[tid].nframes = nframes;
+	tid = WME_AC_TO_TID(tap->txa_ac);
+	wn = (void *)tap->txa_ni;
+	wn->agg[tid].bitmap = bitmap;
+	wn->agg[tid].startidx = start;
+	wn->agg[tid].nframes = nframes;
+
+	res = NULL;
+	ssn = 0;
+	if (!IEEE80211_AMPDU_RUNNING(tap)) {
+		res = tap->txa_private;
+		ssn = tap->txa_start & 0xfff;
 	}
 
 	seqno = le32toh(*(status + nframes)) & 0xfff;
 	for (lastidx = (seqno & 0xff); ring->read != lastidx;) {
 		data = &ring->data[ring->read];
 
-		KASSERT(data->ni != NULL, ("no node"));
-
 		/* Unmap and free mbuf. */
 		bus_dmamap_sync(ring->data_dmat, data->map,
 		    BUS_DMASYNC_POSTWRITE);
 		bus_dmamap_unload(ring->data_dmat, data->map);
 		m = data->m, data->m = NULL;
 		ni = data->ni, data->ni = NULL;
-		vap = ni->ni_vap;
+
+		KASSERT(ni != NULL, ("no node"));
+		KASSERT(m != NULL, ("no mbuf"));
 
 		if (m->m_flags & M_TXCB)
 			ieee80211_process_callback(ni, m, 1);
@@ -2836,6 +2886,15 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 		ring->read = (ring->read + 1) % IWN_TX_RING_COUNT;
 	}
 
+	if (ring->queued == 0 && res != NULL) {
+		iwn_nic_lock(sc);
+		ops->ampdu_tx_stop(sc, qid, tid, ssn);
+		iwn_nic_unlock(sc);
+		sc->qid2tap[qid] = NULL;
+		free(res, M_DEVBUF);
+		return;
+	}
+
 	sc->sc_tx_timer = 0;
 	if (ring->queued < IWN_TX_RING_LOMARK) {
 		sc->qfullmsk &= ~(1 << ring->qid);
@@ -3309,18 +3368,20 @@ iwn_tx_data(struct iwn_softc *sc, struct
 		tid = 0;
 	}
 	ac = M_WME_GETAC(m);
-
-	if (IEEE80211_QOS_HAS_SEQ(wh) &&
-	    IEEE80211_AMPDU_RUNNING(&ni->ni_tx_ampdu[ac])) {
+	if (m->m_flags & M_AMPDU_MPDU) {
 		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
 
-		ring = &sc->txq[*(int *)tap->txa_private];
+		if (!IEEE80211_AMPDU_RUNNING(tap)) {
+			m_freem(m);
+			return EINVAL;
+		}
+
+		ac = *(int *)tap->txa_private;
 		*(uint16_t *)wh->i_seq =
 		    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
 		ni->ni_txseqs[tid]++;
-	} else {
-		ring = &sc->txq[ac];
 	}
+	ring = &sc->txq[ac];
 	desc = &ring->desc[ring->cur];
 	data = &ring->data[ring->cur];
 
@@ -5634,6 +5695,8 @@ iwn_ampdu_tx_start(struct ieee80211com *
 	if ((error = iwn_nic_lock(sc)) != 0)
 		return 0;
 	qid = *(int *)tap->txa_private;
+	DPRINTF(sc, IWN_DEBUG_XMIT, "%s: ra=%d tid=%d ssn=%d qid=%d\n",
+	    __func__, wn->id, tid, tap->txa_start, qid);
 	ops->ampdu_tx_start(sc, ni, qid, tid, tap->txa_start & 0xfff);
 	iwn_nic_unlock(sc);
 
@@ -5649,10 +5712,14 @@ iwn_ampdu_tx_stop(struct ieee80211_node 
 	uint8_t tid = WME_AC_TO_TID(tap->txa_ac);
 	int qid;
 
+	sc->sc_addba_stop(ni, tap);
+
 	if (tap->txa_private == NULL)
 		return;
 
 	qid = *(int *)tap->txa_private;
+	if (sc->txq[qid].queued != 0)
+		return;
 	if (iwn_nic_lock(sc) != 0)
 		return;
 	ops->ampdu_tx_stop(sc, qid, tid, tap->txa_start & 0xfff);
@@ -5660,7 +5727,6 @@ iwn_ampdu_tx_stop(struct ieee80211_node 
 	sc->qid2tap[qid] = NULL;
 	free(tap->txa_private, M_DEVBUF);
 	tap->txa_private = NULL;
-	sc->sc_addba_stop(ni, tap);
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207010930.q619UcKb080436>