6fdd42f8f2e960893897074709d744615ec7e429
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 522-ath9k_aggr_flush.patch
1 --- a/drivers/net/wireless/ath/ath9k/xmit.c
2 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
3 @@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath
4 struct ath_tx_status *ts, int txok);
5 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
6 int nbad, int txok, bool update_rc);
7 +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
8 + int seqno);
9
10 enum {
11 MCS_HT20,
12 @@ -144,18 +146,23 @@ static void ath_tx_flush_tid(struct ath_
13 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
14 struct ath_buf *bf;
15 struct list_head bf_head;
16 - INIT_LIST_HEAD(&bf_head);
17 + struct ath_tx_status ts;
18
19 - WARN_ON(!tid->paused);
20 + INIT_LIST_HEAD(&bf_head);
21
22 + memset(&ts, 0, sizeof(ts));
23 spin_lock_bh(&txq->axq_lock);
24 - tid->paused = false;
25
26 while (!list_empty(&tid->buf_q)) {
27 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
28 - BUG_ON(bf_isretried(bf));
29 list_move_tail(&bf->list, &bf_head);
30 - ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
31 +
32 + if (bf_isretried(bf)) {
33 + ath_tx_update_baw(sc, tid, bf->bf_seqno);
34 + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
35 + } else {
36 + ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
37 + }
38 }
39
40 spin_unlock_bh(&txq->axq_lock);
41 @@ -430,7 +437,7 @@ static void ath_tx_complete_aggr(struct
42 list_move_tail(&bf->list, &bf_head);
43 }
44
45 - if (!txpending) {
46 + if (!txpending || (tid->state & AGGR_CLEANUP)) {
47 /*
48 * complete the acked-ones/xretried ones; update
49 * block-ack window
50 @@ -451,6 +458,7 @@ static void ath_tx_complete_aggr(struct
51 !txfail, sendbar);
52 } else {
53 /* retry the un-acked ones */
54 +
55 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
56 if (bf->bf_next == NULL && bf_last->bf_stale) {
57 struct ath_buf *tbf;
58 @@ -509,15 +517,12 @@ static void ath_tx_complete_aggr(struct
59 }
60
61 if (tid->state & AGGR_CLEANUP) {
62 + ath_tx_flush_tid(sc, tid);
63 +
64 if (tid->baw_head == tid->baw_tail) {
65 tid->state &= ~AGGR_ADDBA_COMPLETE;
66 tid->state &= ~AGGR_CLEANUP;
67 -
68 - /* send buffered frames as singles */
69 - ath_tx_flush_tid(sc, tid);
70 }
71 - rcu_read_unlock();
72 - return;
73 }
74
75 rcu_read_unlock();
76 @@ -808,12 +813,6 @@ void ath_tx_aggr_stop(struct ath_softc *
77 struct ath_node *an = (struct ath_node *)sta->drv_priv;
78 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
79 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
80 - struct ath_tx_status ts;
81 - struct ath_buf *bf;
82 - struct list_head bf_head;
83 -
84 - memset(&ts, 0, sizeof(ts));
85 - INIT_LIST_HEAD(&bf_head);
86
87 if (txtid->state & AGGR_CLEANUP)
88 return;
89 @@ -823,31 +822,22 @@ void ath_tx_aggr_stop(struct ath_softc *
90 return;
91 }
92
93 - /* drop all software retried frames and mark this TID */
94 spin_lock_bh(&txq->axq_lock);
95 txtid->paused = true;
96 - while (!list_empty(&txtid->buf_q)) {
97 - bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
98 - if (!bf_isretried(bf)) {
99 - /*
100 - * NB: it's based on the assumption that
101 - * software retried frame will always stay
102 - * at the head of software queue.
103 - */
104 - break;
105 - }
106 - list_move_tail(&bf->list, &bf_head);
107 - ath_tx_update_baw(sc, txtid, bf->bf_seqno);
108 - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
109 - }
110 - spin_unlock_bh(&txq->axq_lock);
111
112 - if (txtid->baw_head != txtid->baw_tail) {
113 + /*
114 + * If frames are still being transmitted for this TID, they will be
115 + * cleaned up during tx completion. To prevent race conditions, this
116 + * TID can only be reused after all in-progress subframes have been
117 + * completed.
118 + */
119 + if (txtid->baw_head != txtid->baw_tail)
120 txtid->state |= AGGR_CLEANUP;
121 - } else {
122 + else
123 txtid->state &= ~AGGR_ADDBA_COMPLETE;
124 - ath_tx_flush_tid(sc, txtid);
125 - }
126 + spin_unlock_bh(&txq->axq_lock);
127 +
128 + ath_tx_flush_tid(sc, txtid);
129 }
130
131 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)