From owner-svn-src-stable@FreeBSD.ORG Sun Jul 1 09:30:38 2012 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9614D1065670; Sun, 1 Jul 2012 09:30:38 +0000 (UTC) (envelope-from bschmidt@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7F7FF8FC19; Sun, 1 Jul 2012 09:30:38 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q619Ucns080438; Sun, 1 Jul 2012 09:30:38 GMT (envelope-from bschmidt@svn.freebsd.org) Received: (from bschmidt@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q619UcKb080436; Sun, 1 Jul 2012 09:30:38 GMT (envelope-from bschmidt@svn.freebsd.org) Message-Id: <201207010930.q619UcKb080436@svn.freebsd.org> From: Bernhard Schmidt Date: Sun, 1 Jul 2012 09:30:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r237917 - stable/9/sys/dev/iwn X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 01 Jul 2012 09:30:38 -0000 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