blob: ac393a6dbe776c29bad426f0ca8e46acbdf4d1dd [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2008-2011 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Alexey Dobriyanb7f080c2011-06-16 11:01:34 +000017#include <linux/dma-mapping.h>
Sujith394cf0a2009-02-09 13:26:54 +053018#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040019#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070020
21#define BITS_PER_BYTE 8
22#define OFDM_PLCP_BITS 22
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070023#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
24#define L_STF 8
25#define L_LTF 8
26#define L_SIG 4
27#define HT_SIG 8
28#define HT_STF 4
29#define HT_LTF(_ns) (4 * (_ns))
30#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
31#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
32#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
33#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
34
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070035
Felix Fietkauc6663872010-04-19 19:57:33 +020036static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070037 /* 20MHz 40MHz */
38 { 26, 54 }, /* 0: BPSK */
39 { 52, 108 }, /* 1: QPSK 1/2 */
40 { 78, 162 }, /* 2: QPSK 3/4 */
41 { 104, 216 }, /* 3: 16-QAM 1/2 */
42 { 156, 324 }, /* 4: 16-QAM 3/4 */
43 { 208, 432 }, /* 5: 64-QAM 2/3 */
44 { 234, 486 }, /* 6: 64-QAM 3/4 */
45 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070046};
47
48#define IS_HT_RATE(_rate) ((_rate) & 0x80)
49
Felix Fietkau82b873a2010-11-11 03:18:37 +010050static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
51 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +010052 struct list_head *bf_head);
Sujithe8324352009-01-16 21:38:42 +053053static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070054 struct ath_txq *txq, struct list_head *bf_q,
55 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053056static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +020057 struct list_head *head, bool internal);
Felix Fietkau269c44b2010-11-14 15:20:06 +010058static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +010059static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
60 struct ath_tx_status *ts, int nframes, int nbad,
61 int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020062static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
63 int seqno);
Sujithe8324352009-01-16 21:38:42 +053064
Felix Fietkau545750d2009-11-23 22:21:01 +010065enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020066 MCS_HT20,
67 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010068 MCS_HT40,
69 MCS_HT40_SGI,
70};
71
Felix Fietkau0e668cd2010-04-19 19:57:32 +020072static int ath_max_4ms_framelen[4][32] = {
73 [MCS_HT20] = {
74 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
75 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
76 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
77 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
78 },
79 [MCS_HT20_SGI] = {
80 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
81 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
82 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
83 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010084 },
85 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020086 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
87 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
88 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
89 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010090 },
91 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020092 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
93 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
94 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
95 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010096 }
97};
98
Sujithe8324352009-01-16 21:38:42 +053099/*********************/
100/* Aggregation logic */
101/*********************/
102
Sujithe8324352009-01-16 21:38:42 +0530103static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
104{
105 struct ath_atx_ac *ac = tid->ac;
106
107 if (tid->paused)
108 return;
109
110 if (tid->sched)
111 return;
112
113 tid->sched = true;
114 list_add_tail(&tid->list, &ac->tid_q);
115
116 if (ac->sched)
117 return;
118
119 ac->sched = true;
120 list_add_tail(&ac->list, &txq->axq_acq);
121}
122
Sujithe8324352009-01-16 21:38:42 +0530123static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
124{
Felix Fietkau066dae92010-11-07 14:59:39 +0100125 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530126
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200127 WARN_ON(!tid->paused);
128
Sujithe8324352009-01-16 21:38:42 +0530129 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200130 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530131
132 if (list_empty(&tid->buf_q))
133 goto unlock;
134
135 ath_tx_queue_tid(txq, tid);
136 ath_txq_schedule(sc, txq);
137unlock:
138 spin_unlock_bh(&txq->axq_lock);
139}
140
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100141static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
Felix Fietkau76e45222010-11-14 15:20:08 +0100142{
143 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100144 BUILD_BUG_ON(sizeof(struct ath_frame_info) >
145 sizeof(tx_info->rate_driver_data));
146 return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
Felix Fietkau76e45222010-11-14 15:20:08 +0100147}
148
Sujithe8324352009-01-16 21:38:42 +0530149static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
150{
Felix Fietkau066dae92010-11-07 14:59:39 +0100151 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530152 struct ath_buf *bf;
153 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200154 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100155 struct ath_frame_info *fi;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200156
Sujithe8324352009-01-16 21:38:42 +0530157 INIT_LIST_HEAD(&bf_head);
158
Felix Fietkau90fa5392010-09-20 13:45:38 +0200159 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530160 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530161
162 while (!list_empty(&tid->buf_q)) {
163 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530164 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200165
Felix Fietkaue1566d12010-11-20 03:08:46 +0100166 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100167 fi = get_frame_info(bf->bf_mpdu);
168 if (fi->retries) {
169 ath_tx_update_baw(sc, tid, fi->seqno);
Felix Fietkau7d2c16b2011-03-12 01:11:28 +0100170 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200171 } else {
Felix Fietkaua9e99a02011-01-10 17:05:47 -0700172 ath_tx_send_normal(sc, txq, NULL, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200173 }
Felix Fietkaue1566d12010-11-20 03:08:46 +0100174 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530175 }
176
177 spin_unlock_bh(&txq->axq_lock);
178}
179
180static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
181 int seqno)
182{
183 int index, cindex;
184
185 index = ATH_BA_INDEX(tid->seq_start, seqno);
186 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
187
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200188 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530189
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200190 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530191 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
192 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
193 }
194}
195
196static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100197 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530198{
199 int index, cindex;
200
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100201 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530202 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200203 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530204
205 if (index >= ((tid->baw_tail - tid->baw_head) &
206 (ATH_TID_MAX_BUFS - 1))) {
207 tid->baw_tail = cindex;
208 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
209 }
210}
211
212/*
213 * TODO: For frame(s) that are in the retry state, we will reuse the
214 * sequence number(s) without setting the retry bit. The
215 * alternative is to give up on these and BAR the receiver's window
216 * forward.
217 */
218static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
219 struct ath_atx_tid *tid)
220
221{
222 struct ath_buf *bf;
223 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700224 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100225 struct ath_frame_info *fi;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700226
227 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530228 INIT_LIST_HEAD(&bf_head);
229
230 for (;;) {
231 if (list_empty(&tid->buf_q))
232 break;
Sujithe8324352009-01-16 21:38:42 +0530233
Sujithd43f30152009-01-16 21:38:53 +0530234 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
235 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530236
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100237 fi = get_frame_info(bf->bf_mpdu);
238 if (fi->retries)
239 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530240
241 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700242 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530243 spin_lock(&txq->axq_lock);
244 }
245
246 tid->seq_next = tid->seq_start;
247 tid->baw_tail = tid->baw_head;
248}
249
Sujithfec247c2009-07-27 12:08:16 +0530250static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100251 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +0530252{
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100253 struct ath_frame_info *fi = get_frame_info(skb);
Sujithe8324352009-01-16 21:38:42 +0530254 struct ieee80211_hdr *hdr;
255
Sujithfec247c2009-07-27 12:08:16 +0530256 TX_STAT_INC(txq->axq_qnum, a_retries);
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100257 if (fi->retries++ > 0)
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100258 return;
Sujithe8324352009-01-16 21:38:42 +0530259
Sujithe8324352009-01-16 21:38:42 +0530260 hdr = (struct ieee80211_hdr *)skb->data;
261 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
262}
263
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200264static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
265{
266 struct ath_buf *bf = NULL;
267
268 spin_lock_bh(&sc->tx.txbuflock);
269
270 if (unlikely(list_empty(&sc->tx.txbuf))) {
271 spin_unlock_bh(&sc->tx.txbuflock);
272 return NULL;
273 }
274
275 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
276 list_del(&bf->list);
277
278 spin_unlock_bh(&sc->tx.txbuflock);
279
280 return bf;
281}
282
283static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
284{
285 spin_lock_bh(&sc->tx.txbuflock);
286 list_add_tail(&bf->list, &sc->tx.txbuf);
287 spin_unlock_bh(&sc->tx.txbuflock);
288}
289
Sujithd43f30152009-01-16 21:38:53 +0530290static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
291{
292 struct ath_buf *tbf;
293
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200294 tbf = ath_tx_get_buffer(sc);
295 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530296 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530297
298 ATH_TXBUF_RESET(tbf);
299
300 tbf->bf_mpdu = bf->bf_mpdu;
301 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400302 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530303 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530304
305 return tbf;
306}
307
Felix Fietkaub572d032010-11-14 15:20:07 +0100308static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
309 struct ath_tx_status *ts, int txok,
310 int *nframes, int *nbad)
311{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100312 struct ath_frame_info *fi;
Felix Fietkaub572d032010-11-14 15:20:07 +0100313 u16 seq_st = 0;
314 u32 ba[WME_BA_BMP_SIZE >> 5];
315 int ba_index;
316 int isaggr = 0;
317
318 *nbad = 0;
319 *nframes = 0;
320
Felix Fietkaub572d032010-11-14 15:20:07 +0100321 isaggr = bf_isaggr(bf);
322 if (isaggr) {
323 seq_st = ts->ts_seqnum;
324 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
325 }
326
327 while (bf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100328 fi = get_frame_info(bf->bf_mpdu);
329 ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
Felix Fietkaub572d032010-11-14 15:20:07 +0100330
331 (*nframes)++;
332 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
333 (*nbad)++;
334
335 bf = bf->bf_next;
336 }
337}
338
339
Sujithd43f30152009-01-16 21:38:53 +0530340static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
341 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100342 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530343{
344 struct ath_node *an = NULL;
345 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530346 struct ieee80211_sta *sta;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100347 struct ieee80211_hw *hw = sc->hw;
Sujith1286ec62009-01-27 13:30:37 +0530348 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800349 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530350 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530351 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530352 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530353 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530354 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530355 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
356 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200357 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100358 struct ath_frame_info *fi;
Björn Smedmanebd02282010-10-10 22:44:39 +0200359 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100360 u8 tidno;
Felix Fietkau55195412011-04-17 23:28:09 +0200361 bool clear_filter;
Sujithe8324352009-01-16 21:38:42 +0530362
Sujitha22be222009-03-30 15:28:36 +0530363 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530364 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530365
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800366 tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800367
Felix Fietkau78c46532010-06-25 01:26:16 +0200368 memcpy(rates, tx_info->control.rates, sizeof(rates));
369
Sujith1286ec62009-01-27 13:30:37 +0530370 rcu_read_lock();
371
Ben Greear686b9cb2010-09-23 09:44:36 -0700372 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530373 if (!sta) {
374 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200375
Felix Fietkau31e79a52010-07-12 23:16:34 +0200376 INIT_LIST_HEAD(&bf_head);
377 while (bf) {
378 bf_next = bf->bf_next;
379
380 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaufce041b2011-05-19 12:20:25 +0200381 if (!bf->bf_stale || bf_next != NULL)
Felix Fietkau31e79a52010-07-12 23:16:34 +0200382 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
Felix Fietkaufce041b2011-05-19 12:20:25 +0200466 /*
467 * Make sure the last desc is reclaimed if it
468 * not a holding desc.
469 */
470 if (!bf_last->bf_stale || bf_next != NULL)
Sujithd43f30152009-01-16 21:38:53 +0530471 list_move_tail(&bf->list, &bf_head);
Felix Fietkaufce041b2011-05-19 12:20:25 +0200472 else
473 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530474
Felix Fietkau90fa5392010-09-20 13:45:38 +0200475 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530476 /*
477 * complete the acked-ones/xretried ones; update
478 * block-ack window
479 */
480 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100481 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530482 spin_unlock_bh(&txq->axq_lock);
483
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530484 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200485 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100486 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530487 rc_update = false;
488 } else {
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100489 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530490 }
491
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700492 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
493 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530494 } else {
Sujithd43f30152009-01-16 21:38:53 +0530495 /* retry the un-acked ones */
Felix Fietkau55195412011-04-17 23:28:09 +0200496 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400497 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
498 if (bf->bf_next == NULL && bf_last->bf_stale) {
499 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530500
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400501 tbf = ath_clone_txbuf(sc, bf_last);
502 /*
503 * Update tx baw and complete the
504 * frame with failed status if we
505 * run out of tx buf.
506 */
507 if (!tbf) {
508 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100509 ath_tx_update_baw(sc, tid, fi->seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400510 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400511
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400512 bf->bf_state.bf_type |=
513 BUF_XRETRY;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100514 ath_tx_rc_status(sc, bf, ts, nframes,
Felix Fietkaub572d032010-11-14 15:20:07 +0100515 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400516 ath_tx_complete_buf(sc, bf, txq,
517 &bf_head,
518 ts, 0, 0);
519 break;
520 }
521
522 ath9k_hw_cleartxdesc(sc->sc_ah,
523 tbf->bf_desc);
524 list_add_tail(&tbf->list, &bf_head);
525 } else {
526 /*
527 * Clear descriptor status words for
528 * software retry
529 */
530 ath9k_hw_cleartxdesc(sc->sc_ah,
531 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400532 }
Sujithe8324352009-01-16 21:38:42 +0530533 }
534
535 /*
536 * Put this buffer to the temporary pending
537 * queue to retain ordering
538 */
539 list_splice_tail_init(&bf_head, &bf_pending);
540 }
541
542 bf = bf_next;
543 }
544
Felix Fietkau4cee7862010-07-23 03:53:16 +0200545 /* prepend un-acked frames to the beginning of the pending frame queue */
546 if (!list_empty(&bf_pending)) {
Felix Fietkau55195412011-04-17 23:28:09 +0200547 if (an->sleeping)
548 ieee80211_sta_set_tim(sta);
549
Felix Fietkau4cee7862010-07-23 03:53:16 +0200550 spin_lock_bh(&txq->axq_lock);
Felix Fietkau55195412011-04-17 23:28:09 +0200551 if (clear_filter)
552 tid->ac->clear_ps_filter = true;
Felix Fietkau4cee7862010-07-23 03:53:16 +0200553 list_splice(&bf_pending, &tid->buf_q);
Felix Fietkau9af73cf2011-08-10 15:23:35 -0600554 if (!an->sleeping)
555 ath_tx_queue_tid(txq, tid);
Felix Fietkau4cee7862010-07-23 03:53:16 +0200556 spin_unlock_bh(&txq->axq_lock);
557 }
558
Sujithe8324352009-01-16 21:38:42 +0530559 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200560 ath_tx_flush_tid(sc, tid);
561
Sujithe8324352009-01-16 21:38:42 +0530562 if (tid->baw_head == tid->baw_tail) {
563 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530564 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530565 }
Sujithe8324352009-01-16 21:38:42 +0530566 }
567
Sujith1286ec62009-01-27 13:30:37 +0530568 rcu_read_unlock();
569
Rajkumar Manoharanf6b4e4d2011-06-24 17:38:13 +0530570 if (needreset)
Sujithe8324352009-01-16 21:38:42 +0530571 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530572}
573
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530574static bool ath_lookup_legacy(struct ath_buf *bf)
575{
576 struct sk_buff *skb;
577 struct ieee80211_tx_info *tx_info;
578 struct ieee80211_tx_rate *rates;
579 int i;
580
581 skb = bf->bf_mpdu;
582 tx_info = IEEE80211_SKB_CB(skb);
583 rates = tx_info->control.rates;
584
Felix Fietkau059ee092011-08-27 10:25:27 +0200585 for (i = 0; i < 4; i++) {
586 if (!rates[i].count || rates[i].idx < 0)
587 break;
588
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530589 if (!(rates[i].flags & IEEE80211_TX_RC_MCS))
590 return true;
591 }
592
593 return false;
594}
595
Sujithe8324352009-01-16 21:38:42 +0530596static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
597 struct ath_atx_tid *tid)
598{
Sujithe8324352009-01-16 21:38:42 +0530599 struct sk_buff *skb;
600 struct ieee80211_tx_info *tx_info;
601 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530602 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530603 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530604 int i;
605
Sujitha22be222009-03-30 15:28:36 +0530606 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530607 tx_info = IEEE80211_SKB_CB(skb);
608 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530609
610 /*
611 * Find the lowest frame length among the rate series that will have a
612 * 4ms transmit duration.
613 * TODO - TXOP limit needs to be considered.
614 */
615 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
616
617 for (i = 0; i < 4; i++) {
618 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100619 int modeidx;
620 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530621 legacy = 1;
622 break;
623 }
624
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200625 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100626 modeidx = MCS_HT40;
627 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200628 modeidx = MCS_HT20;
629
630 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
631 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100632
633 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530634 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530635 }
636 }
637
638 /*
639 * limit aggregate size by the minimum rate if rate selected is
640 * not a probe rate, if rate selected is a probe rate then
641 * avoid aggregation of this packet.
642 */
643 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
644 return 0;
645
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530646 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
647 aggr_limit = min((max_4ms_framelen * 3) / 8,
648 (u32)ATH_AMPDU_LIMIT_MAX);
649 else
650 aggr_limit = min(max_4ms_framelen,
651 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530652
653 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300654 * h/w can accept aggregates up to 16 bit lengths (65535).
655 * The IE, however can hold up to 65536, which shows up here
Sujithe8324352009-01-16 21:38:42 +0530656 * as zero. Ignore 65536 since we are constrained by hw.
657 */
Sujith4ef70842009-07-23 15:32:41 +0530658 if (tid->an->maxampdu)
659 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530660
661 return aggr_limit;
662}
663
664/*
Sujithd43f30152009-01-16 21:38:53 +0530665 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530666 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530667 */
668static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530669 struct ath_buf *bf, u16 frmlen,
670 bool first_subfrm)
Sujithe8324352009-01-16 21:38:42 +0530671{
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530672#define FIRST_DESC_NDELIMS 60
Sujithe8324352009-01-16 21:38:42 +0530673 struct sk_buff *skb = bf->bf_mpdu;
674 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530675 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530676 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100677 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200678 int width, streams, half_gi, ndelim, mindelim;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100679 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530680
681 /* Select standard number of delimiters based on frame length alone */
682 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
683
684 /*
685 * If encryption enabled, hardware requires some more padding between
686 * subframes.
687 * TODO - this could be improved to be dependent on the rate.
688 * The hardware can keep up at lower rates, but not higher rates
689 */
Rajkumar Manoharan4f6760b2011-07-01 18:37:33 +0530690 if ((fi->keyix != ATH9K_TXKEYIX_INVALID) &&
691 !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))
Sujithe8324352009-01-16 21:38:42 +0530692 ndelim += ATH_AGGR_ENCRYPTDELIM;
693
694 /*
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530695 * Add delimiter when using RTS/CTS with aggregation
696 * and non enterprise AR9003 card
697 */
698 if (first_subfrm)
699 ndelim = max(ndelim, FIRST_DESC_NDELIMS);
700
701 /*
Sujithe8324352009-01-16 21:38:42 +0530702 * Convert desired mpdu density from microeconds to bytes based
703 * on highest rate in rate series (i.e. first rate) to determine
704 * required minimum length for subframe. Take into account
705 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530706 *
Sujithe8324352009-01-16 21:38:42 +0530707 * If there is no mpdu density restriction, no further calculation
708 * is needed.
709 */
Sujith4ef70842009-07-23 15:32:41 +0530710
711 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530712 return ndelim;
713
714 rix = tx_info->control.rates[0].idx;
715 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530716 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
717 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
718
719 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530720 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530721 else
Sujith4ef70842009-07-23 15:32:41 +0530722 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530723
724 if (nsymbols == 0)
725 nsymbols = 1;
726
Felix Fietkauc6663872010-04-19 19:57:33 +0200727 streams = HT_RC_2_STREAMS(rix);
728 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530729 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
730
Sujithe8324352009-01-16 21:38:42 +0530731 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530732 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
733 ndelim = max(mindelim, ndelim);
734 }
735
736 return ndelim;
737}
738
739static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530740 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530741 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100742 struct list_head *bf_q,
743 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530744{
745#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530746 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
747 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530748 u16 aggr_limit = 0, al = 0, bpad = 0,
749 al_delta, h_baw = tid->baw_size / 2;
750 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200751 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100752 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530753
754 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
755
756 do {
757 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100758 fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530759
Sujithd43f30152009-01-16 21:38:53 +0530760 /* do not step over block-ack window */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100761 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530762 status = ATH_AGGR_BAW_CLOSED;
763 break;
764 }
765
766 if (!rl) {
767 aggr_limit = ath_lookup_rate(sc, bf, tid);
768 rl = 1;
769 }
770
Sujithd43f30152009-01-16 21:38:53 +0530771 /* do not exceed aggregation limit */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100772 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
Sujithe8324352009-01-16 21:38:42 +0530773
Sujithd43f30152009-01-16 21:38:53 +0530774 if (nframes &&
Rajkumar Manoharan1a6e9d02011-08-23 12:32:57 +0530775 ((aggr_limit < (al + bpad + al_delta + prev_al)) ||
776 ath_lookup_legacy(bf))) {
Sujithe8324352009-01-16 21:38:42 +0530777 status = ATH_AGGR_LIMITED;
778 break;
779 }
780
Felix Fietkau0299a502010-10-21 02:47:24 +0200781 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
782 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
783 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
784 break;
785
Sujithd43f30152009-01-16 21:38:53 +0530786 /* do not exceed subframe limit */
787 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530788 status = ATH_AGGR_LIMITED;
789 break;
790 }
791
Sujithd43f30152009-01-16 21:38:53 +0530792 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530793 al += bpad + al_delta;
794
795 /*
796 * Get the delimiters needed to meet the MPDU
797 * density for this node.
798 */
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530799 ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen,
800 !nframes);
Sujithe8324352009-01-16 21:38:42 +0530801 bpad = PADBYTES(al_delta) + (ndelim << 2);
802
Rajkumar Manoharan7a12dfd2011-08-13 10:28:08 +0530803 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530804 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400805 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530806
Sujithd43f30152009-01-16 21:38:53 +0530807 /* link buffers of this frame to the aggregate */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100808 if (!fi->retries)
809 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithd43f30152009-01-16 21:38:53 +0530810 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
811 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530812 if (bf_prev) {
813 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400814 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
815 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530816 }
817 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530818
Sujithe8324352009-01-16 21:38:42 +0530819 } while (!list_empty(&tid->buf_q));
820
Felix Fietkau269c44b2010-11-14 15:20:06 +0100821 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530822
Sujithe8324352009-01-16 21:38:42 +0530823 return status;
824#undef PADBYTES
825}
826
827static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
828 struct ath_atx_tid *tid)
829{
Sujithd43f30152009-01-16 21:38:53 +0530830 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530831 enum ATH_AGGR_STATUS status;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100832 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530833 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100834 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530835
836 do {
837 if (list_empty(&tid->buf_q))
838 return;
839
840 INIT_LIST_HEAD(&bf_q);
841
Felix Fietkau269c44b2010-11-14 15:20:06 +0100842 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530843
844 /*
Sujithd43f30152009-01-16 21:38:53 +0530845 * no frames picked up to be aggregated;
846 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530847 */
848 if (list_empty(&bf_q))
849 break;
850
851 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530852 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530853
Felix Fietkau55195412011-04-17 23:28:09 +0200854 if (tid->ac->clear_ps_filter) {
855 tid->ac->clear_ps_filter = false;
856 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
857 }
858
Sujithd43f30152009-01-16 21:38:53 +0530859 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100860 if (bf == bf->bf_lastbf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100861 fi = get_frame_info(bf->bf_mpdu);
862
Sujithe8324352009-01-16 21:38:42 +0530863 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530864 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100865 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +0200866 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
Sujithe8324352009-01-16 21:38:42 +0530867 continue;
868 }
869
Sujithd43f30152009-01-16 21:38:53 +0530870 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530871 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100872 ath_buf_set_rate(sc, bf, aggr_len);
873 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530874
Sujithd43f30152009-01-16 21:38:53 +0530875 /* anchor last desc of aggregate */
876 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530877
Felix Fietkaufce041b2011-05-19 12:20:25 +0200878 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
Sujithfec247c2009-07-27 12:08:16 +0530879 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530880
Felix Fietkau4b3ba662010-12-17 00:57:00 +0100881 } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
Sujithe8324352009-01-16 21:38:42 +0530882 status != ATH_AGGR_BAW_CLOSED);
883}
884
Felix Fietkau231c3a12010-09-20 19:35:28 +0200885int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
886 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530887{
888 struct ath_atx_tid *txtid;
889 struct ath_node *an;
890
891 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530892 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200893
894 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
895 return -EAGAIN;
896
Sujithf83da962009-07-23 15:32:37 +0530897 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200898 txtid->paused = true;
Felix Fietkau49447f22011-01-10 17:05:48 -0700899 *ssn = txtid->seq_start = txtid->seq_next;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200900
Felix Fietkau2ed72222011-01-10 17:05:49 -0700901 memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
902 txtid->baw_head = txtid->baw_tail = 0;
903
Felix Fietkau231c3a12010-09-20 19:35:28 +0200904 return 0;
Sujithe8324352009-01-16 21:38:42 +0530905}
906
Sujithf83da962009-07-23 15:32:37 +0530907void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530908{
909 struct ath_node *an = (struct ath_node *)sta->drv_priv;
910 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100911 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530912
913 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530914 return;
Sujithe8324352009-01-16 21:38:42 +0530915
916 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530917 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530918 return;
Sujithe8324352009-01-16 21:38:42 +0530919 }
920
Sujithe8324352009-01-16 21:38:42 +0530921 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200922 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200923
924 /*
925 * If frames are still being transmitted for this TID, they will be
926 * cleaned up during tx completion. To prevent race conditions, this
927 * TID can only be reused after all in-progress subframes have been
928 * completed.
929 */
930 if (txtid->baw_head != txtid->baw_tail)
931 txtid->state |= AGGR_CLEANUP;
932 else
933 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530934 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530935
Felix Fietkau90fa5392010-09-20 13:45:38 +0200936 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530937}
938
Felix Fietkau55195412011-04-17 23:28:09 +0200939bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
940{
941 struct ath_atx_tid *tid;
942 struct ath_atx_ac *ac;
943 struct ath_txq *txq;
944 bool buffered = false;
945 int tidno;
946
947 for (tidno = 0, tid = &an->tid[tidno];
948 tidno < WME_NUM_TID; tidno++, tid++) {
949
950 if (!tid->sched)
951 continue;
952
953 ac = tid->ac;
954 txq = ac->txq;
955
956 spin_lock_bh(&txq->axq_lock);
957
958 if (!list_empty(&tid->buf_q))
959 buffered = true;
960
961 tid->sched = false;
962 list_del(&tid->list);
963
964 if (ac->sched) {
965 ac->sched = false;
966 list_del(&ac->list);
967 }
968
969 spin_unlock_bh(&txq->axq_lock);
970 }
971
972 return buffered;
973}
974
975void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
976{
977 struct ath_atx_tid *tid;
978 struct ath_atx_ac *ac;
979 struct ath_txq *txq;
980 int tidno;
981
982 for (tidno = 0, tid = &an->tid[tidno];
983 tidno < WME_NUM_TID; tidno++, tid++) {
984
985 ac = tid->ac;
986 txq = ac->txq;
987
988 spin_lock_bh(&txq->axq_lock);
989 ac->clear_ps_filter = true;
990
991 if (!list_empty(&tid->buf_q) && !tid->paused) {
992 ath_tx_queue_tid(txq, tid);
993 ath_txq_schedule(sc, txq);
994 }
995
996 spin_unlock_bh(&txq->axq_lock);
997 }
998}
999
Sujithe8324352009-01-16 21:38:42 +05301000void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
1001{
1002 struct ath_atx_tid *txtid;
1003 struct ath_node *an;
1004
1005 an = (struct ath_node *)sta->drv_priv;
1006
1007 if (sc->sc_flags & SC_OP_TXAGGR) {
1008 txtid = ATH_AN_2_TID(an, tid);
1009 txtid->baw_size =
1010 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
1011 txtid->state |= AGGR_ADDBA_COMPLETE;
1012 txtid->state &= ~AGGR_ADDBA_PROGRESS;
1013 ath_tx_resume_tid(sc, txtid);
1014 }
1015}
1016
Sujithe8324352009-01-16 21:38:42 +05301017/********************/
1018/* Queue Management */
1019/********************/
1020
Sujithe8324352009-01-16 21:38:42 +05301021static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
1022 struct ath_txq *txq)
1023{
1024 struct ath_atx_ac *ac, *ac_tmp;
1025 struct ath_atx_tid *tid, *tid_tmp;
1026
1027 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1028 list_del(&ac->list);
1029 ac->sched = false;
1030 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
1031 list_del(&tid->list);
1032 tid->sched = false;
1033 ath_tid_drain(sc, txq, tid);
1034 }
1035 }
1036}
1037
1038struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
1039{
Sujithcbe61d82009-02-09 13:27:12 +05301040 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001041 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +05301042 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001043 static const int subtype_txq_to_hwq[] = {
1044 [WME_AC_BE] = ATH_TXQ_AC_BE,
1045 [WME_AC_BK] = ATH_TXQ_AC_BK,
1046 [WME_AC_VI] = ATH_TXQ_AC_VI,
1047 [WME_AC_VO] = ATH_TXQ_AC_VO,
1048 };
Ben Greear60f2d1d2011-01-09 23:11:52 -08001049 int axq_qnum, i;
Sujithe8324352009-01-16 21:38:42 +05301050
1051 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +01001052 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +05301053 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
1054 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
1055 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
1056 qi.tqi_physCompBuf = 0;
1057
1058 /*
1059 * Enable interrupts only for EOL and DESC conditions.
1060 * We mark tx descriptors to receive a DESC interrupt
1061 * when a tx queue gets deep; otherwise waiting for the
1062 * EOL to reap descriptors. Note that this is done to
1063 * reduce interrupt load and this only defers reaping
1064 * descriptors, never transmitting frames. Aside from
1065 * reducing interrupts this also permits more concurrency.
1066 * The only potential downside is if the tx queue backs
1067 * up in which case the top half of the kernel may backup
1068 * due to a lack of tx descriptors.
1069 *
1070 * The UAPSD queue is an exception, since we take a desc-
1071 * based intr on the EOSP frames.
1072 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -04001073 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1074 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
1075 TXQ_FLAG_TXERRINT_ENABLE;
1076 } else {
1077 if (qtype == ATH9K_TX_QUEUE_UAPSD)
1078 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
1079 else
1080 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
1081 TXQ_FLAG_TXDESCINT_ENABLE;
1082 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001083 axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
1084 if (axq_qnum == -1) {
Sujithe8324352009-01-16 21:38:42 +05301085 /*
1086 * NB: don't print a message, this happens
1087 * normally on parts with too few tx queues
1088 */
1089 return NULL;
1090 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001091 if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
Joe Perches38002762010-12-02 19:12:36 -08001092 ath_err(common, "qnum %u out of range, max %zu!\n",
Ben Greear60f2d1d2011-01-09 23:11:52 -08001093 axq_qnum, ARRAY_SIZE(sc->tx.txq));
1094 ath9k_hw_releasetxqueue(ah, axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301095 return NULL;
1096 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001097 if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
1098 struct ath_txq *txq = &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301099
Ben Greear60f2d1d2011-01-09 23:11:52 -08001100 txq->axq_qnum = axq_qnum;
1101 txq->mac80211_qnum = -1;
Sujithe8324352009-01-16 21:38:42 +05301102 txq->axq_link = NULL;
1103 INIT_LIST_HEAD(&txq->axq_q);
1104 INIT_LIST_HEAD(&txq->axq_acq);
1105 spin_lock_init(&txq->axq_lock);
1106 txq->axq_depth = 0;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001107 txq->axq_ampdu_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001108 txq->axq_tx_inprogress = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08001109 sc->tx.txqsetup |= 1<<axq_qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001110
1111 txq->txq_headidx = txq->txq_tailidx = 0;
1112 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1113 INIT_LIST_HEAD(&txq->txq_fifo[i]);
Sujithe8324352009-01-16 21:38:42 +05301114 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001115 return &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301116}
1117
Sujithe8324352009-01-16 21:38:42 +05301118int ath_txq_update(struct ath_softc *sc, int qnum,
1119 struct ath9k_tx_queue_info *qinfo)
1120{
Sujithcbe61d82009-02-09 13:27:12 +05301121 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301122 int error = 0;
1123 struct ath9k_tx_queue_info qi;
1124
1125 if (qnum == sc->beacon.beaconq) {
1126 /*
1127 * XXX: for beacon queue, we just save the parameter.
1128 * It will be picked up by ath_beaconq_config when
1129 * it's necessary.
1130 */
1131 sc->beacon.beacon_qi = *qinfo;
1132 return 0;
1133 }
1134
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001135 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301136
1137 ath9k_hw_get_txq_props(ah, qnum, &qi);
1138 qi.tqi_aifs = qinfo->tqi_aifs;
1139 qi.tqi_cwmin = qinfo->tqi_cwmin;
1140 qi.tqi_cwmax = qinfo->tqi_cwmax;
1141 qi.tqi_burstTime = qinfo->tqi_burstTime;
1142 qi.tqi_readyTime = qinfo->tqi_readyTime;
1143
1144 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Joe Perches38002762010-12-02 19:12:36 -08001145 ath_err(ath9k_hw_common(sc->sc_ah),
1146 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301147 error = -EIO;
1148 } else {
1149 ath9k_hw_resettxqueue(ah, qnum);
1150 }
1151
1152 return error;
1153}
1154
1155int ath_cabq_update(struct ath_softc *sc)
1156{
1157 struct ath9k_tx_queue_info qi;
Steve Brown9814f6b2011-02-07 17:10:39 -07001158 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
Sujithe8324352009-01-16 21:38:42 +05301159 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301160
1161 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1162 /*
1163 * Ensure the readytime % is within the bounds.
1164 */
Sujith17d79042009-02-09 13:27:03 +05301165 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1166 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1167 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1168 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301169
Steve Brown9814f6b2011-02-07 17:10:39 -07001170 qi.tqi_readyTime = (cur_conf->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301171 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301172 ath_txq_update(sc, qnum, &qi);
1173
1174 return 0;
1175}
1176
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001177static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
1178{
1179 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
1180 return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
1181}
1182
Felix Fietkaufce041b2011-05-19 12:20:25 +02001183static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
1184 struct list_head *list, bool retry_tx)
Rajkumar Manoharan5479de62011-07-17 11:43:02 +05301185 __releases(txq->axq_lock)
1186 __acquires(txq->axq_lock)
Sujithe8324352009-01-16 21:38:42 +05301187{
1188 struct ath_buf *bf, *lastbf;
1189 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001190 struct ath_tx_status ts;
1191
1192 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301193 INIT_LIST_HEAD(&bf_head);
1194
Felix Fietkaufce041b2011-05-19 12:20:25 +02001195 while (!list_empty(list)) {
1196 bf = list_first_entry(list, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +05301197
Felix Fietkaufce041b2011-05-19 12:20:25 +02001198 if (bf->bf_stale) {
1199 list_del(&bf->list);
Sujithe8324352009-01-16 21:38:42 +05301200
Felix Fietkaufce041b2011-05-19 12:20:25 +02001201 ath_tx_return_buffer(sc, bf);
1202 continue;
Sujithe8324352009-01-16 21:38:42 +05301203 }
1204
1205 lastbf = bf->bf_lastbf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02001206 list_cut_position(&bf_head, list, &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001207
Sujithe8324352009-01-16 21:38:42 +05301208 txq->axq_depth--;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001209 if (bf_is_ampdu_not_probing(bf))
1210 txq->axq_ampdu_depth--;
Sujithe8324352009-01-16 21:38:42 +05301211
Felix Fietkaufce041b2011-05-19 12:20:25 +02001212 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301213 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001214 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1215 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301216 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001217 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001218 spin_lock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001219 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001220}
1221
1222/*
1223 * Drain a given TX queue (could be Beacon or Data)
1224 *
1225 * This assumes output has been stopped and
1226 * we do not need to block ath_tx_tasklet.
1227 */
1228void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
1229{
1230 spin_lock_bh(&txq->axq_lock);
1231 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1232 int idx = txq->txq_tailidx;
1233
1234 while (!list_empty(&txq->txq_fifo[idx])) {
1235 ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
1236 retry_tx);
1237
1238 INCR(idx, ATH_TXFIFO_DEPTH);
1239 }
1240 txq->txq_tailidx = idx;
1241 }
1242
1243 txq->axq_link = NULL;
1244 txq->axq_tx_inprogress = false;
1245 ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001246
1247 /* flush any pending frames if aggregation is enabled */
Felix Fietkaufce041b2011-05-19 12:20:25 +02001248 if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
1249 ath_txq_drain_pending_buffers(sc, txq);
1250
1251 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301252}
1253
Felix Fietkau080e1a22010-12-05 20:17:53 +01001254bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
Sujith043a0402009-01-16 21:38:47 +05301255{
Sujithcbe61d82009-02-09 13:27:12 +05301256 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001257 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301258 struct ath_txq *txq;
1259 int i, npend = 0;
1260
1261 if (sc->sc_flags & SC_OP_INVALID)
Felix Fietkau080e1a22010-12-05 20:17:53 +01001262 return true;
Sujith043a0402009-01-16 21:38:47 +05301263
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001264 ath9k_hw_abort_tx_dma(ah);
Sujith043a0402009-01-16 21:38:47 +05301265
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001266 /* Check if any queue remains active */
Sujith043a0402009-01-16 21:38:47 +05301267 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001268 if (!ATH_TXQ_SETUP(sc, i))
1269 continue;
1270
1271 npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
Sujith043a0402009-01-16 21:38:47 +05301272 }
1273
Felix Fietkau080e1a22010-12-05 20:17:53 +01001274 if (npend)
John W. Linville393934c2010-12-08 16:23:31 -05001275 ath_err(common, "Failed to stop TX DMA!\n");
Sujith043a0402009-01-16 21:38:47 +05301276
1277 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau92460412011-01-24 19:23:14 +01001278 if (!ATH_TXQ_SETUP(sc, i))
1279 continue;
1280
1281 /*
1282 * The caller will resume queues with ieee80211_wake_queues.
1283 * Mark the queue as not stopped to prevent ath_tx_complete
1284 * from waking the queue too early.
1285 */
1286 txq = &sc->tx.txq[i];
1287 txq->stopped = false;
1288 ath_draintxq(sc, txq, retry_tx);
Sujith043a0402009-01-16 21:38:47 +05301289 }
Felix Fietkau080e1a22010-12-05 20:17:53 +01001290
1291 return !npend;
Sujith043a0402009-01-16 21:38:47 +05301292}
1293
Sujithe8324352009-01-16 21:38:42 +05301294void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1295{
1296 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1297 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1298}
1299
Ben Greear7755bad2011-01-18 17:30:00 -08001300/* For each axq_acq entry, for each tid, try to schedule packets
1301 * for transmit until ampdu_depth has reached min Q depth.
1302 */
Sujithe8324352009-01-16 21:38:42 +05301303void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1304{
Ben Greear7755bad2011-01-18 17:30:00 -08001305 struct ath_atx_ac *ac, *ac_tmp, *last_ac;
1306 struct ath_atx_tid *tid, *last_tid;
Sujithe8324352009-01-16 21:38:42 +05301307
Felix Fietkau21f28e62011-01-15 14:30:14 +01001308 if (list_empty(&txq->axq_acq) ||
1309 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
Sujithe8324352009-01-16 21:38:42 +05301310 return;
1311
1312 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
Ben Greear7755bad2011-01-18 17:30:00 -08001313 last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
Sujithe8324352009-01-16 21:38:42 +05301314
Ben Greear7755bad2011-01-18 17:30:00 -08001315 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1316 last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
1317 list_del(&ac->list);
1318 ac->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301319
Ben Greear7755bad2011-01-18 17:30:00 -08001320 while (!list_empty(&ac->tid_q)) {
1321 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
1322 list);
1323 list_del(&tid->list);
1324 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301325
Ben Greear7755bad2011-01-18 17:30:00 -08001326 if (tid->paused)
1327 continue;
Sujithe8324352009-01-16 21:38:42 +05301328
Ben Greear7755bad2011-01-18 17:30:00 -08001329 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301330
Ben Greear7755bad2011-01-18 17:30:00 -08001331 /*
1332 * add tid to round-robin queue if more frames
1333 * are pending for the tid
1334 */
1335 if (!list_empty(&tid->buf_q))
1336 ath_tx_queue_tid(txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301337
Ben Greear7755bad2011-01-18 17:30:00 -08001338 if (tid == last_tid ||
1339 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1340 break;
Sujithe8324352009-01-16 21:38:42 +05301341 }
Ben Greear7755bad2011-01-18 17:30:00 -08001342
1343 if (!list_empty(&ac->tid_q)) {
1344 if (!ac->sched) {
1345 ac->sched = true;
1346 list_add_tail(&ac->list, &txq->axq_acq);
1347 }
1348 }
1349
1350 if (ac == last_ac ||
1351 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1352 return;
Sujithe8324352009-01-16 21:38:42 +05301353 }
1354}
1355
Sujithe8324352009-01-16 21:38:42 +05301356/***********/
1357/* TX, DMA */
1358/***********/
1359
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001360/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001361 * Insert a chain of ath_buf (descriptors) on a txq and
1362 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001363 */
Sujith102e0572008-10-29 10:15:16 +05301364static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +02001365 struct list_head *head, bool internal)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001366{
Sujithcbe61d82009-02-09 13:27:12 +05301367 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001368 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001369 struct ath_buf *bf, *bf_last;
1370 bool puttxbuf = false;
1371 bool edma;
Sujith102e0572008-10-29 10:15:16 +05301372
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001373 /*
1374 * Insert the frame on the outbound list and
1375 * pass it on to the hardware.
1376 */
1377
1378 if (list_empty(head))
1379 return;
1380
Felix Fietkaufce041b2011-05-19 12:20:25 +02001381 edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001382 bf = list_first_entry(head, struct ath_buf, list);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001383 bf_last = list_entry(head->prev, struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001384
Joe Perches226afe62010-12-02 19:12:37 -08001385 ath_dbg(common, ATH_DBG_QUEUE,
1386 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001387
Felix Fietkaufce041b2011-05-19 12:20:25 +02001388 if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
1389 list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001390 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001391 puttxbuf = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001392 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001393 list_splice_tail_init(head, &txq->axq_q);
1394
Felix Fietkaufce041b2011-05-19 12:20:25 +02001395 if (txq->axq_link) {
1396 ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
Joe Perches226afe62010-12-02 19:12:37 -08001397 ath_dbg(common, ATH_DBG_XMIT,
1398 "link[%u] (%p)=%llx (%p)\n",
1399 txq->axq_qnum, txq->axq_link,
1400 ito64(bf->bf_daddr), bf->bf_desc);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001401 } else if (!edma)
1402 puttxbuf = true;
1403
1404 txq->axq_link = bf_last->bf_desc;
1405 }
1406
1407 if (puttxbuf) {
1408 TX_STAT_INC(txq->axq_qnum, puttxbuf);
1409 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1410 ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
1411 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
1412 }
1413
1414 if (!edma) {
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001415 TX_STAT_INC(txq->axq_qnum, txstart);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001416 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001417 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001418
1419 if (!internal) {
1420 txq->axq_depth++;
1421 if (bf_is_ampdu_not_probing(bf))
1422 txq->axq_ampdu_depth++;
1423 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001424}
1425
Sujithe8324352009-01-16 21:38:42 +05301426static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau04caf862010-11-14 15:20:12 +01001427 struct ath_buf *bf, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301428{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001429 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau04caf862010-11-14 15:20:12 +01001430 struct list_head bf_head;
Sujithe8324352009-01-16 21:38:42 +05301431
Sujithe8324352009-01-16 21:38:42 +05301432 bf->bf_state.bf_type |= BUF_AMPDU;
1433
1434 /*
1435 * Do not queue to h/w when any of the following conditions is true:
1436 * - there are pending frames in software queue
1437 * - the TID is currently paused for ADDBA/BAR request
1438 * - seqno is not within block-ack window
1439 * - h/w queue depth exceeds low water mark
1440 */
1441 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001442 !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001443 txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001444 /*
Sujithe8324352009-01-16 21:38:42 +05301445 * Add this frame to software queue for scheduling later
1446 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001447 */
Ben Greearbda8add2011-01-09 23:11:48 -08001448 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
Felix Fietkau04caf862010-11-14 15:20:12 +01001449 list_add_tail(&bf->list, &tid->buf_q);
Felix Fietkau9af73cf2011-08-10 15:23:35 -06001450 if (!txctl->an || !txctl->an->sleeping)
1451 ath_tx_queue_tid(txctl->txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301452 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001453 }
1454
Felix Fietkau04caf862010-11-14 15:20:12 +01001455 INIT_LIST_HEAD(&bf_head);
1456 list_add(&bf->list, &bf_head);
1457
Sujithe8324352009-01-16 21:38:42 +05301458 /* Add sub-frame to BAW */
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001459 if (!fi->retries)
1460 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +05301461
1462 /* Queue to h/w without aggregation */
Ben Greearbda8add2011-01-09 23:11:48 -08001463 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
Sujithd43f30152009-01-16 21:38:53 +05301464 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001465 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001466 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
Sujithc4288392008-11-18 09:09:30 +05301467}
1468
Felix Fietkau82b873a2010-11-11 03:18:37 +01001469static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1470 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001471 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001472{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001473 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +05301474 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001475
Sujithe8324352009-01-16 21:38:42 +05301476 bf = list_first_entry(bf_head, struct ath_buf, list);
1477 bf->bf_state.bf_type &= ~BUF_AMPDU;
1478
1479 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001480 if (tid)
1481 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301482
Sujithd43f30152009-01-16 21:38:53 +05301483 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001484 fi = get_frame_info(bf->bf_mpdu);
1485 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001486 ath_tx_txqaddbuf(sc, txq, bf_head, false);
Sujithfec247c2009-07-27 12:08:16 +05301487 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001488}
1489
Sujith528f0c62008-10-29 10:14:26 +05301490static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001491{
Sujith528f0c62008-10-29 10:14:26 +05301492 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001493 enum ath9k_pkt_type htype;
1494 __le16 fc;
1495
Sujith528f0c62008-10-29 10:14:26 +05301496 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497 fc = hdr->frame_control;
1498
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499 if (ieee80211_is_beacon(fc))
1500 htype = ATH9K_PKT_TYPE_BEACON;
1501 else if (ieee80211_is_probe_resp(fc))
1502 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1503 else if (ieee80211_is_atim(fc))
1504 htype = ATH9K_PKT_TYPE_ATIM;
1505 else if (ieee80211_is_pspoll(fc))
1506 htype = ATH9K_PKT_TYPE_PSPOLL;
1507 else
1508 htype = ATH9K_PKT_TYPE_NORMAL;
1509
1510 return htype;
1511}
1512
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001513static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
1514 int framelen)
Sujith528f0c62008-10-29 10:14:26 +05301515{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001516 struct ath_softc *sc = hw->priv;
Sujith528f0c62008-10-29 10:14:26 +05301517 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001518 struct ieee80211_sta *sta = tx_info->control.sta;
1519 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
Sujith528f0c62008-10-29 10:14:26 +05301520 struct ieee80211_hdr *hdr;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001521 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001522 struct ath_node *an = NULL;
Sujith528f0c62008-10-29 10:14:26 +05301523 struct ath_atx_tid *tid;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001524 enum ath9k_key_type keytype;
1525 u16 seqno = 0;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001526 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301527
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001528 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujith528f0c62008-10-29 10:14:26 +05301529
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001530 if (sta)
1531 an = (struct ath_node *) sta->drv_priv;
1532
Sujith528f0c62008-10-29 10:14:26 +05301533 hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001534 if (an && ieee80211_is_data_qos(hdr->frame_control) &&
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001535 conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001536
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001537 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
1538
1539 /*
1540 * Override seqno set by upper layer with the one
1541 * in tx aggregation state.
1542 */
1543 tid = ATH_AN_2_TID(an, tidno);
1544 seqno = tid->seq_next;
1545 hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
1546 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
1547 }
1548
1549 memset(fi, 0, sizeof(*fi));
1550 if (hw_key)
1551 fi->keyix = hw_key->hw_key_idx;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001552 else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
1553 fi->keyix = an->ps_key;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001554 else
1555 fi->keyix = ATH9K_TXKEYIX_INVALID;
1556 fi->keytype = keytype;
1557 fi->framelen = framelen;
1558 fi->seqno = seqno;
Sujith528f0c62008-10-29 10:14:26 +05301559}
1560
Felix Fietkau82b873a2010-11-11 03:18:37 +01001561static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301562{
1563 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1564 int flags = 0;
1565
Sujith528f0c62008-10-29 10:14:26 +05301566 flags |= ATH9K_TXDESC_INTREQ;
1567
1568 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1569 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301570
Felix Fietkau82b873a2010-11-11 03:18:37 +01001571 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001572 flags |= ATH9K_TXDESC_LDPC;
1573
Sujith528f0c62008-10-29 10:14:26 +05301574 return flags;
1575}
1576
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001577/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001578 * rix - rate index
1579 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1580 * width - 0 for 20 MHz, 1 for 40 MHz
1581 * half_gi - to use 4us v/s 3.6 us for symbol time
1582 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001583static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301584 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001585{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001586 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001587 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301588
1589 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001590 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001591 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001592 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001593 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1594
1595 if (!half_gi)
1596 duration = SYMBOL_TIME(nsymbols);
1597 else
1598 duration = SYMBOL_TIME_HALFGI(nsymbols);
1599
Sujithe63835b2008-11-18 09:07:53 +05301600 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001601 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301602
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001603 return duration;
1604}
1605
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301606u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
1607{
1608 struct ath_hw *ah = sc->sc_ah;
1609 struct ath9k_channel *curchan = ah->curchan;
Rajkumar Manoharand77bf3e2011-08-13 10:28:14 +05301610 if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
1611 (curchan->channelFlags & CHANNEL_5GHZ) &&
1612 (chainmask == 0x7) && (rate < 0x90))
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301613 return 0x3;
1614 else
1615 return chainmask;
1616}
1617
Felix Fietkau269c44b2010-11-14 15:20:06 +01001618static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001619{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001620 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001621 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301622 struct sk_buff *skb;
1623 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301624 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001625 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301626 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301627 int i, flags = 0;
1628 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301629 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301630
1631 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301632
Sujitha22be222009-03-30 15:28:36 +05301633 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301634 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301635 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301636 hdr = (struct ieee80211_hdr *)skb->data;
1637 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301638
Sujithc89424d2009-01-30 14:29:28 +05301639 /*
1640 * We check if Short Preamble is needed for the CTS rate by
1641 * checking the BSS's global flag.
1642 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1643 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001644 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1645 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301646 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001647 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001648
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001649 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001650 bool is_40, is_sgi, is_sp;
1651 int phy;
1652
Sujithe63835b2008-11-18 09:07:53 +05301653 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001654 continue;
1655
Sujitha8efee42008-11-18 09:07:30 +05301656 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301657 series[i].Tries = rates[i].count;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001658
Mohammed Shafi Shajakhancbe8c732011-05-03 13:14:06 +05301659 if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
Sujithc89424d2009-01-30 14:29:28 +05301660 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001661 flags |= ATH9K_TXDESC_RTSENA;
1662 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1663 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1664 flags |= ATH9K_TXDESC_CTSENA;
1665 }
1666
Sujithc89424d2009-01-30 14:29:28 +05301667 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1668 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1669 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1670 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001671
Felix Fietkau545750d2009-11-23 22:21:01 +01001672 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1673 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1674 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1675
1676 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1677 /* MCS rates */
1678 series[i].Rate = rix | 0x80;
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301679 series[i].ChSel = ath_txchainmask_reduction(sc,
1680 common->tx_chainmask, series[i].Rate);
Felix Fietkau269c44b2010-11-14 15:20:06 +01001681 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001682 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001683 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1684 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001685 continue;
1686 }
1687
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301688 /* legacy rates */
Felix Fietkau545750d2009-11-23 22:21:01 +01001689 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1690 !(rate->flags & IEEE80211_RATE_ERP_G))
1691 phy = WLAN_RC_PHY_CCK;
1692 else
1693 phy = WLAN_RC_PHY_OFDM;
1694
1695 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1696 series[i].Rate = rate->hw_value;
1697 if (rate->hw_value_short) {
1698 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1699 series[i].Rate |= rate->hw_value_short;
1700 } else {
1701 is_sp = false;
1702 }
1703
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301704 if (bf->bf_state.bfs_paprd)
1705 series[i].ChSel = common->tx_chainmask;
1706 else
1707 series[i].ChSel = ath_txchainmask_reduction(sc,
1708 common->tx_chainmask, series[i].Rate);
1709
Felix Fietkau545750d2009-11-23 22:21:01 +01001710 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001711 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001712 }
1713
Felix Fietkau27032052010-01-17 21:08:50 +01001714 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001715 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001716 flags &= ~ATH9K_TXDESC_RTSENA;
1717
1718 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1719 if (flags & ATH9K_TXDESC_RTSENA)
1720 flags &= ~ATH9K_TXDESC_CTSENA;
1721
Sujithe63835b2008-11-18 09:07:53 +05301722 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301723 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1724 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301725 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301726 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301727
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001728}
1729
Felix Fietkau82b873a2010-11-11 03:18:37 +01001730static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
Felix Fietkau04caf862010-11-14 15:20:12 +01001731 struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001732 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301733{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001734 struct ath_softc *sc = hw->priv;
Felix Fietkau04caf862010-11-14 15:20:12 +01001735 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001736 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001737 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001738 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001739 struct ath_desc *ds;
Felix Fietkau04caf862010-11-14 15:20:12 +01001740 int frm_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001741
1742 bf = ath_tx_get_buffer(sc);
1743 if (!bf) {
Joe Perches226afe62010-12-02 19:12:37 -08001744 ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001745 return NULL;
1746 }
Sujithe8324352009-01-16 21:38:42 +05301747
Sujithe8324352009-01-16 21:38:42 +05301748 ATH_TXBUF_RESET(bf);
1749
Felix Fietkau82b873a2010-11-11 03:18:37 +01001750 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301751 bf->bf_mpdu = skb;
1752
Ben Greearc1739eb32010-10-14 12:45:29 -07001753 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1754 skb->len, DMA_TO_DEVICE);
1755 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301756 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001757 bf->bf_buf_addr = 0;
Joe Perches38002762010-12-02 19:12:36 -08001758 ath_err(ath9k_hw_common(sc->sc_ah),
1759 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001760 ath_tx_return_buffer(sc, bf);
1761 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301762 }
1763
Sujithe8324352009-01-16 21:38:42 +05301764 frm_type = get_hw_packet_type(skb);
Sujithe8324352009-01-16 21:38:42 +05301765
1766 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001767 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301768
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001769 ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
1770 fi->keyix, fi->keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301771
1772 ath9k_hw_filltxdesc(ah, ds,
1773 skb->len, /* segment length */
1774 true, /* first segment */
1775 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001776 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001777 bf->bf_buf_addr,
Felix Fietkau04caf862010-11-14 15:20:12 +01001778 txq->axq_qnum);
1779
1780
1781 return bf;
1782}
1783
1784/* FIXME: tx power */
1785static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1786 struct ath_tx_control *txctl)
1787{
1788 struct sk_buff *skb = bf->bf_mpdu;
1789 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1790 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau04caf862010-11-14 15:20:12 +01001791 struct list_head bf_head;
Felix Fietkau248a38d2010-12-10 21:16:46 +01001792 struct ath_atx_tid *tid = NULL;
Felix Fietkau04caf862010-11-14 15:20:12 +01001793 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301794
Sujithe8324352009-01-16 21:38:42 +05301795 spin_lock_bh(&txctl->txq->axq_lock);
Mohammed Shafi Shajakhan61e1b0b2011-03-21 18:27:21 +05301796 if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an &&
1797 ieee80211_is_data_qos(hdr->frame_control)) {
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001798 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1799 IEEE80211_QOS_CTL_TID_MASK;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001800 tid = ATH_AN_2_TID(txctl->an, tidno);
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001801
Felix Fietkau066dae92010-11-07 14:59:39 +01001802 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau248a38d2010-12-10 21:16:46 +01001803 }
1804
1805 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
Felix Fietkau04caf862010-11-14 15:20:12 +01001806 /*
1807 * Try aggregation if it's a unicast data frame
1808 * and the destination is HT capable.
1809 */
1810 ath_tx_send_ampdu(sc, tid, bf, txctl);
Sujithe8324352009-01-16 21:38:42 +05301811 } else {
Felix Fietkau04caf862010-11-14 15:20:12 +01001812 INIT_LIST_HEAD(&bf_head);
1813 list_add_tail(&bf->list, &bf_head);
1814
Felix Fietkau82b873a2010-11-11 03:18:37 +01001815 bf->bf_state.bfs_paprd = txctl->paprd;
1816
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001817 if (bf->bf_state.bfs_paprd)
Felix Fietkau04caf862010-11-14 15:20:12 +01001818 ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
1819 bf->bf_state.bfs_paprd);
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001820
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301821 if (txctl->paprd)
1822 bf->bf_state.bfs_paprd_timestamp = jiffies;
1823
Felix Fietkau55195412011-04-17 23:28:09 +02001824 if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
1825 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
1826
Felix Fietkau248a38d2010-12-10 21:16:46 +01001827 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301828 }
1829
1830 spin_unlock_bh(&txctl->txq->axq_lock);
1831}
1832
1833/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001834int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301835 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001836{
Felix Fietkau28d16702010-11-14 15:20:10 +01001837 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1838 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001839 struct ieee80211_sta *sta = info->control.sta;
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001840 struct ieee80211_vif *vif = info->control.vif;
Felix Fietkau9ac586152011-01-24 19:23:18 +01001841 struct ath_softc *sc = hw->priv;
Felix Fietkau84642d62010-06-01 21:33:13 +02001842 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001843 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001844 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001845 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001846 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001847
Ben Greeara9927ba2010-12-06 21:13:49 -08001848 /* NOTE: sta can be NULL according to net/mac80211.h */
1849 if (sta)
1850 txctl->an = (struct ath_node *)sta->drv_priv;
1851
Felix Fietkau04caf862010-11-14 15:20:12 +01001852 if (info->control.hw_key)
1853 frmlen += info->control.hw_key->icv_len;
1854
Felix Fietkau28d16702010-11-14 15:20:10 +01001855 /*
1856 * As a temporary workaround, assign seq# here; this will likely need
1857 * to be cleaned up to work better with Beacon transmission and virtual
1858 * BSSes.
1859 */
1860 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1861 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1862 sc->tx.seq_no += 0x10;
1863 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1864 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1865 }
1866
1867 /* Add the padding after the header if this is not already done */
1868 padpos = ath9k_cmn_padpos(hdr->frame_control);
1869 padsize = padpos & 3;
1870 if (padsize && skb->len > padpos) {
1871 if (skb_headroom(skb) < padsize)
1872 return -ENOMEM;
1873
1874 skb_push(skb, padsize);
1875 memmove(skb->data, skb->data + padsize, padpos);
1876 }
1877
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001878 if ((vif && vif->type != NL80211_IFTYPE_AP &&
1879 vif->type != NL80211_IFTYPE_AP_VLAN) ||
1880 !ieee80211_is_data(hdr->frame_control))
1881 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1882
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001883 setup_frame_info(hw, skb, frmlen);
1884
1885 /*
1886 * At this point, the vif, hw_key and sta pointers in the tx control
1887 * info are no longer valid (overwritten by the ath_frame_info data.
1888 */
1889
1890 bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001891 if (unlikely(!bf))
1892 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001893
Felix Fietkau066dae92010-11-07 14:59:39 +01001894 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001895 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001896 if (txq == sc->tx.txq_map[q] &&
1897 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001898 ieee80211_stop_queue(sc->hw, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001899 txq->stopped = 1;
1900 }
1901 spin_unlock_bh(&txq->axq_lock);
1902
Sujithe8324352009-01-16 21:38:42 +05301903 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001904
1905 return 0;
1906}
1907
Sujithe8324352009-01-16 21:38:42 +05301908/*****************/
1909/* TX Completion */
1910/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001911
Sujithe8324352009-01-16 21:38:42 +05301912static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Rajkumar Manoharan0f9dc292011-07-29 17:38:14 +05301913 int tx_flags, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001914{
Sujithe8324352009-01-16 21:38:42 +05301915 struct ieee80211_hw *hw = sc->hw;
1916 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001917 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001918 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001919 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301920
Joe Perches226afe62010-12-02 19:12:37 -08001921 ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301922
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301923 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301924 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301925
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301926 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301927 /* Frame was ACKed */
1928 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1929 }
1930
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001931 padpos = ath9k_cmn_padpos(hdr->frame_control);
1932 padsize = padpos & 3;
1933 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301934 /*
1935 * Remove MAC header padding before giving the frame back to
1936 * mac80211.
1937 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001938 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301939 skb_pull(skb, padsize);
1940 }
1941
Sujith1b04b932010-01-08 10:36:05 +05301942 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1943 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Joe Perches226afe62010-12-02 19:12:37 -08001944 ath_dbg(common, ATH_DBG_PS,
1945 "Going back to sleep after having received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301946 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1947 PS_WAIT_FOR_CAB |
1948 PS_WAIT_FOR_PSPOLL_DATA |
1949 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001950 }
1951
Felix Fietkau7545daf2011-01-24 19:23:16 +01001952 q = skb_get_queue_mapping(skb);
1953 if (txq == sc->tx.txq_map[q]) {
1954 spin_lock_bh(&txq->axq_lock);
1955 if (WARN_ON(--txq->pending_frames < 0))
1956 txq->pending_frames = 0;
Felix Fietkau92460412011-01-24 19:23:14 +01001957
Felix Fietkau7545daf2011-01-24 19:23:16 +01001958 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
1959 ieee80211_wake_queue(sc->hw, q);
1960 txq->stopped = 0;
Felix Fietkau066dae92010-11-07 14:59:39 +01001961 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001962 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04001963 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001964
1965 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301966}
1967
1968static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001969 struct ath_txq *txq, struct list_head *bf_q,
1970 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301971{
1972 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301973 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301974 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301975
Sujithe8324352009-01-16 21:38:42 +05301976 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301977 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301978
1979 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301980 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301981
1982 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301983 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301984 }
1985
Ben Greearc1739eb32010-10-14 12:45:29 -07001986 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001987 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001988
1989 if (bf->bf_state.bfs_paprd) {
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301990 if (time_after(jiffies,
1991 bf->bf_state.bfs_paprd_timestamp +
1992 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001993 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001994 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001995 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001996 } else {
Felix Fietkau5bec3e52011-01-24 21:29:25 +01001997 ath_debug_stat_tx(sc, bf, ts, txq);
Rajkumar Manoharan0f9dc292011-07-29 17:38:14 +05301998 ath_tx_complete(sc, skb, tx_flags, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001999 }
Ben Greear6cf9e992010-10-14 12:45:30 -07002000 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
2001 * accidentally reference it later.
2002 */
2003 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05302004
2005 /*
2006 * Return the list of ath_buf of this mpdu to free queue
2007 */
2008 spin_lock_irqsave(&sc->tx.txbuflock, flags);
2009 list_splice_tail_init(bf_q, &sc->tx.txbuf);
2010 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
2011}
2012
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002013static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
2014 struct ath_tx_status *ts, int nframes, int nbad,
2015 int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302016{
Sujitha22be222009-03-30 15:28:36 +05302017 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302018 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302019 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01002020 struct ieee80211_hw *hw = sc->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002021 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302022 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302023
Sujith95e4acb2009-03-13 08:56:09 +05302024 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002025 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302026
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002027 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302028 WARN_ON(tx_rateindex >= hw->max_rates);
2029
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002030 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302031 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02002032 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01002033 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302034
Felix Fietkaub572d032010-11-14 15:20:07 +01002035 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02002036
Felix Fietkaub572d032010-11-14 15:20:07 +01002037 tx_info->status.ampdu_len = nframes;
2038 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02002039 }
2040
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002041 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302042 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002043 /*
2044 * If an underrun error is seen assume it as an excessive
2045 * retry only if max frame trigger level has been reached
2046 * (2 KB for single stream, and 4 KB for dual stream).
2047 * Adjust the long retry as if the frame was tried
2048 * hw->max_rate_tries times to affect how rate control updates
2049 * PER for the failed rate.
2050 * In case of congestion on the bus penalizing this type of
2051 * underruns should help hardware actually transmit new frames
2052 * successfully by eventually preferring slower rates.
2053 * This itself should also alleviate congestion on the bus.
2054 */
2055 if (ieee80211_is_data(hdr->frame_control) &&
2056 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
2057 ATH9K_TX_DELIM_UNDERRUN)) &&
Felix Fietkau83860c52011-03-23 20:57:33 +01002058 ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002059 tx_info->status.rates[tx_rateindex].count =
2060 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05302061 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302062
Felix Fietkau545750d2009-11-23 22:21:01 +01002063 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302064 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002065 tx_info->status.rates[i].idx = -1;
2066 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302067
Felix Fietkau78c46532010-06-25 01:26:16 +02002068 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302069}
2070
Felix Fietkaufce041b2011-05-19 12:20:25 +02002071static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
2072 struct ath_tx_status *ts, struct ath_buf *bf,
2073 struct list_head *bf_head)
Rajkumar Manoharan5479de62011-07-17 11:43:02 +05302074 __releases(txq->axq_lock)
2075 __acquires(txq->axq_lock)
Felix Fietkaufce041b2011-05-19 12:20:25 +02002076{
2077 int txok;
2078
2079 txq->axq_depth--;
2080 txok = !(ts->ts_status & ATH9K_TXERR_MASK);
2081 txq->axq_tx_inprogress = false;
2082 if (bf_is_ampdu_not_probing(bf))
2083 txq->axq_ampdu_depth--;
2084
2085 spin_unlock_bh(&txq->axq_lock);
2086
2087 if (!bf_isampdu(bf)) {
2088 /*
2089 * This frame is sent out as a single frame.
2090 * Use hardware retry status for this frame.
2091 */
2092 if (ts->ts_status & ATH9K_TXERR_XRETRY)
2093 bf->bf_state.bf_type |= BUF_XRETRY;
2094 ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
2095 ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
2096 } else
2097 ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
2098
2099 spin_lock_bh(&txq->axq_lock);
2100
2101 if (sc->sc_flags & SC_OP_TXAGGR)
2102 ath_txq_schedule(sc, txq);
2103}
2104
Sujithc4288392008-11-18 09:09:30 +05302105static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002106{
Sujithcbe61d82009-02-09 13:27:12 +05302107 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002108 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2110 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302111 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002112 struct ath_tx_status ts;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002113 int status;
2114
Joe Perches226afe62010-12-02 19:12:37 -08002115 ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2116 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2117 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002118
Felix Fietkaufce041b2011-05-19 12:20:25 +02002119 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002120 for (;;) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002121 if (list_empty(&txq->axq_q)) {
2122 txq->axq_link = NULL;
Felix Fietkau86271e42011-03-11 21:38:19 +01002123 if (sc->sc_flags & SC_OP_TXAGGR)
Ben Greear082f6532011-01-09 23:11:47 -08002124 ath_txq_schedule(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002125 break;
2126 }
2127 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2128
2129 /*
2130 * There is a race condition that a BH gets scheduled
2131 * after sw writes TxE and before hw re-load the last
2132 * descriptor to get the newly chained one.
2133 * Software must keep the last DONE descriptor as a
2134 * holding descriptor - software does so by marking
2135 * it with the STALE flag.
2136 */
2137 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302138 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002139 bf_held = bf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002140 if (list_is_last(&bf_held->list, &txq->axq_q))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002141 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002142
2143 bf = list_entry(bf_held->list.next, struct ath_buf,
2144 list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002145 }
2146
2147 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302148 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002149
Felix Fietkau29bffa92010-03-29 20:14:23 -07002150 memset(&ts, 0, sizeof(ts));
2151 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002152 if (status == -EINPROGRESS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002153 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002154
Ben Greear2dac4fb2011-01-09 23:11:45 -08002155 TX_STAT_INC(txq->axq_qnum, txprocdesc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002156
2157 /*
2158 * Remove ath_buf's of the same transmit unit from txq,
2159 * however leave the last descriptor back as the holding
2160 * descriptor for hw.
2161 */
Sujitha119cc42009-03-30 15:28:38 +05302162 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002163 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164 if (!list_is_singular(&lastbf->list))
2165 list_cut_position(&bf_head,
2166 &txq->axq_q, lastbf->list.prev);
2167
Felix Fietkaufce041b2011-05-19 12:20:25 +02002168 if (bf_held) {
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002169 list_del(&bf_held->list);
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002170 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002171 }
Johannes Berge6a98542008-10-21 12:40:02 +02002172
Felix Fietkaufce041b2011-05-19 12:20:25 +02002173 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002174 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02002175 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002176}
2177
Sujith305fe472009-07-23 15:32:29 +05302178static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002179{
2180 struct ath_softc *sc = container_of(work, struct ath_softc,
2181 tx_complete_work.work);
2182 struct ath_txq *txq;
2183 int i;
2184 bool needreset = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08002185#ifdef CONFIG_ATH9K_DEBUGFS
2186 sc->tx_complete_poll_work_seen++;
2187#endif
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002188
2189 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2190 if (ATH_TXQ_SETUP(sc, i)) {
2191 txq = &sc->tx.txq[i];
2192 spin_lock_bh(&txq->axq_lock);
2193 if (txq->axq_depth) {
2194 if (txq->axq_tx_inprogress) {
2195 needreset = true;
2196 spin_unlock_bh(&txq->axq_lock);
2197 break;
2198 } else {
2199 txq->axq_tx_inprogress = true;
2200 }
2201 }
2202 spin_unlock_bh(&txq->axq_lock);
2203 }
2204
2205 if (needreset) {
Joe Perches226afe62010-12-02 19:12:37 -08002206 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2207 "tx hung, resetting the chip\n");
Rajkumar Manoharanf6b4e4d2011-06-24 17:38:13 +05302208 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002209 ath_reset(sc, true);
Rajkumar Manoharanf6b4e4d2011-06-24 17:38:13 +05302210 spin_unlock_bh(&sc->sc_pcu_lock);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002211 }
2212
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002213 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002214 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2215}
2216
2217
Sujithe8324352009-01-16 21:38:42 +05302218
2219void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002220{
Sujithe8324352009-01-16 21:38:42 +05302221 int i;
2222 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002223
Sujithe8324352009-01-16 21:38:42 +05302224 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002225
2226 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302227 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2228 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002229 }
2230}
2231
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002232void ath_tx_edma_tasklet(struct ath_softc *sc)
2233{
Felix Fietkaufce041b2011-05-19 12:20:25 +02002234 struct ath_tx_status ts;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002235 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2236 struct ath_hw *ah = sc->sc_ah;
2237 struct ath_txq *txq;
2238 struct ath_buf *bf, *lastbf;
2239 struct list_head bf_head;
2240 int status;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002241
2242 for (;;) {
Felix Fietkaufce041b2011-05-19 12:20:25 +02002243 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002244 if (status == -EINPROGRESS)
2245 break;
2246 if (status == -EIO) {
Joe Perches226afe62010-12-02 19:12:37 -08002247 ath_dbg(common, ATH_DBG_XMIT,
2248 "Error processing tx status\n");
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002249 break;
2250 }
2251
2252 /* Skip beacon completions */
Felix Fietkaufce041b2011-05-19 12:20:25 +02002253 if (ts.qid == sc->beacon.beaconq)
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002254 continue;
2255
Felix Fietkaufce041b2011-05-19 12:20:25 +02002256 txq = &sc->tx.txq[ts.qid];
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002257
2258 spin_lock_bh(&txq->axq_lock);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002259
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002260 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2261 spin_unlock_bh(&txq->axq_lock);
2262 return;
2263 }
2264
2265 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2266 struct ath_buf, list);
2267 lastbf = bf->bf_lastbf;
2268
2269 INIT_LIST_HEAD(&bf_head);
2270 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2271 &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002272
Felix Fietkaufce041b2011-05-19 12:20:25 +02002273 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2274 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002275
Felix Fietkaufce041b2011-05-19 12:20:25 +02002276 if (!list_empty(&txq->axq_q)) {
2277 struct list_head bf_q;
2278
2279 INIT_LIST_HEAD(&bf_q);
2280 txq->axq_link = NULL;
2281 list_splice_tail_init(&txq->axq_q, &bf_q);
2282 ath_tx_txqaddbuf(sc, txq, &bf_q, true);
2283 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002284 }
2285
Felix Fietkaufce041b2011-05-19 12:20:25 +02002286 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002287 spin_unlock_bh(&txq->axq_lock);
2288 }
2289}
2290
Sujithe8324352009-01-16 21:38:42 +05302291/*****************/
2292/* Init, Cleanup */
2293/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002294
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002295static int ath_txstatus_setup(struct ath_softc *sc, int size)
2296{
2297 struct ath_descdma *dd = &sc->txsdma;
2298 u8 txs_len = sc->sc_ah->caps.txs_len;
2299
2300 dd->dd_desc_len = size * txs_len;
2301 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2302 &dd->dd_desc_paddr, GFP_KERNEL);
2303 if (!dd->dd_desc)
2304 return -ENOMEM;
2305
2306 return 0;
2307}
2308
2309static int ath_tx_edma_init(struct ath_softc *sc)
2310{
2311 int err;
2312
2313 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2314 if (!err)
2315 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2316 sc->txsdma.dd_desc_paddr,
2317 ATH_TXSTATUS_RING_SIZE);
2318
2319 return err;
2320}
2321
2322static void ath_tx_edma_cleanup(struct ath_softc *sc)
2323{
2324 struct ath_descdma *dd = &sc->txsdma;
2325
2326 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2327 dd->dd_desc_paddr);
2328}
2329
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002330int ath_tx_init(struct ath_softc *sc, int nbufs)
2331{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002332 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002333 int error = 0;
2334
Sujith797fe5cb2009-03-30 15:28:45 +05302335 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002336
Sujith797fe5cb2009-03-30 15:28:45 +05302337 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002338 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302339 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002340 ath_err(common,
2341 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302342 goto err;
2343 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002344
Sujith797fe5cb2009-03-30 15:28:45 +05302345 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002346 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302347 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002348 ath_err(common,
2349 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302350 goto err;
2351 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002352
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002353 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2354
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002355 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2356 error = ath_tx_edma_init(sc);
2357 if (error)
2358 goto err;
2359 }
2360
Sujith797fe5cb2009-03-30 15:28:45 +05302361err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002362 if (error != 0)
2363 ath_tx_cleanup(sc);
2364
2365 return error;
2366}
2367
Sujith797fe5cb2009-03-30 15:28:45 +05302368void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002369{
Sujithb77f4832008-12-07 21:44:03 +05302370 if (sc->beacon.bdma.dd_desc_len != 0)
2371 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002372
Sujithb77f4832008-12-07 21:44:03 +05302373 if (sc->tx.txdma.dd_desc_len != 0)
2374 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002375
2376 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2377 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002378}
2379
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002380void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2381{
Sujithc5170162008-10-29 10:13:59 +05302382 struct ath_atx_tid *tid;
2383 struct ath_atx_ac *ac;
2384 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002385
Sujith8ee5afb2008-12-07 21:43:36 +05302386 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302387 tidno < WME_NUM_TID;
2388 tidno++, tid++) {
2389 tid->an = an;
2390 tid->tidno = tidno;
2391 tid->seq_start = tid->seq_next = 0;
2392 tid->baw_size = WME_MAX_BA;
2393 tid->baw_head = tid->baw_tail = 0;
2394 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302395 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302396 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302397 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302398 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302399 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302400 tid->state &= ~AGGR_ADDBA_COMPLETE;
2401 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302402 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002403
Sujith8ee5afb2008-12-07 21:43:36 +05302404 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302405 acno < WME_NUM_AC; acno++, ac++) {
2406 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002407 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302408 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002409 }
2410}
2411
Sujithb5aa9bf2008-10-29 10:13:31 +05302412void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002413{
Felix Fietkau2b409942010-07-07 19:42:08 +02002414 struct ath_atx_ac *ac;
2415 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002416 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002417 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302418
Felix Fietkau2b409942010-07-07 19:42:08 +02002419 for (tidno = 0, tid = &an->tid[tidno];
2420 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002421
Felix Fietkau2b409942010-07-07 19:42:08 +02002422 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002423 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002424
Felix Fietkau2b409942010-07-07 19:42:08 +02002425 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002426
Felix Fietkau2b409942010-07-07 19:42:08 +02002427 if (tid->sched) {
2428 list_del(&tid->list);
2429 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002430 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002431
2432 if (ac->sched) {
2433 list_del(&ac->list);
2434 tid->ac->sched = false;
2435 }
2436
2437 ath_tid_drain(sc, txq, tid);
2438 tid->state &= ~AGGR_ADDBA_COMPLETE;
2439 tid->state &= ~AGGR_CLEANUP;
2440
2441 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002442 }
2443}