aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c63
1 files changed, 26 insertions, 37 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index d629bfbdfab4..e53433e3e4cc 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
61 struct ath_tx_status *ts, int txok); 61 struct ath_tx_status *ts, int txok);
62static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, 62static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
63 int nbad, int txok, bool update_rc); 63 int nbad, int txok, bool update_rc);
64static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
65 int seqno);
64 66
65enum { 67enum {
66 MCS_HT20, 68 MCS_HT20,
@@ -143,18 +145,23 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
143 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; 145 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
144 struct ath_buf *bf; 146 struct ath_buf *bf;
145 struct list_head bf_head; 147 struct list_head bf_head;
146 INIT_LIST_HEAD(&bf_head); 148 struct ath_tx_status ts;
147 149
148 WARN_ON(!tid->paused); 150 INIT_LIST_HEAD(&bf_head);
149 151
152 memset(&ts, 0, sizeof(ts));
150 spin_lock_bh(&txq->axq_lock); 153 spin_lock_bh(&txq->axq_lock);
151 tid->paused = false;
152 154
153 while (!list_empty(&tid->buf_q)) { 155 while (!list_empty(&tid->buf_q)) {
154 bf = list_first_entry(&tid->buf_q, struct ath_buf, list); 156 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
155 BUG_ON(bf_isretried(bf));
156 list_move_tail(&bf->list, &bf_head); 157 list_move_tail(&bf->list, &bf_head);
157 ath_tx_send_ht_normal(sc, txq, tid, &bf_head); 158
159 if (bf_isretried(bf)) {
160 ath_tx_update_baw(sc, tid, bf->bf_seqno);
161 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
162 } else {
163 ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
164 }
158 } 165 }
159 166
160 spin_unlock_bh(&txq->axq_lock); 167 spin_unlock_bh(&txq->axq_lock);
@@ -429,7 +436,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
429 list_move_tail(&bf->list, &bf_head); 436 list_move_tail(&bf->list, &bf_head);
430 } 437 }
431 438
432 if (!txpending) { 439 if (!txpending || (tid->state & AGGR_CLEANUP)) {
433 /* 440 /*
434 * complete the acked-ones/xretried ones; update 441 * complete the acked-ones/xretried ones; update
435 * block-ack window 442 * block-ack window
@@ -508,15 +515,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
508 } 515 }
509 516
510 if (tid->state & AGGR_CLEANUP) { 517 if (tid->state & AGGR_CLEANUP) {
518 ath_tx_flush_tid(sc, tid);
519
511 if (tid->baw_head == tid->baw_tail) { 520 if (tid->baw_head == tid->baw_tail) {
512 tid->state &= ~AGGR_ADDBA_COMPLETE; 521 tid->state &= ~AGGR_ADDBA_COMPLETE;
513 tid->state &= ~AGGR_CLEANUP; 522 tid->state &= ~AGGR_CLEANUP;
514
515 /* send buffered frames as singles */
516 ath_tx_flush_tid(sc, tid);
517 } 523 }
518 rcu_read_unlock();
519 return;
520 } 524 }
521 525
522 rcu_read_unlock(); 526 rcu_read_unlock();
@@ -807,12 +811,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
807 struct ath_node *an = (struct ath_node *)sta->drv_priv; 811 struct ath_node *an = (struct ath_node *)sta->drv_priv;
808 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); 812 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
809 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; 813 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
810 struct ath_tx_status ts;
811 struct ath_buf *bf;
812 struct list_head bf_head;
813
814 memset(&ts, 0, sizeof(ts));
815 INIT_LIST_HEAD(&bf_head);
816 814
817 if (txtid->state & AGGR_CLEANUP) 815 if (txtid->state & AGGR_CLEANUP)
818 return; 816 return;
@@ -822,31 +820,22 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
822 return; 820 return;
823 } 821 }
824 822
825 /* drop all software retried frames and mark this TID */
826 spin_lock_bh(&txq->axq_lock); 823 spin_lock_bh(&txq->axq_lock);
827 txtid->paused = true; 824 txtid->paused = true;
828 while (!list_empty(&txtid->buf_q)) {
829 bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
830 if (!bf_isretried(bf)) {
831 /*
832 * NB: it's based on the assumption that
833 * software retried frame will always stay
834 * at the head of software queue.
835 */
836 break;
837 }
838 list_move_tail(&bf->list, &bf_head);
839 ath_tx_update_baw(sc, txtid, bf->bf_seqno);
840 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
841 }
842 spin_unlock_bh(&txq->axq_lock);
843 825
844 if (txtid->baw_head != txtid->baw_tail) { 826 /*
827 * If frames are still being transmitted for this TID, they will be
828 * cleaned up during tx completion. To prevent race conditions, this
829 * TID can only be reused after all in-progress subframes have been
830 * completed.
831 */
832 if (txtid->baw_head != txtid->baw_tail)
845 txtid->state |= AGGR_CLEANUP; 833 txtid->state |= AGGR_CLEANUP;
846 } else { 834 else
847 txtid->state &= ~AGGR_ADDBA_COMPLETE; 835 txtid->state &= ~AGGR_ADDBA_COMPLETE;
848 ath_tx_flush_tid(sc, txtid); 836 spin_unlock_bh(&txq->axq_lock);
849 } 837
838 ath_tx_flush_tid(sc, txtid);
850} 839}
851 840
852void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) 841void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)