blob: 33443bcaa8d9b27c6b3a7d70be54a4e470c38efd [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
Sujith394cf0a2009-02-09 13:26:54 +053017#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040018#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070019
20#define BITS_PER_BYTE 8
21#define OFDM_PLCP_BITS 22
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070022#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
23#define L_STF 8
24#define L_LTF 8
25#define L_SIG 4
26#define HT_SIG 8
27#define HT_STF 4
28#define HT_LTF(_ns) (4 * (_ns))
29#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
30#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
31#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
32#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
33
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070034
Felix Fietkauc6663872010-04-19 19:57:33 +020035static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070036 /* 20MHz 40MHz */
37 { 26, 54 }, /* 0: BPSK */
38 { 52, 108 }, /* 1: QPSK 1/2 */
39 { 78, 162 }, /* 2: QPSK 3/4 */
40 { 104, 216 }, /* 3: 16-QAM 1/2 */
41 { 156, 324 }, /* 4: 16-QAM 3/4 */
42 { 208, 432 }, /* 5: 64-QAM 2/3 */
43 { 234, 486 }, /* 6: 64-QAM 3/4 */
44 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070045};
46
47#define IS_HT_RATE(_rate) ((_rate) & 0x80)
48
Felix Fietkau82b873a2010-11-11 03:18:37 +010049static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
50 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +010051 struct list_head *bf_head);
Sujithe8324352009-01-16 21:38:42 +053052static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070053 struct ath_txq *txq, struct list_head *bf_q,
54 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053055static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
56 struct list_head *head);
Felix Fietkau269c44b2010-11-14 15:20:06 +010057static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +010058static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
59 struct ath_tx_status *ts, int nframes, int nbad,
60 int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020061static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
62 int seqno);
Sujithe8324352009-01-16 21:38:42 +053063
Felix Fietkau545750d2009-11-23 22:21:01 +010064enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020065 MCS_HT20,
66 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010067 MCS_HT40,
68 MCS_HT40_SGI,
69};
70
Felix Fietkau0e668cd2010-04-19 19:57:32 +020071static int ath_max_4ms_framelen[4][32] = {
72 [MCS_HT20] = {
73 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
74 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
75 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
76 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
77 },
78 [MCS_HT20_SGI] = {
79 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
80 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
81 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
82 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010083 },
84 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020085 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
86 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
87 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
88 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010089 },
90 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020091 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
92 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
93 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
94 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010095 }
96};
97
Sujithe8324352009-01-16 21:38:42 +053098/*********************/
99/* Aggregation logic */
100/*********************/
101
Sujithe8324352009-01-16 21:38:42 +0530102static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
103{
104 struct ath_atx_ac *ac = tid->ac;
105
106 if (tid->paused)
107 return;
108
109 if (tid->sched)
110 return;
111
112 tid->sched = true;
113 list_add_tail(&tid->list, &ac->tid_q);
114
115 if (ac->sched)
116 return;
117
118 ac->sched = true;
119 list_add_tail(&ac->list, &txq->axq_acq);
120}
121
Sujithe8324352009-01-16 21:38:42 +0530122static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
123{
Felix Fietkau066dae92010-11-07 14:59:39 +0100124 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530125
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200126 WARN_ON(!tid->paused);
127
Sujithe8324352009-01-16 21:38:42 +0530128 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200129 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530130
131 if (list_empty(&tid->buf_q))
132 goto unlock;
133
134 ath_tx_queue_tid(txq, tid);
135 ath_txq_schedule(sc, txq);
136unlock:
137 spin_unlock_bh(&txq->axq_lock);
138}
139
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100140static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
Felix Fietkau76e45222010-11-14 15:20:08 +0100141{
142 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100143 BUILD_BUG_ON(sizeof(struct ath_frame_info) >
144 sizeof(tx_info->rate_driver_data));
145 return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
Felix Fietkau76e45222010-11-14 15:20:08 +0100146}
147
Sujithe8324352009-01-16 21:38:42 +0530148static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
149{
Felix Fietkau066dae92010-11-07 14:59:39 +0100150 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530151 struct ath_buf *bf;
152 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200153 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100154 struct ath_frame_info *fi;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200155
Sujithe8324352009-01-16 21:38:42 +0530156 INIT_LIST_HEAD(&bf_head);
157
Felix Fietkau90fa5392010-09-20 13:45:38 +0200158 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530159 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530160
161 while (!list_empty(&tid->buf_q)) {
162 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530163 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200164
Felix Fietkaue1566d12010-11-20 03:08:46 +0100165 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100166 fi = get_frame_info(bf->bf_mpdu);
167 if (fi->retries) {
168 ath_tx_update_baw(sc, tid, fi->seqno);
Felix Fietkau7d2c16b2011-03-12 01:11:28 +0100169 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200170 } else {
Felix Fietkaua9e99a02011-01-10 17:05:47 -0700171 ath_tx_send_normal(sc, txq, NULL, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200172 }
Felix Fietkaue1566d12010-11-20 03:08:46 +0100173 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530174 }
175
176 spin_unlock_bh(&txq->axq_lock);
177}
178
179static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
180 int seqno)
181{
182 int index, cindex;
183
184 index = ATH_BA_INDEX(tid->seq_start, seqno);
185 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
186
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200187 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530188
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200189 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530190 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
191 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
192 }
193}
194
195static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100196 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530197{
198 int index, cindex;
199
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100200 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530201 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200202 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530203
204 if (index >= ((tid->baw_tail - tid->baw_head) &
205 (ATH_TID_MAX_BUFS - 1))) {
206 tid->baw_tail = cindex;
207 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
208 }
209}
210
211/*
212 * TODO: For frame(s) that are in the retry state, we will reuse the
213 * sequence number(s) without setting the retry bit. The
214 * alternative is to give up on these and BAR the receiver's window
215 * forward.
216 */
217static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
218 struct ath_atx_tid *tid)
219
220{
221 struct ath_buf *bf;
222 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700223 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100224 struct ath_frame_info *fi;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700225
226 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530227 INIT_LIST_HEAD(&bf_head);
228
229 for (;;) {
230 if (list_empty(&tid->buf_q))
231 break;
Sujithe8324352009-01-16 21:38:42 +0530232
Sujithd43f30152009-01-16 21:38:53 +0530233 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
234 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530235
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100236 fi = get_frame_info(bf->bf_mpdu);
237 if (fi->retries)
238 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530239
240 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700241 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530242 spin_lock(&txq->axq_lock);
243 }
244
245 tid->seq_next = tid->seq_start;
246 tid->baw_tail = tid->baw_head;
247}
248
Sujithfec247c2009-07-27 12:08:16 +0530249static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100250 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +0530251{
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100252 struct ath_frame_info *fi = get_frame_info(skb);
Sujithe8324352009-01-16 21:38:42 +0530253 struct ieee80211_hdr *hdr;
254
Sujithfec247c2009-07-27 12:08:16 +0530255 TX_STAT_INC(txq->axq_qnum, a_retries);
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100256 if (fi->retries++ > 0)
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100257 return;
Sujithe8324352009-01-16 21:38:42 +0530258
Sujithe8324352009-01-16 21:38:42 +0530259 hdr = (struct ieee80211_hdr *)skb->data;
260 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
261}
262
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200263static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
264{
265 struct ath_buf *bf = NULL;
266
267 spin_lock_bh(&sc->tx.txbuflock);
268
269 if (unlikely(list_empty(&sc->tx.txbuf))) {
270 spin_unlock_bh(&sc->tx.txbuflock);
271 return NULL;
272 }
273
274 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
275 list_del(&bf->list);
276
277 spin_unlock_bh(&sc->tx.txbuflock);
278
279 return bf;
280}
281
282static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
283{
284 spin_lock_bh(&sc->tx.txbuflock);
285 list_add_tail(&bf->list, &sc->tx.txbuf);
286 spin_unlock_bh(&sc->tx.txbuflock);
287}
288
Sujithd43f30152009-01-16 21:38:53 +0530289static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
290{
291 struct ath_buf *tbf;
292
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200293 tbf = ath_tx_get_buffer(sc);
294 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530295 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530296
297 ATH_TXBUF_RESET(tbf);
298
299 tbf->bf_mpdu = bf->bf_mpdu;
300 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400301 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530302 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530303
304 return tbf;
305}
306
Felix Fietkaub572d032010-11-14 15:20:07 +0100307static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
308 struct ath_tx_status *ts, int txok,
309 int *nframes, int *nbad)
310{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100311 struct ath_frame_info *fi;
Felix Fietkaub572d032010-11-14 15:20:07 +0100312 u16 seq_st = 0;
313 u32 ba[WME_BA_BMP_SIZE >> 5];
314 int ba_index;
315 int isaggr = 0;
316
317 *nbad = 0;
318 *nframes = 0;
319
Felix Fietkaub572d032010-11-14 15:20:07 +0100320 isaggr = bf_isaggr(bf);
321 if (isaggr) {
322 seq_st = ts->ts_seqnum;
323 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
324 }
325
326 while (bf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100327 fi = get_frame_info(bf->bf_mpdu);
328 ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
Felix Fietkaub572d032010-11-14 15:20:07 +0100329
330 (*nframes)++;
331 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
332 (*nbad)++;
333
334 bf = bf->bf_next;
335 }
336}
337
338
Sujithd43f30152009-01-16 21:38:53 +0530339static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
340 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100341 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530342{
343 struct ath_node *an = NULL;
344 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530345 struct ieee80211_sta *sta;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100346 struct ieee80211_hw *hw = sc->hw;
Sujith1286ec62009-01-27 13:30:37 +0530347 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800348 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530349 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530350 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530351 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530352 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530353 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530354 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
355 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200356 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100357 struct ath_frame_info *fi;
Björn Smedmanebd02282010-10-10 22:44:39 +0200358 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100359 u8 tidno;
Felix Fietkau55195412011-04-17 23:28:09 +0200360 bool clear_filter;
Sujithe8324352009-01-16 21:38:42 +0530361
Sujitha22be222009-03-30 15:28:36 +0530362 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530363 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530364
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800365 tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800366
Felix Fietkau78c46532010-06-25 01:26:16 +0200367 memcpy(rates, tx_info->control.rates, sizeof(rates));
368
Sujith1286ec62009-01-27 13:30:37 +0530369 rcu_read_lock();
370
Ben Greear686b9cb2010-09-23 09:44:36 -0700371 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530372 if (!sta) {
373 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200374
Felix Fietkau31e79a52010-07-12 23:16:34 +0200375 INIT_LIST_HEAD(&bf_head);
376 while (bf) {
377 bf_next = bf->bf_next;
378
379 bf->bf_state.bf_type |= BUF_XRETRY;
380 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
381 !bf->bf_stale || bf_next != NULL)
382 list_move_tail(&bf->list, &bf_head);
383
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100384 ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200385 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
386 0, 0);
387
388 bf = bf_next;
389 }
Sujith1286ec62009-01-27 13:30:37 +0530390 return;
Sujithe8324352009-01-16 21:38:42 +0530391 }
392
Sujith1286ec62009-01-27 13:30:37 +0530393 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100394 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
395 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530396
Felix Fietkaub11b1602010-07-11 12:48:44 +0200397 /*
398 * The hardware occasionally sends a tx status for the wrong TID.
399 * In this case, the BA status cannot be considered valid and all
400 * subframes need to be retransmitted
401 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100402 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200403 txok = false;
404
Sujithe8324352009-01-16 21:38:42 +0530405 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530406 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530407
Sujithd43f30152009-01-16 21:38:53 +0530408 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700409 if (ts->ts_flags & ATH9K_TX_BA) {
410 seq_st = ts->ts_seqnum;
411 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530412 } else {
Sujithd43f30152009-01-16 21:38:53 +0530413 /*
414 * AR5416 can become deaf/mute when BA
415 * issue happens. Chip needs to be reset.
416 * But AP code may have sychronization issues
417 * when perform internal reset in this routine.
418 * Only enable reset in STA mode for now.
419 */
Sujith2660b812009-02-09 13:27:26 +0530420 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530421 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530422 }
423 }
424
425 INIT_LIST_HEAD(&bf_pending);
426 INIT_LIST_HEAD(&bf_head);
427
Felix Fietkaub572d032010-11-14 15:20:07 +0100428 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530429 while (bf) {
Felix Fietkauf0b82202011-01-15 14:30:15 +0100430 txfail = txpending = sendbar = 0;
Sujithe8324352009-01-16 21:38:42 +0530431 bf_next = bf->bf_next;
432
Felix Fietkau78c46532010-06-25 01:26:16 +0200433 skb = bf->bf_mpdu;
434 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100435 fi = get_frame_info(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200436
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100437 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530438 /* transmit completion, subframe is
439 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530440 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530441 } else if (!isaggr && txok) {
442 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530443 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530444 } else {
Felix Fietkau55195412011-04-17 23:28:09 +0200445 if ((tid->state & AGGR_CLEANUP) || !retry) {
Sujithe8324352009-01-16 21:38:42 +0530446 /*
447 * cleanup in progress, just fail
448 * the un-acked sub-frames
449 */
450 txfail = 1;
Felix Fietkau55195412011-04-17 23:28:09 +0200451 } else if (fi->retries < ATH_MAX_SW_RETRIES) {
452 if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
453 !an->sleeping)
454 ath_tx_set_retry(sc, txq, bf->bf_mpdu);
455
456 clear_filter = true;
457 txpending = 1;
458 } else {
459 bf->bf_state.bf_type |= BUF_XRETRY;
460 txfail = 1;
461 sendbar = 1;
462 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530463 }
464 }
465
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400466 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
467 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530468 /*
469 * Make sure the last desc is reclaimed if it
470 * not a holding desc.
471 */
472 if (!bf_last->bf_stale)
473 list_move_tail(&bf->list, &bf_head);
474 else
475 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530476 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700477 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530478 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530479 }
480
Felix Fietkau90fa5392010-09-20 13:45:38 +0200481 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530482 /*
483 * complete the acked-ones/xretried ones; update
484 * block-ack window
485 */
486 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100487 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530488 spin_unlock_bh(&txq->axq_lock);
489
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530490 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200491 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100492 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530493 rc_update = false;
494 } else {
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100495 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530496 }
497
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700498 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
499 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530500 } else {
Sujithd43f30152009-01-16 21:38:53 +0530501 /* retry the un-acked ones */
Felix Fietkau55195412011-04-17 23:28:09 +0200502 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400503 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
504 if (bf->bf_next == NULL && bf_last->bf_stale) {
505 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530506
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400507 tbf = ath_clone_txbuf(sc, bf_last);
508 /*
509 * Update tx baw and complete the
510 * frame with failed status if we
511 * run out of tx buf.
512 */
513 if (!tbf) {
514 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100515 ath_tx_update_baw(sc, tid, fi->seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400516 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400517
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400518 bf->bf_state.bf_type |=
519 BUF_XRETRY;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100520 ath_tx_rc_status(sc, bf, ts, nframes,
Felix Fietkaub572d032010-11-14 15:20:07 +0100521 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400522 ath_tx_complete_buf(sc, bf, txq,
523 &bf_head,
524 ts, 0, 0);
525 break;
526 }
527
528 ath9k_hw_cleartxdesc(sc->sc_ah,
529 tbf->bf_desc);
530 list_add_tail(&tbf->list, &bf_head);
531 } else {
532 /*
533 * Clear descriptor status words for
534 * software retry
535 */
536 ath9k_hw_cleartxdesc(sc->sc_ah,
537 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400538 }
Sujithe8324352009-01-16 21:38:42 +0530539 }
540
541 /*
542 * Put this buffer to the temporary pending
543 * queue to retain ordering
544 */
545 list_splice_tail_init(&bf_head, &bf_pending);
546 }
547
548 bf = bf_next;
549 }
550
Felix Fietkau4cee7862010-07-23 03:53:16 +0200551 /* prepend un-acked frames to the beginning of the pending frame queue */
552 if (!list_empty(&bf_pending)) {
Felix Fietkau55195412011-04-17 23:28:09 +0200553 if (an->sleeping)
554 ieee80211_sta_set_tim(sta);
555
Felix Fietkau4cee7862010-07-23 03:53:16 +0200556 spin_lock_bh(&txq->axq_lock);
Felix Fietkau55195412011-04-17 23:28:09 +0200557 if (clear_filter)
558 tid->ac->clear_ps_filter = true;
Felix Fietkau4cee7862010-07-23 03:53:16 +0200559 list_splice(&bf_pending, &tid->buf_q);
560 ath_tx_queue_tid(txq, tid);
561 spin_unlock_bh(&txq->axq_lock);
562 }
563
Sujithe8324352009-01-16 21:38:42 +0530564 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200565 ath_tx_flush_tid(sc, tid);
566
Sujithe8324352009-01-16 21:38:42 +0530567 if (tid->baw_head == tid->baw_tail) {
568 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530569 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530570 }
Sujithe8324352009-01-16 21:38:42 +0530571 }
572
Sujith1286ec62009-01-27 13:30:37 +0530573 rcu_read_unlock();
574
Vivek Natarajanbdd62c02011-01-27 14:45:10 +0530575 if (needreset) {
576 spin_unlock_bh(&sc->sc_pcu_lock);
Sujithe8324352009-01-16 21:38:42 +0530577 ath_reset(sc, false);
Vivek Natarajanbdd62c02011-01-27 14:45:10 +0530578 spin_lock_bh(&sc->sc_pcu_lock);
579 }
Sujithe8324352009-01-16 21:38:42 +0530580}
581
582static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
583 struct ath_atx_tid *tid)
584{
Sujithe8324352009-01-16 21:38:42 +0530585 struct sk_buff *skb;
586 struct ieee80211_tx_info *tx_info;
587 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530588 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530589 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530590 int i;
591
Sujitha22be222009-03-30 15:28:36 +0530592 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530593 tx_info = IEEE80211_SKB_CB(skb);
594 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530595
596 /*
597 * Find the lowest frame length among the rate series that will have a
598 * 4ms transmit duration.
599 * TODO - TXOP limit needs to be considered.
600 */
601 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
602
603 for (i = 0; i < 4; i++) {
604 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100605 int modeidx;
606 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530607 legacy = 1;
608 break;
609 }
610
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200611 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100612 modeidx = MCS_HT40;
613 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200614 modeidx = MCS_HT20;
615
616 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
617 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100618
619 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530620 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530621 }
622 }
623
624 /*
625 * limit aggregate size by the minimum rate if rate selected is
626 * not a probe rate, if rate selected is a probe rate then
627 * avoid aggregation of this packet.
628 */
629 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
630 return 0;
631
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530632 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
633 aggr_limit = min((max_4ms_framelen * 3) / 8,
634 (u32)ATH_AMPDU_LIMIT_MAX);
635 else
636 aggr_limit = min(max_4ms_framelen,
637 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530638
639 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300640 * h/w can accept aggregates up to 16 bit lengths (65535).
641 * The IE, however can hold up to 65536, which shows up here
Sujithe8324352009-01-16 21:38:42 +0530642 * as zero. Ignore 65536 since we are constrained by hw.
643 */
Sujith4ef70842009-07-23 15:32:41 +0530644 if (tid->an->maxampdu)
645 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530646
647 return aggr_limit;
648}
649
650/*
Sujithd43f30152009-01-16 21:38:53 +0530651 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530652 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530653 */
654static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
655 struct ath_buf *bf, u16 frmlen)
656{
Sujithe8324352009-01-16 21:38:42 +0530657 struct sk_buff *skb = bf->bf_mpdu;
658 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530659 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530660 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100661 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200662 int width, streams, half_gi, ndelim, mindelim;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100663 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530664
665 /* Select standard number of delimiters based on frame length alone */
666 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
667
668 /*
669 * If encryption enabled, hardware requires some more padding between
670 * subframes.
671 * TODO - this could be improved to be dependent on the rate.
672 * The hardware can keep up at lower rates, but not higher rates
673 */
Rajkumar Manoharan4f6760b2011-07-01 18:37:33 +0530674 if ((fi->keyix != ATH9K_TXKEYIX_INVALID) &&
675 !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
Sujithe8324352009-01-16 21:38:42 +0530676 ndelim += ATH_AGGR_ENCRYPTDELIM;
677
678 /*
679 * Convert desired mpdu density from microeconds to bytes based
680 * on highest rate in rate series (i.e. first rate) to determine
681 * required minimum length for subframe. Take into account
682 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530683 *
Sujithe8324352009-01-16 21:38:42 +0530684 * If there is no mpdu density restriction, no further calculation
685 * is needed.
686 */
Sujith4ef70842009-07-23 15:32:41 +0530687
688 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530689 return ndelim;
690
691 rix = tx_info->control.rates[0].idx;
692 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530693 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
694 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
695
696 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530697 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530698 else
Sujith4ef70842009-07-23 15:32:41 +0530699 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530700
701 if (nsymbols == 0)
702 nsymbols = 1;
703
Felix Fietkauc6663872010-04-19 19:57:33 +0200704 streams = HT_RC_2_STREAMS(rix);
705 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530706 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
707
Sujithe8324352009-01-16 21:38:42 +0530708 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530709 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
710 ndelim = max(mindelim, ndelim);
711 }
712
713 return ndelim;
714}
715
716static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530717 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530718 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100719 struct list_head *bf_q,
720 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530721{
722#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530723 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
724 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530725 u16 aggr_limit = 0, al = 0, bpad = 0,
726 al_delta, h_baw = tid->baw_size / 2;
727 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200728 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100729 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530730
731 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
732
733 do {
734 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100735 fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530736
Sujithd43f30152009-01-16 21:38:53 +0530737 /* do not step over block-ack window */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100738 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530739 status = ATH_AGGR_BAW_CLOSED;
740 break;
741 }
742
743 if (!rl) {
744 aggr_limit = ath_lookup_rate(sc, bf, tid);
745 rl = 1;
746 }
747
Sujithd43f30152009-01-16 21:38:53 +0530748 /* do not exceed aggregation limit */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100749 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
Sujithe8324352009-01-16 21:38:42 +0530750
Sujithd43f30152009-01-16 21:38:53 +0530751 if (nframes &&
752 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530753 status = ATH_AGGR_LIMITED;
754 break;
755 }
756
Felix Fietkau0299a502010-10-21 02:47:24 +0200757 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
758 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
759 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
760 break;
761
Sujithd43f30152009-01-16 21:38:53 +0530762 /* do not exceed subframe limit */
763 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530764 status = ATH_AGGR_LIMITED;
765 break;
766 }
Sujithd43f30152009-01-16 21:38:53 +0530767 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530768
Sujithd43f30152009-01-16 21:38:53 +0530769 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530770 al += bpad + al_delta;
771
772 /*
773 * Get the delimiters needed to meet the MPDU
774 * density for this node.
775 */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100776 ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +0530777 bpad = PADBYTES(al_delta) + (ndelim << 2);
778
779 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400780 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530781
Sujithd43f30152009-01-16 21:38:53 +0530782 /* link buffers of this frame to the aggregate */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100783 if (!fi->retries)
784 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithd43f30152009-01-16 21:38:53 +0530785 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
786 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530787 if (bf_prev) {
788 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400789 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
790 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530791 }
792 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530793
Sujithe8324352009-01-16 21:38:42 +0530794 } while (!list_empty(&tid->buf_q));
795
Felix Fietkau269c44b2010-11-14 15:20:06 +0100796 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530797
Sujithe8324352009-01-16 21:38:42 +0530798 return status;
799#undef PADBYTES
800}
801
802static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
803 struct ath_atx_tid *tid)
804{
Sujithd43f30152009-01-16 21:38:53 +0530805 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530806 enum ATH_AGGR_STATUS status;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100807 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530808 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100809 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530810
811 do {
812 if (list_empty(&tid->buf_q))
813 return;
814
815 INIT_LIST_HEAD(&bf_q);
816
Felix Fietkau269c44b2010-11-14 15:20:06 +0100817 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530818
819 /*
Sujithd43f30152009-01-16 21:38:53 +0530820 * no frames picked up to be aggregated;
821 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530822 */
823 if (list_empty(&bf_q))
824 break;
825
826 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530827 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530828
Felix Fietkau55195412011-04-17 23:28:09 +0200829 if (tid->ac->clear_ps_filter) {
830 tid->ac->clear_ps_filter = false;
831 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
832 }
833
Sujithd43f30152009-01-16 21:38:53 +0530834 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100835 if (bf == bf->bf_lastbf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100836 fi = get_frame_info(bf->bf_mpdu);
837
Sujithe8324352009-01-16 21:38:42 +0530838 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530839 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100840 ath_buf_set_rate(sc, bf, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +0530841 ath_tx_txqaddbuf(sc, txq, &bf_q);
842 continue;
843 }
844
Sujithd43f30152009-01-16 21:38:53 +0530845 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530846 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100847 ath_buf_set_rate(sc, bf, aggr_len);
848 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530849
Sujithd43f30152009-01-16 21:38:53 +0530850 /* anchor last desc of aggregate */
851 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530852
Sujithe8324352009-01-16 21:38:42 +0530853 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530854 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530855
Felix Fietkau4b3ba662010-12-17 00:57:00 +0100856 } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
Sujithe8324352009-01-16 21:38:42 +0530857 status != ATH_AGGR_BAW_CLOSED);
858}
859
Felix Fietkau231c3a12010-09-20 19:35:28 +0200860int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
861 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530862{
863 struct ath_atx_tid *txtid;
864 struct ath_node *an;
865
866 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530867 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200868
869 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
870 return -EAGAIN;
871
Sujithf83da962009-07-23 15:32:37 +0530872 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200873 txtid->paused = true;
Felix Fietkau49447f22011-01-10 17:05:48 -0700874 *ssn = txtid->seq_start = txtid->seq_next;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200875
Felix Fietkau2ed72222011-01-10 17:05:49 -0700876 memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
877 txtid->baw_head = txtid->baw_tail = 0;
878
Felix Fietkau231c3a12010-09-20 19:35:28 +0200879 return 0;
Sujithe8324352009-01-16 21:38:42 +0530880}
881
Sujithf83da962009-07-23 15:32:37 +0530882void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530883{
884 struct ath_node *an = (struct ath_node *)sta->drv_priv;
885 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100886 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530887
888 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530889 return;
Sujithe8324352009-01-16 21:38:42 +0530890
891 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530892 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530893 return;
Sujithe8324352009-01-16 21:38:42 +0530894 }
895
Sujithe8324352009-01-16 21:38:42 +0530896 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200897 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200898
899 /*
900 * If frames are still being transmitted for this TID, they will be
901 * cleaned up during tx completion. To prevent race conditions, this
902 * TID can only be reused after all in-progress subframes have been
903 * completed.
904 */
905 if (txtid->baw_head != txtid->baw_tail)
906 txtid->state |= AGGR_CLEANUP;
907 else
908 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530909 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530910
Felix Fietkau90fa5392010-09-20 13:45:38 +0200911 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530912}
913
Felix Fietkau55195412011-04-17 23:28:09 +0200914bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
915{
916 struct ath_atx_tid *tid;
917 struct ath_atx_ac *ac;
918 struct ath_txq *txq;
919 bool buffered = false;
920 int tidno;
921
922 for (tidno = 0, tid = &an->tid[tidno];
923 tidno < WME_NUM_TID; tidno++, tid++) {
924
925 if (!tid->sched)
926 continue;
927
928 ac = tid->ac;
929 txq = ac->txq;
930
931 spin_lock_bh(&txq->axq_lock);
932
933 if (!list_empty(&tid->buf_q))
934 buffered = true;
935
936 tid->sched = false;
937 list_del(&tid->list);
938
939 if (ac->sched) {
940 ac->sched = false;
941 list_del(&ac->list);
942 }
943
944 spin_unlock_bh(&txq->axq_lock);
945 }
946
947 return buffered;
948}
949
950void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
951{
952 struct ath_atx_tid *tid;
953 struct ath_atx_ac *ac;
954 struct ath_txq *txq;
955 int tidno;
956
957 for (tidno = 0, tid = &an->tid[tidno];
958 tidno < WME_NUM_TID; tidno++, tid++) {
959
960 ac = tid->ac;
961 txq = ac->txq;
962
963 spin_lock_bh(&txq->axq_lock);
964 ac->clear_ps_filter = true;
965
966 if (!list_empty(&tid->buf_q) && !tid->paused) {
967 ath_tx_queue_tid(txq, tid);
968 ath_txq_schedule(sc, txq);
969 }
970
971 spin_unlock_bh(&txq->axq_lock);
972 }
973}
974
Sujithe8324352009-01-16 21:38:42 +0530975void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
976{
977 struct ath_atx_tid *txtid;
978 struct ath_node *an;
979
980 an = (struct ath_node *)sta->drv_priv;
981
982 if (sc->sc_flags & SC_OP_TXAGGR) {
983 txtid = ATH_AN_2_TID(an, tid);
984 txtid->baw_size =
985 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
986 txtid->state |= AGGR_ADDBA_COMPLETE;
987 txtid->state &= ~AGGR_ADDBA_PROGRESS;
988 ath_tx_resume_tid(sc, txtid);
989 }
990}
991
Sujithe8324352009-01-16 21:38:42 +0530992/********************/
993/* Queue Management */
994/********************/
995
Sujithe8324352009-01-16 21:38:42 +0530996static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
997 struct ath_txq *txq)
998{
999 struct ath_atx_ac *ac, *ac_tmp;
1000 struct ath_atx_tid *tid, *tid_tmp;
1001
1002 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1003 list_del(&ac->list);
1004 ac->sched = false;
1005 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
1006 list_del(&tid->list);
1007 tid->sched = false;
1008 ath_tid_drain(sc, txq, tid);
1009 }
1010 }
1011}
1012
1013struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
1014{
Sujithcbe61d82009-02-09 13:27:12 +05301015 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001016 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +05301017 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001018 static const int subtype_txq_to_hwq[] = {
1019 [WME_AC_BE] = ATH_TXQ_AC_BE,
1020 [WME_AC_BK] = ATH_TXQ_AC_BK,
1021 [WME_AC_VI] = ATH_TXQ_AC_VI,
1022 [WME_AC_VO] = ATH_TXQ_AC_VO,
1023 };
Ben Greear60f2d1d2011-01-09 23:11:52 -08001024 int axq_qnum, i;
Sujithe8324352009-01-16 21:38:42 +05301025
1026 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +01001027 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +05301028 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
1029 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
1030 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
1031 qi.tqi_physCompBuf = 0;
1032
1033 /*
1034 * Enable interrupts only for EOL and DESC conditions.
1035 * We mark tx descriptors to receive a DESC interrupt
1036 * when a tx queue gets deep; otherwise waiting for the
1037 * EOL to reap descriptors. Note that this is done to
1038 * reduce interrupt load and this only defers reaping
1039 * descriptors, never transmitting frames. Aside from
1040 * reducing interrupts this also permits more concurrency.
1041 * The only potential downside is if the tx queue backs
1042 * up in which case the top half of the kernel may backup
1043 * due to a lack of tx descriptors.
1044 *
1045 * The UAPSD queue is an exception, since we take a desc-
1046 * based intr on the EOSP frames.
1047 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -04001048 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1049 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
1050 TXQ_FLAG_TXERRINT_ENABLE;
1051 } else {
1052 if (qtype == ATH9K_TX_QUEUE_UAPSD)
1053 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
1054 else
1055 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
1056 TXQ_FLAG_TXDESCINT_ENABLE;
1057 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001058 axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
1059 if (axq_qnum == -1) {
Sujithe8324352009-01-16 21:38:42 +05301060 /*
1061 * NB: don't print a message, this happens
1062 * normally on parts with too few tx queues
1063 */
1064 return NULL;
1065 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001066 if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
Joe Perches38002762010-12-02 19:12:36 -08001067 ath_err(common, "qnum %u out of range, max %zu!\n",
Ben Greear60f2d1d2011-01-09 23:11:52 -08001068 axq_qnum, ARRAY_SIZE(sc->tx.txq));
1069 ath9k_hw_releasetxqueue(ah, axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301070 return NULL;
1071 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001072 if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
1073 struct ath_txq *txq = &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301074
Ben Greear60f2d1d2011-01-09 23:11:52 -08001075 txq->axq_qnum = axq_qnum;
1076 txq->mac80211_qnum = -1;
Sujithe8324352009-01-16 21:38:42 +05301077 txq->axq_link = NULL;
1078 INIT_LIST_HEAD(&txq->axq_q);
1079 INIT_LIST_HEAD(&txq->axq_acq);
1080 spin_lock_init(&txq->axq_lock);
1081 txq->axq_depth = 0;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001082 txq->axq_ampdu_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001083 txq->axq_tx_inprogress = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08001084 sc->tx.txqsetup |= 1<<axq_qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001085
1086 txq->txq_headidx = txq->txq_tailidx = 0;
1087 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1088 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1089 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301090 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001091 return &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301092}
1093
Sujithe8324352009-01-16 21:38:42 +05301094int ath_txq_update(struct ath_softc *sc, int qnum,
1095 struct ath9k_tx_queue_info *qinfo)
1096{
Sujithcbe61d82009-02-09 13:27:12 +05301097 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301098 int error = 0;
1099 struct ath9k_tx_queue_info qi;
1100
1101 if (qnum == sc->beacon.beaconq) {
1102 /*
1103 * XXX: for beacon queue, we just save the parameter.
1104 * It will be picked up by ath_beaconq_config when
1105 * it's necessary.
1106 */
1107 sc->beacon.beacon_qi = *qinfo;
1108 return 0;
1109 }
1110
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001111 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301112
1113 ath9k_hw_get_txq_props(ah, qnum, &qi);
1114 qi.tqi_aifs = qinfo->tqi_aifs;
1115 qi.tqi_cwmin = qinfo->tqi_cwmin;
1116 qi.tqi_cwmax = qinfo->tqi_cwmax;
1117 qi.tqi_burstTime = qinfo->tqi_burstTime;
1118 qi.tqi_readyTime = qinfo->tqi_readyTime;
1119
1120 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Joe Perches38002762010-12-02 19:12:36 -08001121 ath_err(ath9k_hw_common(sc->sc_ah),
1122 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301123 error = -EIO;
1124 } else {
1125 ath9k_hw_resettxqueue(ah, qnum);
1126 }
1127
1128 return error;
1129}
1130
1131int ath_cabq_update(struct ath_softc *sc)
1132{
1133 struct ath9k_tx_queue_info qi;
Steve Brown9814f6b2011-02-07 17:10:39 -07001134 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
Sujithe8324352009-01-16 21:38:42 +05301135 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301136
1137 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1138 /*
1139 * Ensure the readytime % is within the bounds.
1140 */
Sujith17d79042009-02-09 13:27:03 +05301141 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1142 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1143 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1144 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301145
Steve Brown9814f6b2011-02-07 17:10:39 -07001146 qi.tqi_readyTime = (cur_conf->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301147 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301148 ath_txq_update(sc, qnum, &qi);
1149
1150 return 0;
1151}
1152
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001153static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
1154{
1155 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
1156 return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
1157}
1158
Sujith043a0402009-01-16 21:38:47 +05301159/*
1160 * Drain a given TX queue (could be Beacon or Data)
1161 *
1162 * This assumes output has been stopped and
1163 * we do not need to block ath_tx_tasklet.
1164 */
1165void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301166{
1167 struct ath_buf *bf, *lastbf;
1168 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001169 struct ath_tx_status ts;
1170
1171 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301172 INIT_LIST_HEAD(&bf_head);
1173
Sujithe8324352009-01-16 21:38:42 +05301174 for (;;) {
1175 spin_lock_bh(&txq->axq_lock);
1176
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001177 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1178 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1179 txq->txq_headidx = txq->txq_tailidx = 0;
1180 spin_unlock_bh(&txq->axq_lock);
1181 break;
1182 } else {
1183 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1184 struct ath_buf, list);
1185 }
1186 } else {
1187 if (list_empty(&txq->axq_q)) {
1188 txq->axq_link = NULL;
1189 spin_unlock_bh(&txq->axq_lock);
1190 break;
1191 }
1192 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1193 list);
Sujithe8324352009-01-16 21:38:42 +05301194
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001195 if (bf->bf_stale) {
1196 list_del(&bf->list);
1197 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301198
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001199 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001200 continue;
1201 }
Sujithe8324352009-01-16 21:38:42 +05301202 }
1203
1204 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05301205
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001206 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1207 list_cut_position(&bf_head,
1208 &txq->txq_fifo[txq->txq_tailidx],
1209 &lastbf->list);
1210 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1211 } else {
1212 /* remove ath_buf's of the same mpdu from txq */
1213 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1214 }
1215
Sujithe8324352009-01-16 21:38:42 +05301216 txq->axq_depth--;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001217 if (bf_is_ampdu_not_probing(bf))
1218 txq->axq_ampdu_depth--;
Sujithe8324352009-01-16 21:38:42 +05301219 spin_unlock_bh(&txq->axq_lock);
1220
1221 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001222 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1223 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301224 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001225 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301226 }
1227
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001228 spin_lock_bh(&txq->axq_lock);
1229 txq->axq_tx_inprogress = false;
1230 spin_unlock_bh(&txq->axq_lock);
1231
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001232 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1233 spin_lock_bh(&txq->axq_lock);
1234 while (!list_empty(&txq->txq_fifo_pending)) {
1235 bf = list_first_entry(&txq->txq_fifo_pending,
1236 struct ath_buf, list);
1237 list_cut_position(&bf_head,
1238 &txq->txq_fifo_pending,
1239 &bf->bf_lastbf->list);
1240 spin_unlock_bh(&txq->axq_lock);
1241
1242 if (bf_isampdu(bf))
1243 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
Felix Fietkauc5992612010-11-14 15:20:09 +01001244 &ts, 0, retry_tx);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001245 else
1246 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1247 &ts, 0, 0);
1248 spin_lock_bh(&txq->axq_lock);
1249 }
1250 spin_unlock_bh(&txq->axq_lock);
1251 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001252
1253 /* flush any pending frames if aggregation is enabled */
1254 if (sc->sc_flags & SC_OP_TXAGGR) {
1255 if (!retry_tx) {
1256 spin_lock_bh(&txq->axq_lock);
1257 ath_txq_drain_pending_buffers(sc, txq);
1258 spin_unlock_bh(&txq->axq_lock);
1259 }
1260 }
Sujithe8324352009-01-16 21:38:42 +05301261}
1262
Felix Fietkau080e1a22010-12-05 20:17:53 +01001263bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
Sujith043a0402009-01-16 21:38:47 +05301264{
Sujithcbe61d82009-02-09 13:27:12 +05301265 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001266 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301267 struct ath_txq *txq;
1268 int i, npend = 0;
1269
1270 if (sc->sc_flags & SC_OP_INVALID)
Felix Fietkau080e1a22010-12-05 20:17:53 +01001271 return true;
Sujith043a0402009-01-16 21:38:47 +05301272
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001273 ath9k_hw_abort_tx_dma(ah);
Sujith043a0402009-01-16 21:38:47 +05301274
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001275 /* Check if any queue remains active */
Sujith043a0402009-01-16 21:38:47 +05301276 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001277 if (!ATH_TXQ_SETUP(sc, i))
1278 continue;
1279
1280 npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
Sujith043a0402009-01-16 21:38:47 +05301281 }
1282
Felix Fietkau080e1a22010-12-05 20:17:53 +01001283 if (npend)
John W. Linville393934c2010-12-08 16:23:31 -05001284 ath_err(common, "Failed to stop TX DMA!\n");
Sujith043a0402009-01-16 21:38:47 +05301285
1286 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau92460412011-01-24 19:23:14 +01001287 if (!ATH_TXQ_SETUP(sc, i))
1288 continue;
1289
1290 /*
1291 * The caller will resume queues with ieee80211_wake_queues.
1292 * Mark the queue as not stopped to prevent ath_tx_complete
1293 * from waking the queue too early.
1294 */
1295 txq = &sc->tx.txq[i];
1296 txq->stopped = false;
1297 ath_draintxq(sc, txq, retry_tx);
Sujith043a0402009-01-16 21:38:47 +05301298 }
Felix Fietkau080e1a22010-12-05 20:17:53 +01001299
1300 return !npend;
Sujith043a0402009-01-16 21:38:47 +05301301}
1302
Sujithe8324352009-01-16 21:38:42 +05301303void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1304{
1305 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1306 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1307}
1308
Ben Greear7755bad2011-01-18 17:30:00 -08001309/* For each axq_acq entry, for each tid, try to schedule packets
1310 * for transmit until ampdu_depth has reached min Q depth.
1311 */
Sujithe8324352009-01-16 21:38:42 +05301312void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1313{
Ben Greear7755bad2011-01-18 17:30:00 -08001314 struct ath_atx_ac *ac, *ac_tmp, *last_ac;
1315 struct ath_atx_tid *tid, *last_tid;
Sujithe8324352009-01-16 21:38:42 +05301316
Felix Fietkau21f28e62011-01-15 14:30:14 +01001317 if (list_empty(&txq->axq_acq) ||
1318 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
Sujithe8324352009-01-16 21:38:42 +05301319 return;
1320
1321 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
Ben Greear7755bad2011-01-18 17:30:00 -08001322 last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
Sujithe8324352009-01-16 21:38:42 +05301323
Ben Greear7755bad2011-01-18 17:30:00 -08001324 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1325 last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
1326 list_del(&ac->list);
1327 ac->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301328
Ben Greear7755bad2011-01-18 17:30:00 -08001329 while (!list_empty(&ac->tid_q)) {
1330 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
1331 list);
1332 list_del(&tid->list);
1333 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301334
Ben Greear7755bad2011-01-18 17:30:00 -08001335 if (tid->paused)
1336 continue;
Sujithe8324352009-01-16 21:38:42 +05301337
Ben Greear7755bad2011-01-18 17:30:00 -08001338 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301339
Ben Greear7755bad2011-01-18 17:30:00 -08001340 /*
1341 * add tid to round-robin queue if more frames
1342 * are pending for the tid
1343 */
1344 if (!list_empty(&tid->buf_q))
1345 ath_tx_queue_tid(txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301346
Ben Greear7755bad2011-01-18 17:30:00 -08001347 if (tid == last_tid ||
1348 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1349 break;
Sujithe8324352009-01-16 21:38:42 +05301350 }
Ben Greear7755bad2011-01-18 17:30:00 -08001351
1352 if (!list_empty(&ac->tid_q)) {
1353 if (!ac->sched) {
1354 ac->sched = true;
1355 list_add_tail(&ac->list, &txq->axq_acq);
1356 }
1357 }
1358
1359 if (ac == last_ac ||
1360 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1361 return;
Sujithe8324352009-01-16 21:38:42 +05301362 }
1363}
1364
Sujithe8324352009-01-16 21:38:42 +05301365/***********/
1366/* TX, DMA */
1367/***********/
1368
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001369/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001370 * Insert a chain of ath_buf (descriptors) on a txq and
1371 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001372 */
Sujith102e0572008-10-29 10:15:16 +05301373static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1374 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001375{
Sujithcbe61d82009-02-09 13:27:12 +05301376 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001377 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001378 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301379
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001380 /*
1381 * Insert the frame on the outbound list and
1382 * pass it on to the hardware.
1383 */
1384
1385 if (list_empty(head))
1386 return;
1387
1388 bf = list_first_entry(head, struct ath_buf, list);
1389
Joe Perches226afe62010-12-02 19:12:37 -08001390 ath_dbg(common, ATH_DBG_QUEUE,
1391 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001392
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001393 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1394 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1395 list_splice_tail_init(head, &txq->txq_fifo_pending);
1396 return;
1397 }
1398 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
Joe Perches226afe62010-12-02 19:12:37 -08001399 ath_dbg(common, ATH_DBG_XMIT,
1400 "Initializing tx fifo %d which is non-empty\n",
1401 txq->txq_headidx);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001402 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1403 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1404 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001405 TX_STAT_INC(txq->axq_qnum, puttxbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001406 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Joe Perches226afe62010-12-02 19:12:37 -08001407 ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
1408 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001410 list_splice_tail_init(head, &txq->axq_q);
1411
1412 if (txq->axq_link == NULL) {
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001413 TX_STAT_INC(txq->axq_qnum, puttxbuf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001414 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Joe Perches226afe62010-12-02 19:12:37 -08001415 ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
1416 txq->axq_qnum, ito64(bf->bf_daddr),
1417 bf->bf_desc);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001418 } else {
1419 *txq->axq_link = bf->bf_daddr;
Joe Perches226afe62010-12-02 19:12:37 -08001420 ath_dbg(common, ATH_DBG_XMIT,
1421 "link[%u] (%p)=%llx (%p)\n",
1422 txq->axq_qnum, txq->axq_link,
1423 ito64(bf->bf_daddr), bf->bf_desc);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001424 }
1425 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1426 &txq->axq_link);
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001427 TX_STAT_INC(txq->axq_qnum, txstart);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001428 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001429 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001430 txq->axq_depth++;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001431 if (bf_is_ampdu_not_probing(bf))
1432 txq->axq_ampdu_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001433}
1434
Sujithe8324352009-01-16 21:38:42 +05301435static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau04caf862010-11-14 15:20:12 +01001436 struct ath_buf *bf, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301437{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001438 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau04caf862010-11-14 15:20:12 +01001439 struct list_head bf_head;
Sujithe8324352009-01-16 21:38:42 +05301440
Sujithe8324352009-01-16 21:38:42 +05301441 bf->bf_state.bf_type |= BUF_AMPDU;
1442
1443 /*
1444 * Do not queue to h/w when any of the following conditions is true:
1445 * - there are pending frames in software queue
1446 * - the TID is currently paused for ADDBA/BAR request
1447 * - seqno is not within block-ack window
1448 * - h/w queue depth exceeds low water mark
1449 */
1450 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001451 !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001452 txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001453 /*
Sujithe8324352009-01-16 21:38:42 +05301454 * Add this frame to software queue for scheduling later
1455 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001456 */
Ben Greearbda8add2011-01-09 23:11:48 -08001457 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
Felix Fietkau04caf862010-11-14 15:20:12 +01001458 list_add_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301459 ath_tx_queue_tid(txctl->txq, tid);
1460 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001461 }
1462
Felix Fietkau04caf862010-11-14 15:20:12 +01001463 INIT_LIST_HEAD(&bf_head);
1464 list_add(&bf->list, &bf_head);
1465
Sujithe8324352009-01-16 21:38:42 +05301466 /* Add sub-frame to BAW */
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001467 if (!fi->retries)
1468 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +05301469
1470 /* Queue to h/w without aggregation */
Ben Greearbda8add2011-01-09 23:11:48 -08001471 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
Sujithd43f30152009-01-16 21:38:53 +05301472 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001473 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkau04caf862010-11-14 15:20:12 +01001474 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
Sujithc4288392008-11-18 09:09:30 +05301475}
1476
Felix Fietkau82b873a2010-11-11 03:18:37 +01001477static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1478 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001479 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001480{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001481 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +05301482 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001483
Sujithe8324352009-01-16 21:38:42 +05301484 bf = list_first_entry(bf_head, struct ath_buf, list);
1485 bf->bf_state.bf_type &= ~BUF_AMPDU;
1486
1487 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001488 if (tid)
1489 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301490
Sujithd43f30152009-01-16 21:38:53 +05301491 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001492 fi = get_frame_info(bf->bf_mpdu);
1493 ath_buf_set_rate(sc, bf, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +05301494 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301495 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001496}
1497
Sujith528f0c62008-10-29 10:14:26 +05301498static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499{
Sujith528f0c62008-10-29 10:14:26 +05301500 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001501 enum ath9k_pkt_type htype;
1502 __le16 fc;
1503
Sujith528f0c62008-10-29 10:14:26 +05301504 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 fc = hdr->frame_control;
1506
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001507 if (ieee80211_is_beacon(fc))
1508 htype = ATH9K_PKT_TYPE_BEACON;
1509 else if (ieee80211_is_probe_resp(fc))
1510 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1511 else if (ieee80211_is_atim(fc))
1512 htype = ATH9K_PKT_TYPE_ATIM;
1513 else if (ieee80211_is_pspoll(fc))
1514 htype = ATH9K_PKT_TYPE_PSPOLL;
1515 else
1516 htype = ATH9K_PKT_TYPE_NORMAL;
1517
1518 return htype;
1519}
1520
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001521static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
1522 int framelen)
Sujith528f0c62008-10-29 10:14:26 +05301523{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001524 struct ath_softc *sc = hw->priv;
Sujith528f0c62008-10-29 10:14:26 +05301525 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001526 struct ieee80211_sta *sta = tx_info->control.sta;
1527 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
Sujith528f0c62008-10-29 10:14:26 +05301528 struct ieee80211_hdr *hdr;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001529 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001530 struct ath_node *an = NULL;
Sujith528f0c62008-10-29 10:14:26 +05301531 struct ath_atx_tid *tid;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001532 enum ath9k_key_type keytype;
1533 u16 seqno = 0;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001534 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301535
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001536 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujith528f0c62008-10-29 10:14:26 +05301537
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001538 if (sta)
1539 an = (struct ath_node *) sta->drv_priv;
1540
Sujith528f0c62008-10-29 10:14:26 +05301541 hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001542 if (an && ieee80211_is_data_qos(hdr->frame_control) &&
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001543 conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001544
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001545 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
1546
1547 /*
1548 * Override seqno set by upper layer with the one
1549 * in tx aggregation state.
1550 */
1551 tid = ATH_AN_2_TID(an, tidno);
1552 seqno = tid->seq_next;
1553 hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
1554 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
1555 }
1556
1557 memset(fi, 0, sizeof(*fi));
1558 if (hw_key)
1559 fi->keyix = hw_key->hw_key_idx;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001560 else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
1561 fi->keyix = an->ps_key;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001562 else
1563 fi->keyix = ATH9K_TXKEYIX_INVALID;
1564 fi->keytype = keytype;
1565 fi->framelen = framelen;
1566 fi->seqno = seqno;
Sujith528f0c62008-10-29 10:14:26 +05301567}
1568
Felix Fietkau82b873a2010-11-11 03:18:37 +01001569static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301570{
1571 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1572 int flags = 0;
1573
Sujith528f0c62008-10-29 10:14:26 +05301574 flags |= ATH9K_TXDESC_INTREQ;
1575
1576 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1577 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301578
Felix Fietkau82b873a2010-11-11 03:18:37 +01001579 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001580 flags |= ATH9K_TXDESC_LDPC;
1581
Sujith528f0c62008-10-29 10:14:26 +05301582 return flags;
1583}
1584
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001585/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001586 * rix - rate index
1587 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1588 * width - 0 for 20 MHz, 1 for 40 MHz
1589 * half_gi - to use 4us v/s 3.6 us for symbol time
1590 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001591static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301592 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001593{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001594 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001595 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301596
1597 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001598 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001599 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001600 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001601 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1602
1603 if (!half_gi)
1604 duration = SYMBOL_TIME(nsymbols);
1605 else
1606 duration = SYMBOL_TIME_HALFGI(nsymbols);
1607
Sujithe63835b2008-11-18 09:07:53 +05301608 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001609 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301610
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001611 return duration;
1612}
1613
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301614u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
1615{
1616 struct ath_hw *ah = sc->sc_ah;
1617 struct ath9k_channel *curchan = ah->curchan;
1618 if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
1619 (curchan->channelFlags & CHANNEL_5GHZ) &&
1620 (chainmask == 0x7) && (rate < 0x90))
1621 return 0x3;
1622 else
1623 return chainmask;
1624}
1625
Felix Fietkau269c44b2010-11-14 15:20:06 +01001626static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001627{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001628 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001629 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301630 struct sk_buff *skb;
1631 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301632 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001633 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301634 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301635 int i, flags = 0;
1636 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301637 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301638
1639 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301640
Sujitha22be222009-03-30 15:28:36 +05301641 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301642 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301643 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301644 hdr = (struct ieee80211_hdr *)skb->data;
1645 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301646
Sujithc89424d2009-01-30 14:29:28 +05301647 /*
1648 * We check if Short Preamble is needed for the CTS rate by
1649 * checking the BSS's global flag.
1650 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1651 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001652 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1653 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301654 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001655 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001656
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001657 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001658 bool is_40, is_sgi, is_sp;
1659 int phy;
1660
Sujithe63835b2008-11-18 09:07:53 +05301661 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001662 continue;
1663
Sujitha8efee42008-11-18 09:07:30 +05301664 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301665 series[i].Tries = rates[i].count;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001666
Mohammed Shafi Shajakhancbe8c732011-05-03 13:14:06 +05301667 if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
Sujithc89424d2009-01-30 14:29:28 +05301668 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001669 flags |= ATH9K_TXDESC_RTSENA;
1670 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1671 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1672 flags |= ATH9K_TXDESC_CTSENA;
1673 }
1674
Sujithc89424d2009-01-30 14:29:28 +05301675 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1676 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1677 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1678 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001679
Felix Fietkau545750d2009-11-23 22:21:01 +01001680 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1681 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1682 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1683
1684 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1685 /* MCS rates */
1686 series[i].Rate = rix | 0x80;
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301687 series[i].ChSel = ath_txchainmask_reduction(sc,
1688 common->tx_chainmask, series[i].Rate);
Felix Fietkau269c44b2010-11-14 15:20:06 +01001689 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001690 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001691 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1692 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001693 continue;
1694 }
1695
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301696 /* legacy rates */
Felix Fietkau545750d2009-11-23 22:21:01 +01001697 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1698 !(rate->flags & IEEE80211_RATE_ERP_G))
1699 phy = WLAN_RC_PHY_CCK;
1700 else
1701 phy = WLAN_RC_PHY_OFDM;
1702
1703 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1704 series[i].Rate = rate->hw_value;
1705 if (rate->hw_value_short) {
1706 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1707 series[i].Rate |= rate->hw_value_short;
1708 } else {
1709 is_sp = false;
1710 }
1711
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301712 if (bf->bf_state.bfs_paprd)
1713 series[i].ChSel = common->tx_chainmask;
1714 else
1715 series[i].ChSel = ath_txchainmask_reduction(sc,
1716 common->tx_chainmask, series[i].Rate);
1717
Felix Fietkau545750d2009-11-23 22:21:01 +01001718 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001719 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001720 }
1721
Felix Fietkau27032052010-01-17 21:08:50 +01001722 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001723 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001724 flags &= ~ATH9K_TXDESC_RTSENA;
1725
1726 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1727 if (flags & ATH9K_TXDESC_RTSENA)
1728 flags &= ~ATH9K_TXDESC_CTSENA;
1729
Sujithe63835b2008-11-18 09:07:53 +05301730 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301731 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1732 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301733 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301734 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301735
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001736}
1737
Felix Fietkau82b873a2010-11-11 03:18:37 +01001738static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
Felix Fietkau04caf862010-11-14 15:20:12 +01001739 struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001740 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301741{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001742 struct ath_softc *sc = hw->priv;
Felix Fietkau04caf862010-11-14 15:20:12 +01001743 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001744 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001745 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001746 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001747 struct ath_desc *ds;
Felix Fietkau04caf862010-11-14 15:20:12 +01001748 int frm_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001749
1750 bf = ath_tx_get_buffer(sc);
1751 if (!bf) {
Joe Perches226afe62010-12-02 19:12:37 -08001752 ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001753 return NULL;
1754 }
Sujithe8324352009-01-16 21:38:42 +05301755
Sujithe8324352009-01-16 21:38:42 +05301756 ATH_TXBUF_RESET(bf);
1757
Felix Fietkau82b873a2010-11-11 03:18:37 +01001758 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301759 bf->bf_mpdu = skb;
1760
Ben Greearc1739eb32010-10-14 12:45:29 -07001761 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1762 skb->len, DMA_TO_DEVICE);
1763 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301764 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001765 bf->bf_buf_addr = 0;
Joe Perches38002762010-12-02 19:12:36 -08001766 ath_err(ath9k_hw_common(sc->sc_ah),
1767 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001768 ath_tx_return_buffer(sc, bf);
1769 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301770 }
1771
Sujithe8324352009-01-16 21:38:42 +05301772 frm_type = get_hw_packet_type(skb);
Sujithe8324352009-01-16 21:38:42 +05301773
1774 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001775 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301776
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001777 ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
1778 fi->keyix, fi->keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301779
1780 ath9k_hw_filltxdesc(ah, ds,
1781 skb->len, /* segment length */
1782 true, /* first segment */
1783 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001784 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001785 bf->bf_buf_addr,
Felix Fietkau04caf862010-11-14 15:20:12 +01001786 txq->axq_qnum);
1787
1788
1789 return bf;
1790}
1791
1792/* FIXME: tx power */
1793static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1794 struct ath_tx_control *txctl)
1795{
1796 struct sk_buff *skb = bf->bf_mpdu;
1797 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1798 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau04caf862010-11-14 15:20:12 +01001799 struct list_head bf_head;
Felix Fietkau248a38d2010-12-10 21:16:46 +01001800 struct ath_atx_tid *tid = NULL;
Felix Fietkau04caf862010-11-14 15:20:12 +01001801 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301802
Sujithe8324352009-01-16 21:38:42 +05301803 spin_lock_bh(&txctl->txq->axq_lock);
Mohammed Shafi Shajakhan61e1b0b2011-03-21 18:27:21 +05301804 if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an &&
1805 ieee80211_is_data_qos(hdr->frame_control)) {
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001806 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1807 IEEE80211_QOS_CTL_TID_MASK;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001808 tid = ATH_AN_2_TID(txctl->an, tidno);
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001809
Felix Fietkau066dae92010-11-07 14:59:39 +01001810 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau248a38d2010-12-10 21:16:46 +01001811 }
1812
1813 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
Felix Fietkau04caf862010-11-14 15:20:12 +01001814 /*
1815 * Try aggregation if it's a unicast data frame
1816 * and the destination is HT capable.
1817 */
1818 ath_tx_send_ampdu(sc, tid, bf, txctl);
Sujithe8324352009-01-16 21:38:42 +05301819 } else {
Felix Fietkau04caf862010-11-14 15:20:12 +01001820 INIT_LIST_HEAD(&bf_head);
1821 list_add_tail(&bf->list, &bf_head);
1822
Felix Fietkau61117f02010-11-11 03:18:36 +01001823 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001824 bf->bf_state.bfs_paprd = txctl->paprd;
1825
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001826 if (bf->bf_state.bfs_paprd)
Felix Fietkau04caf862010-11-14 15:20:12 +01001827 ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
1828 bf->bf_state.bfs_paprd);
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001829
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301830 if (txctl->paprd)
1831 bf->bf_state.bfs_paprd_timestamp = jiffies;
1832
Felix Fietkau55195412011-04-17 23:28:09 +02001833 if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
1834 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
1835
Felix Fietkau248a38d2010-12-10 21:16:46 +01001836 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301837 }
1838
1839 spin_unlock_bh(&txctl->txq->axq_lock);
1840}
1841
1842/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001843int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301844 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001845{
Felix Fietkau28d16702010-11-14 15:20:10 +01001846 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1847 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001848 struct ieee80211_sta *sta = info->control.sta;
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001849 struct ieee80211_vif *vif = info->control.vif;
Felix Fietkau9ac586152011-01-24 19:23:18 +01001850 struct ath_softc *sc = hw->priv;
Felix Fietkau84642d62010-06-01 21:33:13 +02001851 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001852 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001853 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001854 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001855 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001856
Ben Greeara9927ba2010-12-06 21:13:49 -08001857 /* NOTE: sta can be NULL according to net/mac80211.h */
1858 if (sta)
1859 txctl->an = (struct ath_node *)sta->drv_priv;
1860
Felix Fietkau04caf862010-11-14 15:20:12 +01001861 if (info->control.hw_key)
1862 frmlen += info->control.hw_key->icv_len;
1863
Felix Fietkau28d16702010-11-14 15:20:10 +01001864 /*
1865 * As a temporary workaround, assign seq# here; this will likely need
1866 * to be cleaned up to work better with Beacon transmission and virtual
1867 * BSSes.
1868 */
1869 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1870 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1871 sc->tx.seq_no += 0x10;
1872 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1873 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1874 }
1875
1876 /* Add the padding after the header if this is not already done */
1877 padpos = ath9k_cmn_padpos(hdr->frame_control);
1878 padsize = padpos & 3;
1879 if (padsize && skb->len > padpos) {
1880 if (skb_headroom(skb) < padsize)
1881 return -ENOMEM;
1882
1883 skb_push(skb, padsize);
1884 memmove(skb->data, skb->data + padsize, padpos);
1885 }
1886
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001887 if ((vif && vif->type != NL80211_IFTYPE_AP &&
1888 vif->type != NL80211_IFTYPE_AP_VLAN) ||
1889 !ieee80211_is_data(hdr->frame_control))
1890 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1891
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001892 setup_frame_info(hw, skb, frmlen);
1893
1894 /*
1895 * At this point, the vif, hw_key and sta pointers in the tx control
1896 * info are no longer valid (overwritten by the ath_frame_info data.
1897 */
1898
1899 bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001900 if (unlikely(!bf))
1901 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001902
Felix Fietkau066dae92010-11-07 14:59:39 +01001903 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001904 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001905 if (txq == sc->tx.txq_map[q] &&
1906 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001907 ieee80211_stop_queue(sc->hw, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001908 txq->stopped = 1;
1909 }
1910 spin_unlock_bh(&txq->axq_lock);
1911
Sujithe8324352009-01-16 21:38:42 +05301912 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001913
1914 return 0;
1915}
1916
Sujithe8324352009-01-16 21:38:42 +05301917/*****************/
1918/* TX Completion */
1919/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001920
Sujithe8324352009-01-16 21:38:42 +05301921static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01001922 int tx_flags, int ftype, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001923{
Sujithe8324352009-01-16 21:38:42 +05301924 struct ieee80211_hw *hw = sc->hw;
1925 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001926 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001927 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001928 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301929
Joe Perches226afe62010-12-02 19:12:37 -08001930 ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301931
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301932 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301933 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301934
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301935 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301936 /* Frame was ACKed */
1937 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1938 }
1939
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001940 padpos = ath9k_cmn_padpos(hdr->frame_control);
1941 padsize = padpos & 3;
1942 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301943 /*
1944 * Remove MAC header padding before giving the frame back to
1945 * mac80211.
1946 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001947 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301948 skb_pull(skb, padsize);
1949 }
1950
Sujith1b04b932010-01-08 10:36:05 +05301951 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1952 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Joe Perches226afe62010-12-02 19:12:37 -08001953 ath_dbg(common, ATH_DBG_PS,
1954 "Going back to sleep after having received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301955 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1956 PS_WAIT_FOR_CAB |
1957 PS_WAIT_FOR_PSPOLL_DATA |
1958 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001959 }
1960
Felix Fietkau7545daf2011-01-24 19:23:16 +01001961 q = skb_get_queue_mapping(skb);
1962 if (txq == sc->tx.txq_map[q]) {
1963 spin_lock_bh(&txq->axq_lock);
1964 if (WARN_ON(--txq->pending_frames < 0))
1965 txq->pending_frames = 0;
Felix Fietkau92460412011-01-24 19:23:14 +01001966
Felix Fietkau7545daf2011-01-24 19:23:16 +01001967 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
1968 ieee80211_wake_queue(sc->hw, q);
1969 txq->stopped = 0;
Felix Fietkau066dae92010-11-07 14:59:39 +01001970 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001971 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04001972 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001973
1974 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301975}
1976
1977static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001978 struct ath_txq *txq, struct list_head *bf_q,
1979 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301980{
1981 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301982 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301983 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301984
Sujithe8324352009-01-16 21:38:42 +05301985 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301986 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301987
1988 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301989 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301990
1991 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301992 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301993 }
1994
Ben Greearc1739eb32010-10-14 12:45:29 -07001995 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001996 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001997
1998 if (bf->bf_state.bfs_paprd) {
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301999 if (time_after(jiffies,
2000 bf->bf_state.bfs_paprd_timestamp +
2001 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07002002 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07002003 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07002004 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04002005 } else {
Felix Fietkau5bec3e52011-01-24 21:29:25 +01002006 ath_debug_stat_tx(sc, bf, ts, txq);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002007 ath_tx_complete(sc, skb, tx_flags,
Felix Fietkau61117f02010-11-11 03:18:36 +01002008 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04002009 }
Ben Greear6cf9e992010-10-14 12:45:30 -07002010 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
2011 * accidentally reference it later.
2012 */
2013 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05302014
2015 /*
2016 * Return the list of ath_buf of this mpdu to free queue
2017 */
2018 spin_lock_irqsave(&sc->tx.txbuflock, flags);
2019 list_splice_tail_init(bf_q, &sc->tx.txbuf);
2020 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
2021}
2022
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002023static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
2024 struct ath_tx_status *ts, int nframes, int nbad,
2025 int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302026{
Sujitha22be222009-03-30 15:28:36 +05302027 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302028 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302029 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002030 struct ieee80211_hw *hw = sc->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002031 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302032 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302033
Sujith95e4acb2009-03-13 08:56:09 +05302034 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002035 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302036
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002037 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302038 WARN_ON(tx_rateindex >= hw->max_rates);
2039
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002040 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302041 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02002042 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01002043 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302044
Felix Fietkaub572d032010-11-14 15:20:07 +01002045 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02002046
Felix Fietkaub572d032010-11-14 15:20:07 +01002047 tx_info->status.ampdu_len = nframes;
2048 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02002049 }
2050
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002051 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302052 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002053 /*
2054 * If an underrun error is seen assume it as an excessive
2055 * retry only if max frame trigger level has been reached
2056 * (2 KB for single stream, and 4 KB for dual stream).
2057 * Adjust the long retry as if the frame was tried
2058 * hw->max_rate_tries times to affect how rate control updates
2059 * PER for the failed rate.
2060 * In case of congestion on the bus penalizing this type of
2061 * underruns should help hardware actually transmit new frames
2062 * successfully by eventually preferring slower rates.
2063 * This itself should also alleviate congestion on the bus.
2064 */
2065 if (ieee80211_is_data(hdr->frame_control) &&
2066 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
2067 ATH9K_TX_DELIM_UNDERRUN)) &&
Felix Fietkau83860c52011-03-23 20:57:33 +01002068 ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002069 tx_info->status.rates[tx_rateindex].count =
2070 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05302071 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302072
Felix Fietkau545750d2009-11-23 22:21:01 +01002073 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302074 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002075 tx_info->status.rates[i].idx = -1;
2076 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302077
Felix Fietkau78c46532010-06-25 01:26:16 +02002078 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302079}
2080
Sujithc4288392008-11-18 09:09:30 +05302081static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002082{
Sujithcbe61d82009-02-09 13:27:12 +05302083 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002084 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2086 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302087 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002088 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302089 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002090 int status;
2091
Joe Perches226afe62010-12-02 19:12:37 -08002092 ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2093 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2094 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002095
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002096 for (;;) {
2097 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 if (list_empty(&txq->axq_q)) {
2099 txq->axq_link = NULL;
Felix Fietkau86271e42011-03-11 21:38:19 +01002100 if (sc->sc_flags & SC_OP_TXAGGR)
Ben Greear082f6532011-01-09 23:11:47 -08002101 ath_txq_schedule(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002102 spin_unlock_bh(&txq->axq_lock);
2103 break;
2104 }
2105 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2106
2107 /*
2108 * There is a race condition that a BH gets scheduled
2109 * after sw writes TxE and before hw re-load the last
2110 * descriptor to get the newly chained one.
2111 * Software must keep the last DONE descriptor as a
2112 * holding descriptor - software does so by marking
2113 * it with the STALE flag.
2114 */
2115 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302116 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117 bf_held = bf;
2118 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302119 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002120 break;
2121 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002122 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302123 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002124 }
2125 }
2126
2127 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302128 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002129
Felix Fietkau29bffa92010-03-29 20:14:23 -07002130 memset(&ts, 0, sizeof(ts));
2131 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002132 if (status == -EINPROGRESS) {
2133 spin_unlock_bh(&txq->axq_lock);
2134 break;
2135 }
Ben Greear2dac4fb2011-01-09 23:11:45 -08002136 TX_STAT_INC(txq->axq_qnum, txprocdesc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002137
2138 /*
2139 * Remove ath_buf's of the same transmit unit from txq,
2140 * however leave the last descriptor back as the holding
2141 * descriptor for hw.
2142 */
Sujitha119cc42009-03-30 15:28:38 +05302143 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002144 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002145 if (!list_is_singular(&lastbf->list))
2146 list_cut_position(&bf_head,
2147 &txq->axq_q, lastbf->list.prev);
2148
2149 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002150 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002151 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002152 if (bf_held)
2153 list_del(&bf_held->list);
Felix Fietkau4b3ba662010-12-17 00:57:00 +01002154
2155 if (bf_is_ampdu_not_probing(bf))
2156 txq->axq_ampdu_depth--;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002157
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002158 spin_unlock_bh(&txq->axq_lock);
2159
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002160 if (bf_held)
2161 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002162
Sujithcd3d39a2008-08-11 14:03:34 +05302163 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164 /*
2165 * This frame is sent out as a single frame.
2166 * Use hardware retry status for this frame.
2167 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002168 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302169 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002170 ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002171 }
Johannes Berge6a98542008-10-21 12:40:02 +02002172
Sujithcd3d39a2008-08-11 14:03:34 +05302173 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002174 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
2175 true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002176 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002177 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002178
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002179 spin_lock_bh(&txq->axq_lock);
Ben Greear60f2d1d2011-01-09 23:11:52 -08002180
Felix Fietkau86271e42011-03-11 21:38:19 +01002181 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002182 ath_txq_schedule(sc, txq);
2183 spin_unlock_bh(&txq->axq_lock);
2184 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002185}
2186
Sujith305fe472009-07-23 15:32:29 +05302187static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002188{
2189 struct ath_softc *sc = container_of(work, struct ath_softc,
2190 tx_complete_work.work);
2191 struct ath_txq *txq;
2192 int i;
2193 bool needreset = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08002194#ifdef CONFIG_ATH9K_DEBUGFS
2195 sc->tx_complete_poll_work_seen++;
2196#endif
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002197
2198 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2199 if (ATH_TXQ_SETUP(sc, i)) {
2200 txq = &sc->tx.txq[i];
2201 spin_lock_bh(&txq->axq_lock);
2202 if (txq->axq_depth) {
2203 if (txq->axq_tx_inprogress) {
2204 needreset = true;
2205 spin_unlock_bh(&txq->axq_lock);
2206 break;
2207 } else {
2208 txq->axq_tx_inprogress = true;
2209 }
2210 }
2211 spin_unlock_bh(&txq->axq_lock);
2212 }
2213
2214 if (needreset) {
Joe Perches226afe62010-12-02 19:12:37 -08002215 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2216 "tx hung, resetting the chip\n");
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002217 ath_reset(sc, true);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002218 }
2219
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002220 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002221 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2222}
2223
2224
Sujithe8324352009-01-16 21:38:42 +05302225
2226void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002227{
Sujithe8324352009-01-16 21:38:42 +05302228 int i;
2229 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002230
Sujithe8324352009-01-16 21:38:42 +05302231 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002232
2233 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302234 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2235 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002236 }
2237}
2238
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002239void ath_tx_edma_tasklet(struct ath_softc *sc)
2240{
2241 struct ath_tx_status txs;
2242 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2243 struct ath_hw *ah = sc->sc_ah;
2244 struct ath_txq *txq;
2245 struct ath_buf *bf, *lastbf;
2246 struct list_head bf_head;
2247 int status;
2248 int txok;
2249
2250 for (;;) {
2251 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2252 if (status == -EINPROGRESS)
2253 break;
2254 if (status == -EIO) {
Joe Perches226afe62010-12-02 19:12:37 -08002255 ath_dbg(common, ATH_DBG_XMIT,
2256 "Error processing tx status\n");
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002257 break;
2258 }
2259
2260 /* Skip beacon completions */
2261 if (txs.qid == sc->beacon.beaconq)
2262 continue;
2263
2264 txq = &sc->tx.txq[txs.qid];
2265
2266 spin_lock_bh(&txq->axq_lock);
2267 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2268 spin_unlock_bh(&txq->axq_lock);
2269 return;
2270 }
2271
2272 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2273 struct ath_buf, list);
2274 lastbf = bf->bf_lastbf;
2275
2276 INIT_LIST_HEAD(&bf_head);
2277 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2278 &lastbf->list);
2279 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2280 txq->axq_depth--;
2281 txq->axq_tx_inprogress = false;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01002282 if (bf_is_ampdu_not_probing(bf))
2283 txq->axq_ampdu_depth--;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002284 spin_unlock_bh(&txq->axq_lock);
2285
2286 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2287
2288 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002289 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2290 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002291 ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002292 }
2293
2294 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002295 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
2296 txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002297 else
2298 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2299 &txs, txok, 0);
2300
2301 spin_lock_bh(&txq->axq_lock);
Ben Greear60f2d1d2011-01-09 23:11:52 -08002302
Felix Fietkau86271e42011-03-11 21:38:19 +01002303 if (!list_empty(&txq->txq_fifo_pending)) {
2304 INIT_LIST_HEAD(&bf_head);
2305 bf = list_first_entry(&txq->txq_fifo_pending,
2306 struct ath_buf, list);
2307 list_cut_position(&bf_head,
2308 &txq->txq_fifo_pending,
2309 &bf->bf_lastbf->list);
2310 ath_tx_txqaddbuf(sc, txq, &bf_head);
2311 } else if (sc->sc_flags & SC_OP_TXAGGR)
2312 ath_txq_schedule(sc, txq);
2313
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002314 spin_unlock_bh(&txq->axq_lock);
2315 }
2316}
2317
Sujithe8324352009-01-16 21:38:42 +05302318/*****************/
2319/* Init, Cleanup */
2320/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002321
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002322static int ath_txstatus_setup(struct ath_softc *sc, int size)
2323{
2324 struct ath_descdma *dd = &sc->txsdma;
2325 u8 txs_len = sc->sc_ah->caps.txs_len;
2326
2327 dd->dd_desc_len = size * txs_len;
2328 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2329 &dd->dd_desc_paddr, GFP_KERNEL);
2330 if (!dd->dd_desc)
2331 return -ENOMEM;
2332
2333 return 0;
2334}
2335
2336static int ath_tx_edma_init(struct ath_softc *sc)
2337{
2338 int err;
2339
2340 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2341 if (!err)
2342 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2343 sc->txsdma.dd_desc_paddr,
2344 ATH_TXSTATUS_RING_SIZE);
2345
2346 return err;
2347}
2348
2349static void ath_tx_edma_cleanup(struct ath_softc *sc)
2350{
2351 struct ath_descdma *dd = &sc->txsdma;
2352
2353 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2354 dd->dd_desc_paddr);
2355}
2356
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002357int ath_tx_init(struct ath_softc *sc, int nbufs)
2358{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002359 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002360 int error = 0;
2361
Sujith797fe5cb2009-03-30 15:28:45 +05302362 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002363
Sujith797fe5cb2009-03-30 15:28:45 +05302364 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002365 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302366 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002367 ath_err(common,
2368 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302369 goto err;
2370 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371
Sujith797fe5cb2009-03-30 15:28:45 +05302372 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002373 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302374 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002375 ath_err(common,
2376 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302377 goto err;
2378 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002379
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002380 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2381
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002382 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2383 error = ath_tx_edma_init(sc);
2384 if (error)
2385 goto err;
2386 }
2387
Sujith797fe5cb2009-03-30 15:28:45 +05302388err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002389 if (error != 0)
2390 ath_tx_cleanup(sc);
2391
2392 return error;
2393}
2394
Sujith797fe5cb2009-03-30 15:28:45 +05302395void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002396{
Sujithb77f4832008-12-07 21:44:03 +05302397 if (sc->beacon.bdma.dd_desc_len != 0)
2398 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002399
Sujithb77f4832008-12-07 21:44:03 +05302400 if (sc->tx.txdma.dd_desc_len != 0)
2401 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002402
2403 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2404 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002405}
2406
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002407void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2408{
Sujithc5170162008-10-29 10:13:59 +05302409 struct ath_atx_tid *tid;
2410 struct ath_atx_ac *ac;
2411 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002412
Sujith8ee5afb2008-12-07 21:43:36 +05302413 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302414 tidno < WME_NUM_TID;
2415 tidno++, tid++) {
2416 tid->an = an;
2417 tid->tidno = tidno;
2418 tid->seq_start = tid->seq_next = 0;
2419 tid->baw_size = WME_MAX_BA;
2420 tid->baw_head = tid->baw_tail = 0;
2421 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302422 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302423 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302424 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302425 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302426 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302427 tid->state &= ~AGGR_ADDBA_COMPLETE;
2428 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302429 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002430
Sujith8ee5afb2008-12-07 21:43:36 +05302431 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302432 acno < WME_NUM_AC; acno++, ac++) {
2433 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002434 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302435 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002436 }
2437}
2438
Sujithb5aa9bf2008-10-29 10:13:31 +05302439void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002440{
Felix Fietkau2b409942010-07-07 19:42:08 +02002441 struct ath_atx_ac *ac;
2442 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002443 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002444 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302445
Felix Fietkau2b409942010-07-07 19:42:08 +02002446 for (tidno = 0, tid = &an->tid[tidno];
2447 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002448
Felix Fietkau2b409942010-07-07 19:42:08 +02002449 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002450 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002451
Felix Fietkau2b409942010-07-07 19:42:08 +02002452 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002453
Felix Fietkau2b409942010-07-07 19:42:08 +02002454 if (tid->sched) {
2455 list_del(&tid->list);
2456 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002457 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002458
2459 if (ac->sched) {
2460 list_del(&ac->list);
2461 tid->ac->sched = false;
2462 }
2463
2464 ath_tid_drain(sc, txq, tid);
2465 tid->state &= ~AGGR_ADDBA_COMPLETE;
2466 tid->state &= ~AGGR_CLEANUP;
2467
2468 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002469 }
2470}