diff options
author | Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | 2010-08-01 15:47:32 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-04 15:27:38 -0400 |
commit | 754018494216e07f43c611d342d7d8bd25b22140 (patch) | |
tree | c8918b551fe0a793a3f98ae54415f45f9062e831 /drivers/net/wireless | |
parent | 824b185adf86163e57892f22a878f97bc4bc69ab (diff) |
ath9k: fix an issue in ath_atx_tid paused flag management
I noticed a possible issue in the paused flag management of the
ath_atx_tid data structure. In particular, in a noisy environment and
under heavy load, I observed that the AGGR session establishment could
fail several times consecutively causing values of the paused flag
greater than one for this TID (ath_tx_pause_tid is called more than
once from ath_tx_aggr_start).
Considering that the session for this TID can not be established also
after the mac80211 stack calls the ieee80211_agg_tx_operational() since
the ath_tx_aggr_resume() lowers the paused flag only by one.
This patch also replaces some BUG_ON calls with WARN_ON, as even if
these unlikely conditions happen, it's not fatal enough to justify a
BUG_ON.
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 34 |
1 files changed, 8 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 700ba8dee5a5..4dda14e36227 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -120,26 +120,14 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) list_add_tail(&ac->list, &txq->axq_acq); } -static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -{ - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - - spin_lock_bh(&txq->axq_lock); - tid->paused++; - spin_unlock_bh(&txq->axq_lock); -} - static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - BUG_ON(tid->paused <= 0); - spin_lock_bh(&txq->axq_lock); - - tid->paused--; + WARN_ON(!tid->paused); - if (tid->paused > 0) - goto unlock; + spin_lock_bh(&txq->axq_lock); + tid->paused = false; if (list_empty(&tid->buf_q)) goto unlock; @@ -157,15 +145,10 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - BUG_ON(tid->paused <= 0); - spin_lock_bh(&txq->axq_lock); + WARN_ON(!tid->paused); - tid->paused--; - - if (tid->paused > 0) { - spin_unlock_bh(&txq->axq_lock); - return; - } + spin_lock_bh(&txq->axq_lock); + tid->paused = false; while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); @@ -811,7 +794,7 @@ void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); txtid->state |= AGGR_ADDBA_PROGRESS; - ath_tx_pause_tid(sc, txtid); + txtid->paused = true; *ssn = txtid->seq_start; } @@ -835,10 +818,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return; } - ath_tx_pause_tid(sc, txtid); - /* drop all software retried frames and mark this TID */ spin_lock_bh(&txq->axq_lock); + txtid->paused = true; while (!list_empty(&txtid->buf_q)) { bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); if (!bf_isretried(bf)) { |