ath9k: fix an issue in ath_atx_tid paused flag management
PATCH 1/1 ath9k: fix an issue in ath_atx_tid paused flag management
From: Lorenzo Bianconi <[email protected]>
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.
---
drivers/net/wireless/ath/ath9k/xmit.c +8 -26
@@ -120,26 +120,14 @@ static void ath_tx_queue_tid(struct ath_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_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 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 *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)) {