Skip to content

Commit

Permalink
ath9k: fix an issue in ath_atx_tid paused flag management
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lorenzo Bianconi authored and John W. Linville committed Aug 4, 2010
1 parent 824b185 commit 7540184
Showing 1 changed file with 8 additions and 26 deletions.
34 changes: 8 additions & 26 deletions drivers/net/wireless/ath/ath9k/xmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)) {
Expand Down

0 comments on commit 7540184

Please sign in to comment.