Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Jun 2012 16:07:01 +0000 (UTC)
From:      Bernhard Schmidt <bschmidt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r237649 - head/sys/dev/iwn
Message-ID:  <201206271607.q5RG71Jg019449@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bschmidt
Date: Wed Jun 27 16:07:01 2012
New Revision: 237649
URL: http://svn.freebsd.org/changeset/base/237649

Log:
  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
  Tested by:	osa@, Brandon Gooch (earlier version),
  		    Bojan Petrovic (earlier version)
  MFC after:	3 days

Modified:
  head/sys/dev/iwn/if_iwn.c

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Wed Jun 27 16:05:09 2012	(r237648)
+++ head/sys/dev/iwn/if_iwn.c	Wed Jun 27 16:07:01 2012	(r237649)
@@ -2432,6 +2432,7 @@ 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;
@@ -2441,8 +2442,9 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 	struct ieee80211_tx_ampdu *tap;
 	struct mbuf *m;
 	uint64_t bitmap;
+	uint16_t ssn;
 	uint8_t tid;
-	int ackfailcnt = 0, i, lastidx, qid, shift;
+	int ackfailcnt = 0, i, lastidx, qid, *res, shift;
 
 	bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
@@ -2452,6 +2454,13 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 	tid = tap->txa_tid;
 	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];
 
@@ -2475,6 +2484,15 @@ iwn_rx_compressed_ba(struct iwn_softc *s
 		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;
 
@@ -2785,6 +2803,7 @@ 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;
@@ -2795,8 +2814,9 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 	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) {
@@ -2829,12 +2849,17 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, 
 		bitmap |= 1ULL << bit;
 	}
 	tap = sc->qid2tap[qid];
-	if (tap != NULL) {
-		tid = tap->txa_tid;
-		wn = (void *)tap->txa_ni;
-		wn->agg[tid].bitmap = bitmap;
-		wn->agg[tid].startidx = start;
-		wn->agg[tid].nframes = nframes;
+	tid = tap->txa_tid;
+	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;
@@ -2861,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);
@@ -5661,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);
 
@@ -5676,10 +5712,14 @@ iwn_ampdu_tx_stop(struct ieee80211_node 
 	uint8_t tid = tap->txa_tid;
 	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);
@@ -5687,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?201206271607.q5RG71Jg019449>