diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 63 |
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); |
62 | static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, | 62 | static 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); |
64 | static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, | ||
65 | int seqno); | ||
64 | 66 | ||
65 | enum { | 67 | enum { |
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 | ||
852 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) | 841 | void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) |