ath9k: clean up tx fifo handling on ar9380 based hardware
[librecmc/librecmc.git] / package / mac80211 / patches / 580-ath9k_tx_fifo_cleanup.patch
1 --- a/drivers/net/wireless/ath/ath9k/xmit.c
2 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
3 @@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct a
4                                 struct ath_txq *txq, struct list_head *bf_q,
5                                 struct ath_tx_status *ts, int txok, int sendbar);
6  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
7 -                            struct list_head *head);
8 +                            struct list_head *head, bool internal);
9  static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
10  static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
11                              struct ath_tx_status *ts, int nframes, int nbad,
12 @@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct 
13                         bf_next = bf->bf_next;
14  
15                         bf->bf_state.bf_type |= BUF_XRETRY;
16 -                       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
17 -                           !bf->bf_stale || bf_next != NULL)
18 +                       if (!bf->bf_stale || bf_next != NULL)
19                                 list_move_tail(&bf->list, &bf_head);
20  
21                         ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
22 @@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct 
23                         }
24                 }
25  
26 -               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
27 -                   bf_next == NULL) {
28 -                       /*
29 -                        * Make sure the last desc is reclaimed if it
30 -                        * not a holding desc.
31 -                        */
32 -                       if (!bf_last->bf_stale)
33 -                               list_move_tail(&bf->list, &bf_head);
34 -                       else
35 -                               INIT_LIST_HEAD(&bf_head);
36 -               } else {
37 -                       BUG_ON(list_empty(bf_q));
38 +               /*
39 +                * Make sure the last desc is reclaimed if it
40 +                * not a holding desc.
41 +                */
42 +               if (!bf_last->bf_stale || bf_next != NULL)
43                         list_move_tail(&bf->list, &bf_head);
44 -               }
45 +               else
46 +                       INIT_LIST_HEAD(&bf_head);
47  
48                 if (!txpending || (tid->state & AGGR_CLEANUP)) {
49                         /*
50 @@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath
51                         bf->bf_state.bf_type &= ~BUF_AGGR;
52                         ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
53                         ath_buf_set_rate(sc, bf, fi->framelen);
54 -                       ath_tx_txqaddbuf(sc, txq, &bf_q);
55 +                       ath_tx_txqaddbuf(sc, txq, &bf_q, false);
56                         continue;
57                 }
58  
59 @@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath
60                 /* anchor last desc of aggregate */
61                 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
62  
63 -               ath_tx_txqaddbuf(sc, txq, &bf_q);
64 +               ath_tx_txqaddbuf(sc, txq, &bf_q, false);
65                 TX_STAT_INC(txq->axq_qnum, a_aggr);
66  
67         } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
68 @@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath
69                 txq->txq_headidx = txq->txq_tailidx = 0;
70                 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
71                         INIT_LIST_HEAD(&txq->txq_fifo[i]);
72 -               INIT_LIST_HEAD(&txq->txq_fifo_pending);
73         }
74         return &sc->tx.txq[axq_qnum];
75  }
76 @@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(stru
77      return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
78  }
79  
80 -/*
81 - * Drain a given TX queue (could be Beacon or Data)
82 - *
83 - * This assumes output has been stopped and
84 - * we do not need to block ath_tx_tasklet.
85 - */
86 -void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
87 +static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
88 +                              struct list_head *list, bool retry_tx)
89  {
90         struct ath_buf *bf, *lastbf;
91         struct list_head bf_head;
92 @@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, 
93         memset(&ts, 0, sizeof(ts));
94         INIT_LIST_HEAD(&bf_head);
95  
96 -       for (;;) {
97 -               spin_lock_bh(&txq->axq_lock);
98 +       while (!list_empty(list)) {
99 +               bf = list_first_entry(list, struct ath_buf, list);
100  
101 -               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
102 -                       if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
103 -                               txq->txq_headidx = txq->txq_tailidx = 0;
104 -                               spin_unlock_bh(&txq->axq_lock);
105 -                               break;
106 -                       } else {
107 -                               bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
108 -                                                     struct ath_buf, list);
109 -                       }
110 -               } else {
111 -                       if (list_empty(&txq->axq_q)) {
112 -                               txq->axq_link = NULL;
113 -                               spin_unlock_bh(&txq->axq_lock);
114 -                               break;
115 -                       }
116 -                       bf = list_first_entry(&txq->axq_q, struct ath_buf,
117 -                                             list);
118 -
119 -                       if (bf->bf_stale) {
120 -                               list_del(&bf->list);
121 -                               spin_unlock_bh(&txq->axq_lock);
122 +               if (bf->bf_stale) {
123 +                       list_del(&bf->list);
124  
125 -                               ath_tx_return_buffer(sc, bf);
126 -                               continue;
127 -                       }
128 +                       ath_tx_return_buffer(sc, bf);
129 +                       continue;
130                 }
131  
132                 lastbf = bf->bf_lastbf;
133 -
134 -               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
135 -                       list_cut_position(&bf_head,
136 -                                         &txq->txq_fifo[txq->txq_tailidx],
137 -                                         &lastbf->list);
138 -                       INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
139 -               } else {
140 -                       /* remove ath_buf's of the same mpdu from txq */
141 -                       list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
142 -               }
143 +               list_cut_position(&bf_head, list, &lastbf->list);
144  
145                 txq->axq_depth--;
146                 if (bf_is_ampdu_not_probing(bf))
147                         txq->axq_ampdu_depth--;
148 -               spin_unlock_bh(&txq->axq_lock);
149  
150 +               spin_unlock_bh(&txq->axq_lock);
151                 if (bf_isampdu(bf))
152                         ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
153                                              retry_tx);
154                 else
155                         ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
156 +               spin_lock_bh(&txq->axq_lock);
157         }
158 +}
159  
160 +/*
161 + * Drain a given TX queue (could be Beacon or Data)
162 + *
163 + * This assumes output has been stopped and
164 + * we do not need to block ath_tx_tasklet.
165 + */
166 +void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
167 +{
168         spin_lock_bh(&txq->axq_lock);
169 -       txq->axq_tx_inprogress = false;
170 -       spin_unlock_bh(&txq->axq_lock);
171 -
172         if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
173 -               spin_lock_bh(&txq->axq_lock);
174 -               while (!list_empty(&txq->txq_fifo_pending)) {
175 -                       bf = list_first_entry(&txq->txq_fifo_pending,
176 -                                             struct ath_buf, list);
177 -                       list_cut_position(&bf_head,
178 -                                         &txq->txq_fifo_pending,
179 -                                         &bf->bf_lastbf->list);
180 -                       spin_unlock_bh(&txq->axq_lock);
181 +               int idx = txq->txq_tailidx;
182  
183 -                       if (bf_isampdu(bf))
184 -                               ath_tx_complete_aggr(sc, txq, bf, &bf_head,
185 -                                                    &ts, 0, retry_tx);
186 -                       else
187 -                               ath_tx_complete_buf(sc, bf, txq, &bf_head,
188 -                                                   &ts, 0, 0);
189 -                       spin_lock_bh(&txq->axq_lock);
190 +               while (!list_empty(&txq->txq_fifo[idx])) {
191 +                       ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
192 +                                          retry_tx);
193 +
194 +                       INCR(idx, ATH_TXFIFO_DEPTH);
195                 }
196 -               spin_unlock_bh(&txq->axq_lock);
197 +               txq->txq_tailidx = idx;
198         }
199  
200 +       txq->axq_link = NULL;
201 +       txq->axq_tx_inprogress = false;
202 +       ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
203 +
204         /* flush any pending frames if aggregation is enabled */
205 -       if (sc->sc_flags & SC_OP_TXAGGR) {
206 -               if (!retry_tx) {
207 -                       spin_lock_bh(&txq->axq_lock);
208 -                       ath_txq_drain_pending_buffers(sc, txq);
209 -                       spin_unlock_bh(&txq->axq_lock);
210 -               }
211 -       }
212 +       if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
213 +               ath_txq_drain_pending_buffers(sc, txq);
214 +
215 +       spin_unlock_bh(&txq->axq_lock);
216  }
217  
218  bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
219 @@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *
220   * assume the descriptors are already chained together by caller.
221   */
222  static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
223 -                            struct list_head *head)
224 +                            struct list_head *head, bool internal)
225  {
226         struct ath_hw *ah = sc->sc_ah;
227         struct ath_common *common = ath9k_hw_common(ah);
228 -       struct ath_buf *bf;
229 +       struct ath_buf *bf, *bf_last;
230 +       bool puttxbuf = false;
231 +       bool edma;
232  
233         /*
234          * Insert the frame on the outbound list and
235 @@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_
236         if (list_empty(head))
237                 return;
238  
239 +       edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
240         bf = list_first_entry(head, struct ath_buf, list);
241 +       bf_last = list_entry(head->prev, struct ath_buf, list);
242  
243         ath_dbg(common, ATH_DBG_QUEUE,
244                 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
245  
246 -       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
247 -               if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
248 -                       list_splice_tail_init(head, &txq->txq_fifo_pending);
249 -                       return;
250 -               }
251 -               if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
252 -                       ath_dbg(common, ATH_DBG_XMIT,
253 -                               "Initializing tx fifo %d which is non-empty\n",
254 -                               txq->txq_headidx);
255 -               INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
256 -               list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
257 +       if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
258 +               list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
259                 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
260 -               TX_STAT_INC(txq->axq_qnum, puttxbuf);
261 -               ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
262 -               ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
263 -                       txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
264 +               puttxbuf = true;
265         } else {
266                 list_splice_tail_init(head, &txq->axq_q);
267  
268 -               if (txq->axq_link == NULL) {
269 -                       TX_STAT_INC(txq->axq_qnum, puttxbuf);
270 -                       ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
271 -                       ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
272 -                               txq->axq_qnum, ito64(bf->bf_daddr),
273 -                               bf->bf_desc);
274 -               } else {
275 -                       *txq->axq_link = bf->bf_daddr;
276 +               if (txq->axq_link) {
277 +                       ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
278                         ath_dbg(common, ATH_DBG_XMIT,
279                                 "link[%u] (%p)=%llx (%p)\n",
280                                 txq->axq_qnum, txq->axq_link,
281                                 ito64(bf->bf_daddr), bf->bf_desc);
282 -               }
283 -               ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
284 -                                      &txq->axq_link);
285 +               } else if (!edma)
286 +                       puttxbuf = true;
287 +
288 +               txq->axq_link = bf_last->bf_desc;
289 +       }
290 +
291 +       if (puttxbuf) {
292 +               TX_STAT_INC(txq->axq_qnum, puttxbuf);
293 +               ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
294 +               ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
295 +                       txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
296 +       }
297 +
298 +       if (!edma) {
299                 TX_STAT_INC(txq->axq_qnum, txstart);
300                 ath9k_hw_txstart(ah, txq->axq_qnum);
301         }
302 -       txq->axq_depth++;
303 -       if (bf_is_ampdu_not_probing(bf))
304 -               txq->axq_ampdu_depth++;
305 +
306 +       if (!internal) {
307 +               txq->axq_depth++;
308 +               if (bf_is_ampdu_not_probing(bf))
309 +                       txq->axq_ampdu_depth++;
310 +       }
311  }
312  
313  static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
314 @@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath
315         TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
316         bf->bf_lastbf = bf;
317         ath_buf_set_rate(sc, bf, fi->framelen);
318 -       ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
319 +       ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
320  }
321  
322  static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
323 @@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct at
324         bf->bf_lastbf = bf;
325         fi = get_frame_info(bf->bf_mpdu);
326         ath_buf_set_rate(sc, bf, fi->framelen);
327 -       ath_tx_txqaddbuf(sc, txq, bf_head);
328 +       ath_tx_txqaddbuf(sc, txq, bf_head, false);
329         TX_STAT_INC(txq->axq_qnum, queued);
330  }
331  
332 @@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_
333         tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
334  }
335  
336 +static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
337 +                                 struct ath_tx_status *ts, struct ath_buf *bf,
338 +                                 struct list_head *bf_head)
339 +{
340 +       int txok;
341 +
342 +       txq->axq_depth--;
343 +       txok = !(ts->ts_status & ATH9K_TXERR_MASK);
344 +       txq->axq_tx_inprogress = false;
345 +       if (bf_is_ampdu_not_probing(bf))
346 +               txq->axq_ampdu_depth--;
347 +
348 +       spin_unlock_bh(&txq->axq_lock);
349 +
350 +       if (!bf_isampdu(bf)) {
351 +               /*
352 +                * This frame is sent out as a single frame.
353 +                * Use hardware retry status for this frame.
354 +                */
355 +               if (ts->ts_status & ATH9K_TXERR_XRETRY)
356 +                       bf->bf_state.bf_type |= BUF_XRETRY;
357 +               ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
358 +               ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
359 +       } else
360 +               ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
361 +
362 +       spin_lock_bh(&txq->axq_lock);
363 +
364 +       if (sc->sc_flags & SC_OP_TXAGGR)
365 +               ath_txq_schedule(sc, txq);
366 +}
367 +
368  static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
369  {
370         struct ath_hw *ah = sc->sc_ah;
371 @@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_s
372         struct list_head bf_head;
373         struct ath_desc *ds;
374         struct ath_tx_status ts;
375 -       int txok;
376         int status;
377  
378         ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
379                 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
380                 txq->axq_link);
381  
382 +       spin_lock_bh(&txq->axq_lock);
383         for (;;) {
384 -               spin_lock_bh(&txq->axq_lock);
385                 if (list_empty(&txq->axq_q)) {
386                         txq->axq_link = NULL;
387                         if (sc->sc_flags & SC_OP_TXAGGR)
388                                 ath_txq_schedule(sc, txq);
389 -                       spin_unlock_bh(&txq->axq_lock);
390                         break;
391                 }
392                 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
393 @@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_s
394                 bf_held = NULL;
395                 if (bf->bf_stale) {
396                         bf_held = bf;
397 -                       if (list_is_last(&bf_held->list, &txq->axq_q)) {
398 -                               spin_unlock_bh(&txq->axq_lock);
399 +                       if (list_is_last(&bf_held->list, &txq->axq_q))
400                                 break;
401 -                       } else {
402 -                               bf = list_entry(bf_held->list.next,
403 -                                               struct ath_buf, list);
404 -                       }
405 +
406 +                       bf = list_entry(bf_held->list.next, struct ath_buf,
407 +                                       list);
408                 }
409  
410                 lastbf = bf->bf_lastbf;
411 @@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_s
412  
413                 memset(&ts, 0, sizeof(ts));
414                 status = ath9k_hw_txprocdesc(ah, ds, &ts);
415 -               if (status == -EINPROGRESS) {
416 -                       spin_unlock_bh(&txq->axq_lock);
417 +               if (status == -EINPROGRESS)
418                         break;
419 -               }
420 +
421                 TX_STAT_INC(txq->axq_qnum, txprocdesc);
422  
423                 /*
424 @@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_s
425                         list_cut_position(&bf_head,
426                                 &txq->axq_q, lastbf->list.prev);
427  
428 -               txq->axq_depth--;
429 -               txok = !(ts.ts_status & ATH9K_TXERR_MASK);
430 -               txq->axq_tx_inprogress = false;
431 -               if (bf_held)
432 +               if (bf_held) {
433                         list_del(&bf_held->list);
434 -
435 -               if (bf_is_ampdu_not_probing(bf))
436 -                       txq->axq_ampdu_depth--;
437 -
438 -               spin_unlock_bh(&txq->axq_lock);
439 -
440 -               if (bf_held)
441                         ath_tx_return_buffer(sc, bf_held);
442 -
443 -               if (!bf_isampdu(bf)) {
444 -                       /*
445 -                        * This frame is sent out as a single frame.
446 -                        * Use hardware retry status for this frame.
447 -                        */
448 -                       if (ts.ts_status & ATH9K_TXERR_XRETRY)
449 -                               bf->bf_state.bf_type |= BUF_XRETRY;
450 -                       ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
451                 }
452  
453 -               if (bf_isampdu(bf))
454 -                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
455 -                                            true);
456 -               else
457 -                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
458 -
459 -               spin_lock_bh(&txq->axq_lock);
460 -
461 -               if (sc->sc_flags & SC_OP_TXAGGR)
462 -                       ath_txq_schedule(sc, txq);
463 -               spin_unlock_bh(&txq->axq_lock);
464 +               ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
465         }
466 +       spin_unlock_bh(&txq->axq_lock);
467  }
468  
469  static void ath_tx_complete_poll_work(struct work_struct *work)
470 @@ -2237,17 +2193,17 @@ void ath_tx_tasklet(struct ath_softc *sc
471  
472  void ath_tx_edma_tasklet(struct ath_softc *sc)
473  {
474 -       struct ath_tx_status txs;
475 +       struct ath_tx_status ts;
476         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
477         struct ath_hw *ah = sc->sc_ah;
478         struct ath_txq *txq;
479         struct ath_buf *bf, *lastbf;
480         struct list_head bf_head;
481         int status;
482 -       int txok;
483  
484 +       spin_lock_bh(&txq->axq_lock);
485         for (;;) {
486 -               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
487 +               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
488                 if (status == -EINPROGRESS)
489                         break;
490                 if (status == -EIO) {
491 @@ -2257,16 +2213,16 @@ void ath_tx_edma_tasklet(struct ath_soft
492                 }
493  
494                 /* Skip beacon completions */
495 -               if (txs.qid == sc->beacon.beaconq)
496 +               if (ts.qid == sc->beacon.beaconq)
497                         continue;
498  
499 -               txq = &sc->tx.txq[txs.qid];
500 +               ath_dbg(common, ATH_DBG_XMIT,
501 +                       "Tx status, descid=%04x\n", ts.desc_id);
502  
503 -               spin_lock_bh(&txq->axq_lock);
504 -               if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
505 -                       spin_unlock_bh(&txq->axq_lock);
506 -                       return;
507 -               }
508 +               txq = &sc->tx.txq[ts.qid];
509 +
510 +               if (list_empty(&txq->txq_fifo[txq->txq_tailidx]))
511 +                       break;
512  
513                 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
514                                       struct ath_buf, list);
515 @@ -2275,43 +2231,24 @@ void ath_tx_edma_tasklet(struct ath_soft
516                 INIT_LIST_HEAD(&bf_head);
517                 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
518                                   &lastbf->list);
519 -               INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
520 -               txq->axq_depth--;
521 -               txq->axq_tx_inprogress = false;
522 -               if (bf_is_ampdu_not_probing(bf))
523 -                       txq->axq_ampdu_depth--;
524 -               spin_unlock_bh(&txq->axq_lock);
525  
526 -               txok = !(txs.ts_status & ATH9K_TXERR_MASK);
527 +               if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
528 +                       INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
529  
530 -               if (!bf_isampdu(bf)) {
531 -                       if (txs.ts_status & ATH9K_TXERR_XRETRY)
532 -                               bf->bf_state.bf_type |= BUF_XRETRY;
533 -                       ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
534 -               }
535 +                       if (!list_empty(&txq->axq_q)) {
536 +                               struct list_head bf_q;
537  
538 -               if (bf_isampdu(bf))
539 -                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
540 -                                            txok, true);
541 -               else
542 -                       ath_tx_complete_buf(sc, bf, txq, &bf_head,
543 -                                           &txs, txok, 0);
544 -
545 -               spin_lock_bh(&txq->axq_lock);
546 +                               INIT_LIST_HEAD(&bf_q);
547 +                               txq->axq_link = NULL;
548 +                               list_splice_tail_init(&txq->axq_q, &bf_q);
549 +                               ath_tx_txqaddbuf(sc, txq, &bf_q, true);
550 +                       }
551 +               }
552  
553 -               if (!list_empty(&txq->txq_fifo_pending)) {
554 -                       INIT_LIST_HEAD(&bf_head);
555 -                       bf = list_first_entry(&txq->txq_fifo_pending,
556 -                                             struct ath_buf, list);
557 -                       list_cut_position(&bf_head,
558 -                                         &txq->txq_fifo_pending,
559 -                                         &bf->bf_lastbf->list);
560 -                       ath_tx_txqaddbuf(sc, txq, &bf_head);
561 -               } else if (sc->sc_flags & SC_OP_TXAGGR)
562 -                       ath_txq_schedule(sc, txq);
563 +               ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
564  
565 -               spin_unlock_bh(&txq->axq_lock);
566         }
567 +       spin_unlock_bh(&txq->axq_lock);
568  }
569  
570  /*****************/
571 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
572 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
573 @@ -179,7 +179,7 @@ enum ATH_AGGR_STATUS {
574  struct ath_txq {
575         int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
576         u32 axq_qnum; /* ath9k hardware queue number */
577 -       u32 *axq_link;
578 +       void *axq_link;
579         struct list_head axq_q;
580         spinlock_t axq_lock;
581         u32 axq_depth;
582 @@ -188,7 +188,6 @@ struct ath_txq {
583         bool axq_tx_inprogress;
584         struct list_head axq_acq;
585         struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
586 -       struct list_head txq_fifo_pending;
587         u8 txq_headidx;
588         u8 txq_tailidx;
589         int pending_frames;
590 --- a/drivers/net/wireless/ath/ath9k/main.c
591 +++ b/drivers/net/wireless/ath/ath9k/main.c
592 @@ -62,8 +62,6 @@ static bool ath9k_has_pending_frames(str
593  
594         if (txq->axq_depth || !list_empty(&txq->axq_acq))
595                 pending = true;
596 -       else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
597 -               pending = !list_empty(&txq->txq_fifo_pending);
598  
599         spin_unlock_bh(&txq->axq_lock);
600         return pending;
601 --- a/drivers/net/wireless/ath/ath9k/debug.c
602 +++ b/drivers/net/wireless/ath/ath9k/debug.c
603 @@ -586,7 +586,6 @@ static ssize_t read_file_xmit(struct fil
604  
605         PRQLE("axq_q empty:       ", axq_q);
606         PRQLE("axq_acq empty:     ", axq_acq);
607 -       PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
608         for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
609                 snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
610                 PRQLE(tmp, txq_fifo[i]);