6fdd42f8f2e960893897074709d744615ec7e429
[openwrt.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)