|
|
@@ -0,0 +1,68 @@
|
|
|
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
|
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
|
+@@ -2430,37 +2430,37 @@ void ath_tx_node_init(struct ath_softc *
|
|
|
+
|
|
|
+ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
|
|
+ {
|
|
|
+- int i;
|
|
|
+- struct ath_atx_ac *ac, *ac_tmp;
|
|
|
+- struct ath_atx_tid *tid, *tid_tmp;
|
|
|
++ struct ath_atx_ac *ac;
|
|
|
++ struct ath_atx_tid *tid;
|
|
|
+ struct ath_txq *txq;
|
|
|
++ int i, tidno;
|
|
|
+
|
|
|
+- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
|
|
|
+- if (ATH_TXQ_SETUP(sc, i)) {
|
|
|
+- txq = &sc->tx.txq[i];
|
|
|
+-
|
|
|
+- spin_lock_bh(&txq->axq_lock);
|
|
|
+-
|
|
|
+- list_for_each_entry_safe(ac,
|
|
|
+- ac_tmp, &txq->axq_acq, list) {
|
|
|
+- tid = list_first_entry(&ac->tid_q,
|
|
|
+- struct ath_atx_tid, list);
|
|
|
+- if (tid && tid->an != an)
|
|
|
+- continue;
|
|
|
+- list_del(&ac->list);
|
|
|
+- ac->sched = false;
|
|
|
+-
|
|
|
+- list_for_each_entry_safe(tid,
|
|
|
+- tid_tmp, &ac->tid_q, list) {
|
|
|
+- list_del(&tid->list);
|
|
|
+- tid->sched = false;
|
|
|
+- ath_tid_drain(sc, txq, tid);
|
|
|
+- tid->state &= ~AGGR_ADDBA_COMPLETE;
|
|
|
+- tid->state &= ~AGGR_CLEANUP;
|
|
|
+- }
|
|
|
+- }
|
|
|
++ for (tidno = 0, tid = &an->tid[tidno];
|
|
|
++ tidno < WME_NUM_TID; tidno++, tid++) {
|
|
|
++ i = tid->ac->qnum;
|
|
|
+
|
|
|
+- spin_unlock_bh(&txq->axq_lock);
|
|
|
++ if (!ATH_TXQ_SETUP(sc, i))
|
|
|
++ continue;
|
|
|
++
|
|
|
++ txq = &sc->tx.txq[i];
|
|
|
++ ac = tid->ac;
|
|
|
++
|
|
|
++ spin_lock_bh(&txq->axq_lock);
|
|
|
++
|
|
|
++ if (tid->sched) {
|
|
|
++ list_del(&tid->list);
|
|
|
++ tid->sched = false;
|
|
|
+ }
|
|
|
++
|
|
|
++ if (ac->sched) {
|
|
|
++ list_del(&ac->list);
|
|
|
++ tid->ac->sched = false;
|
|
|
++ }
|
|
|
++
|
|
|
++ ath_tid_drain(sc, txq, tid);
|
|
|
++ tid->state &= ~AGGR_ADDBA_COMPLETE;
|
|
|
++ tid->state &= ~AGGR_CLEANUP;
|
|
|
++
|
|
|
++ spin_unlock_bh(&txq->axq_lock);
|
|
|
+ }
|
|
|
+ }
|