blob: ec012b4317afb1ccdf5ea4b7014ac7448094f38d [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2008-2011 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Sujith394cf0a2009-02-09 13:26:54 +053017#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040018#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070019
20#define BITS_PER_BYTE 8
21#define OFDM_PLCP_BITS 22
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070022#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
23#define L_STF 8
24#define L_LTF 8
25#define L_SIG 4
26#define HT_SIG 8
27#define HT_STF 4
28#define HT_LTF(_ns) (4 * (_ns))
29#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
30#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
31#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
32#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
33
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070034
Felix Fietkauc6663872010-04-19 19:57:33 +020035static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070036 /* 20MHz 40MHz */
37 { 26, 54 }, /* 0: BPSK */
38 { 52, 108 }, /* 1: QPSK 1/2 */
39 { 78, 162 }, /* 2: QPSK 3/4 */
40 { 104, 216 }, /* 3: 16-QAM 1/2 */
41 { 156, 324 }, /* 4: 16-QAM 3/4 */
42 { 208, 432 }, /* 5: 64-QAM 2/3 */
43 { 234, 486 }, /* 6: 64-QAM 3/4 */
44 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070045};
46
47#define IS_HT_RATE(_rate) ((_rate) & 0x80)
48
Felix Fietkau82b873a2010-11-11 03:18:37 +010049static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
50 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +010051 struct list_head *bf_head);
Sujithe8324352009-01-16 21:38:42 +053052static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070053 struct ath_txq *txq, struct list_head *bf_q,
54 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053055static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +020056 struct list_head *head, bool internal);
Felix Fietkau269c44b2010-11-14 15:20:06 +010057static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +010058static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
59 struct ath_tx_status *ts, int nframes, int nbad,
60 int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020061static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
62 int seqno);
Sujithe8324352009-01-16 21:38:42 +053063
Felix Fietkau545750d2009-11-23 22:21:01 +010064enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020065 MCS_HT20,
66 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010067 MCS_HT40,
68 MCS_HT40_SGI,
69};
70
Felix Fietkau0e668cd2010-04-19 19:57:32 +020071static int ath_max_4ms_framelen[4][32] = {
72 [MCS_HT20] = {
73 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
74 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
75 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
76 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
77 },
78 [MCS_HT20_SGI] = {
79 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
80 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
81 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
82 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010083 },
84 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020085 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
86 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
87 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
88 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010089 },
90 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020091 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
92 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
93 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
94 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010095 }
96};
97
Sujithe8324352009-01-16 21:38:42 +053098/*********************/
99/* Aggregation logic */
100/*********************/
101
Sujithe8324352009-01-16 21:38:42 +0530102static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
103{
104 struct ath_atx_ac *ac = tid->ac;
105
106 if (tid->paused)
107 return;
108
109 if (tid->sched)
110 return;
111
112 tid->sched = true;
113 list_add_tail(&tid->list, &ac->tid_q);
114
115 if (ac->sched)
116 return;
117
118 ac->sched = true;
119 list_add_tail(&ac->list, &txq->axq_acq);
120}
121
Sujithe8324352009-01-16 21:38:42 +0530122static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
123{
Felix Fietkau066dae92010-11-07 14:59:39 +0100124 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530125
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200126 WARN_ON(!tid->paused);
127
Sujithe8324352009-01-16 21:38:42 +0530128 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200129 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530130
131 if (list_empty(&tid->buf_q))
132 goto unlock;
133
134 ath_tx_queue_tid(txq, tid);
135 ath_txq_schedule(sc, txq);
136unlock:
137 spin_unlock_bh(&txq->axq_lock);
138}
139
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100140static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
Felix Fietkau76e45222010-11-14 15:20:08 +0100141{
142 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100143 BUILD_BUG_ON(sizeof(struct ath_frame_info) >
144 sizeof(tx_info->rate_driver_data));
145 return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
Felix Fietkau76e45222010-11-14 15:20:08 +0100146}
147
Sujithe8324352009-01-16 21:38:42 +0530148static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
149{
Felix Fietkau066dae92010-11-07 14:59:39 +0100150 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530151 struct ath_buf *bf;
152 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200153 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100154 struct ath_frame_info *fi;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200155
Sujithe8324352009-01-16 21:38:42 +0530156 INIT_LIST_HEAD(&bf_head);
157
Felix Fietkau90fa5392010-09-20 13:45:38 +0200158 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530159 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530160
161 while (!list_empty(&tid->buf_q)) {
162 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530163 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200164
Felix Fietkaue1566d12010-11-20 03:08:46 +0100165 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100166 fi = get_frame_info(bf->bf_mpdu);
167 if (fi->retries) {
168 ath_tx_update_baw(sc, tid, fi->seqno);
Felix Fietkau7d2c16b2011-03-12 01:11:28 +0100169 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200170 } else {
Felix Fietkaua9e99a02011-01-10 17:05:47 -0700171 ath_tx_send_normal(sc, txq, NULL, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200172 }
Felix Fietkaue1566d12010-11-20 03:08:46 +0100173 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530174 }
175
176 spin_unlock_bh(&txq->axq_lock);
177}
178
179static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
180 int seqno)
181{
182 int index, cindex;
183
184 index = ATH_BA_INDEX(tid->seq_start, seqno);
185 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
186
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200187 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530188
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200189 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530190 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
191 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
192 }
193}
194
195static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100196 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530197{
198 int index, cindex;
199
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100200 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530201 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200202 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530203
204 if (index >= ((tid->baw_tail - tid->baw_head) &
205 (ATH_TID_MAX_BUFS - 1))) {
206 tid->baw_tail = cindex;
207 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
208 }
209}
210
211/*
212 * TODO: For frame(s) that are in the retry state, we will reuse the
213 * sequence number(s) without setting the retry bit. The
214 * alternative is to give up on these and BAR the receiver's window
215 * forward.
216 */
217static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
218 struct ath_atx_tid *tid)
219
220{
221 struct ath_buf *bf;
222 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700223 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100224 struct ath_frame_info *fi;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700225
226 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530227 INIT_LIST_HEAD(&bf_head);
228
229 for (;;) {
230 if (list_empty(&tid->buf_q))
231 break;
Sujithe8324352009-01-16 21:38:42 +0530232
Sujithd43f30152009-01-16 21:38:53 +0530233 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
234 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530235
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100236 fi = get_frame_info(bf->bf_mpdu);
237 if (fi->retries)
238 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530239
240 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700241 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530242 spin_lock(&txq->axq_lock);
243 }
244
245 tid->seq_next = tid->seq_start;
246 tid->baw_tail = tid->baw_head;
247}
248
Sujithfec247c2009-07-27 12:08:16 +0530249static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100250 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +0530251{
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100252 struct ath_frame_info *fi = get_frame_info(skb);
Sujithe8324352009-01-16 21:38:42 +0530253 struct ieee80211_hdr *hdr;
254
Sujithfec247c2009-07-27 12:08:16 +0530255 TX_STAT_INC(txq->axq_qnum, a_retries);
Felix Fietkau8b7f8532010-11-28 19:37:48 +0100256 if (fi->retries++ > 0)
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100257 return;
Sujithe8324352009-01-16 21:38:42 +0530258
Sujithe8324352009-01-16 21:38:42 +0530259 hdr = (struct ieee80211_hdr *)skb->data;
260 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
261}
262
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200263static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
264{
265 struct ath_buf *bf = NULL;
266
267 spin_lock_bh(&sc->tx.txbuflock);
268
269 if (unlikely(list_empty(&sc->tx.txbuf))) {
270 spin_unlock_bh(&sc->tx.txbuflock);
271 return NULL;
272 }
273
274 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
275 list_del(&bf->list);
276
277 spin_unlock_bh(&sc->tx.txbuflock);
278
279 return bf;
280}
281
282static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
283{
284 spin_lock_bh(&sc->tx.txbuflock);
285 list_add_tail(&bf->list, &sc->tx.txbuf);
286 spin_unlock_bh(&sc->tx.txbuflock);
287}
288
Sujithd43f30152009-01-16 21:38:53 +0530289static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
290{
291 struct ath_buf *tbf;
292
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200293 tbf = ath_tx_get_buffer(sc);
294 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530295 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530296
297 ATH_TXBUF_RESET(tbf);
298
299 tbf->bf_mpdu = bf->bf_mpdu;
300 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400301 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530302 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530303
304 return tbf;
305}
306
Felix Fietkaub572d032010-11-14 15:20:07 +0100307static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
308 struct ath_tx_status *ts, int txok,
309 int *nframes, int *nbad)
310{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100311 struct ath_frame_info *fi;
Felix Fietkaub572d032010-11-14 15:20:07 +0100312 u16 seq_st = 0;
313 u32 ba[WME_BA_BMP_SIZE >> 5];
314 int ba_index;
315 int isaggr = 0;
316
317 *nbad = 0;
318 *nframes = 0;
319
Felix Fietkaub572d032010-11-14 15:20:07 +0100320 isaggr = bf_isaggr(bf);
321 if (isaggr) {
322 seq_st = ts->ts_seqnum;
323 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
324 }
325
326 while (bf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100327 fi = get_frame_info(bf->bf_mpdu);
328 ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
Felix Fietkaub572d032010-11-14 15:20:07 +0100329
330 (*nframes)++;
331 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
332 (*nbad)++;
333
334 bf = bf->bf_next;
335 }
336}
337
338
Sujithd43f30152009-01-16 21:38:53 +0530339static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
340 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100341 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530342{
343 struct ath_node *an = NULL;
344 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530345 struct ieee80211_sta *sta;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100346 struct ieee80211_hw *hw = sc->hw;
Sujith1286ec62009-01-27 13:30:37 +0530347 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800348 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530349 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530350 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530351 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530352 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530353 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530354 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
355 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200356 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100357 struct ath_frame_info *fi;
Björn Smedmanebd02282010-10-10 22:44:39 +0200358 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100359 u8 tidno;
Felix Fietkau55195412011-04-17 23:28:09 +0200360 bool clear_filter;
Sujithe8324352009-01-16 21:38:42 +0530361
Sujitha22be222009-03-30 15:28:36 +0530362 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530363 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530364
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800365 tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800366
Felix Fietkau78c46532010-06-25 01:26:16 +0200367 memcpy(rates, tx_info->control.rates, sizeof(rates));
368
Sujith1286ec62009-01-27 13:30:37 +0530369 rcu_read_lock();
370
Ben Greear686b9cb2010-09-23 09:44:36 -0700371 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530372 if (!sta) {
373 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200374
Felix Fietkau31e79a52010-07-12 23:16:34 +0200375 INIT_LIST_HEAD(&bf_head);
376 while (bf) {
377 bf_next = bf->bf_next;
378
379 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaufce041b2011-05-19 12:20:25 +0200380 if (!bf->bf_stale || bf_next != NULL)
Felix Fietkau31e79a52010-07-12 23:16:34 +0200381 list_move_tail(&bf->list, &bf_head);
382
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100383 ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200384 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
385 0, 0);
386
387 bf = bf_next;
388 }
Sujith1286ec62009-01-27 13:30:37 +0530389 return;
Sujithe8324352009-01-16 21:38:42 +0530390 }
391
Sujith1286ec62009-01-27 13:30:37 +0530392 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100393 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
394 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530395
Felix Fietkaub11b1602010-07-11 12:48:44 +0200396 /*
397 * The hardware occasionally sends a tx status for the wrong TID.
398 * In this case, the BA status cannot be considered valid and all
399 * subframes need to be retransmitted
400 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100401 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200402 txok = false;
403
Sujithe8324352009-01-16 21:38:42 +0530404 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530405 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530406
Sujithd43f30152009-01-16 21:38:53 +0530407 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700408 if (ts->ts_flags & ATH9K_TX_BA) {
409 seq_st = ts->ts_seqnum;
410 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530411 } else {
Sujithd43f30152009-01-16 21:38:53 +0530412 /*
413 * AR5416 can become deaf/mute when BA
414 * issue happens. Chip needs to be reset.
415 * But AP code may have sychronization issues
416 * when perform internal reset in this routine.
417 * Only enable reset in STA mode for now.
418 */
Sujith2660b812009-02-09 13:27:26 +0530419 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530420 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530421 }
422 }
423
424 INIT_LIST_HEAD(&bf_pending);
425 INIT_LIST_HEAD(&bf_head);
426
Felix Fietkaub572d032010-11-14 15:20:07 +0100427 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530428 while (bf) {
Felix Fietkauf0b82202011-01-15 14:30:15 +0100429 txfail = txpending = sendbar = 0;
Sujithe8324352009-01-16 21:38:42 +0530430 bf_next = bf->bf_next;
431
Felix Fietkau78c46532010-06-25 01:26:16 +0200432 skb = bf->bf_mpdu;
433 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100434 fi = get_frame_info(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200435
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100436 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530437 /* transmit completion, subframe is
438 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530439 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530440 } else if (!isaggr && txok) {
441 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530442 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530443 } else {
Felix Fietkau55195412011-04-17 23:28:09 +0200444 if ((tid->state & AGGR_CLEANUP) || !retry) {
Sujithe8324352009-01-16 21:38:42 +0530445 /*
446 * cleanup in progress, just fail
447 * the un-acked sub-frames
448 */
449 txfail = 1;
Felix Fietkau55195412011-04-17 23:28:09 +0200450 } else if (fi->retries < ATH_MAX_SW_RETRIES) {
451 if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
452 !an->sleeping)
453 ath_tx_set_retry(sc, txq, bf->bf_mpdu);
454
455 clear_filter = true;
456 txpending = 1;
457 } else {
458 bf->bf_state.bf_type |= BUF_XRETRY;
459 txfail = 1;
460 sendbar = 1;
461 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530462 }
463 }
464
Felix Fietkaufce041b2011-05-19 12:20:25 +0200465 /*
466 * Make sure the last desc is reclaimed if it
467 * not a holding desc.
468 */
469 if (!bf_last->bf_stale || bf_next != NULL)
Sujithd43f30152009-01-16 21:38:53 +0530470 list_move_tail(&bf->list, &bf_head);
Felix Fietkaufce041b2011-05-19 12:20:25 +0200471 else
472 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530473
Felix Fietkau90fa5392010-09-20 13:45:38 +0200474 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530475 /*
476 * complete the acked-ones/xretried ones; update
477 * block-ack window
478 */
479 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100480 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530481 spin_unlock_bh(&txq->axq_lock);
482
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530483 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200484 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100485 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530486 rc_update = false;
487 } else {
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100488 ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530489 }
490
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700491 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
492 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530493 } else {
Sujithd43f30152009-01-16 21:38:53 +0530494 /* retry the un-acked ones */
Felix Fietkau55195412011-04-17 23:28:09 +0200495 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400496 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
497 if (bf->bf_next == NULL && bf_last->bf_stale) {
498 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530499
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400500 tbf = ath_clone_txbuf(sc, bf_last);
501 /*
502 * Update tx baw and complete the
503 * frame with failed status if we
504 * run out of tx buf.
505 */
506 if (!tbf) {
507 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100508 ath_tx_update_baw(sc, tid, fi->seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400509 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400510
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400511 bf->bf_state.bf_type |=
512 BUF_XRETRY;
Felix Fietkau0cdd5c62011-01-24 19:23:17 +0100513 ath_tx_rc_status(sc, bf, ts, nframes,
Felix Fietkaub572d032010-11-14 15:20:07 +0100514 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400515 ath_tx_complete_buf(sc, bf, txq,
516 &bf_head,
517 ts, 0, 0);
518 break;
519 }
520
521 ath9k_hw_cleartxdesc(sc->sc_ah,
522 tbf->bf_desc);
523 list_add_tail(&tbf->list, &bf_head);
524 } else {
525 /*
526 * Clear descriptor status words for
527 * software retry
528 */
529 ath9k_hw_cleartxdesc(sc->sc_ah,
530 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400531 }
Sujithe8324352009-01-16 21:38:42 +0530532 }
533
534 /*
535 * Put this buffer to the temporary pending
536 * queue to retain ordering
537 */
538 list_splice_tail_init(&bf_head, &bf_pending);
539 }
540
541 bf = bf_next;
542 }
543
Felix Fietkau4cee7862010-07-23 03:53:16 +0200544 /* prepend un-acked frames to the beginning of the pending frame queue */
545 if (!list_empty(&bf_pending)) {
Felix Fietkau55195412011-04-17 23:28:09 +0200546 if (an->sleeping)
547 ieee80211_sta_set_tim(sta);
548
Felix Fietkau4cee7862010-07-23 03:53:16 +0200549 spin_lock_bh(&txq->axq_lock);
Felix Fietkau55195412011-04-17 23:28:09 +0200550 if (clear_filter)
551 tid->ac->clear_ps_filter = true;
Felix Fietkau4cee7862010-07-23 03:53:16 +0200552 list_splice(&bf_pending, &tid->buf_q);
553 ath_tx_queue_tid(txq, tid);
554 spin_unlock_bh(&txq->axq_lock);
555 }
556
Sujithe8324352009-01-16 21:38:42 +0530557 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200558 ath_tx_flush_tid(sc, tid);
559
Sujithe8324352009-01-16 21:38:42 +0530560 if (tid->baw_head == tid->baw_tail) {
561 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530562 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530563 }
Sujithe8324352009-01-16 21:38:42 +0530564 }
565
Sujith1286ec62009-01-27 13:30:37 +0530566 rcu_read_unlock();
567
Vivek Natarajanbdd62c02011-01-27 14:45:10 +0530568 if (needreset) {
569 spin_unlock_bh(&sc->sc_pcu_lock);
Sujithe8324352009-01-16 21:38:42 +0530570 ath_reset(sc, false);
Vivek Natarajanbdd62c02011-01-27 14:45:10 +0530571 spin_lock_bh(&sc->sc_pcu_lock);
572 }
Sujithe8324352009-01-16 21:38:42 +0530573}
574
575static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
576 struct ath_atx_tid *tid)
577{
Sujithe8324352009-01-16 21:38:42 +0530578 struct sk_buff *skb;
579 struct ieee80211_tx_info *tx_info;
580 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530581 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530582 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530583 int i;
584
Sujitha22be222009-03-30 15:28:36 +0530585 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530586 tx_info = IEEE80211_SKB_CB(skb);
587 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530588
589 /*
590 * Find the lowest frame length among the rate series that will have a
591 * 4ms transmit duration.
592 * TODO - TXOP limit needs to be considered.
593 */
594 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
595
596 for (i = 0; i < 4; i++) {
597 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100598 int modeidx;
599 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530600 legacy = 1;
601 break;
602 }
603
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200604 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100605 modeidx = MCS_HT40;
606 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200607 modeidx = MCS_HT20;
608
609 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
610 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100611
612 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530613 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530614 }
615 }
616
617 /*
618 * limit aggregate size by the minimum rate if rate selected is
619 * not a probe rate, if rate selected is a probe rate then
620 * avoid aggregation of this packet.
621 */
622 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
623 return 0;
624
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530625 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
626 aggr_limit = min((max_4ms_framelen * 3) / 8,
627 (u32)ATH_AMPDU_LIMIT_MAX);
628 else
629 aggr_limit = min(max_4ms_framelen,
630 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530631
632 /*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300633 * h/w can accept aggregates up to 16 bit lengths (65535).
634 * The IE, however can hold up to 65536, which shows up here
Sujithe8324352009-01-16 21:38:42 +0530635 * as zero. Ignore 65536 since we are constrained by hw.
636 */
Sujith4ef70842009-07-23 15:32:41 +0530637 if (tid->an->maxampdu)
638 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530639
640 return aggr_limit;
641}
642
643/*
Sujithd43f30152009-01-16 21:38:53 +0530644 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530645 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530646 */
647static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
648 struct ath_buf *bf, u16 frmlen)
649{
Sujithe8324352009-01-16 21:38:42 +0530650 struct sk_buff *skb = bf->bf_mpdu;
651 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530652 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530653 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100654 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200655 int width, streams, half_gi, ndelim, mindelim;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100656 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530657
658 /* Select standard number of delimiters based on frame length alone */
659 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
660
661 /*
662 * If encryption enabled, hardware requires some more padding between
663 * subframes.
664 * TODO - this could be improved to be dependent on the rate.
665 * The hardware can keep up at lower rates, but not higher rates
666 */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100667 if (fi->keyix != ATH9K_TXKEYIX_INVALID)
Sujithe8324352009-01-16 21:38:42 +0530668 ndelim += ATH_AGGR_ENCRYPTDELIM;
669
670 /*
671 * Convert desired mpdu density from microeconds to bytes based
672 * on highest rate in rate series (i.e. first rate) to determine
673 * required minimum length for subframe. Take into account
674 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530675 *
Sujithe8324352009-01-16 21:38:42 +0530676 * If there is no mpdu density restriction, no further calculation
677 * is needed.
678 */
Sujith4ef70842009-07-23 15:32:41 +0530679
680 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530681 return ndelim;
682
683 rix = tx_info->control.rates[0].idx;
684 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530685 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
686 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
687
688 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530689 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530690 else
Sujith4ef70842009-07-23 15:32:41 +0530691 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530692
693 if (nsymbols == 0)
694 nsymbols = 1;
695
Felix Fietkauc6663872010-04-19 19:57:33 +0200696 streams = HT_RC_2_STREAMS(rix);
697 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530698 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
699
Sujithe8324352009-01-16 21:38:42 +0530700 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530701 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
702 ndelim = max(mindelim, ndelim);
703 }
704
705 return ndelim;
706}
707
708static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530709 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530710 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100711 struct list_head *bf_q,
712 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530713{
714#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530715 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
716 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530717 u16 aggr_limit = 0, al = 0, bpad = 0,
718 al_delta, h_baw = tid->baw_size / 2;
719 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200720 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100721 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530722
723 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
724
725 do {
726 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100727 fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530728
Sujithd43f30152009-01-16 21:38:53 +0530729 /* do not step over block-ack window */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100730 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530731 status = ATH_AGGR_BAW_CLOSED;
732 break;
733 }
734
735 if (!rl) {
736 aggr_limit = ath_lookup_rate(sc, bf, tid);
737 rl = 1;
738 }
739
Sujithd43f30152009-01-16 21:38:53 +0530740 /* do not exceed aggregation limit */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100741 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
Sujithe8324352009-01-16 21:38:42 +0530742
Sujithd43f30152009-01-16 21:38:53 +0530743 if (nframes &&
744 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530745 status = ATH_AGGR_LIMITED;
746 break;
747 }
748
Felix Fietkau0299a502010-10-21 02:47:24 +0200749 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
750 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
751 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
752 break;
753
Sujithd43f30152009-01-16 21:38:53 +0530754 /* do not exceed subframe limit */
755 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530756 status = ATH_AGGR_LIMITED;
757 break;
758 }
Sujithd43f30152009-01-16 21:38:53 +0530759 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530760
Sujithd43f30152009-01-16 21:38:53 +0530761 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530762 al += bpad + al_delta;
763
764 /*
765 * Get the delimiters needed to meet the MPDU
766 * density for this node.
767 */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100768 ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +0530769 bpad = PADBYTES(al_delta) + (ndelim << 2);
770
771 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400772 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530773
Sujithd43f30152009-01-16 21:38:53 +0530774 /* link buffers of this frame to the aggregate */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100775 if (!fi->retries)
776 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithd43f30152009-01-16 21:38:53 +0530777 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
778 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530779 if (bf_prev) {
780 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400781 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
782 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530783 }
784 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530785
Sujithe8324352009-01-16 21:38:42 +0530786 } while (!list_empty(&tid->buf_q));
787
Felix Fietkau269c44b2010-11-14 15:20:06 +0100788 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530789
Sujithe8324352009-01-16 21:38:42 +0530790 return status;
791#undef PADBYTES
792}
793
794static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
795 struct ath_atx_tid *tid)
796{
Sujithd43f30152009-01-16 21:38:53 +0530797 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530798 enum ATH_AGGR_STATUS status;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100799 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530800 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100801 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530802
803 do {
804 if (list_empty(&tid->buf_q))
805 return;
806
807 INIT_LIST_HEAD(&bf_q);
808
Felix Fietkau269c44b2010-11-14 15:20:06 +0100809 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530810
811 /*
Sujithd43f30152009-01-16 21:38:53 +0530812 * no frames picked up to be aggregated;
813 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530814 */
815 if (list_empty(&bf_q))
816 break;
817
818 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530819 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530820
Felix Fietkau55195412011-04-17 23:28:09 +0200821 if (tid->ac->clear_ps_filter) {
822 tid->ac->clear_ps_filter = false;
823 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
824 }
825
Sujithd43f30152009-01-16 21:38:53 +0530826 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100827 if (bf == bf->bf_lastbf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100828 fi = get_frame_info(bf->bf_mpdu);
829
Sujithe8324352009-01-16 21:38:42 +0530830 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530831 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100832 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +0200833 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
Sujithe8324352009-01-16 21:38:42 +0530834 continue;
835 }
836
Sujithd43f30152009-01-16 21:38:53 +0530837 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530838 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100839 ath_buf_set_rate(sc, bf, aggr_len);
840 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530841
Sujithd43f30152009-01-16 21:38:53 +0530842 /* anchor last desc of aggregate */
843 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530844
Felix Fietkaufce041b2011-05-19 12:20:25 +0200845 ath_tx_txqaddbuf(sc, txq, &bf_q, false);
Sujithfec247c2009-07-27 12:08:16 +0530846 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530847
Felix Fietkau4b3ba662010-12-17 00:57:00 +0100848 } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
Sujithe8324352009-01-16 21:38:42 +0530849 status != ATH_AGGR_BAW_CLOSED);
850}
851
Felix Fietkau231c3a12010-09-20 19:35:28 +0200852int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
853 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530854{
855 struct ath_atx_tid *txtid;
856 struct ath_node *an;
857
858 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530859 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200860
861 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
862 return -EAGAIN;
863
Sujithf83da962009-07-23 15:32:37 +0530864 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200865 txtid->paused = true;
Felix Fietkau49447f22011-01-10 17:05:48 -0700866 *ssn = txtid->seq_start = txtid->seq_next;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200867
Felix Fietkau2ed72222011-01-10 17:05:49 -0700868 memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf));
869 txtid->baw_head = txtid->baw_tail = 0;
870
Felix Fietkau231c3a12010-09-20 19:35:28 +0200871 return 0;
Sujithe8324352009-01-16 21:38:42 +0530872}
873
Sujithf83da962009-07-23 15:32:37 +0530874void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530875{
876 struct ath_node *an = (struct ath_node *)sta->drv_priv;
877 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100878 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530879
880 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530881 return;
Sujithe8324352009-01-16 21:38:42 +0530882
883 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530884 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530885 return;
Sujithe8324352009-01-16 21:38:42 +0530886 }
887
Sujithe8324352009-01-16 21:38:42 +0530888 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200889 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200890
891 /*
892 * If frames are still being transmitted for this TID, they will be
893 * cleaned up during tx completion. To prevent race conditions, this
894 * TID can only be reused after all in-progress subframes have been
895 * completed.
896 */
897 if (txtid->baw_head != txtid->baw_tail)
898 txtid->state |= AGGR_CLEANUP;
899 else
900 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530901 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530902
Felix Fietkau90fa5392010-09-20 13:45:38 +0200903 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530904}
905
Felix Fietkau55195412011-04-17 23:28:09 +0200906bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
907{
908 struct ath_atx_tid *tid;
909 struct ath_atx_ac *ac;
910 struct ath_txq *txq;
911 bool buffered = false;
912 int tidno;
913
914 for (tidno = 0, tid = &an->tid[tidno];
915 tidno < WME_NUM_TID; tidno++, tid++) {
916
917 if (!tid->sched)
918 continue;
919
920 ac = tid->ac;
921 txq = ac->txq;
922
923 spin_lock_bh(&txq->axq_lock);
924
925 if (!list_empty(&tid->buf_q))
926 buffered = true;
927
928 tid->sched = false;
929 list_del(&tid->list);
930
931 if (ac->sched) {
932 ac->sched = false;
933 list_del(&ac->list);
934 }
935
936 spin_unlock_bh(&txq->axq_lock);
937 }
938
939 return buffered;
940}
941
942void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
943{
944 struct ath_atx_tid *tid;
945 struct ath_atx_ac *ac;
946 struct ath_txq *txq;
947 int tidno;
948
949 for (tidno = 0, tid = &an->tid[tidno];
950 tidno < WME_NUM_TID; tidno++, tid++) {
951
952 ac = tid->ac;
953 txq = ac->txq;
954
955 spin_lock_bh(&txq->axq_lock);
956 ac->clear_ps_filter = true;
957
958 if (!list_empty(&tid->buf_q) && !tid->paused) {
959 ath_tx_queue_tid(txq, tid);
960 ath_txq_schedule(sc, txq);
961 }
962
963 spin_unlock_bh(&txq->axq_lock);
964 }
965}
966
Sujithe8324352009-01-16 21:38:42 +0530967void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
968{
969 struct ath_atx_tid *txtid;
970 struct ath_node *an;
971
972 an = (struct ath_node *)sta->drv_priv;
973
974 if (sc->sc_flags & SC_OP_TXAGGR) {
975 txtid = ATH_AN_2_TID(an, tid);
976 txtid->baw_size =
977 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
978 txtid->state |= AGGR_ADDBA_COMPLETE;
979 txtid->state &= ~AGGR_ADDBA_PROGRESS;
980 ath_tx_resume_tid(sc, txtid);
981 }
982}
983
Sujithe8324352009-01-16 21:38:42 +0530984/********************/
985/* Queue Management */
986/********************/
987
Sujithe8324352009-01-16 21:38:42 +0530988static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
989 struct ath_txq *txq)
990{
991 struct ath_atx_ac *ac, *ac_tmp;
992 struct ath_atx_tid *tid, *tid_tmp;
993
994 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
995 list_del(&ac->list);
996 ac->sched = false;
997 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
998 list_del(&tid->list);
999 tid->sched = false;
1000 ath_tid_drain(sc, txq, tid);
1001 }
1002 }
1003}
1004
1005struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
1006{
Sujithcbe61d82009-02-09 13:27:12 +05301007 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001008 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +05301009 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001010 static const int subtype_txq_to_hwq[] = {
1011 [WME_AC_BE] = ATH_TXQ_AC_BE,
1012 [WME_AC_BK] = ATH_TXQ_AC_BK,
1013 [WME_AC_VI] = ATH_TXQ_AC_VI,
1014 [WME_AC_VO] = ATH_TXQ_AC_VO,
1015 };
Ben Greear60f2d1d2011-01-09 23:11:52 -08001016 int axq_qnum, i;
Sujithe8324352009-01-16 21:38:42 +05301017
1018 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +01001019 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +05301020 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
1021 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
1022 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
1023 qi.tqi_physCompBuf = 0;
1024
1025 /*
1026 * Enable interrupts only for EOL and DESC conditions.
1027 * We mark tx descriptors to receive a DESC interrupt
1028 * when a tx queue gets deep; otherwise waiting for the
1029 * EOL to reap descriptors. Note that this is done to
1030 * reduce interrupt load and this only defers reaping
1031 * descriptors, never transmitting frames. Aside from
1032 * reducing interrupts this also permits more concurrency.
1033 * The only potential downside is if the tx queue backs
1034 * up in which case the top half of the kernel may backup
1035 * due to a lack of tx descriptors.
1036 *
1037 * The UAPSD queue is an exception, since we take a desc-
1038 * based intr on the EOSP frames.
1039 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -04001040 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1041 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
1042 TXQ_FLAG_TXERRINT_ENABLE;
1043 } else {
1044 if (qtype == ATH9K_TX_QUEUE_UAPSD)
1045 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
1046 else
1047 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
1048 TXQ_FLAG_TXDESCINT_ENABLE;
1049 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001050 axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
1051 if (axq_qnum == -1) {
Sujithe8324352009-01-16 21:38:42 +05301052 /*
1053 * NB: don't print a message, this happens
1054 * normally on parts with too few tx queues
1055 */
1056 return NULL;
1057 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001058 if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
Joe Perches38002762010-12-02 19:12:36 -08001059 ath_err(common, "qnum %u out of range, max %zu!\n",
Ben Greear60f2d1d2011-01-09 23:11:52 -08001060 axq_qnum, ARRAY_SIZE(sc->tx.txq));
1061 ath9k_hw_releasetxqueue(ah, axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301062 return NULL;
1063 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001064 if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
1065 struct ath_txq *txq = &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301066
Ben Greear60f2d1d2011-01-09 23:11:52 -08001067 txq->axq_qnum = axq_qnum;
1068 txq->mac80211_qnum = -1;
Sujithe8324352009-01-16 21:38:42 +05301069 txq->axq_link = NULL;
1070 INIT_LIST_HEAD(&txq->axq_q);
1071 INIT_LIST_HEAD(&txq->axq_acq);
1072 spin_lock_init(&txq->axq_lock);
1073 txq->axq_depth = 0;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001074 txq->axq_ampdu_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001075 txq->axq_tx_inprogress = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08001076 sc->tx.txqsetup |= 1<<axq_qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001077
1078 txq->txq_headidx = txq->txq_tailidx = 0;
1079 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1080 INIT_LIST_HEAD(&txq->txq_fifo[i]);
Sujithe8324352009-01-16 21:38:42 +05301081 }
Ben Greear60f2d1d2011-01-09 23:11:52 -08001082 return &sc->tx.txq[axq_qnum];
Sujithe8324352009-01-16 21:38:42 +05301083}
1084
Sujithe8324352009-01-16 21:38:42 +05301085int ath_txq_update(struct ath_softc *sc, int qnum,
1086 struct ath9k_tx_queue_info *qinfo)
1087{
Sujithcbe61d82009-02-09 13:27:12 +05301088 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301089 int error = 0;
1090 struct ath9k_tx_queue_info qi;
1091
1092 if (qnum == sc->beacon.beaconq) {
1093 /*
1094 * XXX: for beacon queue, we just save the parameter.
1095 * It will be picked up by ath_beaconq_config when
1096 * it's necessary.
1097 */
1098 sc->beacon.beacon_qi = *qinfo;
1099 return 0;
1100 }
1101
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001102 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301103
1104 ath9k_hw_get_txq_props(ah, qnum, &qi);
1105 qi.tqi_aifs = qinfo->tqi_aifs;
1106 qi.tqi_cwmin = qinfo->tqi_cwmin;
1107 qi.tqi_cwmax = qinfo->tqi_cwmax;
1108 qi.tqi_burstTime = qinfo->tqi_burstTime;
1109 qi.tqi_readyTime = qinfo->tqi_readyTime;
1110
1111 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Joe Perches38002762010-12-02 19:12:36 -08001112 ath_err(ath9k_hw_common(sc->sc_ah),
1113 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301114 error = -EIO;
1115 } else {
1116 ath9k_hw_resettxqueue(ah, qnum);
1117 }
1118
1119 return error;
1120}
1121
1122int ath_cabq_update(struct ath_softc *sc)
1123{
1124 struct ath9k_tx_queue_info qi;
Steve Brown9814f6b2011-02-07 17:10:39 -07001125 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
Sujithe8324352009-01-16 21:38:42 +05301126 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301127
1128 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1129 /*
1130 * Ensure the readytime % is within the bounds.
1131 */
Sujith17d79042009-02-09 13:27:03 +05301132 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1133 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1134 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1135 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301136
Steve Brown9814f6b2011-02-07 17:10:39 -07001137 qi.tqi_readyTime = (cur_conf->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301138 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301139 ath_txq_update(sc, qnum, &qi);
1140
1141 return 0;
1142}
1143
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001144static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
1145{
1146 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
1147 return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
1148}
1149
Felix Fietkaufce041b2011-05-19 12:20:25 +02001150static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
1151 struct list_head *list, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301152{
1153 struct ath_buf *bf, *lastbf;
1154 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001155 struct ath_tx_status ts;
1156
1157 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301158 INIT_LIST_HEAD(&bf_head);
1159
Felix Fietkaufce041b2011-05-19 12:20:25 +02001160 while (!list_empty(list)) {
1161 bf = list_first_entry(list, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +05301162
Felix Fietkaufce041b2011-05-19 12:20:25 +02001163 if (bf->bf_stale) {
1164 list_del(&bf->list);
Sujithe8324352009-01-16 21:38:42 +05301165
Felix Fietkaufce041b2011-05-19 12:20:25 +02001166 ath_tx_return_buffer(sc, bf);
1167 continue;
Sujithe8324352009-01-16 21:38:42 +05301168 }
1169
1170 lastbf = bf->bf_lastbf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02001171 list_cut_position(&bf_head, list, &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001172
Sujithe8324352009-01-16 21:38:42 +05301173 txq->axq_depth--;
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001174 if (bf_is_ampdu_not_probing(bf))
1175 txq->axq_ampdu_depth--;
Sujithe8324352009-01-16 21:38:42 +05301176
Felix Fietkaufce041b2011-05-19 12:20:25 +02001177 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301178 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001179 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1180 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301181 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001182 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001183 spin_lock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001184 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001185}
1186
1187/*
1188 * Drain a given TX queue (could be Beacon or Data)
1189 *
1190 * This assumes output has been stopped and
1191 * we do not need to block ath_tx_tasklet.
1192 */
1193void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
1194{
1195 spin_lock_bh(&txq->axq_lock);
1196 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1197 int idx = txq->txq_tailidx;
1198
1199 while (!list_empty(&txq->txq_fifo[idx])) {
1200 ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
1201 retry_tx);
1202
1203 INCR(idx, ATH_TXFIFO_DEPTH);
1204 }
1205 txq->txq_tailidx = idx;
1206 }
1207
1208 txq->axq_link = NULL;
1209 txq->axq_tx_inprogress = false;
1210 ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001211
1212 /* flush any pending frames if aggregation is enabled */
Felix Fietkaufce041b2011-05-19 12:20:25 +02001213 if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
1214 ath_txq_drain_pending_buffers(sc, txq);
1215
1216 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301217}
1218
Felix Fietkau080e1a22010-12-05 20:17:53 +01001219bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
Sujith043a0402009-01-16 21:38:47 +05301220{
Sujithcbe61d82009-02-09 13:27:12 +05301221 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001222 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301223 struct ath_txq *txq;
1224 int i, npend = 0;
1225
1226 if (sc->sc_flags & SC_OP_INVALID)
Felix Fietkau080e1a22010-12-05 20:17:53 +01001227 return true;
Sujith043a0402009-01-16 21:38:47 +05301228
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001229 ath9k_hw_abort_tx_dma(ah);
Sujith043a0402009-01-16 21:38:47 +05301230
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001231 /* Check if any queue remains active */
Sujith043a0402009-01-16 21:38:47 +05301232 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau0d51ccc2011-03-11 21:38:18 +01001233 if (!ATH_TXQ_SETUP(sc, i))
1234 continue;
1235
1236 npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
Sujith043a0402009-01-16 21:38:47 +05301237 }
1238
Felix Fietkau080e1a22010-12-05 20:17:53 +01001239 if (npend)
John W. Linville393934c2010-12-08 16:23:31 -05001240 ath_err(common, "Failed to stop TX DMA!\n");
Sujith043a0402009-01-16 21:38:47 +05301241
1242 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Felix Fietkau92460412011-01-24 19:23:14 +01001243 if (!ATH_TXQ_SETUP(sc, i))
1244 continue;
1245
1246 /*
1247 * The caller will resume queues with ieee80211_wake_queues.
1248 * Mark the queue as not stopped to prevent ath_tx_complete
1249 * from waking the queue too early.
1250 */
1251 txq = &sc->tx.txq[i];
1252 txq->stopped = false;
1253 ath_draintxq(sc, txq, retry_tx);
Sujith043a0402009-01-16 21:38:47 +05301254 }
Felix Fietkau080e1a22010-12-05 20:17:53 +01001255
1256 return !npend;
Sujith043a0402009-01-16 21:38:47 +05301257}
1258
Sujithe8324352009-01-16 21:38:42 +05301259void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1260{
1261 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1262 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1263}
1264
Ben Greear7755bad2011-01-18 17:30:00 -08001265/* For each axq_acq entry, for each tid, try to schedule packets
1266 * for transmit until ampdu_depth has reached min Q depth.
1267 */
Sujithe8324352009-01-16 21:38:42 +05301268void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1269{
Ben Greear7755bad2011-01-18 17:30:00 -08001270 struct ath_atx_ac *ac, *ac_tmp, *last_ac;
1271 struct ath_atx_tid *tid, *last_tid;
Sujithe8324352009-01-16 21:38:42 +05301272
Felix Fietkau21f28e62011-01-15 14:30:14 +01001273 if (list_empty(&txq->axq_acq) ||
1274 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
Sujithe8324352009-01-16 21:38:42 +05301275 return;
1276
1277 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
Ben Greear7755bad2011-01-18 17:30:00 -08001278 last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
Sujithe8324352009-01-16 21:38:42 +05301279
Ben Greear7755bad2011-01-18 17:30:00 -08001280 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
1281 last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
1282 list_del(&ac->list);
1283 ac->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301284
Ben Greear7755bad2011-01-18 17:30:00 -08001285 while (!list_empty(&ac->tid_q)) {
1286 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
1287 list);
1288 list_del(&tid->list);
1289 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05301290
Ben Greear7755bad2011-01-18 17:30:00 -08001291 if (tid->paused)
1292 continue;
Sujithe8324352009-01-16 21:38:42 +05301293
Ben Greear7755bad2011-01-18 17:30:00 -08001294 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301295
Ben Greear7755bad2011-01-18 17:30:00 -08001296 /*
1297 * add tid to round-robin queue if more frames
1298 * are pending for the tid
1299 */
1300 if (!list_empty(&tid->buf_q))
1301 ath_tx_queue_tid(txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301302
Ben Greear7755bad2011-01-18 17:30:00 -08001303 if (tid == last_tid ||
1304 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1305 break;
Sujithe8324352009-01-16 21:38:42 +05301306 }
Ben Greear7755bad2011-01-18 17:30:00 -08001307
1308 if (!list_empty(&ac->tid_q)) {
1309 if (!ac->sched) {
1310 ac->sched = true;
1311 list_add_tail(&ac->list, &txq->axq_acq);
1312 }
1313 }
1314
1315 if (ac == last_ac ||
1316 txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
1317 return;
Sujithe8324352009-01-16 21:38:42 +05301318 }
1319}
1320
Sujithe8324352009-01-16 21:38:42 +05301321/***********/
1322/* TX, DMA */
1323/***********/
1324
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001325/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001326 * Insert a chain of ath_buf (descriptors) on a txq and
1327 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001328 */
Sujith102e0572008-10-29 10:15:16 +05301329static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkaufce041b2011-05-19 12:20:25 +02001330 struct list_head *head, bool internal)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001331{
Sujithcbe61d82009-02-09 13:27:12 +05301332 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001333 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001334 struct ath_buf *bf, *bf_last;
1335 bool puttxbuf = false;
1336 bool edma;
Sujith102e0572008-10-29 10:15:16 +05301337
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001338 /*
1339 * Insert the frame on the outbound list and
1340 * pass it on to the hardware.
1341 */
1342
1343 if (list_empty(head))
1344 return;
1345
Felix Fietkaufce041b2011-05-19 12:20:25 +02001346 edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001347 bf = list_first_entry(head, struct ath_buf, list);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001348 bf_last = list_entry(head->prev, struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001349
Joe Perches226afe62010-12-02 19:12:37 -08001350 ath_dbg(common, ATH_DBG_QUEUE,
1351 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001352
Felix Fietkaufce041b2011-05-19 12:20:25 +02001353 if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
1354 list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001355 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001356 puttxbuf = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001357 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001358 list_splice_tail_init(head, &txq->axq_q);
1359
Felix Fietkaufce041b2011-05-19 12:20:25 +02001360 if (txq->axq_link) {
1361 ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
Joe Perches226afe62010-12-02 19:12:37 -08001362 ath_dbg(common, ATH_DBG_XMIT,
1363 "link[%u] (%p)=%llx (%p)\n",
1364 txq->axq_qnum, txq->axq_link,
1365 ito64(bf->bf_daddr), bf->bf_desc);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001366 } else if (!edma)
1367 puttxbuf = true;
1368
1369 txq->axq_link = bf_last->bf_desc;
1370 }
1371
1372 if (puttxbuf) {
1373 TX_STAT_INC(txq->axq_qnum, puttxbuf);
1374 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1375 ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
1376 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
1377 }
1378
1379 if (!edma) {
Felix Fietkau8d8d3fd2011-01-24 19:11:54 +01001380 TX_STAT_INC(txq->axq_qnum, txstart);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001381 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001382 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02001383
1384 if (!internal) {
1385 txq->axq_depth++;
1386 if (bf_is_ampdu_not_probing(bf))
1387 txq->axq_ampdu_depth++;
1388 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001389}
1390
Sujithe8324352009-01-16 21:38:42 +05301391static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau04caf862010-11-14 15:20:12 +01001392 struct ath_buf *bf, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301393{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001394 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau04caf862010-11-14 15:20:12 +01001395 struct list_head bf_head;
Sujithe8324352009-01-16 21:38:42 +05301396
Sujithe8324352009-01-16 21:38:42 +05301397 bf->bf_state.bf_type |= BUF_AMPDU;
1398
1399 /*
1400 * Do not queue to h/w when any of the following conditions is true:
1401 * - there are pending frames in software queue
1402 * - the TID is currently paused for ADDBA/BAR request
1403 * - seqno is not within block-ack window
1404 * - h/w queue depth exceeds low water mark
1405 */
1406 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001407 !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
Felix Fietkau4b3ba662010-12-17 00:57:00 +01001408 txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001409 /*
Sujithe8324352009-01-16 21:38:42 +05301410 * Add this frame to software queue for scheduling later
1411 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001412 */
Ben Greearbda8add2011-01-09 23:11:48 -08001413 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
Felix Fietkau04caf862010-11-14 15:20:12 +01001414 list_add_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301415 ath_tx_queue_tid(txctl->txq, tid);
1416 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001417 }
1418
Felix Fietkau04caf862010-11-14 15:20:12 +01001419 INIT_LIST_HEAD(&bf_head);
1420 list_add(&bf->list, &bf_head);
1421
Sujithe8324352009-01-16 21:38:42 +05301422 /* Add sub-frame to BAW */
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001423 if (!fi->retries)
1424 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +05301425
1426 /* Queue to h/w without aggregation */
Ben Greearbda8add2011-01-09 23:11:48 -08001427 TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
Sujithd43f30152009-01-16 21:38:53 +05301428 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001429 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001430 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
Sujithc4288392008-11-18 09:09:30 +05301431}
1432
Felix Fietkau82b873a2010-11-11 03:18:37 +01001433static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1434 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001435 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001436{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001437 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +05301438 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439
Sujithe8324352009-01-16 21:38:42 +05301440 bf = list_first_entry(bf_head, struct ath_buf, list);
1441 bf->bf_state.bf_type &= ~BUF_AMPDU;
1442
1443 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001444 if (tid)
1445 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301446
Sujithd43f30152009-01-16 21:38:53 +05301447 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001448 fi = get_frame_info(bf->bf_mpdu);
1449 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkaufce041b2011-05-19 12:20:25 +02001450 ath_tx_txqaddbuf(sc, txq, bf_head, false);
Sujithfec247c2009-07-27 12:08:16 +05301451 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001452}
1453
Sujith528f0c62008-10-29 10:14:26 +05301454static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001455{
Sujith528f0c62008-10-29 10:14:26 +05301456 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001457 enum ath9k_pkt_type htype;
1458 __le16 fc;
1459
Sujith528f0c62008-10-29 10:14:26 +05301460 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001461 fc = hdr->frame_control;
1462
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001463 if (ieee80211_is_beacon(fc))
1464 htype = ATH9K_PKT_TYPE_BEACON;
1465 else if (ieee80211_is_probe_resp(fc))
1466 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1467 else if (ieee80211_is_atim(fc))
1468 htype = ATH9K_PKT_TYPE_ATIM;
1469 else if (ieee80211_is_pspoll(fc))
1470 htype = ATH9K_PKT_TYPE_PSPOLL;
1471 else
1472 htype = ATH9K_PKT_TYPE_NORMAL;
1473
1474 return htype;
1475}
1476
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001477static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
1478 int framelen)
Sujith528f0c62008-10-29 10:14:26 +05301479{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001480 struct ath_softc *sc = hw->priv;
Sujith528f0c62008-10-29 10:14:26 +05301481 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001482 struct ieee80211_sta *sta = tx_info->control.sta;
1483 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
Sujith528f0c62008-10-29 10:14:26 +05301484 struct ieee80211_hdr *hdr;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001485 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001486 struct ath_node *an = NULL;
Sujith528f0c62008-10-29 10:14:26 +05301487 struct ath_atx_tid *tid;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001488 enum ath9k_key_type keytype;
1489 u16 seqno = 0;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001490 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301491
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001492 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujith528f0c62008-10-29 10:14:26 +05301493
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001494 if (sta)
1495 an = (struct ath_node *) sta->drv_priv;
1496
Sujith528f0c62008-10-29 10:14:26 +05301497 hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001498 if (an && ieee80211_is_data_qos(hdr->frame_control) &&
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001499 conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001500
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001501 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
1502
1503 /*
1504 * Override seqno set by upper layer with the one
1505 * in tx aggregation state.
1506 */
1507 tid = ATH_AN_2_TID(an, tidno);
1508 seqno = tid->seq_next;
1509 hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
1510 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
1511 }
1512
1513 memset(fi, 0, sizeof(*fi));
1514 if (hw_key)
1515 fi->keyix = hw_key->hw_key_idx;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001516 else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
1517 fi->keyix = an->ps_key;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001518 else
1519 fi->keyix = ATH9K_TXKEYIX_INVALID;
1520 fi->keytype = keytype;
1521 fi->framelen = framelen;
1522 fi->seqno = seqno;
Sujith528f0c62008-10-29 10:14:26 +05301523}
1524
Felix Fietkau82b873a2010-11-11 03:18:37 +01001525static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301526{
1527 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1528 int flags = 0;
1529
Sujith528f0c62008-10-29 10:14:26 +05301530 flags |= ATH9K_TXDESC_INTREQ;
1531
1532 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1533 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301534
Felix Fietkau82b873a2010-11-11 03:18:37 +01001535 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001536 flags |= ATH9K_TXDESC_LDPC;
1537
Sujith528f0c62008-10-29 10:14:26 +05301538 return flags;
1539}
1540
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001541/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001542 * rix - rate index
1543 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1544 * width - 0 for 20 MHz, 1 for 40 MHz
1545 * half_gi - to use 4us v/s 3.6 us for symbol time
1546 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001547static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301548 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001549{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001550 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001551 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301552
1553 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001554 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001555 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001556 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001557 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1558
1559 if (!half_gi)
1560 duration = SYMBOL_TIME(nsymbols);
1561 else
1562 duration = SYMBOL_TIME_HALFGI(nsymbols);
1563
Sujithe63835b2008-11-18 09:07:53 +05301564 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001565 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301566
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001567 return duration;
1568}
1569
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301570u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
1571{
1572 struct ath_hw *ah = sc->sc_ah;
1573 struct ath9k_channel *curchan = ah->curchan;
1574 if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
1575 (curchan->channelFlags & CHANNEL_5GHZ) &&
1576 (chainmask == 0x7) && (rate < 0x90))
1577 return 0x3;
1578 else
1579 return chainmask;
1580}
1581
Felix Fietkau269c44b2010-11-14 15:20:06 +01001582static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001583{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001584 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001585 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301586 struct sk_buff *skb;
1587 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301588 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001589 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301590 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301591 int i, flags = 0;
1592 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301593 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301594
1595 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301596
Sujitha22be222009-03-30 15:28:36 +05301597 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301598 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301599 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301600 hdr = (struct ieee80211_hdr *)skb->data;
1601 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301602
Sujithc89424d2009-01-30 14:29:28 +05301603 /*
1604 * We check if Short Preamble is needed for the CTS rate by
1605 * checking the BSS's global flag.
1606 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1607 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001608 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1609 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301610 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001611 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001612
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001613 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001614 bool is_40, is_sgi, is_sp;
1615 int phy;
1616
Sujithe63835b2008-11-18 09:07:53 +05301617 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001618 continue;
1619
Sujitha8efee42008-11-18 09:07:30 +05301620 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301621 series[i].Tries = rates[i].count;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001622
Mohammed Shafi Shajakhancbe8c732011-05-03 13:14:06 +05301623 if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
Sujithc89424d2009-01-30 14:29:28 +05301624 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001625 flags |= ATH9K_TXDESC_RTSENA;
1626 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1627 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1628 flags |= ATH9K_TXDESC_CTSENA;
1629 }
1630
Sujithc89424d2009-01-30 14:29:28 +05301631 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1632 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1633 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1634 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001635
Felix Fietkau545750d2009-11-23 22:21:01 +01001636 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1637 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1638 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1639
1640 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1641 /* MCS rates */
1642 series[i].Rate = rix | 0x80;
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301643 series[i].ChSel = ath_txchainmask_reduction(sc,
1644 common->tx_chainmask, series[i].Rate);
Felix Fietkau269c44b2010-11-14 15:20:06 +01001645 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001646 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001647 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1648 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001649 continue;
1650 }
1651
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301652 /* legacy rates */
Felix Fietkau545750d2009-11-23 22:21:01 +01001653 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1654 !(rate->flags & IEEE80211_RATE_ERP_G))
1655 phy = WLAN_RC_PHY_CCK;
1656 else
1657 phy = WLAN_RC_PHY_OFDM;
1658
1659 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1660 series[i].Rate = rate->hw_value;
1661 if (rate->hw_value_short) {
1662 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1663 series[i].Rate |= rate->hw_value_short;
1664 } else {
1665 is_sp = false;
1666 }
1667
Mohammed Shafi Shajakhanea066d52010-11-23 20:42:27 +05301668 if (bf->bf_state.bfs_paprd)
1669 series[i].ChSel = common->tx_chainmask;
1670 else
1671 series[i].ChSel = ath_txchainmask_reduction(sc,
1672 common->tx_chainmask, series[i].Rate);
1673
Felix Fietkau545750d2009-11-23 22:21:01 +01001674 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001675 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001676 }
1677
Felix Fietkau27032052010-01-17 21:08:50 +01001678 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001679 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001680 flags &= ~ATH9K_TXDESC_RTSENA;
1681
1682 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1683 if (flags & ATH9K_TXDESC_RTSENA)
1684 flags &= ~ATH9K_TXDESC_CTSENA;
1685
Sujithe63835b2008-11-18 09:07:53 +05301686 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301687 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1688 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301689 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301690 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301691
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001692}
1693
Felix Fietkau82b873a2010-11-11 03:18:37 +01001694static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
Felix Fietkau04caf862010-11-14 15:20:12 +01001695 struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001696 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301697{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001698 struct ath_softc *sc = hw->priv;
Felix Fietkau04caf862010-11-14 15:20:12 +01001699 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001700 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001701 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001702 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001703 struct ath_desc *ds;
Felix Fietkau04caf862010-11-14 15:20:12 +01001704 int frm_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001705
1706 bf = ath_tx_get_buffer(sc);
1707 if (!bf) {
Joe Perches226afe62010-12-02 19:12:37 -08001708 ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001709 return NULL;
1710 }
Sujithe8324352009-01-16 21:38:42 +05301711
Sujithe8324352009-01-16 21:38:42 +05301712 ATH_TXBUF_RESET(bf);
1713
Felix Fietkau82b873a2010-11-11 03:18:37 +01001714 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301715 bf->bf_mpdu = skb;
1716
Ben Greearc1739eb32010-10-14 12:45:29 -07001717 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1718 skb->len, DMA_TO_DEVICE);
1719 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301720 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001721 bf->bf_buf_addr = 0;
Joe Perches38002762010-12-02 19:12:36 -08001722 ath_err(ath9k_hw_common(sc->sc_ah),
1723 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001724 ath_tx_return_buffer(sc, bf);
1725 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301726 }
1727
Sujithe8324352009-01-16 21:38:42 +05301728 frm_type = get_hw_packet_type(skb);
Sujithe8324352009-01-16 21:38:42 +05301729
1730 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001731 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301732
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001733 ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
1734 fi->keyix, fi->keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301735
1736 ath9k_hw_filltxdesc(ah, ds,
1737 skb->len, /* segment length */
1738 true, /* first segment */
1739 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001740 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001741 bf->bf_buf_addr,
Felix Fietkau04caf862010-11-14 15:20:12 +01001742 txq->axq_qnum);
1743
1744
1745 return bf;
1746}
1747
1748/* FIXME: tx power */
1749static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1750 struct ath_tx_control *txctl)
1751{
1752 struct sk_buff *skb = bf->bf_mpdu;
1753 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1754 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau04caf862010-11-14 15:20:12 +01001755 struct list_head bf_head;
Felix Fietkau248a38d2010-12-10 21:16:46 +01001756 struct ath_atx_tid *tid = NULL;
Felix Fietkau04caf862010-11-14 15:20:12 +01001757 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301758
Sujithe8324352009-01-16 21:38:42 +05301759 spin_lock_bh(&txctl->txq->axq_lock);
Mohammed Shafi Shajakhan61e1b0b2011-03-21 18:27:21 +05301760 if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an &&
1761 ieee80211_is_data_qos(hdr->frame_control)) {
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001762 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1763 IEEE80211_QOS_CTL_TID_MASK;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001764 tid = ATH_AN_2_TID(txctl->an, tidno);
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001765
Felix Fietkau066dae92010-11-07 14:59:39 +01001766 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau248a38d2010-12-10 21:16:46 +01001767 }
1768
1769 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
Felix Fietkau04caf862010-11-14 15:20:12 +01001770 /*
1771 * Try aggregation if it's a unicast data frame
1772 * and the destination is HT capable.
1773 */
1774 ath_tx_send_ampdu(sc, tid, bf, txctl);
Sujithe8324352009-01-16 21:38:42 +05301775 } else {
Felix Fietkau04caf862010-11-14 15:20:12 +01001776 INIT_LIST_HEAD(&bf_head);
1777 list_add_tail(&bf->list, &bf_head);
1778
Felix Fietkau61117f02010-11-11 03:18:36 +01001779 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001780 bf->bf_state.bfs_paprd = txctl->paprd;
1781
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001782 if (bf->bf_state.bfs_paprd)
Felix Fietkau04caf862010-11-14 15:20:12 +01001783 ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
1784 bf->bf_state.bfs_paprd);
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001785
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301786 if (txctl->paprd)
1787 bf->bf_state.bfs_paprd_timestamp = jiffies;
1788
Felix Fietkau55195412011-04-17 23:28:09 +02001789 if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
1790 ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
1791
Felix Fietkau248a38d2010-12-10 21:16:46 +01001792 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301793 }
1794
1795 spin_unlock_bh(&txctl->txq->axq_lock);
1796}
1797
1798/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001799int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301800 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001801{
Felix Fietkau28d16702010-11-14 15:20:10 +01001802 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1803 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001804 struct ieee80211_sta *sta = info->control.sta;
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001805 struct ieee80211_vif *vif = info->control.vif;
Felix Fietkau9ac586152011-01-24 19:23:18 +01001806 struct ath_softc *sc = hw->priv;
Felix Fietkau84642d62010-06-01 21:33:13 +02001807 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001808 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001809 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001810 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001811 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001812
Ben Greeara9927ba2010-12-06 21:13:49 -08001813 /* NOTE: sta can be NULL according to net/mac80211.h */
1814 if (sta)
1815 txctl->an = (struct ath_node *)sta->drv_priv;
1816
Felix Fietkau04caf862010-11-14 15:20:12 +01001817 if (info->control.hw_key)
1818 frmlen += info->control.hw_key->icv_len;
1819
Felix Fietkau28d16702010-11-14 15:20:10 +01001820 /*
1821 * As a temporary workaround, assign seq# here; this will likely need
1822 * to be cleaned up to work better with Beacon transmission and virtual
1823 * BSSes.
1824 */
1825 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1826 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1827 sc->tx.seq_no += 0x10;
1828 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1829 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1830 }
1831
1832 /* Add the padding after the header if this is not already done */
1833 padpos = ath9k_cmn_padpos(hdr->frame_control);
1834 padsize = padpos & 3;
1835 if (padsize && skb->len > padpos) {
1836 if (skb_headroom(skb) < padsize)
1837 return -ENOMEM;
1838
1839 skb_push(skb, padsize);
1840 memmove(skb->data, skb->data + padsize, padpos);
1841 }
1842
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001843 if ((vif && vif->type != NL80211_IFTYPE_AP &&
1844 vif->type != NL80211_IFTYPE_AP_VLAN) ||
1845 !ieee80211_is_data(hdr->frame_control))
1846 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
1847
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001848 setup_frame_info(hw, skb, frmlen);
1849
1850 /*
1851 * At this point, the vif, hw_key and sta pointers in the tx control
1852 * info are no longer valid (overwritten by the ath_frame_info data.
1853 */
1854
1855 bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001856 if (unlikely(!bf))
1857 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001858
Felix Fietkau066dae92010-11-07 14:59:39 +01001859 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001860 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001861 if (txq == sc->tx.txq_map[q] &&
1862 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001863 ieee80211_stop_queue(sc->hw, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001864 txq->stopped = 1;
1865 }
1866 spin_unlock_bh(&txq->axq_lock);
1867
Sujithe8324352009-01-16 21:38:42 +05301868 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001869
1870 return 0;
1871}
1872
Sujithe8324352009-01-16 21:38:42 +05301873/*****************/
1874/* TX Completion */
1875/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001876
Sujithe8324352009-01-16 21:38:42 +05301877static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01001878 int tx_flags, int ftype, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001879{
Sujithe8324352009-01-16 21:38:42 +05301880 struct ieee80211_hw *hw = sc->hw;
1881 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001882 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001883 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001884 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301885
Joe Perches226afe62010-12-02 19:12:37 -08001886 ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301887
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301888 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301889 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301890
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301891 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301892 /* Frame was ACKed */
1893 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1894 }
1895
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001896 padpos = ath9k_cmn_padpos(hdr->frame_control);
1897 padsize = padpos & 3;
1898 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301899 /*
1900 * Remove MAC header padding before giving the frame back to
1901 * mac80211.
1902 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001903 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301904 skb_pull(skb, padsize);
1905 }
1906
Sujith1b04b932010-01-08 10:36:05 +05301907 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1908 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Joe Perches226afe62010-12-02 19:12:37 -08001909 ath_dbg(common, ATH_DBG_PS,
1910 "Going back to sleep after having received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301911 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1912 PS_WAIT_FOR_CAB |
1913 PS_WAIT_FOR_PSPOLL_DATA |
1914 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001915 }
1916
Felix Fietkau7545daf2011-01-24 19:23:16 +01001917 q = skb_get_queue_mapping(skb);
1918 if (txq == sc->tx.txq_map[q]) {
1919 spin_lock_bh(&txq->axq_lock);
1920 if (WARN_ON(--txq->pending_frames < 0))
1921 txq->pending_frames = 0;
Felix Fietkau92460412011-01-24 19:23:14 +01001922
Felix Fietkau7545daf2011-01-24 19:23:16 +01001923 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
1924 ieee80211_wake_queue(sc->hw, q);
1925 txq->stopped = 0;
Felix Fietkau066dae92010-11-07 14:59:39 +01001926 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001927 spin_unlock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04001928 }
Felix Fietkau7545daf2011-01-24 19:23:16 +01001929
1930 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301931}
1932
1933static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001934 struct ath_txq *txq, struct list_head *bf_q,
1935 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301936{
1937 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301938 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301939 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301940
Sujithe8324352009-01-16 21:38:42 +05301941 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301942 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301943
1944 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301945 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301946
1947 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301948 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301949 }
1950
Ben Greearc1739eb32010-10-14 12:45:29 -07001951 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001952 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001953
1954 if (bf->bf_state.bfs_paprd) {
Mohammed Shafi Shajakhan9cf04dc2011-02-04 18:38:23 +05301955 if (time_after(jiffies,
1956 bf->bf_state.bfs_paprd_timestamp +
1957 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001958 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001959 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001960 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001961 } else {
Felix Fietkau5bec3e52011-01-24 21:29:25 +01001962 ath_debug_stat_tx(sc, bf, ts, txq);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01001963 ath_tx_complete(sc, skb, tx_flags,
Felix Fietkau61117f02010-11-11 03:18:36 +01001964 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001965 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001966 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1967 * accidentally reference it later.
1968 */
1969 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301970
1971 /*
1972 * Return the list of ath_buf of this mpdu to free queue
1973 */
1974 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1975 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1976 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1977}
1978
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01001979static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
1980 struct ath_tx_status *ts, int nframes, int nbad,
1981 int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301982{
Sujitha22be222009-03-30 15:28:36 +05301983 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301984 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301985 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau0cdd5c62011-01-24 19:23:17 +01001986 struct ieee80211_hw *hw = sc->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001987 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301988 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301989
Sujith95e4acb2009-03-13 08:56:09 +05301990 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001991 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301992
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001993 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301994 WARN_ON(tx_rateindex >= hw->max_rates);
1995
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001996 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301997 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001998 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001999 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302000
Felix Fietkaub572d032010-11-14 15:20:07 +01002001 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02002002
Felix Fietkaub572d032010-11-14 15:20:07 +01002003 tx_info->status.ampdu_len = nframes;
2004 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02002005 }
2006
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002007 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302008 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002009 /*
2010 * If an underrun error is seen assume it as an excessive
2011 * retry only if max frame trigger level has been reached
2012 * (2 KB for single stream, and 4 KB for dual stream).
2013 * Adjust the long retry as if the frame was tried
2014 * hw->max_rate_tries times to affect how rate control updates
2015 * PER for the failed rate.
2016 * In case of congestion on the bus penalizing this type of
2017 * underruns should help hardware actually transmit new frames
2018 * successfully by eventually preferring slower rates.
2019 * This itself should also alleviate congestion on the bus.
2020 */
2021 if (ieee80211_is_data(hdr->frame_control) &&
2022 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
2023 ATH9K_TX_DELIM_UNDERRUN)) &&
Felix Fietkau83860c52011-03-23 20:57:33 +01002024 ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
Felix Fietkauf0c255a2010-11-11 03:18:35 +01002025 tx_info->status.rates[tx_rateindex].count =
2026 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05302027 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302028
Felix Fietkau545750d2009-11-23 22:21:01 +01002029 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302030 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002031 tx_info->status.rates[i].idx = -1;
2032 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302033
Felix Fietkau78c46532010-06-25 01:26:16 +02002034 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302035}
2036
Felix Fietkaufce041b2011-05-19 12:20:25 +02002037static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
2038 struct ath_tx_status *ts, struct ath_buf *bf,
2039 struct list_head *bf_head)
2040{
2041 int txok;
2042
2043 txq->axq_depth--;
2044 txok = !(ts->ts_status & ATH9K_TXERR_MASK);
2045 txq->axq_tx_inprogress = false;
2046 if (bf_is_ampdu_not_probing(bf))
2047 txq->axq_ampdu_depth--;
2048
2049 spin_unlock_bh(&txq->axq_lock);
2050
2051 if (!bf_isampdu(bf)) {
2052 /*
2053 * This frame is sent out as a single frame.
2054 * Use hardware retry status for this frame.
2055 */
2056 if (ts->ts_status & ATH9K_TXERR_XRETRY)
2057 bf->bf_state.bf_type |= BUF_XRETRY;
2058 ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
2059 ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
2060 } else
2061 ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
2062
2063 spin_lock_bh(&txq->axq_lock);
2064
2065 if (sc->sc_flags & SC_OP_TXAGGR)
2066 ath_txq_schedule(sc, txq);
2067}
2068
Sujithc4288392008-11-18 09:09:30 +05302069static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002070{
Sujithcbe61d82009-02-09 13:27:12 +05302071 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002072 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002073 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2074 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302075 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002076 struct ath_tx_status ts;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002077 int status;
2078
Joe Perches226afe62010-12-02 19:12:37 -08002079 ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2080 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2081 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002082
Felix Fietkaufce041b2011-05-19 12:20:25 +02002083 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084 for (;;) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 if (list_empty(&txq->axq_q)) {
2086 txq->axq_link = NULL;
Felix Fietkau86271e42011-03-11 21:38:19 +01002087 if (sc->sc_flags & SC_OP_TXAGGR)
Ben Greear082f6532011-01-09 23:11:47 -08002088 ath_txq_schedule(sc, txq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002089 break;
2090 }
2091 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2092
2093 /*
2094 * There is a race condition that a BH gets scheduled
2095 * after sw writes TxE and before hw re-load the last
2096 * descriptor to get the newly chained one.
2097 * Software must keep the last DONE descriptor as a
2098 * holding descriptor - software does so by marking
2099 * it with the STALE flag.
2100 */
2101 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302102 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002103 bf_held = bf;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002104 if (list_is_last(&bf_held->list, &txq->axq_q))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002105 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002106
2107 bf = list_entry(bf_held->list.next, struct ath_buf,
2108 list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109 }
2110
2111 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302112 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002113
Felix Fietkau29bffa92010-03-29 20:14:23 -07002114 memset(&ts, 0, sizeof(ts));
2115 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002116 if (status == -EINPROGRESS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117 break;
Felix Fietkaufce041b2011-05-19 12:20:25 +02002118
Ben Greear2dac4fb2011-01-09 23:11:45 -08002119 TX_STAT_INC(txq->axq_qnum, txprocdesc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002120
2121 /*
2122 * Remove ath_buf's of the same transmit unit from txq,
2123 * however leave the last descriptor back as the holding
2124 * descriptor for hw.
2125 */
Sujitha119cc42009-03-30 15:28:38 +05302126 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002127 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002128 if (!list_is_singular(&lastbf->list))
2129 list_cut_position(&bf_head,
2130 &txq->axq_q, lastbf->list.prev);
2131
Felix Fietkaufce041b2011-05-19 12:20:25 +02002132 if (bf_held) {
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002133 list_del(&bf_held->list);
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002134 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002135 }
Johannes Berge6a98542008-10-21 12:40:02 +02002136
Felix Fietkaufce041b2011-05-19 12:20:25 +02002137 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002138 }
Felix Fietkaufce041b2011-05-19 12:20:25 +02002139 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140}
2141
Sujith305fe472009-07-23 15:32:29 +05302142static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002143{
2144 struct ath_softc *sc = container_of(work, struct ath_softc,
2145 tx_complete_work.work);
2146 struct ath_txq *txq;
2147 int i;
2148 bool needreset = false;
Ben Greear60f2d1d2011-01-09 23:11:52 -08002149#ifdef CONFIG_ATH9K_DEBUGFS
2150 sc->tx_complete_poll_work_seen++;
2151#endif
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002152
2153 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2154 if (ATH_TXQ_SETUP(sc, i)) {
2155 txq = &sc->tx.txq[i];
2156 spin_lock_bh(&txq->axq_lock);
2157 if (txq->axq_depth) {
2158 if (txq->axq_tx_inprogress) {
2159 needreset = true;
2160 spin_unlock_bh(&txq->axq_lock);
2161 break;
2162 } else {
2163 txq->axq_tx_inprogress = true;
2164 }
2165 }
2166 spin_unlock_bh(&txq->axq_lock);
2167 }
2168
2169 if (needreset) {
Joe Perches226afe62010-12-02 19:12:37 -08002170 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2171 "tx hung, resetting the chip\n");
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002172 ath_reset(sc, true);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002173 }
2174
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002175 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002176 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2177}
2178
2179
Sujithe8324352009-01-16 21:38:42 +05302180
2181void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002182{
Sujithe8324352009-01-16 21:38:42 +05302183 int i;
2184 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002185
Sujithe8324352009-01-16 21:38:42 +05302186 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002187
2188 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302189 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2190 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002191 }
2192}
2193
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002194void ath_tx_edma_tasklet(struct ath_softc *sc)
2195{
Felix Fietkaufce041b2011-05-19 12:20:25 +02002196 struct ath_tx_status ts;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002197 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2198 struct ath_hw *ah = sc->sc_ah;
2199 struct ath_txq *txq;
2200 struct ath_buf *bf, *lastbf;
2201 struct list_head bf_head;
2202 int status;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002203
2204 for (;;) {
Felix Fietkaufce041b2011-05-19 12:20:25 +02002205 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002206 if (status == -EINPROGRESS)
2207 break;
2208 if (status == -EIO) {
Joe Perches226afe62010-12-02 19:12:37 -08002209 ath_dbg(common, ATH_DBG_XMIT,
2210 "Error processing tx status\n");
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002211 break;
2212 }
2213
2214 /* Skip beacon completions */
Felix Fietkaufce041b2011-05-19 12:20:25 +02002215 if (ts.qid == sc->beacon.beaconq)
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002216 continue;
2217
Felix Fietkaufce041b2011-05-19 12:20:25 +02002218 txq = &sc->tx.txq[ts.qid];
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002219
2220 spin_lock_bh(&txq->axq_lock);
Felix Fietkaufce041b2011-05-19 12:20:25 +02002221
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002222 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2223 spin_unlock_bh(&txq->axq_lock);
2224 return;
2225 }
2226
2227 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2228 struct ath_buf, list);
2229 lastbf = bf->bf_lastbf;
2230
2231 INIT_LIST_HEAD(&bf_head);
2232 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2233 &lastbf->list);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002234
Felix Fietkaufce041b2011-05-19 12:20:25 +02002235 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2236 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002237
Felix Fietkaufce041b2011-05-19 12:20:25 +02002238 if (!list_empty(&txq->axq_q)) {
2239 struct list_head bf_q;
2240
2241 INIT_LIST_HEAD(&bf_q);
2242 txq->axq_link = NULL;
2243 list_splice_tail_init(&txq->axq_q, &bf_q);
2244 ath_tx_txqaddbuf(sc, txq, &bf_q, true);
2245 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002246 }
2247
Felix Fietkaufce041b2011-05-19 12:20:25 +02002248 ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002249 spin_unlock_bh(&txq->axq_lock);
2250 }
2251}
2252
Sujithe8324352009-01-16 21:38:42 +05302253/*****************/
2254/* Init, Cleanup */
2255/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002256
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002257static int ath_txstatus_setup(struct ath_softc *sc, int size)
2258{
2259 struct ath_descdma *dd = &sc->txsdma;
2260 u8 txs_len = sc->sc_ah->caps.txs_len;
2261
2262 dd->dd_desc_len = size * txs_len;
2263 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2264 &dd->dd_desc_paddr, GFP_KERNEL);
2265 if (!dd->dd_desc)
2266 return -ENOMEM;
2267
2268 return 0;
2269}
2270
2271static int ath_tx_edma_init(struct ath_softc *sc)
2272{
2273 int err;
2274
2275 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2276 if (!err)
2277 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2278 sc->txsdma.dd_desc_paddr,
2279 ATH_TXSTATUS_RING_SIZE);
2280
2281 return err;
2282}
2283
2284static void ath_tx_edma_cleanup(struct ath_softc *sc)
2285{
2286 struct ath_descdma *dd = &sc->txsdma;
2287
2288 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2289 dd->dd_desc_paddr);
2290}
2291
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002292int ath_tx_init(struct ath_softc *sc, int nbufs)
2293{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002294 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002295 int error = 0;
2296
Sujith797fe5cb2009-03-30 15:28:45 +05302297 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002298
Sujith797fe5cb2009-03-30 15:28:45 +05302299 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002300 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302301 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002302 ath_err(common,
2303 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302304 goto err;
2305 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002306
Sujith797fe5cb2009-03-30 15:28:45 +05302307 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002308 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302309 if (error != 0) {
Joe Perches38002762010-12-02 19:12:36 -08002310 ath_err(common,
2311 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302312 goto err;
2313 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002314
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002315 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2316
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002317 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2318 error = ath_tx_edma_init(sc);
2319 if (error)
2320 goto err;
2321 }
2322
Sujith797fe5cb2009-03-30 15:28:45 +05302323err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002324 if (error != 0)
2325 ath_tx_cleanup(sc);
2326
2327 return error;
2328}
2329
Sujith797fe5cb2009-03-30 15:28:45 +05302330void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002331{
Sujithb77f4832008-12-07 21:44:03 +05302332 if (sc->beacon.bdma.dd_desc_len != 0)
2333 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002334
Sujithb77f4832008-12-07 21:44:03 +05302335 if (sc->tx.txdma.dd_desc_len != 0)
2336 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002337
2338 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2339 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002340}
2341
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002342void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2343{
Sujithc5170162008-10-29 10:13:59 +05302344 struct ath_atx_tid *tid;
2345 struct ath_atx_ac *ac;
2346 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002347
Sujith8ee5afb2008-12-07 21:43:36 +05302348 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302349 tidno < WME_NUM_TID;
2350 tidno++, tid++) {
2351 tid->an = an;
2352 tid->tidno = tidno;
2353 tid->seq_start = tid->seq_next = 0;
2354 tid->baw_size = WME_MAX_BA;
2355 tid->baw_head = tid->baw_tail = 0;
2356 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302357 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302358 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302359 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302360 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302361 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302362 tid->state &= ~AGGR_ADDBA_COMPLETE;
2363 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302364 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002365
Sujith8ee5afb2008-12-07 21:43:36 +05302366 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302367 acno < WME_NUM_AC; acno++, ac++) {
2368 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002369 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302370 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371 }
2372}
2373
Sujithb5aa9bf2008-10-29 10:13:31 +05302374void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002375{
Felix Fietkau2b409942010-07-07 19:42:08 +02002376 struct ath_atx_ac *ac;
2377 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002378 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002379 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302380
Felix Fietkau2b409942010-07-07 19:42:08 +02002381 for (tidno = 0, tid = &an->tid[tidno];
2382 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002383
Felix Fietkau2b409942010-07-07 19:42:08 +02002384 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002385 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002386
Felix Fietkau2b409942010-07-07 19:42:08 +02002387 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002388
Felix Fietkau2b409942010-07-07 19:42:08 +02002389 if (tid->sched) {
2390 list_del(&tid->list);
2391 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002392 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002393
2394 if (ac->sched) {
2395 list_del(&ac->list);
2396 tid->ac->sched = false;
2397 }
2398
2399 ath_tid_drain(sc, txq, tid);
2400 tid->state &= ~AGGR_ADDBA_COMPLETE;
2401 tid->state &= ~AGGR_CLEANUP;
2402
2403 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002404 }
2405}