blob: 4d571394c7a82523404db2d9ae3ef0ba0af760c6 [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2008-2011 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Alexey Dobriyanb7f080c2011-06-16 11:01:34 +000017#include <linux/dma-mapping.h>
Sujith394cf0a2009-02-09 13:26:54 +053018#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040019#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070020
21#define BITS_PER_BYTE 8
22#define OFDM_PLCP_BITS 22
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070023#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
24#define L_STF 8
25#define L_LTF 8
26#define L_SIG 4
27#define HT_SIG 8
28#define HT_STF 4
29#define HT_LTF(_ns) (4 * (_ns))
30#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
31#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
32#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
33#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
34
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070035
Felix Fietkauc6663872010-04-19 19:57:33 +020036static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070037 /* 20MHz 40MHz */
38 { 26, 54 }, /* 0: BPSK */
39 { 52, 108 }, /* 1: QPSK 1/2 */
40 { 78, 162 }, /* 2: QPSK 3/4 */
41 { 104, 216 }, /* 3: 16-QAM 1/2 */
42 { 156, 324 }, /* 4: 16-QAM 3/4 */
43 { 208, 432 }, /* 5: 64-QAM 2/3 */
44 { 234, 486 }, /* 6: 64-QAM 3/4 */
45 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070046};
47
48#define IS_HT_RATE(_rate) ((_rate) & 0x80)
49
Felix Fietkau82b873a2010-11-11 03:18:37 +010050static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau44f1d262011-08-28 00:32:25 +020051 struct ath_atx_tid *tid, struct sk_buff *skb);
52static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
53 int tx_flags, struct ath_txq *txq);
Sujithe8324352009-01-16 21:38:42 +053054static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070055 struct ath_txq *txq, struct list_head *bf_q,
Felix Fietkau156369f2011-12-14 22:08:04 +010056 struct ath_tx_status *ts, int txok);
Sujithe8324352009-01-16 21:38:42 +053057static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +020058 struct list_head *head, bool internal);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +010059static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
60 struct ath_tx_status *ts, int nframes, int nbad,
Felix Fietkau3afd21e2011-09-14 21:24:26 +020061 int txok);
Felix Fietkau90fa5392010-09-20 13:45:38 +020062static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
63 int seqno);
Felix Fietkau44f1d262011-08-28 00:32:25 +020064static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
65 struct ath_txq *txq,
66 struct ath_atx_tid *tid,
Felix Fietkau81357a22012-05-24 14:32:20 +020067 struct sk_buff *skb,
68 bool dequeue);
Sujithe8324352009-01-16 21:38:42 +053069
Felix Fietkau545750d2009-11-23 22:21:01 +010070enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020071 MCS_HT20,
72 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010073 MCS_HT40,
74 MCS_HT40_SGI,
75};
76
Felix Fietkau0e668cd2010-04-19 19:57:32 +020077static int ath_max_4ms_framelen[4][32] = {
78 [MCS_HT20] = {
79 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
80 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
81 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
82 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
83 },
84 [MCS_HT20_SGI] = {
85 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
86 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
87 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
88 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010089 },
90 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020091 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
92 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
93 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
94 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010095 },
96 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020097 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
98 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
99 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
100 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +0100101 }
102};
103
Sujithe8324352009-01-16 21:38:42 +0530104/*********************/
105/* Aggregation logic */
106/*********************/
107
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100108static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguez1512a482011-12-20 10:46:09 -0800109 __acquires(&txq->axq_lock)
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100110{
111 spin_lock_bh(&txq->axq_lock);
112}
113
114static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguez1512a482011-12-20 10:46:09 -0800115 __releases(&txq->axq_lock)
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100116{
117 spin_unlock_bh(&txq->axq_lock);
118}
119
120static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguez1512a482011-12-20 10:46:09 -0800121 __releases(&txq->axq_lock)
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100122{
123 struct sk_buff_head q;
124 struct sk_buff *skb;
125
126 __skb_queue_head_init(&q);
127 skb_queue_splice_init(&txq->complete_q, &q);
128 spin_unlock_bh(&txq->axq_lock);
129
130 while ((skb = __skb_dequeue(&q)))
131 ieee80211_tx_status(sc->hw, skb);
132}
133
Sujithe8324352009-01-16 21:38:42 +0530134static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
135{
136 struct ath_atx_ac *ac = tid->ac;
137
138 if (tid->paused)
139 return;
140
141 if (tid->sched)
142 return;
143
144 tid->sched = true;
145 list_add_tail(&tid->list, &ac->tid_q);
146
147 if (ac->sched)
148 return;
149
150 ac->sched = true;
151 list_add_tail(&ac->list, &txq->axq_acq);
152}
153
Sujithe8324352009-01-16 21:38:42 +0530154static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
155{
Felix Fietkau066dae92010-11-07 14:59:39 +0100156 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530157
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200158 WARN_ON(!tid->paused);
159
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100160 ath_txq_lock(sc, txq);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200161 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530162
Felix Fietkau56dc6332011-08-28 00:32:22 +0200163 if (skb_queue_empty(&tid->buf_q))
Sujithe8324352009-01-16 21:38:42 +0530164 goto unlock;
165
166 ath_tx_queue_tid(txq, tid);
167 ath_txq_schedule(sc, txq);
168unlock:
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100169 ath_txq_unlock_complete(sc, txq);
Sujithe8324352009-01-16 21:38:42 +0530170}
171
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100172static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
Felix Fietkau76e45222010-11-14 15:20:08 +0100173{
174 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100175 BUILD_BUG_ON(sizeof(struct ath_frame_info) >
176 sizeof(tx_info->rate_driver_data));
177 return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
Felix Fietkau76e45222010-11-14 15:20:08 +0100178}
179
Felix Fietkau156369f2011-12-14 22:08:04 +0100180static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno)
181{
182 ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno,
183 seqno << IEEE80211_SEQ_SEQ_SHIFT);
184}
185
Sujithe8324352009-01-16 21:38:42 +0530186static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
187{
Felix Fietkau066dae92010-11-07 14:59:39 +0100188 struct ath_txq *txq = tid->ac->txq;
Felix Fietkau56dc6332011-08-28 00:32:22 +0200189 struct sk_buff *skb;
Sujithe8324352009-01-16 21:38:42 +0530190 struct ath_buf *bf;
191 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200192 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100193 struct ath_frame_info *fi;
Felix Fietkau156369f2011-12-14 22:08:04 +0100194 bool sendbar = false;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200195
Sujithe8324352009-01-16 21:38:42 +0530196 INIT_LIST_HEAD(&bf_head);
197
Felix Fietkau90fa5392010-09-20 13:45:38 +0200198 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530199
Felix Fietkau56dc6332011-08-28 00:32:22 +0200200 while ((skb = __skb_dequeue(&tid->buf_q))) {
201 fi = get_frame_info(skb);
202 bf = fi->bf;
203
Felix Fietkau44f1d262011-08-28 00:32:25 +0200204 if (bf && fi->retries) {
205 list_add_tail(&bf->list, &bf_head);
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200206 ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
Felix Fietkau156369f2011-12-14 22:08:04 +0100207 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
208 sendbar = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200209 } else {
Felix Fietkau44f1d262011-08-28 00:32:25 +0200210 ath_tx_send_normal(sc, txq, NULL, skb);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200211 }
Sujithe8324352009-01-16 21:38:42 +0530212 }
213
Nikolay Martynov4eb287a2011-11-21 17:32:06 -0500214 if (tid->baw_head == tid->baw_tail) {
215 tid->state &= ~AGGR_ADDBA_COMPLETE;
216 tid->state &= ~AGGR_CLEANUP;
217 }
218
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100219 if (sendbar) {
220 ath_txq_unlock(sc, txq);
Felix Fietkau156369f2011-12-14 22:08:04 +0100221 ath_send_bar(tid, tid->seq_start);
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100222 ath_txq_lock(sc, txq);
223 }
Sujithe8324352009-01-16 21:38:42 +0530224}
225
226static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
227 int seqno)
228{
229 int index, cindex;
230
231 index = ATH_BA_INDEX(tid->seq_start, seqno);
232 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
233
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200234 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530235
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200236 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530237 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
238 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
Felix Fietkauf9437542011-12-14 22:08:08 +0100239 if (tid->bar_index >= 0)
240 tid->bar_index--;
Sujithe8324352009-01-16 21:38:42 +0530241 }
242}
243
244static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100245 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530246{
247 int index, cindex;
248
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100249 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530250 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200251 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530252
253 if (index >= ((tid->baw_tail - tid->baw_head) &
254 (ATH_TID_MAX_BUFS - 1))) {
255 tid->baw_tail = cindex;
256 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
257 }
258}
259
260/*
261 * TODO: For frame(s) that are in the retry state, we will reuse the
262 * sequence number(s) without setting the retry bit. The
263 * alternative is to give up on these and BAR the receiver's window
264 * forward.
265 */
266static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
267 struct ath_atx_tid *tid)
268
269{
Felix Fietkau56dc6332011-08-28 00:32:22 +0200270 struct sk_buff *skb;
Sujithe8324352009-01-16 21:38:42 +0530271 struct ath_buf *bf;
272 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700273 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100274 struct ath_frame_info *fi;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700275
276 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530277 INIT_LIST_HEAD(&bf_head);
278
Felix Fietkau56dc6332011-08-28 00:32:22 +0200279 while ((skb = __skb_dequeue(&tid->buf_q))) {
280 fi = get_frame_info(skb);
281 bf = fi->bf;
Sujithe8324352009-01-16 21:38:42 +0530282
Felix Fietkau44f1d262011-08-28 00:32:25 +0200283 if (!bf) {
Felix Fietkau44f1d262011-08-28 00:32:25 +0200284 ath_tx_complete(sc, skb, ATH_TX_ERROR, txq);
Felix Fietkau44f1d262011-08-28 00:32:25 +0200285 continue;
286 }
287
Felix Fietkau56dc6332011-08-28 00:32:22 +0200288 list_add_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530289
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100290 if (fi->retries)
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200291 ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
Sujithe8324352009-01-16 21:38:42 +0530292
Felix Fietkau156369f2011-12-14 22:08:04 +0100293 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +0530294 }
295
296 tid->seq_next = tid->seq_start;
297 tid->baw_tail = tid->baw_head;
Felix Fietkauf9437542011-12-14 22:08:08 +0100298 tid->bar_index = -1;
Sujithe8324352009-01-16 21:38:42 +0530299}
300
Sujithfec247c2009-07-27 12:08:16 +0530301static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkauda647622011-12-14 22:08:03 +0100302 struct sk_buff *skb, int count)
Sujithe8324352009-01-16 21:38:42 +0530303{
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100304 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkauf11cc942011-09-15 12:59:49 +0200305 struct ath_buf *bf = fi->bf;
Sujithe8324352009-01-16 21:38:42 +0530306 struct ieee80211_hdr *hdr;
Felix Fietkauda647622011-12-14 22:08:03 +0100307 int prev = fi->retries;
Sujithe8324352009-01-16 21:38:42 +0530308
Sujithfec247c2009-07-27 12:08:16 +0530309 TX_STAT_INC(txq->axq_qnum, a_retries);
Felix Fietkauda647622011-12-14 22:08:03 +0100310 fi->retries += count;
311
312 if (prev > 0)
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100313 return;
Sujithe8324352009-01-16 21:38:42 +0530314
Sujithe8324352009-01-16 21:38:42 +0530315 hdr = (struct ieee80211_hdr *)skb->data;
316 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
Felix Fietkauf11cc942011-09-15 12:59:49 +0200317 dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
318 sizeof(*hdr), DMA_TO_DEVICE);
Sujithe8324352009-01-16 21:38:42 +0530319}
320
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200321static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
322{
323 struct ath_buf *bf = NULL;
324
325 spin_lock_bh(&sc->tx.txbuflock);
326
327 if (unlikely(list_empty(&sc->tx.txbuf))) {
328 spin_unlock_bh(&sc->tx.txbuflock);
329 return NULL;
330 }
331
332 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
333 list_del(&bf->list);
334
335 spin_unlock_bh(&sc->tx.txbuflock);
336
337 return bf;
338}
339
340static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
341{
342 spin_lock_bh(&sc->tx.txbuflock);
343 list_add_tail(&bf->list, &sc->tx.txbuf);
344 spin_unlock_bh(&sc->tx.txbuflock);
345}
346
Sujithd43f30152009-01-16 21:38:53 +0530347static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
348{
349 struct ath_buf *tbf;
350
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200351 tbf = ath_tx_get_buffer(sc);
352 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530353 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530354
355 ATH_TXBUF_RESET(tbf);
356
357 tbf->bf_mpdu = bf->bf_mpdu;
358 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400359 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530360 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530361
362 return tbf;
363}
364
Felix Fietkaub572d032010-11-14 15:20:07 +0100365static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
366 struct ath_tx_status *ts, int txok,
367 int *nframes, int *nbad)
368{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100369 struct ath_frame_info *fi;
Felix Fietkaub572d032010-11-14 15:20:07 +0100370 u16 seq_st = 0;
371 u32 ba[WME_BA_BMP_SIZE >> 5];
372 int ba_index;
373 int isaggr = 0;
374
375 *nbad = 0;
376 *nframes = 0;
377
Felix Fietkaub572d032010-11-14 15:20:07 +0100378 isaggr = bf_isaggr(bf);
379 if (isaggr) {
380 seq_st = ts->ts_seqnum;
381 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
382 }
383
384 while (bf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100385 fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200386 ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno);
Felix Fietkaub572d032010-11-14 15:20:07 +0100387
388 (*nframes)++;
389 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
390 (*nbad)++;
391
392 bf = bf->bf_next;
393 }
394}
395
396
Sujithd43f30152009-01-16 21:38:53 +0530397static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
398 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100399 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530400{
401 struct ath_node *an = NULL;
402 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530403 struct ieee80211_sta *sta;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100404 struct ieee80211_hw *hw = sc->hw;
Sujith1286ec62009-01-27 13:30:37 +0530405 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800406 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530407 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530408 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Felix Fietkau56dc6332011-08-28 00:32:22 +0200409 struct list_head bf_head;
410 struct sk_buff_head bf_pending;
Felix Fietkau156369f2011-12-14 22:08:04 +0100411 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first;
Sujithe8324352009-01-16 21:38:42 +0530412 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530413 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
414 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200415 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100416 struct ath_frame_info *fi;
Björn Smedmanebd02282010-10-10 22:44:39 +0200417 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100418 u8 tidno;
Felix Fietkaudaa5c402011-10-07 02:28:15 +0200419 bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
Felix Fietkauda647622011-12-14 22:08:03 +0100420 int i, retries;
Felix Fietkau156369f2011-12-14 22:08:04 +0100421 int bar_index = -1;
Sujithe8324352009-01-16 21:38:42 +0530422
Sujitha22be222009-03-30 15:28:36 +0530423 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530424 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530425
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800426 tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800427
Felix Fietkau78c46532010-06-25 01:26:16 +0200428 memcpy(rates, tx_info->control.rates, sizeof(rates));
429
Felix Fietkauda647622011-12-14 22:08:03 +0100430 retries = ts->ts_longretry + 1;
431 for (i = 0; i < ts->ts_rateindex; i++)
432 retries += rates[i].count;
433
Sujith1286ec62009-01-27 13:30:37 +0530434 rcu_read_lock();
435
Ben Greear686b9cb2010-09-23 09:44:36 -0700436 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530437 if (!sta) {
438 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200439
Felix Fietkau31e79a52010-07-12 23:16:34 +0200440 INIT_LIST_HEAD(&bf_head);
441 while (bf) {
442 bf_next = bf->bf_next;
443
Felix Fietkaufce041b2011-05-19 12:20:25 +0200444 if (!bf->bf_stale || bf_next != NULL)
Felix Fietkau31e79a52010-07-12 23:16:34 +0200445 list_move_tail(&bf->list, &bf_head);
446
Felix Fietkau156369f2011-12-14 22:08:04 +0100447 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200448
449 bf = bf_next;
450 }
Sujith1286ec62009-01-27 13:30:37 +0530451 return;
Sujithe8324352009-01-16 21:38:42 +0530452 }
453
Sujith1286ec62009-01-27 13:30:37 +0530454 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100455 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
456 tid = ATH_AN_2_TID(an, tidno);
Felix Fietkau156369f2011-12-14 22:08:04 +0100457 seq_first = tid->seq_start;
Sujith1286ec62009-01-27 13:30:37 +0530458
Felix Fietkaub11b1602010-07-11 12:48:44 +0200459 /*
460 * The hardware occasionally sends a tx status for the wrong TID.
461 * In this case, the BA status cannot be considered valid and all
462 * subframes need to be retransmitted
463 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100464 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200465 txok = false;
466
Sujithe8324352009-01-16 21:38:42 +0530467 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530468 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530469
Sujithd43f30152009-01-16 21:38:53 +0530470 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700471 if (ts->ts_flags & ATH9K_TX_BA) {
472 seq_st = ts->ts_seqnum;
473 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530474 } else {
Sujithd43f30152009-01-16 21:38:53 +0530475 /*
476 * AR5416 can become deaf/mute when BA
477 * issue happens. Chip needs to be reset.
478 * But AP code may have sychronization issues
479 * when perform internal reset in this routine.
480 * Only enable reset in STA mode for now.
481 */
Sujith2660b812009-02-09 13:27:26 +0530482 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530483 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530484 }
485 }
486
Felix Fietkau56dc6332011-08-28 00:32:22 +0200487 __skb_queue_head_init(&bf_pending);
Sujithe8324352009-01-16 21:38:42 +0530488
Felix Fietkaub572d032010-11-14 15:20:07 +0100489 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530490 while (bf) {
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200491 u16 seqno = bf->bf_state.seqno;
492
Felix Fietkauf0b82202011-01-15 14:30:15 +0100493 txfail = txpending = sendbar = 0;
Sujithe8324352009-01-16 21:38:42 +0530494 bf_next = bf->bf_next;
495
Felix Fietkau78c46532010-06-25 01:26:16 +0200496 skb = bf->bf_mpdu;
497 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100498 fi = get_frame_info(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200499
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200500 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530501 /* transmit completion, subframe is
502 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530503 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530504 } else if (!isaggr && txok) {
505 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530506 acked_cnt++;
Felix Fietkaub0477012011-12-14 22:08:05 +0100507 } else if ((tid->state & AGGR_CLEANUP) || !retry) {
508 /*
509 * cleanup in progress, just fail
510 * the un-acked sub-frames
511 */
512 txfail = 1;
513 } else if (flush) {
514 txpending = 1;
515 } else if (fi->retries < ATH_MAX_SW_RETRIES) {
516 if (txok || !an->sleeping)
517 ath_tx_set_retry(sc, txq, bf->bf_mpdu,
518 retries);
Felix Fietkau55195412011-04-17 23:28:09 +0200519
Felix Fietkaub0477012011-12-14 22:08:05 +0100520 txpending = 1;
521 } else {
522 txfail = 1;
523 txfail_cnt++;
524 bar_index = max_t(int, bar_index,
525 ATH_BA_INDEX(seq_first, seqno));
Sujithe8324352009-01-16 21:38:42 +0530526 }
527
Felix Fietkaufce041b2011-05-19 12:20:25 +0200528 /*
529 * Make sure the last desc is reclaimed if it
530 * not a holding desc.
531 */
Felix Fietkau56dc6332011-08-28 00:32:22 +0200532 INIT_LIST_HEAD(&bf_head);
533 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
534 bf_next != NULL || !bf_last->bf_stale)
Sujithd43f30152009-01-16 21:38:53 +0530535 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530536
Felix Fietkau90fa5392010-09-20 13:45:38 +0200537 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530538 /*
539 * complete the acked-ones/xretried ones; update
540 * block-ack window
541 */
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200542 ath_tx_update_baw(sc, tid, seqno);
Sujithe8324352009-01-16 21:38:42 +0530543
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530544 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200545 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkau3afd21e2011-09-14 21:24:26 +0200546 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530547 rc_update = false;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530548 }
549
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700550 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
Felix Fietkau156369f2011-12-14 22:08:04 +0100551 !txfail);
Sujithe8324352009-01-16 21:38:42 +0530552 } else {
Sujithd43f30152009-01-16 21:38:53 +0530553 /* retry the un-acked ones */
Felix Fietkaub0477012011-12-14 22:08:05 +0100554 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
555 bf->bf_next == NULL && bf_last->bf_stale) {
556 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530557
Felix Fietkaub0477012011-12-14 22:08:05 +0100558 tbf = ath_clone_txbuf(sc, bf_last);
559 /*
560 * Update tx baw and complete the
561 * frame with failed status if we
562 * run out of tx buf.
563 */
564 if (!tbf) {
Felix Fietkaub0477012011-12-14 22:08:05 +0100565 ath_tx_update_baw(sc, tid, seqno);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400566
Felix Fietkaub0477012011-12-14 22:08:05 +0100567 ath_tx_complete_buf(sc, bf, txq,
568 &bf_head, ts, 0);
569 bar_index = max_t(int, bar_index,
570 ATH_BA_INDEX(seq_first, seqno));
571 break;
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400572 }
Felix Fietkaub0477012011-12-14 22:08:05 +0100573
574 fi->bf = tbf;
Sujithe8324352009-01-16 21:38:42 +0530575 }
576
577 /*
578 * Put this buffer to the temporary pending
579 * queue to retain ordering
580 */
Felix Fietkau56dc6332011-08-28 00:32:22 +0200581 __skb_queue_tail(&bf_pending, skb);
Sujithe8324352009-01-16 21:38:42 +0530582 }
583
584 bf = bf_next;
585 }
586
Felix Fietkau4cee7862010-07-23 03:53:16 +0200587 /* prepend un-acked frames to the beginning of the pending frame queue */
Felix Fietkau56dc6332011-08-28 00:32:22 +0200588 if (!skb_queue_empty(&bf_pending)) {
Felix Fietkau55195412011-04-17 23:28:09 +0200589 if (an->sleeping)
Johannes Berg042ec452011-09-29 16:04:26 +0200590 ieee80211_sta_set_buffered(sta, tid->tidno, true);
Felix Fietkau55195412011-04-17 23:28:09 +0200591
Felix Fietkau56dc6332011-08-28 00:32:22 +0200592 skb_queue_splice(&bf_pending, &tid->buf_q);
Felix Fietkau26a64252011-10-07 02:28:14 +0200593 if (!an->sleeping) {
Felix Fietkau9af73cf2011-08-10 15:23:35 -0600594 ath_tx_queue_tid(txq, tid);
Felix Fietkau26a64252011-10-07 02:28:14 +0200595
596 if (ts->ts_status & ATH9K_TXERR_FILT)
597 tid->ac->clear_ps_filter = true;
598 }
Felix Fietkau4cee7862010-07-23 03:53:16 +0200599 }
600
Felix Fietkau23de5dc2011-12-19 16:45:54 +0100601 if (bar_index >= 0) {
602 u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index);
603
604 if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq))
605 tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq);
606
607 ath_txq_unlock(sc, txq);
608 ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1));
609 ath_txq_lock(sc, txq);
610 }
611
Nikolay Martynov4eb287a2011-11-21 17:32:06 -0500612 if (tid->state & AGGR_CLEANUP)
Felix Fietkau90fa5392010-09-20 13:45:38 +0200613 ath_tx_flush_tid(sc, tid);
614
Sujith1286ec62009-01-27 13:30:37 +0530615 rcu_read_unlock();
616
Felix Fietkau030d6292011-10-07 02:28:13 +0200617 if (needreset) {
618 RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR);
Felix Fietkau236de512011-09-03 01:40:25 +0200619 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
Felix Fietkau030d6292011-10-07 02:28:13 +0200620 }
Sujithe8324352009-01-16 21:38:42 +0530621}
622
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530623static bool ath_lookup_legacy(struct ath_buf *bf)
624{
625 struct sk_buff *skb;
626 struct ieee80211_tx_info *tx_info;
627 struct ieee80211_tx_rate *rates;
628 int i;
629
630 skb = bf->bf_mpdu;
631 tx_info = IEEE80211_SKB_CB(skb);
632 rates = tx_info->control.rates;
633
Felix Fietkau059ee092011-08-27 10:25:27 +0200634 for (i = 0; i < 4; i++) {
635 if (!rates[i].count || rates[i].idx < 0)
636 break;
637
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530638 if (!(rates[i].flags & IEEE80211_TX_RC_MCS))
639 return true;
640 }
641
642 return false;
643}
644
Sujithe8324352009-01-16 21:38:42 +0530645static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
646 struct ath_atx_tid *tid)
647{
Sujithe8324352009-01-16 21:38:42 +0530648 struct sk_buff *skb;
649 struct ieee80211_tx_info *tx_info;
650 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530651 u32 max_4ms_framelen, frmlen;
Sujith Manoharanc0ac53f2012-02-22 12:40:38 +0530652 u16 aggr_limit, bt_aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530653 int i;
654
Sujitha22be222009-03-30 15:28:36 +0530655 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530656 tx_info = IEEE80211_SKB_CB(skb);
657 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530658
659 /*
660 * Find the lowest frame length among the rate series that will have a
661 * 4ms transmit duration.
662 * TODO - TXOP limit needs to be considered.
663 */
664 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
665
666 for (i = 0; i < 4; i++) {
Felix Fietkaub0477012011-12-14 22:08:05 +0100667 int modeidx;
Sujithe8324352009-01-16 21:38:42 +0530668
Felix Fietkaub0477012011-12-14 22:08:05 +0100669 if (!rates[i].count)
670 continue;
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200671
Felix Fietkaub0477012011-12-14 22:08:05 +0100672 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
673 legacy = 1;
674 break;
Sujithe8324352009-01-16 21:38:42 +0530675 }
Felix Fietkaub0477012011-12-14 22:08:05 +0100676
677 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
678 modeidx = MCS_HT40;
679 else
680 modeidx = MCS_HT20;
681
682 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
683 modeidx++;
684
685 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
686 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530687 }
688
689 /*
690 * limit aggregate size by the minimum rate if rate selected is
691 * not a probe rate, if rate selected is a probe rate then
692 * avoid aggregation of this packet.
693 */
694 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
695 return 0;
696
Sujith Manoharanc0ac53f2012-02-22 12:40:38 +0530697 aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
698
699 /*
700 * Override the default aggregation limit for BTCOEX.
701 */
702 bt_aggr_limit = ath9k_btcoex_aggr_limit(sc, max_4ms_framelen);
703 if (bt_aggr_limit)
704 aggr_limit = bt_aggr_limit;
Sujithe8324352009-01-16 21:38:42 +0530705
706 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300707 * h/w can accept aggregates up to 16 bit lengths (65535).
708 * The IE, however can hold up to 65536, which shows up here
Sujithe8324352009-01-16 21:38:42 +0530709 * as zero. Ignore 65536 since we are constrained by hw.
710 */
Sujith4ef70842009-07-23 15:32:41 +0530711 if (tid->an->maxampdu)
712 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530713
714 return aggr_limit;
715}
716
717/*
Sujithd43f30152009-01-16 21:38:53 +0530718 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530719 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530720 */
721static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530722 struct ath_buf *bf, u16 frmlen,
723 bool first_subfrm)
Sujithe8324352009-01-16 21:38:42 +0530724{
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530725#define FIRST_DESC_NDELIMS 60
Sujithe8324352009-01-16 21:38:42 +0530726 struct sk_buff *skb = bf->bf_mpdu;
727 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530728 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530729 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100730 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200731 int width, streams, half_gi, ndelim, mindelim;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100732 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530733
734 /* Select standard number of delimiters based on frame length alone */
735 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
736
737 /*
738 * If encryption enabled, hardware requires some more padding between
739 * subframes.
740 * TODO - this could be improved to be dependent on the rate.
741 * The hardware can keep up at lower rates, but not higher rates
742 */
Rajkumar Manoharan4f6760b2011-07-01 18:37:33 +0530743 if ((fi->keyix != ATH9K_TXKEYIX_INVALID) &&
744 !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
Sujithe8324352009-01-16 21:38:42 +0530745 ndelim += ATH_AGGR_ENCRYPTDELIM;
746
747 /*
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530748 * Add delimiter when using RTS/CTS with aggregation
749 * and non enterprise AR9003 card
750 */
Felix Fietkau34597312011-08-29 18:57:54 +0200751 if (first_subfrm && !AR_SREV_9580_10_OR_LATER(sc->sc_ah) &&
752 (sc->sc_ah->ent_mode & AR_ENT_OTP_MIN_PKT_SIZE_DISABLE))
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530753 ndelim = max(ndelim, FIRST_DESC_NDELIMS);
754
755 /*
Sujithe8324352009-01-16 21:38:42 +0530756 * Convert desired mpdu density from microeconds to bytes based
757 * on highest rate in rate series (i.e. first rate) to determine
758 * required minimum length for subframe. Take into account
759 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530760 *
Sujithe8324352009-01-16 21:38:42 +0530761 * If there is no mpdu density restriction, no further calculation
762 * is needed.
763 */
Sujith4ef70842009-07-23 15:32:41 +0530764
765 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530766 return ndelim;
767
768 rix = tx_info->control.rates[0].idx;
769 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530770 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
771 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
772
773 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530774 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530775 else
Sujith4ef70842009-07-23 15:32:41 +0530776 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530777
778 if (nsymbols == 0)
779 nsymbols = 1;
780
Felix Fietkauc6663872010-04-19 19:57:33 +0200781 streams = HT_RC_2_STREAMS(rix);
782 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530783 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
784
Sujithe8324352009-01-16 21:38:42 +0530785 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530786 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
787 ndelim = max(mindelim, ndelim);
788 }
789
790 return ndelim;
791}
792
793static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530794 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530795 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100796 struct list_head *bf_q,
797 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530798{
799#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Felix Fietkau56dc6332011-08-28 00:32:22 +0200800 struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530801 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530802 u16 aggr_limit = 0, al = 0, bpad = 0,
803 al_delta, h_baw = tid->baw_size / 2;
804 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200805 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100806 struct ath_frame_info *fi;
Felix Fietkau56dc6332011-08-28 00:32:22 +0200807 struct sk_buff *skb;
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200808 u16 seqno;
Sujithe8324352009-01-16 21:38:42 +0530809
810 do {
Felix Fietkau56dc6332011-08-28 00:32:22 +0200811 skb = skb_peek(&tid->buf_q);
812 fi = get_frame_info(skb);
813 bf = fi->bf;
Felix Fietkau44f1d262011-08-28 00:32:25 +0200814 if (!fi->bf)
Felix Fietkau81357a22012-05-24 14:32:20 +0200815 bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
Felix Fietkau56dc6332011-08-28 00:32:22 +0200816
Felix Fietkau44f1d262011-08-28 00:32:25 +0200817 if (!bf)
818 continue;
819
Felix Fietkau399c6482011-09-14 21:24:17 +0200820 bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
Felix Fietkau44f1d262011-08-28 00:32:25 +0200821 seqno = bf->bf_state.seqno;
Sujithe8324352009-01-16 21:38:42 +0530822
Sujithd43f30152009-01-16 21:38:53 +0530823 /* do not step over block-ack window */
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200824 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530825 status = ATH_AGGR_BAW_CLOSED;
826 break;
827 }
828
Felix Fietkauf9437542011-12-14 22:08:08 +0100829 if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
830 struct ath_tx_status ts = {};
831 struct list_head bf_head;
832
833 INIT_LIST_HEAD(&bf_head);
834 list_add(&bf->list, &bf_head);
835 __skb_unlink(skb, &tid->buf_q);
836 ath_tx_update_baw(sc, tid, seqno);
837 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
838 continue;
839 }
840
841 if (!bf_first)
842 bf_first = bf;
843
Sujithe8324352009-01-16 21:38:42 +0530844 if (!rl) {
845 aggr_limit = ath_lookup_rate(sc, bf, tid);
846 rl = 1;
847 }
848
Sujithd43f30152009-01-16 21:38:53 +0530849 /* do not exceed aggregation limit */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100850 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
Sujithe8324352009-01-16 21:38:42 +0530851
Sujithd43f30152009-01-16 21:38:53 +0530852 if (nframes &&
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530853 ((aggr_limit < (al + bpad + al_delta + prev_al)) ||
854 ath_lookup_legacy(bf))) {
Sujithe8324352009-01-16 21:38:42 +0530855 status = ATH_AGGR_LIMITED;
856 break;
857 }
858
Felix Fietkau0299a502010-10-21 02:47:24 +0200859 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
Felix Fietkaubdf2dbf2011-09-14 21:24:25 +0200860 if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
Felix Fietkau0299a502010-10-21 02:47:24 +0200861 break;
862
Sujithd43f30152009-01-16 21:38:53 +0530863 /* do not exceed subframe limit */
864 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530865 status = ATH_AGGR_LIMITED;
866 break;
867 }
868
Sujithd43f30152009-01-16 21:38:53 +0530869 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530870 al += bpad + al_delta;
871
872 /*
873 * Get the delimiters needed to meet the MPDU
874 * density for this node.
875 */
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530876 ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen,
877 !nframes);
Sujithe8324352009-01-16 21:38:42 +0530878 bpad = PADBYTES(al_delta) + (ndelim << 2);
879
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530880 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530881 bf->bf_next = NULL;
Sujithe8324352009-01-16 21:38:42 +0530882
Sujithd43f30152009-01-16 21:38:53 +0530883 /* link buffers of this frame to the aggregate */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100884 if (!fi->retries)
Felix Fietkau6a0ddae2011-08-28 00:32:23 +0200885 ath_tx_addto_baw(sc, tid, seqno);
Felix Fietkau399c6482011-09-14 21:24:17 +0200886 bf->bf_state.ndelim = ndelim;
Felix Fietkau56dc6332011-08-28 00:32:22 +0200887
888 __skb_unlink(skb, &tid->buf_q);
889 list_add_tail(&bf->list, bf_q);
Felix Fietkau399c6482011-09-14 21:24:17 +0200890 if (bf_prev)
Sujithe8324352009-01-16 21:38:42 +0530891 bf_prev->bf_next = bf;
Felix Fietkau399c6482011-09-14 21:24:17 +0200892
Sujithe8324352009-01-16 21:38:42 +0530893 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530894
Felix Fietkau56dc6332011-08-28 00:32:22 +0200895 } while (!skb_queue_empty(&tid->buf_q));
Sujithe8324352009-01-16 21:38:42 +0530896
Felix Fietkau269c44b2010-11-14 15:20:06 +0100897 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530898
Sujithe8324352009-01-16 21:38:42 +0530899 return status;
900#undef PADBYTES
901}
902
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200903/*
904 * rix - rate index
905 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
906 * width - 0 for 20 MHz, 1 for 40 MHz
907 * half_gi - to use 4us v/s 3.6 us for symbol time
908 */
909static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
910 int width, int half_gi, bool shortPreamble)
911{
912 u32 nbits, nsymbits, duration, nsymbols;
913 int streams;
914
915 /* find number of symbols: PLCP + data */
916 streams = HT_RC_2_STREAMS(rix);
917 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
918 nsymbits = bits_per_symbol[rix % 8][width] * streams;
919 nsymbols = (nbits + nsymbits - 1) / nsymbits;
920
921 if (!half_gi)
922 duration = SYMBOL_TIME(nsymbols);
923 else
924 duration = SYMBOL_TIME_HALFGI(nsymbols);
925
926 /* addup duration for legacy/ht training and signal fields */
927 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
928
929 return duration;
930}
931
Felix Fietkau493cf042011-09-14 21:24:22 +0200932static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
933 struct ath_tx_info *info, int len)
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200934{
935 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200936 struct sk_buff *skb;
937 struct ieee80211_tx_info *tx_info;
938 struct ieee80211_tx_rate *rates;
939 const struct ieee80211_rate *rate;
940 struct ieee80211_hdr *hdr;
Felix Fietkau80b08a82012-06-15 03:04:53 +0200941 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau493cf042011-09-14 21:24:22 +0200942 int i;
943 u8 rix = 0;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200944
945 skb = bf->bf_mpdu;
946 tx_info = IEEE80211_SKB_CB(skb);
947 rates = tx_info->control.rates;
948 hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau493cf042011-09-14 21:24:22 +0200949
950 /* set dur_update_en for l-sig computation except for PS-Poll frames */
951 info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
Felix Fietkau80b08a82012-06-15 03:04:53 +0200952 info->rtscts_rate = fi->rtscts_rate;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200953
954 for (i = 0; i < 4; i++) {
955 bool is_40, is_sgi, is_sp;
956 int phy;
957
958 if (!rates[i].count || (rates[i].idx < 0))
959 continue;
960
961 rix = rates[i].idx;
Felix Fietkau493cf042011-09-14 21:24:22 +0200962 info->rates[i].Tries = rates[i].count;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200963
964 if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
Felix Fietkau493cf042011-09-14 21:24:22 +0200965 info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
966 info->flags |= ATH9K_TXDESC_RTSENA;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200967 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
Felix Fietkau493cf042011-09-14 21:24:22 +0200968 info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
969 info->flags |= ATH9K_TXDESC_CTSENA;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200970 }
971
972 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau493cf042011-09-14 21:24:22 +0200973 info->rates[i].RateFlags |= ATH9K_RATESERIES_2040;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200974 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
Felix Fietkau493cf042011-09-14 21:24:22 +0200975 info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200976
977 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
978 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
979 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
980
981 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
982 /* MCS rates */
Felix Fietkau493cf042011-09-14 21:24:22 +0200983 info->rates[i].Rate = rix | 0x80;
984 info->rates[i].ChSel = ath_txchainmask_reduction(sc,
985 ah->txchainmask, info->rates[i].Rate);
986 info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200987 is_40, is_sgi, is_sp);
988 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
Felix Fietkau493cf042011-09-14 21:24:22 +0200989 info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200990 continue;
991 }
992
993 /* legacy rates */
Felix Fietkau76591be2012-06-15 03:04:52 +0200994 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
Felix Fietkau38dad7b2011-09-14 21:24:18 +0200995 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
996 !(rate->flags & IEEE80211_RATE_ERP_G))
997 phy = WLAN_RC_PHY_CCK;
998 else
999 phy = WLAN_RC_PHY_OFDM;
1000
Felix Fietkau493cf042011-09-14 21:24:22 +02001001 info->rates[i].Rate = rate->hw_value;
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001002 if (rate->hw_value_short) {
1003 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
Felix Fietkau493cf042011-09-14 21:24:22 +02001004 info->rates[i].Rate |= rate->hw_value_short;
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001005 } else {
1006 is_sp = false;
1007 }
1008
1009 if (bf->bf_state.bfs_paprd)
Felix Fietkau493cf042011-09-14 21:24:22 +02001010 info->rates[i].ChSel = ah->txchainmask;
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001011 else
Felix Fietkau493cf042011-09-14 21:24:22 +02001012 info->rates[i].ChSel = ath_txchainmask_reduction(sc,
1013 ah->txchainmask, info->rates[i].Rate);
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001014
Felix Fietkau493cf042011-09-14 21:24:22 +02001015 info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001016 phy, rate->bitrate * 100, len, rix, is_sp);
1017 }
1018
1019 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1020 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau493cf042011-09-14 21:24:22 +02001021 info->flags &= ~ATH9K_TXDESC_RTSENA;
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001022
1023 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
Felix Fietkau493cf042011-09-14 21:24:22 +02001024 if (info->flags & ATH9K_TXDESC_RTSENA)
1025 info->flags &= ~ATH9K_TXDESC_CTSENA;
Felix Fietkau38dad7b2011-09-14 21:24:18 +02001026}
1027
Felix Fietkau493cf042011-09-14 21:24:22 +02001028static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
1029{
1030 struct ieee80211_hdr *hdr;
1031 enum ath9k_pkt_type htype;
1032 __le16 fc;
1033
1034 hdr = (struct ieee80211_hdr *)skb->data;
1035 fc = hdr->frame_control;
1036
1037 if (ieee80211_is_beacon(fc))
1038 htype = ATH9K_PKT_TYPE_BEACON;
1039 else if (ieee80211_is_probe_resp(fc))
1040 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1041 else if (ieee80211_is_atim(fc))
1042 htype = ATH9K_PKT_TYPE_ATIM;
1043 else if (ieee80211_is_pspoll(fc))
1044 htype = ATH9K_PKT_TYPE_PSPOLL;
1045 else
1046 htype = ATH9K_PKT_TYPE_NORMAL;
1047
1048 return htype;
1049}
1050
1051static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
1052 struct ath_txq *txq, int len)
Felix Fietkau399c6482011-09-14 21:24:17 +02001053{
1054 struct ath_hw *ah = sc->sc_ah;
1055 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
1056 struct ath_buf *bf_first = bf;
Felix Fietkau493cf042011-09-14 21:24:22 +02001057 struct ath_tx_info info;
Felix Fietkau399c6482011-09-14 21:24:17 +02001058 bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR);
Felix Fietkau399c6482011-09-14 21:24:17 +02001059
Felix Fietkau493cf042011-09-14 21:24:22 +02001060 memset(&info, 0, sizeof(info));
1061 info.is_first = true;
1062 info.is_last = true;
1063 info.txpower = MAX_RATE_POWER;
1064 info.qcu = txq->axq_qnum;
Felix Fietkau399c6482011-09-14 21:24:17 +02001065
Felix Fietkau493cf042011-09-14 21:24:22 +02001066 info.flags = ATH9K_TXDESC_INTREQ;
1067 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1068 info.flags |= ATH9K_TXDESC_NOACK;
1069 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1070 info.flags |= ATH9K_TXDESC_LDPC;
1071
1072 ath_buf_set_rate(sc, bf, &info, len);
1073
1074 if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
1075 info.flags |= ATH9K_TXDESC_CLRDMASK;
1076
1077 if (bf->bf_state.bfs_paprd)
1078 info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S;
1079
Felix Fietkau399c6482011-09-14 21:24:17 +02001080
1081 while (bf) {
Felix Fietkau493cf042011-09-14 21:24:22 +02001082 struct sk_buff *skb = bf->bf_mpdu;
1083 struct ath_frame_info *fi = get_frame_info(skb);
1084
1085 info.type = get_hw_packet_type(skb);
Felix Fietkau399c6482011-09-14 21:24:17 +02001086 if (bf->bf_next)
Felix Fietkau493cf042011-09-14 21:24:22 +02001087 info.link = bf->bf_next->bf_daddr;
Felix Fietkau399c6482011-09-14 21:24:17 +02001088 else
Felix Fietkau493cf042011-09-14 21:24:22 +02001089 info.link = 0;
Felix Fietkau399c6482011-09-14 21:24:17 +02001090
John W. Linville42cecc32011-09-19 15:42:31 -04001091 info.buf_addr[0] = bf->bf_buf_addr;
1092 info.buf_len[0] = skb->len;
Felix Fietkau493cf042011-09-14 21:24:22 +02001093 info.pkt_len = fi->framelen;
1094 info.keyix = fi->keyix;
1095 info.keytype = fi->keytype;
1096
1097 if (aggr) {
Felix Fietkau399c6482011-09-14 21:24:17 +02001098 if (bf == bf_first)
Felix Fietkau493cf042011-09-14 21:24:22 +02001099 info.aggr = AGGR_BUF_FIRST;
1100 else if (!bf->bf_next)
1101 info.aggr = AGGR_BUF_LAST;
1102 else
1103 info.aggr = AGGR_BUF_MIDDLE;
Felix Fietkau399c6482011-09-14 21:24:17 +02001104
Felix Fietkau493cf042011-09-14 21:24:22 +02001105 info.ndelim = bf->bf_state.ndelim;
1106 info.aggr_len = len;
Felix Fietkau399c6482011-09-14 21:24:17 +02001107 }
1108
Felix Fietkau493cf042011-09-14 21:24:22 +02001109 ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
Felix Fietkau399c6482011-09-14 21:24:17 +02001110 bf = bf->bf_next;
1111 }
1112}
1113
Sujithe8324352009-01-16 21:38:42 +05301114static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
1115 struct ath_atx_tid *tid)
1116{
Sujithd43f30152009-01-16 21:38:53 +05301117 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301118 enum ATH_AGGR_STATUS status;
Felix Fietkau399c6482011-09-14 21:24:17 +02001119 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +05301120 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001121 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +05301122
1123 do {
Felix Fietkau56dc6332011-08-28 00:32:22 +02001124 if (skb_queue_empty(&tid->buf_q))
Sujithe8324352009-01-16 21:38:42 +05301125 return;
1126
1127 INIT_LIST_HEAD(&bf_q);
1128
Felix Fietkau269c44b2010-11-14 15:20:06 +01001129 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +05301130
1131 /*
Sujithd43f30152009-01-16 21:38:53 +05301132 * no frames picked up to be aggregated;
1133 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +05301134 */
1135 if (list_empty(&bf_q))
1136 break;
1137
1138 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +05301139 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Felix Fietkau399c6482011-09-14 21:24:17 +02001140 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301141
Felix Fietkau55195412011-04-17 23:28:09 +02001142 if (tid->ac->clear_ps_filter) {
1143 tid->ac->clear_ps_filter = false;
Felix Fietkau399c6482011-09-14 21:24:17 +02001144 tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1145 } else {
1146 tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
Felix Fietkau55195412011-04-17 23:28:09 +02001147 }
1148
Sujithd43f30152009-01-16 21:38:53 +05301149 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +01001150 if (bf == bf->bf_lastbf) {
Felix Fietkau399c6482011-09-14 21:24:17 +02001151 aggr_len = get_frame_info(bf->bf_mpdu)->framelen;
1152 bf->bf_state.bf_type = BUF_AMPDU;
1153 } else {
1154 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +05301155 }
1156
Felix Fietkau493cf042011-09-14 21:24:22 +02001157 ath_tx_fill_desc(sc, bf, txq, aggr_len);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001158 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001159 } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
Sujithe8324352009-01-16 21:38:42 +05301160 status != ATH_AGGR_BAW_CLOSED);
1161}
1162
Felix Fietkau231c3a12010-09-20 19:35:28 +02001163int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
1164 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +05301165{
1166 struct ath_atx_tid *txtid;
1167 struct ath_node *an;
1168
1169 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +05301170 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +02001171
1172 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
1173 return -EAGAIN;
1174
Sujithf83da962009-07-23 15:32:37 +05301175 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +02001176 txtid->paused = true;
Felix Fietkau49447f22011-01-10 17:05:48 -07001177 *ssn = txtid->seq_start = txtid->seq_next;
Felix Fietkauf9437542011-12-14 22:08:08 +01001178 txtid->bar_index = -1;
Felix Fietkau231c3a12010-09-20 19:35:28 +02001179
Felix Fietkau2ed72222011-01-10 17:05:49 -07001180 memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
1181 txtid->baw_head = txtid->baw_tail = 0;
1182
Felix Fietkau231c3a12010-09-20 19:35:28 +02001183 return 0;
Sujithe8324352009-01-16 21:38:42 +05301184}
1185
Sujithf83da962009-07-23 15:32:37 +05301186void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +05301187{
1188 struct ath_node *an = (struct ath_node *)sta->drv_priv;
1189 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +01001190 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +05301191
1192 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +05301193 return;
Sujithe8324352009-01-16 21:38:42 +05301194
1195 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +05301196 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +05301197 return;
Sujithe8324352009-01-16 21:38:42 +05301198 }
1199
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001200 ath_txq_lock(sc, txq);
Lorenzo Bianconi75401842010-08-01 15:47:32 +02001201 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +02001202
1203 /*
1204 * If frames are still being transmitted for this TID, they will be
1205 * cleaned up during tx completion. To prevent race conditions, this
1206 * TID can only be reused after all in-progress subframes have been
1207 * completed.
1208 */
1209 if (txtid->baw_head != txtid->baw_tail)
1210 txtid->state |= AGGR_CLEANUP;
1211 else
1212 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +05301213
Felix Fietkau90fa5392010-09-20 13:45:38 +02001214 ath_tx_flush_tid(sc, txtid);
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001215 ath_txq_unlock_complete(sc, txq);
Sujithe8324352009-01-16 21:38:42 +05301216}
1217
Johannes Berg042ec452011-09-29 16:04:26 +02001218void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
1219 struct ath_node *an)
Felix Fietkau55195412011-04-17 23:28:09 +02001220{
1221 struct ath_atx_tid *tid;
1222 struct ath_atx_ac *ac;
1223 struct ath_txq *txq;
Johannes Berg042ec452011-09-29 16:04:26 +02001224 bool buffered;
Felix Fietkau55195412011-04-17 23:28:09 +02001225 int tidno;
1226
1227 for (tidno = 0, tid = &an->tid[tidno];
1228 tidno < WME_NUM_TID; tidno++, tid++) {
1229
1230 if (!tid->sched)
1231 continue;
1232
1233 ac = tid->ac;
1234 txq = ac->txq;
1235
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001236 ath_txq_lock(sc, txq);
Felix Fietkau55195412011-04-17 23:28:09 +02001237
Johannes Berg042ec452011-09-29 16:04:26 +02001238 buffered = !skb_queue_empty(&tid->buf_q);
Felix Fietkau55195412011-04-17 23:28:09 +02001239
1240 tid->sched = false;
1241 list_del(&tid->list);
1242
1243 if (ac->sched) {
1244 ac->sched = false;
1245 list_del(&ac->list);
1246 }
1247
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001248 ath_txq_unlock(sc, txq);
Felix Fietkau55195412011-04-17 23:28:09 +02001249
Johannes Berg042ec452011-09-29 16:04:26 +02001250 ieee80211_sta_set_buffered(sta, tidno, buffered);
1251 }
Felix Fietkau55195412011-04-17 23:28:09 +02001252}
1253
1254void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
1255{
1256 struct ath_atx_tid *tid;
1257 struct ath_atx_ac *ac;
1258 struct ath_txq *txq;
1259 int tidno;
1260
1261 for (tidno = 0, tid = &an->tid[tidno];
1262 tidno < WME_NUM_TID; tidno++, tid++) {
1263
1264 ac = tid->ac;
1265 txq = ac->txq;
1266
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001267 ath_txq_lock(sc, txq);
Felix Fietkau55195412011-04-17 23:28:09 +02001268 ac->clear_ps_filter = true;
1269
Felix Fietkau56dc6332011-08-28 00:32:22 +02001270 if (!skb_queue_empty(&tid->buf_q) && !tid->paused) {
Felix Fietkau55195412011-04-17 23:28:09 +02001271 ath_tx_queue_tid(txq, tid);
1272 ath_txq_schedule(sc, txq);
1273 }
1274
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001275 ath_txq_unlock_complete(sc, txq);
Felix Fietkau55195412011-04-17 23:28:09 +02001276 }
1277}
1278
Sujithe8324352009-01-16 21:38:42 +05301279void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
1280{
1281 struct ath_atx_tid *txtid;
1282 struct ath_node *an;
1283
1284 an = (struct ath_node *)sta->drv_priv;
1285
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +05301286 txtid = ATH_AN_2_TID(an, tid);
1287 txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
1288 txtid->state |= AGGR_ADDBA_COMPLETE;
1289 txtid->state &= ~AGGR_ADDBA_PROGRESS;
1290 ath_tx_resume_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +05301291}
1292
Sujithe8324352009-01-16 21:38:42 +05301293/********************/
1294/* Queue Management */
1295/********************/
1296
Sujithe8324352009-01-16 21:38:42 +05301297static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
1298 struct ath_txq *txq)
1299{
1300 struct ath_atx_ac *ac, *ac_tmp;
1301 struct ath_atx_tid *tid, *tid_tmp;
1302
1303 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1304 list_del(&ac->list);
1305 ac->sched = false;
1306 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
1307 list_del(&tid->list);
1308 tid->sched = false;
1309 ath_tid_drain(sc, txq, tid);
1310 }
1311 }
1312}
1313
1314struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
1315{
Sujithcbe61d82009-02-09 13:27:12 +05301316 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301317 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001318 static const int subtype_txq_to_hwq[] = {
1319 [WME_AC_BE] = ATH_TXQ_AC_BE,
1320 [WME_AC_BK] = ATH_TXQ_AC_BK,
1321 [WME_AC_VI] = ATH_TXQ_AC_VI,
1322 [WME_AC_VO] = ATH_TXQ_AC_VO,
1323 };
Ben Greear60f2d1d2011-01-09 23:11:52 -08001324 int axq_qnum, i;
Sujithe8324352009-01-16 21:38:42 +05301325
1326 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +01001327 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +05301328 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
1329 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
1330 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
1331 qi.tqi_physCompBuf = 0;
1332
1333 /*
1334 * Enable interrupts only for EOL and DESC conditions.
1335 * We mark tx descriptors to receive a DESC interrupt
1336 * when a tx queue gets deep; otherwise waiting for the
1337 * EOL to reap descriptors. Note that this is done to
1338 * reduce interrupt load and this only defers reaping
1339 * descriptors, never transmitting frames. Aside from
1340 * reducing interrupts this also permits more concurrency.
1341 * The only potential downside is if the tx queue backs
1342 * up in which case the top half of the kernel may backup
1343 * due to a lack of tx descriptors.
1344 *
1345 * The UAPSD queue is an exception, since we take a desc-
1346 * based intr on the EOSP frames.
1347 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -04001348 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
Felix Fietkauce8fdf62012-03-14 16:40:22 +01001349 qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE;
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -04001350 } else {
1351 if (qtype == ATH9K_TX_QUEUE_UAPSD)
1352 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
1353 else
1354 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
1355 TXQ_FLAG_TXDESCINT_ENABLE;
1356 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001357 axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
1358 if (axq_qnum == -1) {
Sujithe8324352009-01-16 21:38:42 +05301359 /*
1360 * NB: don't print a message, this happens
1361 * normally on parts with too few tx queues
1362 */
1363 return NULL;
1364 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001365 if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
1366 struct ath_txq *txq = &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301367
Ben Greear60f2d1d2011-01-09 23:11:52 -08001368 txq->axq_qnum = axq_qnum;
1369 txq->mac80211_qnum = -1;
Sujithe8324352009-01-16 21:38:42 +05301370 txq->axq_link = NULL;
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001371 __skb_queue_head_init(&txq->complete_q);
Sujithe8324352009-01-16 21:38:42 +05301372 INIT_LIST_HEAD(&txq->axq_q);
1373 INIT_LIST_HEAD(&txq->axq_acq);
1374 spin_lock_init(&txq->axq_lock);
1375 txq->axq_depth = 0;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001376 txq->axq_ampdu_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001377 txq->axq_tx_inprogress = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08001378 sc->tx.txqsetup |= 1<<axq_qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001379
1380 txq->txq_headidx = txq->txq_tailidx = 0;
1381 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1382 INIT_LIST_HEAD(&txq->txq_fifo[i]);
Sujithe8324352009-01-16 21:38:42 +05301383 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001384 return &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301385}
1386
Sujithe8324352009-01-16 21:38:42 +05301387int ath_txq_update(struct ath_softc *sc, int qnum,
1388 struct ath9k_tx_queue_info *qinfo)
1389{
Sujithcbe61d82009-02-09 13:27:12 +05301390 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301391 int error = 0;
1392 struct ath9k_tx_queue_info qi;
1393
1394 if (qnum == sc->beacon.beaconq) {
1395 /*
1396 * XXX: for beacon queue, we just save the parameter.
1397 * It will be picked up by ath_beaconq_config when
1398 * it's necessary.
1399 */
1400 sc->beacon.beacon_qi = *qinfo;
1401 return 0;
1402 }
1403
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001404 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301405
1406 ath9k_hw_get_txq_props(ah, qnum, &qi);
1407 qi.tqi_aifs = qinfo->tqi_aifs;
1408 qi.tqi_cwmin = qinfo->tqi_cwmin;
1409 qi.tqi_cwmax = qinfo->tqi_cwmax;
1410 qi.tqi_burstTime = qinfo->tqi_burstTime;
1411 qi.tqi_readyTime = qinfo->tqi_readyTime;
1412
1413 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Joe Perches38002762010-12-02 19:12:36 -08001414 ath_err(ath9k_hw_common(sc->sc_ah),
1415 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301416 error = -EIO;
1417 } else {
1418 ath9k_hw_resettxqueue(ah, qnum);
1419 }
1420
1421 return error;
1422}
1423
1424int ath_cabq_update(struct ath_softc *sc)
1425{
1426 struct ath9k_tx_queue_info qi;
Steve Brown9814f6b2011-02-07 17:10:39 -07001427 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
Sujithe8324352009-01-16 21:38:42 +05301428 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301429
1430 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1431 /*
1432 * Ensure the readytime % is within the bounds.
1433 */
Sujith17d79042009-02-09 13:27:03 +05301434 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1435 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1436 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1437 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301438
Steve Brown9814f6b2011-02-07 17:10:39 -07001439 qi.tqi_readyTime = (cur_conf->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301440 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301441 ath_txq_update(sc, qnum, &qi);
1442
1443 return 0;
1444}
1445
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001446static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
1447{
1448 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
1449 return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
1450}
1451
Felix Fietkaufce041b2011-05-19 12:20:25 +02001452static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
1453 struct list_head *list, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301454{
1455 struct ath_buf *bf, *lastbf;
1456 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001457 struct ath_tx_status ts;
1458
1459 memset(&ts, 0, sizeof(ts));
Felix Fietkaudaa5c402011-10-07 02:28:15 +02001460 ts.ts_status = ATH9K_TX_FLUSH;
Sujithe8324352009-01-16 21:38:42 +05301461 INIT_LIST_HEAD(&bf_head);
1462
Felix Fietkaufce041b2011-05-19 12:20:25 +02001463 while (!list_empty(list)) {
1464 bf = list_first_entry(list, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +05301465
Felix Fietkaufce041b2011-05-19 12:20:25 +02001466 if (bf->bf_stale) {
1467 list_del(&bf->list);
Sujithe8324352009-01-16 21:38:42 +05301468
Felix Fietkaufce041b2011-05-19 12:20:25 +02001469 ath_tx_return_buffer(sc, bf);
1470 continue;
Sujithe8324352009-01-16 21:38:42 +05301471 }
1472
1473 lastbf = bf->bf_lastbf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02001474 list_cut_position(&bf_head, list, &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001475
Sujithe8324352009-01-16 21:38:42 +05301476 txq->axq_depth--;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001477 if (bf_is_ampdu_not_probing(bf))
1478 txq->axq_ampdu_depth--;
Sujithe8324352009-01-16 21:38:42 +05301479
1480 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001481 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1482 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301483 else
Felix Fietkau156369f2011-12-14 22:08:04 +01001484 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001485 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001486}
1487
1488/*
1489 * Drain a given TX queue (could be Beacon or Data)
1490 *
1491 * This assumes output has been stopped and
1492 * we do not need to block ath_tx_tasklet.
1493 */
1494void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
1495{
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001496 ath_txq_lock(sc, txq);
1497
Felix Fietkaufce041b2011-05-19 12:20:25 +02001498 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1499 int idx = txq->txq_tailidx;
1500
1501 while (!list_empty(&txq->txq_fifo[idx])) {
1502 ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
1503 retry_tx);
1504
1505 INCR(idx, ATH_TXFIFO_DEPTH);
1506 }
1507 txq->txq_tailidx = idx;
1508 }
1509
1510 txq->axq_link = NULL;
1511 txq->axq_tx_inprogress = false;
1512 ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001513
1514 /* flush any pending frames if aggregation is enabled */
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +05301515 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
Felix Fietkaufce041b2011-05-19 12:20:25 +02001516 ath_txq_drain_pending_buffers(sc, txq);
1517
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001518 ath_txq_unlock_complete(sc, txq);
Sujithe8324352009-01-16 21:38:42 +05301519}
1520
Felix Fietkau080e1a22010-12-05 20:17:53 +01001521bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
Sujith043a0402009-01-16 21:38:47 +05301522{
Sujithcbe61d82009-02-09 13:27:12 +05301523 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001524 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301525 struct ath_txq *txq;
Felix Fietkau34d25812011-10-07 02:28:12 +02001526 int i;
1527 u32 npend = 0;
Sujith043a0402009-01-16 21:38:47 +05301528
1529 if (sc->sc_flags & SC_OP_INVALID)
Felix Fietkau080e1a22010-12-05 20:17:53 +01001530 return true;
Sujith043a0402009-01-16 21:38:47 +05301531
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001532 ath9k_hw_abort_tx_dma(ah);
Sujith043a0402009-01-16 21:38:47 +05301533
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001534 /* Check if any queue remains active */
Sujith043a0402009-01-16 21:38:47 +05301535 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001536 if (!ATH_TXQ_SETUP(sc, i))
1537 continue;
1538
Felix Fietkau34d25812011-10-07 02:28:12 +02001539 if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))
1540 npend |= BIT(i);
Sujith043a0402009-01-16 21:38:47 +05301541 }
1542
Felix Fietkau080e1a22010-12-05 20:17:53 +01001543 if (npend)
Felix Fietkau34d25812011-10-07 02:28:12 +02001544 ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
Sujith043a0402009-01-16 21:38:47 +05301545
1546 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau92460412011-01-24 19:23:14 +01001547 if (!ATH_TXQ_SETUP(sc, i))
1548 continue;
1549
1550 /*
1551 * The caller will resume queues with ieee80211_wake_queues.
1552 * Mark the queue as not stopped to prevent ath_tx_complete
1553 * from waking the queue too early.
1554 */
1555 txq = &sc->tx.txq[i];
1556 txq->stopped = false;
1557 ath_draintxq(sc, txq, retry_tx);
Sujith043a0402009-01-16 21:38:47 +05301558 }
Felix Fietkau080e1a22010-12-05 20:17:53 +01001559
1560 return !npend;
Sujith043a0402009-01-16 21:38:47 +05301561}
1562
Sujithe8324352009-01-16 21:38:42 +05301563void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1564{
1565 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1566 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1567}
1568
Ben Greear7755bad2011-01-18 17:30:00 -08001569/* For each axq_acq entry, for each tid, try to schedule packets
1570 * for transmit until ampdu_depth has reached min Q depth.
1571 */
Sujithe8324352009-01-16 21:38:42 +05301572void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1573{
Ben Greear7755bad2011-01-18 17:30:00 -08001574 struct ath_atx_ac *ac, *ac_tmp, *last_ac;
1575 struct ath_atx_tid *tid, *last_tid;
Sujithe8324352009-01-16 21:38:42 +05301576
Felix Fietkau236de512011-09-03 01:40:25 +02001577 if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) ||
Felix Fietkau21f28e62011-01-15 14:30:14 +01001578 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
Sujithe8324352009-01-16 21:38:42 +05301579 return;
1580
1581 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
Ben Greear7755bad2011-01-18 17:30:00 -08001582 last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
Sujithe8324352009-01-16 21:38:42 +05301583
Ben Greear7755bad2011-01-18 17:30:00 -08001584 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1585 last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
1586 list_del(&ac->list);
1587 ac->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301588
Ben Greear7755bad2011-01-18 17:30:00 -08001589 while (!list_empty(&ac->tid_q)) {
1590 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
1591 list);
1592 list_del(&tid->list);
1593 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301594
Ben Greear7755bad2011-01-18 17:30:00 -08001595 if (tid->paused)
1596 continue;
Sujithe8324352009-01-16 21:38:42 +05301597
Ben Greear7755bad2011-01-18 17:30:00 -08001598 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301599
Ben Greear7755bad2011-01-18 17:30:00 -08001600 /*
1601 * add tid to round-robin queue if more frames
1602 * are pending for the tid
1603 */
Felix Fietkau56dc6332011-08-28 00:32:22 +02001604 if (!skb_queue_empty(&tid->buf_q))
Ben Greear7755bad2011-01-18 17:30:00 -08001605 ath_tx_queue_tid(txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301606
Ben Greear7755bad2011-01-18 17:30:00 -08001607 if (tid == last_tid ||
1608 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1609 break;
Sujithe8324352009-01-16 21:38:42 +05301610 }
Ben Greear7755bad2011-01-18 17:30:00 -08001611
Felix Fietkaub0477012011-12-14 22:08:05 +01001612 if (!list_empty(&ac->tid_q) && !ac->sched) {
1613 ac->sched = true;
1614 list_add_tail(&ac->list, &txq->axq_acq);
Ben Greear7755bad2011-01-18 17:30:00 -08001615 }
1616
1617 if (ac == last_ac ||
1618 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1619 return;
Sujithe8324352009-01-16 21:38:42 +05301620 }
1621}
1622
Sujithe8324352009-01-16 21:38:42 +05301623/***********/
1624/* TX, DMA */
1625/***********/
1626
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001627/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001628 * Insert a chain of ath_buf (descriptors) on a txq and
1629 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001630 */
Sujith102e0572008-10-29 10:15:16 +05301631static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +02001632 struct list_head *head, bool internal)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001633{
Sujithcbe61d82009-02-09 13:27:12 +05301634 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001635 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001636 struct ath_buf *bf, *bf_last;
1637 bool puttxbuf = false;
1638 bool edma;
Sujith102e0572008-10-29 10:15:16 +05301639
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001640 /*
1641 * Insert the frame on the outbound list and
1642 * pass it on to the hardware.
1643 */
1644
1645 if (list_empty(head))
1646 return;
1647
Felix Fietkaufce041b2011-05-19 12:20:25 +02001648 edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001649 bf = list_first_entry(head, struct ath_buf, list);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001650 bf_last = list_entry(head->prev, struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001651
Joe Perchesd2182b62011-12-15 14:55:53 -08001652 ath_dbg(common, QUEUE, "qnum: %d, txq depth: %d\n",
1653 txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001654
Felix Fietkaufce041b2011-05-19 12:20:25 +02001655 if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
1656 list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001657 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001658 puttxbuf = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001659 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001660 list_splice_tail_init(head, &txq->axq_q);
1661
Felix Fietkaufce041b2011-05-19 12:20:25 +02001662 if (txq->axq_link) {
1663 ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
Joe Perchesd2182b62011-12-15 14:55:53 -08001664 ath_dbg(common, XMIT, "link[%u] (%p)=%llx (%p)\n",
Joe Perches226afe62010-12-02 19:12:37 -08001665 txq->axq_qnum, txq->axq_link,
1666 ito64(bf->bf_daddr), bf->bf_desc);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001667 } else if (!edma)
1668 puttxbuf = true;
1669
1670 txq->axq_link = bf_last->bf_desc;
1671 }
1672
1673 if (puttxbuf) {
1674 TX_STAT_INC(txq->axq_qnum, puttxbuf);
1675 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Joe Perchesd2182b62011-12-15 14:55:53 -08001676 ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n",
Felix Fietkaufce041b2011-05-19 12:20:25 +02001677 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
1678 }
1679
1680 if (!edma) {
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001681 TX_STAT_INC(txq->axq_qnum, txstart);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001682 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001683 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001684
1685 if (!internal) {
1686 txq->axq_depth++;
1687 if (bf_is_ampdu_not_probing(bf))
1688 txq->axq_ampdu_depth++;
1689 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001690}
1691
Sujithe8324352009-01-16 21:38:42 +05301692static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau44f1d262011-08-28 00:32:25 +02001693 struct sk_buff *skb, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301694{
Felix Fietkau44f1d262011-08-28 00:32:25 +02001695 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau04caf862010-11-14 15:20:12 +01001696 struct list_head bf_head;
Felix Fietkau44f1d262011-08-28 00:32:25 +02001697 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301698
1699 /*
1700 * Do not queue to h/w when any of the following conditions is true:
1701 * - there are pending frames in software queue
1702 * - the TID is currently paused for ADDBA/BAR request
1703 * - seqno is not within block-ack window
1704 * - h/w queue depth exceeds low water mark
1705 */
Felix Fietkau56dc6332011-08-28 00:32:22 +02001706 if (!skb_queue_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau44f1d262011-08-28 00:32:25 +02001707 !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001708 txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001709 /*
Sujithe8324352009-01-16 21:38:42 +05301710 * Add this frame to software queue for scheduling later
1711 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001712 */
Ben Greearbda8add2011-01-09 23:11:48 -08001713 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001714 __skb_queue_tail(&tid->buf_q, skb);
Felix Fietkau9af73cf2011-08-10 15:23:35 -06001715 if (!txctl->an || !txctl->an->sleeping)
1716 ath_tx_queue_tid(txctl->txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301717 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001718 }
1719
Felix Fietkau81357a22012-05-24 14:32:20 +02001720 bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001721 if (!bf)
1722 return;
1723
Felix Fietkau399c6482011-09-14 21:24:17 +02001724 bf->bf_state.bf_type = BUF_AMPDU;
Felix Fietkau04caf862010-11-14 15:20:12 +01001725 INIT_LIST_HEAD(&bf_head);
1726 list_add(&bf->list, &bf_head);
1727
Sujithe8324352009-01-16 21:38:42 +05301728 /* Add sub-frame to BAW */
Felix Fietkau44f1d262011-08-28 00:32:25 +02001729 ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
Sujithe8324352009-01-16 21:38:42 +05301730
1731 /* Queue to h/w without aggregation */
Ben Greearbda8add2011-01-09 23:11:48 -08001732 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
Sujithd43f30152009-01-16 21:38:53 +05301733 bf->bf_lastbf = bf;
Felix Fietkau493cf042011-09-14 21:24:22 +02001734 ath_tx_fill_desc(sc, bf, txctl->txq, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001735 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
Sujithc4288392008-11-18 09:09:30 +05301736}
1737
Felix Fietkau82b873a2010-11-11 03:18:37 +01001738static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau44f1d262011-08-28 00:32:25 +02001739 struct ath_atx_tid *tid, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001740{
Felix Fietkau44f1d262011-08-28 00:32:25 +02001741 struct ath_frame_info *fi = get_frame_info(skb);
1742 struct list_head bf_head;
Sujithe8324352009-01-16 21:38:42 +05301743 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744
Felix Fietkau44f1d262011-08-28 00:32:25 +02001745 bf = fi->bf;
1746 if (!bf)
Felix Fietkau81357a22012-05-24 14:32:20 +02001747 bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001748
1749 if (!bf)
1750 return;
1751
1752 INIT_LIST_HEAD(&bf_head);
1753 list_add_tail(&bf->list, &bf_head);
Felix Fietkau399c6482011-09-14 21:24:17 +02001754 bf->bf_state.bf_type = 0;
Sujithe8324352009-01-16 21:38:42 +05301755
Sujithd43f30152009-01-16 21:38:53 +05301756 bf->bf_lastbf = bf;
Felix Fietkau493cf042011-09-14 21:24:22 +02001757 ath_tx_fill_desc(sc, bf, txq, fi->framelen);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001758 ath_tx_txqaddbuf(sc, txq, &bf_head, false);
Sujithfec247c2009-07-27 12:08:16 +05301759 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001760}
1761
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001762static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
1763 int framelen)
Sujith528f0c62008-10-29 10:14:26 +05301764{
1765 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001766 struct ieee80211_sta *sta = tx_info->control.sta;
1767 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
Felix Fietkau6a0ddae2011-08-28 00:32:23 +02001768 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau80b08a82012-06-15 03:04:53 +02001769 const struct ieee80211_rate *rate;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001770 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001771 struct ath_node *an = NULL;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001772 enum ath9k_key_type keytype;
Felix Fietkau80b08a82012-06-15 03:04:53 +02001773 bool short_preamble = false;
Sujith528f0c62008-10-29 10:14:26 +05301774
Felix Fietkau80b08a82012-06-15 03:04:53 +02001775 /*
1776 * We check if Short Preamble is needed for the CTS rate by
1777 * checking the BSS's global flag.
1778 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1779 */
1780 if (tx_info->control.vif &&
1781 tx_info->control.vif->bss_conf.use_short_preamble)
1782 short_preamble = true;
1783
1784 rate = ieee80211_get_rts_cts_rate(hw, tx_info);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001785 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujith528f0c62008-10-29 10:14:26 +05301786
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001787 if (sta)
1788 an = (struct ath_node *) sta->drv_priv;
1789
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001790 memset(fi, 0, sizeof(*fi));
1791 if (hw_key)
1792 fi->keyix = hw_key->hw_key_idx;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001793 else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
1794 fi->keyix = an->ps_key;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001795 else
1796 fi->keyix = ATH9K_TXKEYIX_INVALID;
1797 fi->keytype = keytype;
1798 fi->framelen = framelen;
Felix Fietkau80b08a82012-06-15 03:04:53 +02001799 fi->rtscts_rate = rate->hw_value;
1800 if (short_preamble)
1801 fi->rtscts_rate |= rate->hw_value_short;
Sujith528f0c62008-10-29 10:14:26 +05301802}
1803
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301804u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
1805{
1806 struct ath_hw *ah = sc->sc_ah;
1807 struct ath9k_channel *curchan = ah->curchan;
Rajkumar Manoharand77bf3e2011-08-13 10:28:14 +05301808 if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
1809 (curchan->channelFlags & CHANNEL_5GHZ) &&
1810 (chainmask == 0x7) && (rate < 0x90))
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301811 return 0x3;
1812 else
1813 return chainmask;
1814}
1815
Felix Fietkau44f1d262011-08-28 00:32:25 +02001816/*
1817 * Assign a descriptor (and sequence number if necessary,
1818 * and map buffer for DMA. Frees skb on error
1819 */
Felix Fietkaufa05f872011-08-28 00:32:24 +02001820static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
Felix Fietkau04caf862010-11-14 15:20:12 +01001821 struct ath_txq *txq,
Felix Fietkaufa05f872011-08-28 00:32:24 +02001822 struct ath_atx_tid *tid,
Felix Fietkau81357a22012-05-24 14:32:20 +02001823 struct sk_buff *skb,
1824 bool dequeue)
Sujithe8324352009-01-16 21:38:42 +05301825{
Felix Fietkau82b873a2010-11-11 03:18:37 +01001826 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001827 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkaufa05f872011-08-28 00:32:24 +02001828 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001829 struct ath_buf *bf;
Sujith Manoharanfd09c852012-04-17 08:34:50 +05301830 int fragno;
Felix Fietkaufa05f872011-08-28 00:32:24 +02001831 u16 seqno;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001832
1833 bf = ath_tx_get_buffer(sc);
1834 if (!bf) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001835 ath_dbg(common, XMIT, "TX buffers are full\n");
Felix Fietkau44f1d262011-08-28 00:32:25 +02001836 goto error;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001837 }
Sujithe8324352009-01-16 21:38:42 +05301838
Sujithe8324352009-01-16 21:38:42 +05301839 ATH_TXBUF_RESET(bf);
1840
Felix Fietkaufa05f872011-08-28 00:32:24 +02001841 if (tid) {
Sujith Manoharanfd09c852012-04-17 08:34:50 +05301842 fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
Felix Fietkaufa05f872011-08-28 00:32:24 +02001843 seqno = tid->seq_next;
1844 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Sujith Manoharanfd09c852012-04-17 08:34:50 +05301845
1846 if (fragno)
1847 hdr->seq_ctrl |= cpu_to_le16(fragno);
1848
1849 if (!ieee80211_has_morefrags(hdr->frame_control))
1850 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
1851
Felix Fietkaufa05f872011-08-28 00:32:24 +02001852 bf->bf_state.seqno = seqno;
1853 }
1854
Sujithe8324352009-01-16 21:38:42 +05301855 bf->bf_mpdu = skb;
1856
Ben Greearc1739eb32010-10-14 12:45:29 -07001857 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1858 skb->len, DMA_TO_DEVICE);
1859 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301860 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001861 bf->bf_buf_addr = 0;
Joe Perches38002762010-12-02 19:12:36 -08001862 ath_err(ath9k_hw_common(sc->sc_ah),
1863 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001864 ath_tx_return_buffer(sc, bf);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001865 goto error;
Sujithe8324352009-01-16 21:38:42 +05301866 }
1867
Felix Fietkau56dc6332011-08-28 00:32:22 +02001868 fi->bf = bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001869
1870 return bf;
Felix Fietkau44f1d262011-08-28 00:32:25 +02001871
1872error:
Felix Fietkau81357a22012-05-24 14:32:20 +02001873 if (dequeue)
1874 __skb_unlink(skb, &tid->buf_q);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001875 dev_kfree_skb_any(skb);
1876 return NULL;
Felix Fietkau04caf862010-11-14 15:20:12 +01001877}
1878
1879/* FIXME: tx power */
Felix Fietkau44f1d262011-08-28 00:32:25 +02001880static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau04caf862010-11-14 15:20:12 +01001881 struct ath_tx_control *txctl)
1882{
Felix Fietkau04caf862010-11-14 15:20:12 +01001883 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1884 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau248a38d2010-12-10 21:16:46 +01001885 struct ath_atx_tid *tid = NULL;
Felix Fietkaufa05f872011-08-28 00:32:24 +02001886 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001887 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301888
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +05301889 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an &&
Mohammed Shafi Shajakhan61e1b0b2011-03-21 18:27:21 +05301890 ieee80211_is_data_qos(hdr->frame_control)) {
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001891 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1892 IEEE80211_QOS_CTL_TID_MASK;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001893 tid = ATH_AN_2_TID(txctl->an, tidno);
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001894
Felix Fietkau066dae92010-11-07 14:59:39 +01001895 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau248a38d2010-12-10 21:16:46 +01001896 }
1897
1898 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
Felix Fietkau04caf862010-11-14 15:20:12 +01001899 /*
1900 * Try aggregation if it's a unicast data frame
1901 * and the destination is HT capable.
1902 */
Felix Fietkau44f1d262011-08-28 00:32:25 +02001903 ath_tx_send_ampdu(sc, tid, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301904 } else {
Felix Fietkau81357a22012-05-24 14:32:20 +02001905 bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
Felix Fietkau44f1d262011-08-28 00:32:25 +02001906 if (!bf)
Felix Fietkau3ad29522011-12-14 22:08:07 +01001907 return;
Felix Fietkau04caf862010-11-14 15:20:12 +01001908
Felix Fietkau82b873a2010-11-11 03:18:37 +01001909 bf->bf_state.bfs_paprd = txctl->paprd;
1910
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301911 if (txctl->paprd)
1912 bf->bf_state.bfs_paprd_timestamp = jiffies;
1913
Felix Fietkau44f1d262011-08-28 00:32:25 +02001914 ath_tx_send_normal(sc, txctl->txq, tid, skb);
Sujithe8324352009-01-16 21:38:42 +05301915 }
Sujithe8324352009-01-16 21:38:42 +05301916}
1917
1918/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001919int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301920 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001921{
Felix Fietkau28d16702010-11-14 15:20:10 +01001922 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1923 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001924 struct ieee80211_sta *sta = info->control.sta;
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001925 struct ieee80211_vif *vif = info->control.vif;
Felix Fietkau9ac58612011-01-24 19:23:18 +01001926 struct ath_softc *sc = hw->priv;
Felix Fietkau84642d62010-06-01 21:33:13 +02001927 struct ath_txq *txq = txctl->txq;
Felix Fietkau28d16702010-11-14 15:20:10 +01001928 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001929 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001930 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001931
Ben Greeara9927ba2010-12-06 21:13:49 -08001932 /* NOTE: sta can be NULL according to net/mac80211.h */
1933 if (sta)
1934 txctl->an = (struct ath_node *)sta->drv_priv;
1935
Felix Fietkau04caf862010-11-14 15:20:12 +01001936 if (info->control.hw_key)
1937 frmlen += info->control.hw_key->icv_len;
1938
Felix Fietkau28d16702010-11-14 15:20:10 +01001939 /*
1940 * As a temporary workaround, assign seq# here; this will likely need
1941 * to be cleaned up to work better with Beacon transmission and virtual
1942 * BSSes.
1943 */
1944 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1945 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1946 sc->tx.seq_no += 0x10;
1947 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1948 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1949 }
1950
John W. Linville42cecc32011-09-19 15:42:31 -04001951 /* Add the padding after the header if this is not already done */
1952 padpos = ath9k_cmn_padpos(hdr->frame_control);
1953 padsize = padpos & 3;
1954 if (padsize && skb->len > padpos) {
1955 if (skb_headroom(skb) < padsize)
1956 return -ENOMEM;
Felix Fietkau28d16702010-11-14 15:20:10 +01001957
John W. Linville42cecc32011-09-19 15:42:31 -04001958 skb_push(skb, padsize);
1959 memmove(skb->data, skb->data + padsize, padpos);
Felix Fietkau6e82bc4a2011-09-15 10:03:12 +02001960 hdr = (struct ieee80211_hdr *) skb->data;
Felix Fietkau28d16702010-11-14 15:20:10 +01001961 }
1962
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001963 if ((vif && vif->type != NL80211_IFTYPE_AP &&
1964 vif->type != NL80211_IFTYPE_AP_VLAN) ||
1965 !ieee80211_is_data(hdr->frame_control))
1966 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1967
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001968 setup_frame_info(hw, skb, frmlen);
1969
1970 /*
1971 * At this point, the vif, hw_key and sta pointers in the tx control
1972 * info are no longer valid (overwritten by the ath_frame_info data.
1973 */
1974
Felix Fietkau066dae92010-11-07 14:59:39 +01001975 q = skb_get_queue_mapping(skb);
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001976
1977 ath_txq_lock(sc, txq);
Felix Fietkau066dae92010-11-07 14:59:39 +01001978 if (txq == sc->tx.txq_map[q] &&
1979 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001980 ieee80211_stop_queue(sc->hw, q);
Rusty Russell3db1cd52011-12-19 13:56:45 +00001981 txq->stopped = true;
Felix Fietkau97923b12010-06-12 00:33:55 -04001982 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001983
Felix Fietkau44f1d262011-08-28 00:32:25 +02001984 ath_tx_start_dma(sc, skb, txctl);
Felix Fietkau3ad29522011-12-14 22:08:07 +01001985
Felix Fietkau23de5dc2011-12-19 16:45:54 +01001986 ath_txq_unlock(sc, txq);
Felix Fietkau3ad29522011-12-14 22:08:07 +01001987
Felix Fietkau44f1d262011-08-28 00:32:25 +02001988 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001989}
1990
Sujithe8324352009-01-16 21:38:42 +05301991/*****************/
1992/* TX Completion */
1993/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001994
Sujithe8324352009-01-16 21:38:42 +05301995static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Rajkumar Manoharan0f9dc292011-07-29 17:38:14 +05301996 int tx_flags, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001997{
Sujithe8324352009-01-16 21:38:42 +05301998 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001999 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01002000 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04002001 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05302002
Joe Perchesd2182b62011-12-15 14:55:53 -08002003 ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05302004
Felix Fietkau55797b12011-09-14 21:24:16 +02002005 if (!(tx_flags & ATH_TX_ERROR))
Sujithe8324352009-01-16 21:38:42 +05302006 /* Frame was ACKed */
2007 tx_info->flags |= IEEE80211_TX_STAT_ACK;
Sujithe8324352009-01-16 21:38:42 +05302008
John W. Linville42cecc32011-09-19 15:42:31 -04002009 padpos = ath9k_cmn_padpos(hdr->frame_control);
2010 padsize = padpos & 3;
2011 if (padsize && skb->len>padpos+padsize) {
2012 /*
2013 * Remove MAC header padding before giving the frame back to
2014 * mac80211.
2015 */
2016 memmove(skb->data + padsize, skb->data, padpos);
2017 skb_pull(skb, padsize);
Sujithe8324352009-01-16 21:38:42 +05302018 }
2019
Felix Fietkauc8e88682011-11-16 13:08:40 +01002020 if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
Sujith1b04b932010-01-08 10:36:05 +05302021 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Joe Perchesd2182b62011-12-15 14:55:53 -08002022 ath_dbg(common, PS,
Joe Perches226afe62010-12-02 19:12:37 -08002023 "Going back to sleep after having received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05302024 sc->ps_flags & (PS_WAIT_FOR_BEACON |
2025 PS_WAIT_FOR_CAB |
2026 PS_WAIT_FOR_PSPOLL_DATA |
2027 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03002028 }
2029
Felix Fietkau7545daf2011-01-24 19:23:16 +01002030 q = skb_get_queue_mapping(skb);
2031 if (txq == sc->tx.txq_map[q]) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01002032 if (WARN_ON(--txq->pending_frames < 0))
2033 txq->pending_frames = 0;
Felix Fietkau92460412011-01-24 19:23:14 +01002034
Felix Fietkau7545daf2011-01-24 19:23:16 +01002035 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
2036 ieee80211_wake_queue(sc->hw, q);
Rusty Russell3db1cd52011-12-19 13:56:45 +00002037 txq->stopped = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002038 }
Felix Fietkau97923b12010-06-12 00:33:55 -04002039 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01002040
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002041 __skb_queue_tail(&txq->complete_q, skb);
Sujithe8324352009-01-16 21:38:42 +05302042}
2043
2044static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002045 struct ath_txq *txq, struct list_head *bf_q,
Felix Fietkau156369f2011-12-14 22:08:04 +01002046 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05302047{
2048 struct sk_buff *skb = bf->bf_mpdu;
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002049 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithe8324352009-01-16 21:38:42 +05302050 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05302051 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05302052
Felix Fietkau55797b12011-09-14 21:24:16 +02002053 if (!txok)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05302054 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05302055
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002056 if (ts->ts_status & ATH9K_TXERR_FILT)
2057 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
2058
Ben Greearc1739eb32010-10-14 12:45:29 -07002059 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07002060 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04002061
2062 if (bf->bf_state.bfs_paprd) {
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05302063 if (time_after(jiffies,
2064 bf->bf_state.bfs_paprd_timestamp +
2065 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07002066 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07002067 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07002068 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04002069 } else {
Felix Fietkau55797b12011-09-14 21:24:16 +02002070 ath_debug_stat_tx(sc, bf, ts, txq, tx_flags);
Rajkumar Manoharan0f9dc292011-07-29 17:38:14 +05302071 ath_tx_complete(sc, skb, tx_flags, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04002072 }
Ben Greear6cf9e992010-10-14 12:45:30 -07002073 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
2074 * accidentally reference it later.
2075 */
2076 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05302077
2078 /*
2079 * Return the list of ath_buf of this mpdu to free queue
2080 */
2081 spin_lock_irqsave(&sc->tx.txbuflock, flags);
2082 list_splice_tail_init(bf_q, &sc->tx.txbuf);
2083 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
2084}
2085
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002086static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
2087 struct ath_tx_status *ts, int nframes, int nbad,
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002088 int txok)
Sujithc4288392008-11-18 09:09:30 +05302089{
Sujitha22be222009-03-30 15:28:36 +05302090 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302091 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302092 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002093 struct ieee80211_hw *hw = sc->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002094 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302095 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302096
Sujith95e4acb2009-03-13 08:56:09 +05302097 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002098 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302099
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002100 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302101 WARN_ON(tx_rateindex >= hw->max_rates);
2102
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002103 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Felix Fietkaud9698472010-03-01 13:32:11 +01002104 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302105
Felix Fietkaub572d032010-11-14 15:20:07 +01002106 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02002107 }
Rajkumar Manoharan185d1582011-09-26 21:48:39 +05302108 tx_info->status.ampdu_len = nframes;
2109 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02002110
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002111 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002112 (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002113 /*
2114 * If an underrun error is seen assume it as an excessive
2115 * retry only if max frame trigger level has been reached
2116 * (2 KB for single stream, and 4 KB for dual stream).
2117 * Adjust the long retry as if the frame was tried
2118 * hw->max_rate_tries times to affect how rate control updates
2119 * PER for the failed rate.
2120 * In case of congestion on the bus penalizing this type of
2121 * underruns should help hardware actually transmit new frames
2122 * successfully by eventually preferring slower rates.
2123 * This itself should also alleviate congestion on the bus.
2124 */
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002125 if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
2126 ATH9K_TX_DELIM_UNDERRUN)) &&
2127 ieee80211_is_data(hdr->frame_control) &&
Felix Fietkau83860c52011-03-23 20:57:33 +01002128 ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002129 tx_info->status.rates[tx_rateindex].count =
2130 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05302131 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302132
Felix Fietkau545750d2009-11-23 22:21:01 +01002133 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302134 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002135 tx_info->status.rates[i].idx = -1;
2136 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302137
Felix Fietkau78c46532010-06-25 01:26:16 +02002138 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302139}
2140
Felix Fietkaufce041b2011-05-19 12:20:25 +02002141static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
2142 struct ath_tx_status *ts, struct ath_buf *bf,
2143 struct list_head *bf_head)
2144{
2145 int txok;
2146
2147 txq->axq_depth--;
2148 txok = !(ts->ts_status & ATH9K_TXERR_MASK);
2149 txq->axq_tx_inprogress = false;
2150 if (bf_is_ampdu_not_probing(bf))
2151 txq->axq_ampdu_depth--;
2152
Felix Fietkaufce041b2011-05-19 12:20:25 +02002153 if (!bf_isampdu(bf)) {
Felix Fietkau3afd21e2011-09-14 21:24:26 +02002154 ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
Felix Fietkau156369f2011-12-14 22:08:04 +01002155 ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002156 } else
2157 ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
2158
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +05302159 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
Felix Fietkaufce041b2011-05-19 12:20:25 +02002160 ath_txq_schedule(sc, txq);
2161}
2162
Sujithc4288392008-11-18 09:09:30 +05302163static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164{
Sujithcbe61d82009-02-09 13:27:12 +05302165 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002166 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002167 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2168 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302169 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002170 struct ath_tx_status ts;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002171 int status;
2172
Joe Perchesd2182b62011-12-15 14:55:53 -08002173 ath_dbg(common, QUEUE, "tx queue %d (%x), link %p\n",
Joe Perches226afe62010-12-02 19:12:37 -08002174 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2175 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002176
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002177 ath_txq_lock(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002178 for (;;) {
Felix Fietkau236de512011-09-03 01:40:25 +02002179 if (work_pending(&sc->hw_reset_work))
2180 break;
2181
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002182 if (list_empty(&txq->axq_q)) {
2183 txq->axq_link = NULL;
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +05302184 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
Ben Greear082f6532011-01-09 23:11:47 -08002185 ath_txq_schedule(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002186 break;
2187 }
2188 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2189
2190 /*
2191 * There is a race condition that a BH gets scheduled
2192 * after sw writes TxE and before hw re-load the last
2193 * descriptor to get the newly chained one.
2194 * Software must keep the last DONE descriptor as a
2195 * holding descriptor - software does so by marking
2196 * it with the STALE flag.
2197 */
2198 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302199 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002200 bf_held = bf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002201 if (list_is_last(&bf_held->list, &txq->axq_q))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002202 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002203
2204 bf = list_entry(bf_held->list.next, struct ath_buf,
2205 list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002206 }
2207
2208 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302209 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002210
Felix Fietkau29bffa92010-03-29 20:14:23 -07002211 memset(&ts, 0, sizeof(ts));
2212 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002213 if (status == -EINPROGRESS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002214 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002215
Ben Greear2dac4fb2011-01-09 23:11:45 -08002216 TX_STAT_INC(txq->axq_qnum, txprocdesc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002217
2218 /*
2219 * Remove ath_buf's of the same transmit unit from txq,
2220 * however leave the last descriptor back as the holding
2221 * descriptor for hw.
2222 */
Sujitha119cc42009-03-30 15:28:38 +05302223 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002224 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002225 if (!list_is_singular(&lastbf->list))
2226 list_cut_position(&bf_head,
2227 &txq->axq_q, lastbf->list.prev);
2228
Felix Fietkaufce041b2011-05-19 12:20:25 +02002229 if (bf_held) {
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002230 list_del(&bf_held->list);
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002231 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002232 }
Johannes Berge6a98542008-10-21 12:40:02 +02002233
Felix Fietkaufce041b2011-05-19 12:20:25 +02002234 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002235 }
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002236 ath_txq_unlock_complete(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002237}
2238
Sujith305fe472009-07-23 15:32:29 +05302239static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002240{
2241 struct ath_softc *sc = container_of(work, struct ath_softc,
2242 tx_complete_work.work);
2243 struct ath_txq *txq;
2244 int i;
2245 bool needreset = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08002246#ifdef CONFIG_ATH9K_DEBUGFS
2247 sc->tx_complete_poll_work_seen++;
2248#endif
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002249
2250 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2251 if (ATH_TXQ_SETUP(sc, i)) {
2252 txq = &sc->tx.txq[i];
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002253 ath_txq_lock(sc, txq);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002254 if (txq->axq_depth) {
2255 if (txq->axq_tx_inprogress) {
2256 needreset = true;
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002257 ath_txq_unlock(sc, txq);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002258 break;
2259 } else {
2260 txq->axq_tx_inprogress = true;
2261 }
2262 }
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002263 ath_txq_unlock_complete(sc, txq);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002264 }
2265
2266 if (needreset) {
Joe Perchesd2182b62011-12-15 14:55:53 -08002267 ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
Joe Perches226afe62010-12-02 19:12:37 -08002268 "tx hung, resetting the chip\n");
Felix Fietkau030d6292011-10-07 02:28:13 +02002269 RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
Felix Fietkau236de512011-09-03 01:40:25 +02002270 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002271 }
2272
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002273 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002274 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2275}
2276
2277
Sujithe8324352009-01-16 21:38:42 +05302278
2279void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002280{
Felix Fietkau239c7952012-03-14 16:40:26 +01002281 struct ath_hw *ah = sc->sc_ah;
2282 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs;
Sujithe8324352009-01-16 21:38:42 +05302283 int i;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002284
2285 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302286 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2287 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002288 }
2289}
2290
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002291void ath_tx_edma_tasklet(struct ath_softc *sc)
2292{
Felix Fietkaufce041b2011-05-19 12:20:25 +02002293 struct ath_tx_status ts;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002294 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2295 struct ath_hw *ah = sc->sc_ah;
2296 struct ath_txq *txq;
2297 struct ath_buf *bf, *lastbf;
2298 struct list_head bf_head;
2299 int status;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002300
2301 for (;;) {
Felix Fietkau236de512011-09-03 01:40:25 +02002302 if (work_pending(&sc->hw_reset_work))
2303 break;
2304
Felix Fietkaufce041b2011-05-19 12:20:25 +02002305 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002306 if (status == -EINPROGRESS)
2307 break;
2308 if (status == -EIO) {
Joe Perchesd2182b62011-12-15 14:55:53 -08002309 ath_dbg(common, XMIT, "Error processing tx status\n");
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002310 break;
2311 }
2312
Felix Fietkau4e0ad252012-02-27 19:58:42 +01002313 /* Process beacon completions separately */
2314 if (ts.qid == sc->beacon.beaconq) {
2315 sc->beacon.tx_processed = true;
2316 sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002317 continue;
Felix Fietkau4e0ad252012-02-27 19:58:42 +01002318 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002319
Felix Fietkaufce041b2011-05-19 12:20:25 +02002320 txq = &sc->tx.txq[ts.qid];
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002321
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002322 ath_txq_lock(sc, txq);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002323
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002324 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002325 ath_txq_unlock(sc, txq);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002326 return;
2327 }
2328
2329 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2330 struct ath_buf, list);
2331 lastbf = bf->bf_lastbf;
2332
2333 INIT_LIST_HEAD(&bf_head);
2334 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2335 &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002336
Felix Fietkaufce041b2011-05-19 12:20:25 +02002337 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2338 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002339
Felix Fietkaufce041b2011-05-19 12:20:25 +02002340 if (!list_empty(&txq->axq_q)) {
2341 struct list_head bf_q;
2342
2343 INIT_LIST_HEAD(&bf_q);
2344 txq->axq_link = NULL;
2345 list_splice_tail_init(&txq->axq_q, &bf_q);
2346 ath_tx_txqaddbuf(sc, txq, &bf_q, true);
2347 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002348 }
2349
Felix Fietkaufce041b2011-05-19 12:20:25 +02002350 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002351 ath_txq_unlock_complete(sc, txq);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002352 }
2353}
2354
Sujithe8324352009-01-16 21:38:42 +05302355/*****************/
2356/* Init, Cleanup */
2357/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002358
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002359static int ath_txstatus_setup(struct ath_softc *sc, int size)
2360{
2361 struct ath_descdma *dd = &sc->txsdma;
2362 u8 txs_len = sc->sc_ah->caps.txs_len;
2363
2364 dd->dd_desc_len = size * txs_len;
2365 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2366 &dd->dd_desc_paddr, GFP_KERNEL);
2367 if (!dd->dd_desc)
2368 return -ENOMEM;
2369
2370 return 0;
2371}
2372
2373static int ath_tx_edma_init(struct ath_softc *sc)
2374{
2375 int err;
2376
2377 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2378 if (!err)
2379 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2380 sc->txsdma.dd_desc_paddr,
2381 ATH_TXSTATUS_RING_SIZE);
2382
2383 return err;
2384}
2385
2386static void ath_tx_edma_cleanup(struct ath_softc *sc)
2387{
2388 struct ath_descdma *dd = &sc->txsdma;
2389
2390 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2391 dd->dd_desc_paddr);
2392}
2393
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002394int ath_tx_init(struct ath_softc *sc, int nbufs)
2395{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002396 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002397 int error = 0;
2398
Sujith797fe5cb2009-03-30 15:28:45 +05302399 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002400
Sujith797fe5cb2009-03-30 15:28:45 +05302401 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002402 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302403 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002404 ath_err(common,
2405 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302406 goto err;
2407 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002408
Sujith797fe5cb2009-03-30 15:28:45 +05302409 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002410 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302411 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002412 ath_err(common,
2413 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302414 goto err;
2415 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002416
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002417 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2418
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002419 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2420 error = ath_tx_edma_init(sc);
2421 if (error)
2422 goto err;
2423 }
2424
Sujith797fe5cb2009-03-30 15:28:45 +05302425err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002426 if (error != 0)
2427 ath_tx_cleanup(sc);
2428
2429 return error;
2430}
2431
Sujith797fe5cb2009-03-30 15:28:45 +05302432void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002433{
Sujithb77f4832008-12-07 21:44:03 +05302434 if (sc->beacon.bdma.dd_desc_len != 0)
2435 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002436
Sujithb77f4832008-12-07 21:44:03 +05302437 if (sc->tx.txdma.dd_desc_len != 0)
2438 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002439
2440 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2441 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002442}
2443
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002444void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2445{
Sujithc5170162008-10-29 10:13:59 +05302446 struct ath_atx_tid *tid;
2447 struct ath_atx_ac *ac;
2448 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002449
Sujith8ee5afb2008-12-07 21:43:36 +05302450 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302451 tidno < WME_NUM_TID;
2452 tidno++, tid++) {
2453 tid->an = an;
2454 tid->tidno = tidno;
2455 tid->seq_start = tid->seq_next = 0;
2456 tid->baw_size = WME_MAX_BA;
2457 tid->baw_head = tid->baw_tail = 0;
2458 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302459 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302460 tid->state &= ~AGGR_CLEANUP;
Felix Fietkau56dc6332011-08-28 00:32:22 +02002461 __skb_queue_head_init(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302462 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302463 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302464 tid->state &= ~AGGR_ADDBA_COMPLETE;
2465 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302466 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002467
Sujith8ee5afb2008-12-07 21:43:36 +05302468 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302469 acno < WME_NUM_AC; acno++, ac++) {
2470 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002471 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302472 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002473 }
2474}
2475
Sujithb5aa9bf2008-10-29 10:13:31 +05302476void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002477{
Felix Fietkau2b409942010-07-07 19:42:08 +02002478 struct ath_atx_ac *ac;
2479 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002480 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002481 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302482
Felix Fietkau2b409942010-07-07 19:42:08 +02002483 for (tidno = 0, tid = &an->tid[tidno];
2484 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002485
Felix Fietkau2b409942010-07-07 19:42:08 +02002486 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002487 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002488
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002489 ath_txq_lock(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002490
Felix Fietkau2b409942010-07-07 19:42:08 +02002491 if (tid->sched) {
2492 list_del(&tid->list);
2493 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002494 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002495
2496 if (ac->sched) {
2497 list_del(&ac->list);
2498 tid->ac->sched = false;
2499 }
2500
2501 ath_tid_drain(sc, txq, tid);
2502 tid->state &= ~AGGR_ADDBA_COMPLETE;
2503 tid->state &= ~AGGR_CLEANUP;
2504
Felix Fietkau23de5dc2011-12-19 16:45:54 +01002505 ath_txq_unlock(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002506 }
2507}