blob: 527151e44f102af06f2f23a7af4fafeb0082eeea [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 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
Felix Fietkau7817e4c2010-04-19 19:57:31 +020022#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070023#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
24#define L_STF 8
25#define L_LTF 8
26#define L_SIG 4
27#define HT_SIG 8
28#define HT_STF 4
29#define HT_LTF(_ns) (4 * (_ns))
30#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
31#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
32#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
33#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
34
35#define OFDM_SIFS_TIME 16
36
Felix Fietkauc6663872010-04-19 19:57:33 +020037static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070038 /* 20MHz 40MHz */
39 { 26, 54 }, /* 0: BPSK */
40 { 52, 108 }, /* 1: QPSK 1/2 */
41 { 78, 162 }, /* 2: QPSK 3/4 */
42 { 104, 216 }, /* 3: 16-QAM 1/2 */
43 { 156, 324 }, /* 4: 16-QAM 3/4 */
44 { 208, 432 }, /* 5: 64-QAM 2/3 */
45 { 234, 486 }, /* 6: 64-QAM 3/4 */
46 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070047};
48
49#define IS_HT_RATE(_rate) ((_rate) & 0x80)
50
Felix Fietkau82b873a2010-11-11 03:18:37 +010051static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
52 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +010053 struct list_head *bf_head, int frmlen);
Sujithe8324352009-01-16 21:38:42 +053054static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070055 struct ath_txq *txq, struct list_head *bf_q,
56 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053057static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
58 struct list_head *head);
Felix Fietkau269c44b2010-11-14 15:20:06 +010059static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
Felix Fietkaudb1a0522010-03-29 20:07:11 -070060static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +010061 int nframes, int nbad, int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020062static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
63 int seqno);
Sujithe8324352009-01-16 21:38:42 +053064
Felix Fietkau545750d2009-11-23 22:21:01 +010065enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020066 MCS_HT20,
67 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010068 MCS_HT40,
69 MCS_HT40_SGI,
70};
71
Felix Fietkau0e668cd2010-04-19 19:57:32 +020072static int ath_max_4ms_framelen[4][32] = {
73 [MCS_HT20] = {
74 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
75 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
76 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
77 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
78 },
79 [MCS_HT20_SGI] = {
80 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
81 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
82 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
83 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010084 },
85 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020086 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
87 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
88 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
89 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010090 },
91 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020092 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
93 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
94 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
95 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010096 }
97};
98
Sujithe8324352009-01-16 21:38:42 +053099/*********************/
100/* Aggregation logic */
101/*********************/
102
Sujithe8324352009-01-16 21:38:42 +0530103static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
104{
105 struct ath_atx_ac *ac = tid->ac;
106
107 if (tid->paused)
108 return;
109
110 if (tid->sched)
111 return;
112
113 tid->sched = true;
114 list_add_tail(&tid->list, &ac->tid_q);
115
116 if (ac->sched)
117 return;
118
119 ac->sched = true;
120 list_add_tail(&ac->list, &txq->axq_acq);
121}
122
Sujithe8324352009-01-16 21:38:42 +0530123static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
124{
Felix Fietkau066dae92010-11-07 14:59:39 +0100125 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530126
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200127 WARN_ON(!tid->paused);
128
Sujithe8324352009-01-16 21:38:42 +0530129 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200130 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530131
132 if (list_empty(&tid->buf_q))
133 goto unlock;
134
135 ath_tx_queue_tid(txq, tid);
136 ath_txq_schedule(sc, txq);
137unlock:
138 spin_unlock_bh(&txq->axq_lock);
139}
140
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100141static u16 ath_frame_seqno(struct sk_buff *skb)
142{
143 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
144 return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
145}
146
Felix Fietkau76e45222010-11-14 15:20:08 +0100147static int ath_frame_len(struct sk_buff *skb)
148{
149 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
150 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
151 int frmlen = skb->len + FCS_LEN;
152 int padpos, padsize;
153
154 /* Remove the padding size, if any */
155 padpos = ath9k_cmn_padpos(hdr->frame_control);
156 padsize = padpos & 3;
157
158 if (padsize && skb->len > padpos + padsize)
159 frmlen -= padsize;
160
161 if (tx_info->control.hw_key)
162 frmlen += tx_info->control.hw_key->icv_len;
163
164 return frmlen;
165}
166
Sujithe8324352009-01-16 21:38:42 +0530167static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
168{
Felix Fietkau066dae92010-11-07 14:59:39 +0100169 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530170 struct ath_buf *bf;
171 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200172 struct ath_tx_status ts;
173
Sujithe8324352009-01-16 21:38:42 +0530174 INIT_LIST_HEAD(&bf_head);
175
Felix Fietkau90fa5392010-09-20 13:45:38 +0200176 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530177 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530178
179 while (!list_empty(&tid->buf_q)) {
180 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530181 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200182
183 if (bf_isretried(bf)) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100184 ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200185 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
186 } else {
Felix Fietkau76e45222010-11-14 15:20:08 +0100187 ath_tx_send_normal(sc, txq, tid, &bf_head,
188 ath_frame_len(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200189 }
Sujithe8324352009-01-16 21:38:42 +0530190 }
191
192 spin_unlock_bh(&txq->axq_lock);
193}
194
195static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
196 int seqno)
197{
198 int index, cindex;
199
200 index = ATH_BA_INDEX(tid->seq_start, seqno);
201 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
202
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200203 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530204
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200205 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530206 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
207 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
208 }
209}
210
211static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100212 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530213{
214 int index, cindex;
215
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100216 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530217 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200218 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530219
220 if (index >= ((tid->baw_tail - tid->baw_head) &
221 (ATH_TID_MAX_BUFS - 1))) {
222 tid->baw_tail = cindex;
223 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
224 }
225}
226
227/*
228 * TODO: For frame(s) that are in the retry state, we will reuse the
229 * sequence number(s) without setting the retry bit. The
230 * alternative is to give up on these and BAR the receiver's window
231 * forward.
232 */
233static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
234 struct ath_atx_tid *tid)
235
236{
237 struct ath_buf *bf;
238 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700239 struct ath_tx_status ts;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100240 u16 bf_seqno;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700241
242 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530243 INIT_LIST_HEAD(&bf_head);
244
245 for (;;) {
246 if (list_empty(&tid->buf_q))
247 break;
Sujithe8324352009-01-16 21:38:42 +0530248
Sujithd43f30152009-01-16 21:38:53 +0530249 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
250 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530251
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100252 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530253 if (bf_isretried(bf))
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100254 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530255
256 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700257 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530258 spin_lock(&txq->axq_lock);
259 }
260
261 tid->seq_next = tid->seq_start;
262 tid->baw_tail = tid->baw_head;
263}
264
Sujithfec247c2009-07-27 12:08:16 +0530265static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
266 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530267{
268 struct sk_buff *skb;
269 struct ieee80211_hdr *hdr;
270
271 bf->bf_state.bf_type |= BUF_RETRY;
272 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530273 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530274
275 skb = bf->bf_mpdu;
276 hdr = (struct ieee80211_hdr *)skb->data;
277 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
278}
279
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200280static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
281{
282 struct ath_buf *bf = NULL;
283
284 spin_lock_bh(&sc->tx.txbuflock);
285
286 if (unlikely(list_empty(&sc->tx.txbuf))) {
287 spin_unlock_bh(&sc->tx.txbuflock);
288 return NULL;
289 }
290
291 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
292 list_del(&bf->list);
293
294 spin_unlock_bh(&sc->tx.txbuflock);
295
296 return bf;
297}
298
299static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
300{
301 spin_lock_bh(&sc->tx.txbuflock);
302 list_add_tail(&bf->list, &sc->tx.txbuf);
303 spin_unlock_bh(&sc->tx.txbuflock);
304}
305
Sujithd43f30152009-01-16 21:38:53 +0530306static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
307{
308 struct ath_buf *tbf;
309
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200310 tbf = ath_tx_get_buffer(sc);
311 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530312 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530313
314 ATH_TXBUF_RESET(tbf);
315
Felix Fietkau827e69b2009-11-15 23:09:25 +0100316 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530317 tbf->bf_mpdu = bf->bf_mpdu;
318 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400319 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530320 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530321
322 return tbf;
323}
324
Felix Fietkaub572d032010-11-14 15:20:07 +0100325static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
326 struct ath_tx_status *ts, int txok,
327 int *nframes, int *nbad)
328{
329 u16 seq_st = 0;
330 u32 ba[WME_BA_BMP_SIZE >> 5];
331 int ba_index;
332 int isaggr = 0;
333
334 *nbad = 0;
335 *nframes = 0;
336
337 if (bf->bf_lastbf->bf_tx_aborted)
338 return;
339
340 isaggr = bf_isaggr(bf);
341 if (isaggr) {
342 seq_st = ts->ts_seqnum;
343 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
344 }
345
346 while (bf) {
347 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
348
349 (*nframes)++;
350 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
351 (*nbad)++;
352
353 bf = bf->bf_next;
354 }
355}
356
357
Sujithd43f30152009-01-16 21:38:53 +0530358static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
359 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700360 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530361{
362 struct ath_node *an = NULL;
363 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530364 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800365 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530366 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800367 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530368 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530369 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530370 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530371 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530372 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530373 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
374 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200375 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100376 u16 bf_seqno;
Björn Smedmanebd02282010-10-10 22:44:39 +0200377 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100378 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530379
Sujitha22be222009-03-30 15:28:36 +0530380 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530381 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530382
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800383 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100384 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800385
Felix Fietkau78c46532010-06-25 01:26:16 +0200386 memcpy(rates, tx_info->control.rates, sizeof(rates));
387
Sujith1286ec62009-01-27 13:30:37 +0530388 rcu_read_lock();
389
Ben Greear686b9cb2010-09-23 09:44:36 -0700390 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530391 if (!sta) {
392 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200393
Felix Fietkau31e79a52010-07-12 23:16:34 +0200394 INIT_LIST_HEAD(&bf_head);
395 while (bf) {
396 bf_next = bf->bf_next;
397
398 bf->bf_state.bf_type |= BUF_XRETRY;
399 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
400 !bf->bf_stale || bf_next != NULL)
401 list_move_tail(&bf->list, &bf_head);
402
Felix Fietkaub572d032010-11-14 15:20:07 +0100403 ath_tx_rc_status(bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200404 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
405 0, 0);
406
407 bf = bf_next;
408 }
Sujith1286ec62009-01-27 13:30:37 +0530409 return;
Sujithe8324352009-01-16 21:38:42 +0530410 }
411
Sujith1286ec62009-01-27 13:30:37 +0530412 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100413 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
414 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530415
Felix Fietkaub11b1602010-07-11 12:48:44 +0200416 /*
417 * The hardware occasionally sends a tx status for the wrong TID.
418 * In this case, the BA status cannot be considered valid and all
419 * subframes need to be retransmitted
420 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100421 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200422 txok = false;
423
Sujithe8324352009-01-16 21:38:42 +0530424 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530425 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530426
Sujithd43f30152009-01-16 21:38:53 +0530427 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700428 if (ts->ts_flags & ATH9K_TX_BA) {
429 seq_st = ts->ts_seqnum;
430 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530431 } else {
Sujithd43f30152009-01-16 21:38:53 +0530432 /*
433 * AR5416 can become deaf/mute when BA
434 * issue happens. Chip needs to be reset.
435 * But AP code may have sychronization issues
436 * when perform internal reset in this routine.
437 * Only enable reset in STA mode for now.
438 */
Sujith2660b812009-02-09 13:27:26 +0530439 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530440 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530441 }
442 }
443
444 INIT_LIST_HEAD(&bf_pending);
445 INIT_LIST_HEAD(&bf_head);
446
Felix Fietkaub572d032010-11-14 15:20:07 +0100447 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530448 while (bf) {
449 txfail = txpending = 0;
450 bf_next = bf->bf_next;
451
Felix Fietkau78c46532010-06-25 01:26:16 +0200452 skb = bf->bf_mpdu;
453 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100454 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200455
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100456 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530457 /* transmit completion, subframe is
458 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530459 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530460 } else if (!isaggr && txok) {
461 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530462 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530463 } else {
Sujithe8324352009-01-16 21:38:42 +0530464 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400465 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530466 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530467 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530468 txpending = 1;
469 } else {
470 bf->bf_state.bf_type |= BUF_XRETRY;
471 txfail = 1;
472 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530473 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530474 }
475 } else {
476 /*
477 * cleanup in progress, just fail
478 * the un-acked sub-frames
479 */
480 txfail = 1;
481 }
482 }
483
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400484 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
485 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530486 /*
487 * Make sure the last desc is reclaimed if it
488 * not a holding desc.
489 */
490 if (!bf_last->bf_stale)
491 list_move_tail(&bf->list, &bf_head);
492 else
493 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530494 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700495 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530496 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530497 }
498
Felix Fietkau90fa5392010-09-20 13:45:38 +0200499 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530500 /*
501 * complete the acked-ones/xretried ones; update
502 * block-ack window
503 */
504 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100505 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530506 spin_unlock_bh(&txq->axq_lock);
507
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530508 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200509 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaub572d032010-11-14 15:20:07 +0100510 ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530511 rc_update = false;
512 } else {
Felix Fietkaub572d032010-11-14 15:20:07 +0100513 ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530514 }
515
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700516 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
517 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530518 } else {
Sujithd43f30152009-01-16 21:38:53 +0530519 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400520 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
521 if (bf->bf_next == NULL && bf_last->bf_stale) {
522 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530523
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400524 tbf = ath_clone_txbuf(sc, bf_last);
525 /*
526 * Update tx baw and complete the
527 * frame with failed status if we
528 * run out of tx buf.
529 */
530 if (!tbf) {
531 spin_lock_bh(&txq->axq_lock);
532 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100533 bf_seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400534 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400535
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400536 bf->bf_state.bf_type |=
537 BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +0100538 ath_tx_rc_status(bf, ts, nframes,
539 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400540 ath_tx_complete_buf(sc, bf, txq,
541 &bf_head,
542 ts, 0, 0);
543 break;
544 }
545
546 ath9k_hw_cleartxdesc(sc->sc_ah,
547 tbf->bf_desc);
548 list_add_tail(&tbf->list, &bf_head);
549 } else {
550 /*
551 * Clear descriptor status words for
552 * software retry
553 */
554 ath9k_hw_cleartxdesc(sc->sc_ah,
555 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400556 }
Sujithe8324352009-01-16 21:38:42 +0530557 }
558
559 /*
560 * Put this buffer to the temporary pending
561 * queue to retain ordering
562 */
563 list_splice_tail_init(&bf_head, &bf_pending);
564 }
565
566 bf = bf_next;
567 }
568
Felix Fietkau4cee7862010-07-23 03:53:16 +0200569 /* prepend un-acked frames to the beginning of the pending frame queue */
570 if (!list_empty(&bf_pending)) {
571 spin_lock_bh(&txq->axq_lock);
572 list_splice(&bf_pending, &tid->buf_q);
573 ath_tx_queue_tid(txq, tid);
574 spin_unlock_bh(&txq->axq_lock);
575 }
576
Sujithe8324352009-01-16 21:38:42 +0530577 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200578 ath_tx_flush_tid(sc, tid);
579
Sujithe8324352009-01-16 21:38:42 +0530580 if (tid->baw_head == tid->baw_tail) {
581 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530582 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530583 }
Sujithe8324352009-01-16 21:38:42 +0530584 }
585
Sujith1286ec62009-01-27 13:30:37 +0530586 rcu_read_unlock();
587
Sujithe8324352009-01-16 21:38:42 +0530588 if (needreset)
589 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530590}
591
592static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
593 struct ath_atx_tid *tid)
594{
Sujithe8324352009-01-16 21:38:42 +0530595 struct sk_buff *skb;
596 struct ieee80211_tx_info *tx_info;
597 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530598 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530599 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530600 int i;
601
Sujitha22be222009-03-30 15:28:36 +0530602 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530603 tx_info = IEEE80211_SKB_CB(skb);
604 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530605
606 /*
607 * Find the lowest frame length among the rate series that will have a
608 * 4ms transmit duration.
609 * TODO - TXOP limit needs to be considered.
610 */
611 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
612
613 for (i = 0; i < 4; i++) {
614 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100615 int modeidx;
616 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530617 legacy = 1;
618 break;
619 }
620
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200621 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100622 modeidx = MCS_HT40;
623 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200624 modeidx = MCS_HT20;
625
626 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
627 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100628
629 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530630 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530631 }
632 }
633
634 /*
635 * limit aggregate size by the minimum rate if rate selected is
636 * not a probe rate, if rate selected is a probe rate then
637 * avoid aggregation of this packet.
638 */
639 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
640 return 0;
641
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530642 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
643 aggr_limit = min((max_4ms_framelen * 3) / 8,
644 (u32)ATH_AMPDU_LIMIT_MAX);
645 else
646 aggr_limit = min(max_4ms_framelen,
647 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530648
649 /*
650 * h/w can accept aggregates upto 16 bit lengths (65535).
651 * The IE, however can hold upto 65536, which shows up here
652 * as zero. Ignore 65536 since we are constrained by hw.
653 */
Sujith4ef70842009-07-23 15:32:41 +0530654 if (tid->an->maxampdu)
655 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530656
657 return aggr_limit;
658}
659
660/*
Sujithd43f30152009-01-16 21:38:53 +0530661 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530662 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530663 */
664static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
665 struct ath_buf *bf, u16 frmlen)
666{
Sujithe8324352009-01-16 21:38:42 +0530667 struct sk_buff *skb = bf->bf_mpdu;
668 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530669 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530670 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100671 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200672 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530673
674 /* Select standard number of delimiters based on frame length alone */
675 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
676
677 /*
678 * If encryption enabled, hardware requires some more padding between
679 * subframes.
680 * TODO - this could be improved to be dependent on the rate.
681 * The hardware can keep up at lower rates, but not higher rates
682 */
Felix Fietkau952cd692010-11-14 15:20:03 +0100683 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +0530684 ndelim += ATH_AGGR_ENCRYPTDELIM;
685
686 /*
687 * Convert desired mpdu density from microeconds to bytes based
688 * on highest rate in rate series (i.e. first rate) to determine
689 * required minimum length for subframe. Take into account
690 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530691 *
Sujithe8324352009-01-16 21:38:42 +0530692 * If there is no mpdu density restriction, no further calculation
693 * is needed.
694 */
Sujith4ef70842009-07-23 15:32:41 +0530695
696 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530697 return ndelim;
698
699 rix = tx_info->control.rates[0].idx;
700 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530701 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
702 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
703
704 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530705 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530706 else
Sujith4ef70842009-07-23 15:32:41 +0530707 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530708
709 if (nsymbols == 0)
710 nsymbols = 1;
711
Felix Fietkauc6663872010-04-19 19:57:33 +0200712 streams = HT_RC_2_STREAMS(rix);
713 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530714 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
715
Sujithe8324352009-01-16 21:38:42 +0530716 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530717 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
718 ndelim = max(mindelim, ndelim);
719 }
720
721 return ndelim;
722}
723
724static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530725 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530726 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100727 struct list_head *bf_q,
728 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530729{
730#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530731 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
732 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530733 u16 aggr_limit = 0, al = 0, bpad = 0,
734 al_delta, h_baw = tid->baw_size / 2;
735 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200736 struct ieee80211_tx_info *tx_info;
Felix Fietkau76e45222010-11-14 15:20:08 +0100737 int frmlen;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100738 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530739
740 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
741
742 do {
743 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100744 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530745
Sujithd43f30152009-01-16 21:38:53 +0530746 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100747 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530748 status = ATH_AGGR_BAW_CLOSED;
749 break;
750 }
751
752 if (!rl) {
753 aggr_limit = ath_lookup_rate(sc, bf, tid);
754 rl = 1;
755 }
756
Sujithd43f30152009-01-16 21:38:53 +0530757 /* do not exceed aggregation limit */
Felix Fietkau76e45222010-11-14 15:20:08 +0100758 frmlen = ath_frame_len(bf->bf_mpdu);
759 al_delta = ATH_AGGR_DELIM_SZ + frmlen;
Sujithe8324352009-01-16 21:38:42 +0530760
Sujithd43f30152009-01-16 21:38:53 +0530761 if (nframes &&
762 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530763 status = ATH_AGGR_LIMITED;
764 break;
765 }
766
Felix Fietkau0299a502010-10-21 02:47:24 +0200767 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
768 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
769 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
770 break;
771
Sujithd43f30152009-01-16 21:38:53 +0530772 /* do not exceed subframe limit */
773 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530774 status = ATH_AGGR_LIMITED;
775 break;
776 }
Sujithd43f30152009-01-16 21:38:53 +0530777 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530778
Sujithd43f30152009-01-16 21:38:53 +0530779 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530780 al += bpad + al_delta;
781
782 /*
783 * Get the delimiters needed to meet the MPDU
784 * density for this node.
785 */
Felix Fietkau76e45222010-11-14 15:20:08 +0100786 ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530787 bpad = PADBYTES(al_delta) + (ndelim << 2);
788
789 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400790 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530791
Sujithd43f30152009-01-16 21:38:53 +0530792 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100793 if (!bf_isretried(bf))
794 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530795 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
796 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530797 if (bf_prev) {
798 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400799 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
800 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530801 }
802 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530803
Sujithe8324352009-01-16 21:38:42 +0530804 } while (!list_empty(&tid->buf_q));
805
Felix Fietkau269c44b2010-11-14 15:20:06 +0100806 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530807
Sujithe8324352009-01-16 21:38:42 +0530808 return status;
809#undef PADBYTES
810}
811
812static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
813 struct ath_atx_tid *tid)
814{
Sujithd43f30152009-01-16 21:38:53 +0530815 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530816 enum ATH_AGGR_STATUS status;
817 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100818 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530819
820 do {
821 if (list_empty(&tid->buf_q))
822 return;
823
824 INIT_LIST_HEAD(&bf_q);
825
Felix Fietkau269c44b2010-11-14 15:20:06 +0100826 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530827
828 /*
Sujithd43f30152009-01-16 21:38:53 +0530829 * no frames picked up to be aggregated;
830 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530831 */
832 if (list_empty(&bf_q))
833 break;
834
835 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530836 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530837
Sujithd43f30152009-01-16 21:38:53 +0530838 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100839 if (bf == bf->bf_lastbf) {
Sujithe8324352009-01-16 21:38:42 +0530840 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530841 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau76e45222010-11-14 15:20:08 +0100842 ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +0530843 ath_tx_txqaddbuf(sc, txq, &bf_q);
844 continue;
845 }
846
Sujithd43f30152009-01-16 21:38:53 +0530847 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530848 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100849 ath_buf_set_rate(sc, bf, aggr_len);
850 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530851
Sujithd43f30152009-01-16 21:38:53 +0530852 /* anchor last desc of aggregate */
853 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530854
Sujithe8324352009-01-16 21:38:42 +0530855 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530856 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530857
858 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
859 status != ATH_AGGR_BAW_CLOSED);
860}
861
Felix Fietkau231c3a12010-09-20 19:35:28 +0200862int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
863 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530864{
865 struct ath_atx_tid *txtid;
866 struct ath_node *an;
867
868 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530869 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200870
871 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
872 return -EAGAIN;
873
Sujithf83da962009-07-23 15:32:37 +0530874 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200875 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530876 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200877
878 return 0;
Sujithe8324352009-01-16 21:38:42 +0530879}
880
Sujithf83da962009-07-23 15:32:37 +0530881void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530882{
883 struct ath_node *an = (struct ath_node *)sta->drv_priv;
884 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100885 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530886
887 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530888 return;
Sujithe8324352009-01-16 21:38:42 +0530889
890 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530891 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530892 return;
Sujithe8324352009-01-16 21:38:42 +0530893 }
894
Sujithe8324352009-01-16 21:38:42 +0530895 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200896 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200897
898 /*
899 * If frames are still being transmitted for this TID, they will be
900 * cleaned up during tx completion. To prevent race conditions, this
901 * TID can only be reused after all in-progress subframes have been
902 * completed.
903 */
904 if (txtid->baw_head != txtid->baw_tail)
905 txtid->state |= AGGR_CLEANUP;
906 else
907 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530908 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530909
Felix Fietkau90fa5392010-09-20 13:45:38 +0200910 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530911}
912
913void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
914{
915 struct ath_atx_tid *txtid;
916 struct ath_node *an;
917
918 an = (struct ath_node *)sta->drv_priv;
919
920 if (sc->sc_flags & SC_OP_TXAGGR) {
921 txtid = ATH_AN_2_TID(an, tid);
922 txtid->baw_size =
923 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
924 txtid->state |= AGGR_ADDBA_COMPLETE;
925 txtid->state &= ~AGGR_ADDBA_PROGRESS;
926 ath_tx_resume_tid(sc, txtid);
927 }
928}
929
Sujithe8324352009-01-16 21:38:42 +0530930/********************/
931/* Queue Management */
932/********************/
933
Sujithe8324352009-01-16 21:38:42 +0530934static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
935 struct ath_txq *txq)
936{
937 struct ath_atx_ac *ac, *ac_tmp;
938 struct ath_atx_tid *tid, *tid_tmp;
939
940 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
941 list_del(&ac->list);
942 ac->sched = false;
943 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
944 list_del(&tid->list);
945 tid->sched = false;
946 ath_tid_drain(sc, txq, tid);
947 }
948 }
949}
950
951struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
952{
Sujithcbe61d82009-02-09 13:27:12 +0530953 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700954 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530955 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100956 static const int subtype_txq_to_hwq[] = {
957 [WME_AC_BE] = ATH_TXQ_AC_BE,
958 [WME_AC_BK] = ATH_TXQ_AC_BK,
959 [WME_AC_VI] = ATH_TXQ_AC_VI,
960 [WME_AC_VO] = ATH_TXQ_AC_VO,
961 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400962 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530963
964 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100965 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530966 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
967 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
968 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
969 qi.tqi_physCompBuf = 0;
970
971 /*
972 * Enable interrupts only for EOL and DESC conditions.
973 * We mark tx descriptors to receive a DESC interrupt
974 * when a tx queue gets deep; otherwise waiting for the
975 * EOL to reap descriptors. Note that this is done to
976 * reduce interrupt load and this only defers reaping
977 * descriptors, never transmitting frames. Aside from
978 * reducing interrupts this also permits more concurrency.
979 * The only potential downside is if the tx queue backs
980 * up in which case the top half of the kernel may backup
981 * due to a lack of tx descriptors.
982 *
983 * The UAPSD queue is an exception, since we take a desc-
984 * based intr on the EOSP frames.
985 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400986 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
987 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
988 TXQ_FLAG_TXERRINT_ENABLE;
989 } else {
990 if (qtype == ATH9K_TX_QUEUE_UAPSD)
991 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
992 else
993 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
994 TXQ_FLAG_TXDESCINT_ENABLE;
995 }
Sujithe8324352009-01-16 21:38:42 +0530996 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
997 if (qnum == -1) {
998 /*
999 * NB: don't print a message, this happens
1000 * normally on parts with too few tx queues
1001 */
1002 return NULL;
1003 }
1004 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001005 ath_print(common, ATH_DBG_FATAL,
1006 "qnum %u out of range, max %u!\n",
1007 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +05301008 ath9k_hw_releasetxqueue(ah, qnum);
1009 return NULL;
1010 }
1011 if (!ATH_TXQ_SETUP(sc, qnum)) {
1012 struct ath_txq *txq = &sc->tx.txq[qnum];
1013
1014 txq->axq_qnum = qnum;
1015 txq->axq_link = NULL;
1016 INIT_LIST_HEAD(&txq->axq_q);
1017 INIT_LIST_HEAD(&txq->axq_acq);
1018 spin_lock_init(&txq->axq_lock);
1019 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001020 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +05301021 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001022
1023 txq->txq_headidx = txq->txq_tailidx = 0;
1024 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1025 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1026 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301027 }
1028 return &sc->tx.txq[qnum];
1029}
1030
Sujithe8324352009-01-16 21:38:42 +05301031int ath_txq_update(struct ath_softc *sc, int qnum,
1032 struct ath9k_tx_queue_info *qinfo)
1033{
Sujithcbe61d82009-02-09 13:27:12 +05301034 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301035 int error = 0;
1036 struct ath9k_tx_queue_info qi;
1037
1038 if (qnum == sc->beacon.beaconq) {
1039 /*
1040 * XXX: for beacon queue, we just save the parameter.
1041 * It will be picked up by ath_beaconq_config when
1042 * it's necessary.
1043 */
1044 sc->beacon.beacon_qi = *qinfo;
1045 return 0;
1046 }
1047
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001048 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301049
1050 ath9k_hw_get_txq_props(ah, qnum, &qi);
1051 qi.tqi_aifs = qinfo->tqi_aifs;
1052 qi.tqi_cwmin = qinfo->tqi_cwmin;
1053 qi.tqi_cwmax = qinfo->tqi_cwmax;
1054 qi.tqi_burstTime = qinfo->tqi_burstTime;
1055 qi.tqi_readyTime = qinfo->tqi_readyTime;
1056
1057 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001058 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1059 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301060 error = -EIO;
1061 } else {
1062 ath9k_hw_resettxqueue(ah, qnum);
1063 }
1064
1065 return error;
1066}
1067
1068int ath_cabq_update(struct ath_softc *sc)
1069{
1070 struct ath9k_tx_queue_info qi;
1071 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301072
1073 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1074 /*
1075 * Ensure the readytime % is within the bounds.
1076 */
Sujith17d79042009-02-09 13:27:03 +05301077 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1078 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1079 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1080 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301081
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001082 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301083 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301084 ath_txq_update(sc, qnum, &qi);
1085
1086 return 0;
1087}
1088
Sujith043a0402009-01-16 21:38:47 +05301089/*
1090 * Drain a given TX queue (could be Beacon or Data)
1091 *
1092 * This assumes output has been stopped and
1093 * we do not need to block ath_tx_tasklet.
1094 */
1095void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301096{
1097 struct ath_buf *bf, *lastbf;
1098 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001099 struct ath_tx_status ts;
1100
1101 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301102 INIT_LIST_HEAD(&bf_head);
1103
Sujithe8324352009-01-16 21:38:42 +05301104 for (;;) {
1105 spin_lock_bh(&txq->axq_lock);
1106
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001107 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1108 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1109 txq->txq_headidx = txq->txq_tailidx = 0;
1110 spin_unlock_bh(&txq->axq_lock);
1111 break;
1112 } else {
1113 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1114 struct ath_buf, list);
1115 }
1116 } else {
1117 if (list_empty(&txq->axq_q)) {
1118 txq->axq_link = NULL;
1119 spin_unlock_bh(&txq->axq_lock);
1120 break;
1121 }
1122 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1123 list);
Sujithe8324352009-01-16 21:38:42 +05301124
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001125 if (bf->bf_stale) {
1126 list_del(&bf->list);
1127 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301128
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001129 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001130 continue;
1131 }
Sujithe8324352009-01-16 21:38:42 +05301132 }
1133
1134 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001135 if (!retry_tx)
1136 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301137
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001138 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1139 list_cut_position(&bf_head,
1140 &txq->txq_fifo[txq->txq_tailidx],
1141 &lastbf->list);
1142 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1143 } else {
1144 /* remove ath_buf's of the same mpdu from txq */
1145 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1146 }
1147
Sujithe8324352009-01-16 21:38:42 +05301148 txq->axq_depth--;
1149
1150 spin_unlock_bh(&txq->axq_lock);
1151
1152 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001153 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301154 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001155 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301156 }
1157
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001158 spin_lock_bh(&txq->axq_lock);
1159 txq->axq_tx_inprogress = false;
1160 spin_unlock_bh(&txq->axq_lock);
1161
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001162 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1163 spin_lock_bh(&txq->axq_lock);
1164 while (!list_empty(&txq->txq_fifo_pending)) {
1165 bf = list_first_entry(&txq->txq_fifo_pending,
1166 struct ath_buf, list);
1167 list_cut_position(&bf_head,
1168 &txq->txq_fifo_pending,
1169 &bf->bf_lastbf->list);
1170 spin_unlock_bh(&txq->axq_lock);
1171
1172 if (bf_isampdu(bf))
1173 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1174 &ts, 0);
1175 else
1176 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1177 &ts, 0, 0);
1178 spin_lock_bh(&txq->axq_lock);
1179 }
1180 spin_unlock_bh(&txq->axq_lock);
1181 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001182
1183 /* flush any pending frames if aggregation is enabled */
1184 if (sc->sc_flags & SC_OP_TXAGGR) {
1185 if (!retry_tx) {
1186 spin_lock_bh(&txq->axq_lock);
1187 ath_txq_drain_pending_buffers(sc, txq);
1188 spin_unlock_bh(&txq->axq_lock);
1189 }
1190 }
Sujithe8324352009-01-16 21:38:42 +05301191}
1192
Sujith043a0402009-01-16 21:38:47 +05301193void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1194{
Sujithcbe61d82009-02-09 13:27:12 +05301195 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001196 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301197 struct ath_txq *txq;
1198 int i, npend = 0;
1199
1200 if (sc->sc_flags & SC_OP_INVALID)
1201 return;
1202
1203 /* Stop beacon queue */
1204 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1205
1206 /* Stop data queues */
1207 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1208 if (ATH_TXQ_SETUP(sc, i)) {
1209 txq = &sc->tx.txq[i];
1210 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1211 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1212 }
1213 }
1214
1215 if (npend) {
1216 int r;
1217
Sujithe8009e92009-12-14 14:57:08 +05301218 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001219 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301220
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001221 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301222 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001223 ath_print(common, ATH_DBG_FATAL,
1224 "Unable to reset hardware; reset status %d\n",
1225 r);
Sujith043a0402009-01-16 21:38:47 +05301226 }
1227
1228 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1229 if (ATH_TXQ_SETUP(sc, i))
1230 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1231 }
1232}
1233
Sujithe8324352009-01-16 21:38:42 +05301234void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1235{
1236 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1237 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1238}
1239
Sujithe8324352009-01-16 21:38:42 +05301240void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1241{
1242 struct ath_atx_ac *ac;
1243 struct ath_atx_tid *tid;
1244
1245 if (list_empty(&txq->axq_acq))
1246 return;
1247
1248 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1249 list_del(&ac->list);
1250 ac->sched = false;
1251
1252 do {
1253 if (list_empty(&ac->tid_q))
1254 return;
1255
1256 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1257 list_del(&tid->list);
1258 tid->sched = false;
1259
1260 if (tid->paused)
1261 continue;
1262
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001263 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301264
1265 /*
1266 * add tid to round-robin queue if more frames
1267 * are pending for the tid
1268 */
1269 if (!list_empty(&tid->buf_q))
1270 ath_tx_queue_tid(txq, tid);
1271
1272 break;
1273 } while (!list_empty(&ac->tid_q));
1274
1275 if (!list_empty(&ac->tid_q)) {
1276 if (!ac->sched) {
1277 ac->sched = true;
1278 list_add_tail(&ac->list, &txq->axq_acq);
1279 }
1280 }
1281}
1282
Sujithe8324352009-01-16 21:38:42 +05301283/***********/
1284/* TX, DMA */
1285/***********/
1286
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001287/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001288 * Insert a chain of ath_buf (descriptors) on a txq and
1289 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001290 */
Sujith102e0572008-10-29 10:15:16 +05301291static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1292 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001293{
Sujithcbe61d82009-02-09 13:27:12 +05301294 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001295 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001296 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301297
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001298 /*
1299 * Insert the frame on the outbound list and
1300 * pass it on to the hardware.
1301 */
1302
1303 if (list_empty(head))
1304 return;
1305
1306 bf = list_first_entry(head, struct ath_buf, list);
1307
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001308 ath_print(common, ATH_DBG_QUEUE,
1309 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001310
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001311 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1312 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1313 list_splice_tail_init(head, &txq->txq_fifo_pending);
1314 return;
1315 }
1316 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1317 ath_print(common, ATH_DBG_XMIT,
1318 "Initializing tx fifo %d which "
1319 "is non-empty\n",
1320 txq->txq_headidx);
1321 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1322 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1323 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001324 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001325 ath_print(common, ATH_DBG_XMIT,
1326 "TXDP[%u] = %llx (%p)\n",
1327 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001328 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001329 list_splice_tail_init(head, &txq->axq_q);
1330
1331 if (txq->axq_link == NULL) {
1332 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1333 ath_print(common, ATH_DBG_XMIT,
1334 "TXDP[%u] = %llx (%p)\n",
1335 txq->axq_qnum, ito64(bf->bf_daddr),
1336 bf->bf_desc);
1337 } else {
1338 *txq->axq_link = bf->bf_daddr;
1339 ath_print(common, ATH_DBG_XMIT,
1340 "link[%u] (%p)=%llx (%p)\n",
1341 txq->axq_qnum, txq->axq_link,
1342 ito64(bf->bf_daddr), bf->bf_desc);
1343 }
1344 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1345 &txq->axq_link);
1346 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001347 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001348 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001349}
1350
Sujithe8324352009-01-16 21:38:42 +05301351static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1352 struct list_head *bf_head,
Felix Fietkau76e45222010-11-14 15:20:08 +01001353 struct ath_tx_control *txctl, int frmlen)
Sujithe8324352009-01-16 21:38:42 +05301354{
1355 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001356 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301357
Sujithe8324352009-01-16 21:38:42 +05301358 bf = list_first_entry(bf_head, struct ath_buf, list);
1359 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301360 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001361 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301362
1363 /*
1364 * Do not queue to h/w when any of the following conditions is true:
1365 * - there are pending frames in software queue
1366 * - the TID is currently paused for ADDBA/BAR request
1367 * - seqno is not within block-ack window
1368 * - h/w queue depth exceeds low water mark
1369 */
1370 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001371 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301372 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001373 /*
Sujithe8324352009-01-16 21:38:42 +05301374 * Add this frame to software queue for scheduling later
1375 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001376 */
Sujithd43f30152009-01-16 21:38:53 +05301377 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301378 ath_tx_queue_tid(txctl->txq, tid);
1379 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001380 }
1381
Sujithe8324352009-01-16 21:38:42 +05301382 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001383 if (!bf_isretried(bf))
1384 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301385
1386 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301387 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001388 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301389 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301390}
1391
Felix Fietkau82b873a2010-11-11 03:18:37 +01001392static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1393 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +01001394 struct list_head *bf_head, int frmlen)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001395{
Sujithe8324352009-01-16 21:38:42 +05301396 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001397
Sujithe8324352009-01-16 21:38:42 +05301398 bf = list_first_entry(bf_head, struct ath_buf, list);
1399 bf->bf_state.bf_type &= ~BUF_AMPDU;
1400
1401 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001402 if (tid)
1403 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301404
Sujithd43f30152009-01-16 21:38:53 +05301405 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001406 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301407 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301408 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409}
1410
Sujith528f0c62008-10-29 10:14:26 +05301411static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001412{
Sujith528f0c62008-10-29 10:14:26 +05301413 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001414 enum ath9k_pkt_type htype;
1415 __le16 fc;
1416
Sujith528f0c62008-10-29 10:14:26 +05301417 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001418 fc = hdr->frame_control;
1419
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001420 if (ieee80211_is_beacon(fc))
1421 htype = ATH9K_PKT_TYPE_BEACON;
1422 else if (ieee80211_is_probe_resp(fc))
1423 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1424 else if (ieee80211_is_atim(fc))
1425 htype = ATH9K_PKT_TYPE_ATIM;
1426 else if (ieee80211_is_pspoll(fc))
1427 htype = ATH9K_PKT_TYPE_PSPOLL;
1428 else
1429 htype = ATH9K_PKT_TYPE_NORMAL;
1430
1431 return htype;
1432}
1433
Sujith528f0c62008-10-29 10:14:26 +05301434static void assign_aggr_tid_seqno(struct sk_buff *skb,
1435 struct ath_buf *bf)
1436{
1437 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1438 struct ieee80211_hdr *hdr;
1439 struct ath_node *an;
1440 struct ath_atx_tid *tid;
1441 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001442 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301443
1444 if (!tx_info->control.sta)
1445 return;
1446
1447 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1448 hdr = (struct ieee80211_hdr *)skb->data;
1449 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001450 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001451
Sujithe8324352009-01-16 21:38:42 +05301452 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001453 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301454 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301455 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001456 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301457 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301458 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301459}
1460
Felix Fietkau82b873a2010-11-11 03:18:37 +01001461static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301462{
1463 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1464 int flags = 0;
1465
1466 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1467 flags |= ATH9K_TXDESC_INTREQ;
1468
1469 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1470 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301471
Felix Fietkau82b873a2010-11-11 03:18:37 +01001472 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001473 flags |= ATH9K_TXDESC_LDPC;
1474
Sujith528f0c62008-10-29 10:14:26 +05301475 return flags;
1476}
1477
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001478/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001479 * rix - rate index
1480 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1481 * width - 0 for 20 MHz, 1 for 40 MHz
1482 * half_gi - to use 4us v/s 3.6 us for symbol time
1483 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001484static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301485 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001486{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001488 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301489
1490 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001491 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001492 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001493 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001494 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1495
1496 if (!half_gi)
1497 duration = SYMBOL_TIME(nsymbols);
1498 else
1499 duration = SYMBOL_TIME_HALFGI(nsymbols);
1500
Sujithe63835b2008-11-18 09:07:53 +05301501 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001502 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301503
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001504 return duration;
1505}
1506
Felix Fietkau269c44b2010-11-14 15:20:06 +01001507static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001508{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001509 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001510 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301511 struct sk_buff *skb;
1512 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301513 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001514 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301515 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301516 int i, flags = 0;
1517 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301518 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301519
1520 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301521
Sujitha22be222009-03-30 15:28:36 +05301522 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301523 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301524 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301525 hdr = (struct ieee80211_hdr *)skb->data;
1526 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301527
Sujithc89424d2009-01-30 14:29:28 +05301528 /*
1529 * We check if Short Preamble is needed for the CTS rate by
1530 * checking the BSS's global flag.
1531 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1532 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001533 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1534 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301535 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001536 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001537
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001538 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001539 bool is_40, is_sgi, is_sp;
1540 int phy;
1541
Sujithe63835b2008-11-18 09:07:53 +05301542 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001543 continue;
1544
Sujitha8efee42008-11-18 09:07:30 +05301545 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301546 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001547 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001548
Felix Fietkau27032052010-01-17 21:08:50 +01001549 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1550 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301551 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001552 flags |= ATH9K_TXDESC_RTSENA;
1553 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1554 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1555 flags |= ATH9K_TXDESC_CTSENA;
1556 }
1557
Sujithc89424d2009-01-30 14:29:28 +05301558 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1559 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1560 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1561 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001562
Felix Fietkau545750d2009-11-23 22:21:01 +01001563 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1564 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1565 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1566
1567 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1568 /* MCS rates */
1569 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001570 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001571 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001572 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1573 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001574 continue;
1575 }
1576
1577 /* legcay rates */
1578 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1579 !(rate->flags & IEEE80211_RATE_ERP_G))
1580 phy = WLAN_RC_PHY_CCK;
1581 else
1582 phy = WLAN_RC_PHY_OFDM;
1583
1584 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1585 series[i].Rate = rate->hw_value;
1586 if (rate->hw_value_short) {
1587 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1588 series[i].Rate |= rate->hw_value_short;
1589 } else {
1590 is_sp = false;
1591 }
1592
1593 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001594 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001595 }
1596
Felix Fietkau27032052010-01-17 21:08:50 +01001597 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001598 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001599 flags &= ~ATH9K_TXDESC_RTSENA;
1600
1601 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1602 if (flags & ATH9K_TXDESC_RTSENA)
1603 flags &= ~ATH9K_TXDESC_CTSENA;
1604
Sujithe63835b2008-11-18 09:07:53 +05301605 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301606 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1607 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301608 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301609 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301610
Sujith17d79042009-02-09 13:27:03 +05301611 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301612 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001613}
1614
Felix Fietkau82b873a2010-11-11 03:18:37 +01001615static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1616 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301617{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001618 struct ath_wiphy *aphy = hw->priv;
1619 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001620 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301621 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001622 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301623 int hdrlen;
1624 __le16 fc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001625
1626 bf = ath_tx_get_buffer(sc);
1627 if (!bf) {
1628 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1629 return NULL;
1630 }
Sujithe8324352009-01-16 21:38:42 +05301631
Sujithe8324352009-01-16 21:38:42 +05301632 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1633 fc = hdr->frame_control;
1634
1635 ATH_TXBUF_RESET(bf);
1636
Felix Fietkau827e69b2009-11-15 23:09:25 +01001637 bf->aphy = aphy;
Sujithe8324352009-01-16 21:38:42 +05301638
Felix Fietkau82b873a2010-11-11 03:18:37 +01001639 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301640 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001641 if (sc->sc_flags & SC_OP_TXAGGR)
1642 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001643 }
Sujithe8324352009-01-16 21:38:42 +05301644
Felix Fietkau82b873a2010-11-11 03:18:37 +01001645 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301646
Sujithe8324352009-01-16 21:38:42 +05301647 bf->bf_mpdu = skb;
1648
Ben Greearc1739eb32010-10-14 12:45:29 -07001649 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1650 skb->len, DMA_TO_DEVICE);
1651 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301652 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001653 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001654 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1655 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001656 ath_tx_return_buffer(sc, bf);
1657 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301658 }
1659
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001660 bf->bf_tx_aborted = false;
1661
Felix Fietkau82b873a2010-11-11 03:18:37 +01001662 return bf;
Sujithe8324352009-01-16 21:38:42 +05301663}
1664
1665/* FIXME: tx power */
1666static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1667 struct ath_tx_control *txctl)
1668{
Sujitha22be222009-03-30 15:28:36 +05301669 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301670 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301671 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301672 struct ath_node *an = NULL;
1673 struct list_head bf_head;
1674 struct ath_desc *ds;
1675 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301676 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001677 enum ath9k_key_type keytype;
Felix Fietkau30170472010-11-14 15:20:05 +01001678 u32 keyix;
Sujithe8324352009-01-16 21:38:42 +05301679 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301680 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001681 u8 tidno;
Felix Fietkau76e45222010-11-14 15:20:08 +01001682 int frmlen;
Sujithe8324352009-01-16 21:38:42 +05301683
1684 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301685 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301686
1687 INIT_LIST_HEAD(&bf_head);
1688 list_add_tail(&bf->list, &bf_head);
1689
1690 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001691 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301692
Felix Fietkau952cd692010-11-14 15:20:03 +01001693 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001694 if (tx_info->control.hw_key)
1695 keyix = tx_info->control.hw_key->hw_key_idx;
1696 else
1697 keyix = ATH9K_TXKEYIX_INVALID;
1698
Felix Fietkau76e45222010-11-14 15:20:08 +01001699 frmlen = ath_frame_len(bf->bf_mpdu);
1700 ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001701 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301702
1703 ath9k_hw_filltxdesc(ah, ds,
1704 skb->len, /* segment length */
1705 true, /* first segment */
1706 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001707 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001708 bf->bf_buf_addr,
1709 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301710
Sujithe8324352009-01-16 21:38:42 +05301711 spin_lock_bh(&txctl->txq->axq_lock);
1712
1713 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1714 tx_info->control.sta) {
1715 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001716 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1717 IEEE80211_QOS_CTL_TID_MASK;
1718 tid = ATH_AN_2_TID(an, tidno);
1719
Sujithe8324352009-01-16 21:38:42 +05301720
Felix Fietkau066dae92010-11-07 14:59:39 +01001721 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001722 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301723 /*
1724 * Try aggregation if it's a unicast data frame
1725 * and the destination is HT capable.
1726 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001727 ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301728 } else {
1729 /*
1730 * Send this frame as regular when ADDBA
1731 * exchange is neither complete nor pending.
1732 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001733 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301734 }
1735 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001736 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001737 bf->bf_state.bfs_paprd = txctl->paprd;
1738
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001739 if (bf->bf_state.bfs_paprd)
1740 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1741
Felix Fietkau76e45222010-11-14 15:20:08 +01001742 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301743 }
1744
1745 spin_unlock_bh(&txctl->txq->axq_lock);
1746}
1747
1748/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001749int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301750 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001751{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001752 struct ath_wiphy *aphy = hw->priv;
1753 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001754 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001755 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001756 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001757
Felix Fietkau82b873a2010-11-11 03:18:37 +01001758 bf = ath_tx_setup_buffer(hw, skb);
1759 if (unlikely(!bf))
1760 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001761
Felix Fietkau066dae92010-11-07 14:59:39 +01001762 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001763 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001764 if (txq == sc->tx.txq_map[q] &&
1765 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1766 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001767 txq->stopped = 1;
1768 }
1769 spin_unlock_bh(&txq->axq_lock);
1770
Sujithe8324352009-01-16 21:38:42 +05301771 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001772
1773 return 0;
1774}
1775
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001776void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001777{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001778 struct ath_wiphy *aphy = hw->priv;
1779 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001780 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001781 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1782 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301783 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1784 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001785
Sujithe8324352009-01-16 21:38:42 +05301786 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001787
Sujithe8324352009-01-16 21:38:42 +05301788 /*
1789 * As a temporary workaround, assign seq# here; this will likely need
1790 * to be cleaned up to work better with Beacon transmission and virtual
1791 * BSSes.
1792 */
1793 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301794 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1795 sc->tx.seq_no += 0x10;
1796 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1797 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001798 }
1799
Sujithe8324352009-01-16 21:38:42 +05301800 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001801 padpos = ath9k_cmn_padpos(hdr->frame_control);
1802 padsize = padpos & 3;
1803 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301804 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001805 ath_print(common, ATH_DBG_XMIT,
1806 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301807 dev_kfree_skb_any(skb);
1808 return;
1809 }
1810 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001811 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001812 }
1813
Sujithe8324352009-01-16 21:38:42 +05301814 txctl.txq = sc->beacon.cabq;
1815
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001816 ath_print(common, ATH_DBG_XMIT,
1817 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301818
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001819 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001820 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301821 goto exit;
1822 }
1823
1824 return;
1825exit:
1826 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001827}
1828
Sujithe8324352009-01-16 21:38:42 +05301829/*****************/
1830/* TX Completion */
1831/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001832
Sujithe8324352009-01-16 21:38:42 +05301833static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001834 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001835 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001836{
Sujithe8324352009-01-16 21:38:42 +05301837 struct ieee80211_hw *hw = sc->hw;
1838 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001839 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001840 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001841 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301842
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001843 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301844
Felix Fietkau827e69b2009-11-15 23:09:25 +01001845 if (aphy)
1846 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301847
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301848 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301849 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301850
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301851 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301852 /* Frame was ACKed */
1853 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1854 }
1855
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001856 padpos = ath9k_cmn_padpos(hdr->frame_control);
1857 padsize = padpos & 3;
1858 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301859 /*
1860 * Remove MAC header padding before giving the frame back to
1861 * mac80211.
1862 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001863 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301864 skb_pull(skb, padsize);
1865 }
1866
Sujith1b04b932010-01-08 10:36:05 +05301867 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1868 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001869 ath_print(common, ATH_DBG_PS,
1870 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001871 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301872 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1873 PS_WAIT_FOR_CAB |
1874 PS_WAIT_FOR_PSPOLL_DATA |
1875 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001876 }
1877
Felix Fietkau61117f02010-11-11 03:18:36 +01001878 if (unlikely(ftype))
1879 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001880 else {
1881 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001882 if (txq == sc->tx.txq_map[q]) {
1883 spin_lock_bh(&txq->axq_lock);
1884 if (WARN_ON(--txq->pending_frames < 0))
1885 txq->pending_frames = 0;
1886 spin_unlock_bh(&txq->axq_lock);
1887 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001888
Felix Fietkau827e69b2009-11-15 23:09:25 +01001889 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001890 }
Sujithe8324352009-01-16 21:38:42 +05301891}
1892
1893static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001894 struct ath_txq *txq, struct list_head *bf_q,
1895 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301896{
1897 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301898 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301899 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301900
Sujithe8324352009-01-16 21:38:42 +05301901 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301902 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301903
1904 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301905 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301906
1907 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301908 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301909 }
1910
Ben Greearc1739eb32010-10-14 12:45:29 -07001911 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001912 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001913
1914 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001915 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001916 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001917 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001918 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001919 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001920 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001921 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1922 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001923 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001924 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1925 * accidentally reference it later.
1926 */
1927 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301928
1929 /*
1930 * Return the list of ath_buf of this mpdu to free queue
1931 */
1932 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1933 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1934 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1935}
1936
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001937static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001938 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301939{
Sujitha22be222009-03-30 15:28:36 +05301940 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301941 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301942 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001943 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001944 struct ath_softc *sc = bf->aphy->sc;
1945 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301946 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301947
Sujith95e4acb2009-03-13 08:56:09 +05301948 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001949 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301950
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001951 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301952 WARN_ON(tx_rateindex >= hw->max_rates);
1953
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001954 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301955 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001956 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001957 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301958
Felix Fietkaub572d032010-11-14 15:20:07 +01001959 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001960
Felix Fietkaub572d032010-11-14 15:20:07 +01001961 tx_info->status.ampdu_len = nframes;
1962 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001963 }
1964
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001965 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301966 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001967 /*
1968 * If an underrun error is seen assume it as an excessive
1969 * retry only if max frame trigger level has been reached
1970 * (2 KB for single stream, and 4 KB for dual stream).
1971 * Adjust the long retry as if the frame was tried
1972 * hw->max_rate_tries times to affect how rate control updates
1973 * PER for the failed rate.
1974 * In case of congestion on the bus penalizing this type of
1975 * underruns should help hardware actually transmit new frames
1976 * successfully by eventually preferring slower rates.
1977 * This itself should also alleviate congestion on the bus.
1978 */
1979 if (ieee80211_is_data(hdr->frame_control) &&
1980 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1981 ATH9K_TX_DELIM_UNDERRUN)) &&
1982 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1983 tx_info->status.rates[tx_rateindex].count =
1984 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301985 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301986
Felix Fietkau545750d2009-11-23 22:21:01 +01001987 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301988 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001989 tx_info->status.rates[i].idx = -1;
1990 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301991
Felix Fietkau78c46532010-06-25 01:26:16 +02001992 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301993}
1994
Felix Fietkau066dae92010-11-07 14:59:39 +01001995static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301996{
Felix Fietkau066dae92010-11-07 14:59:39 +01001997 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301998
Felix Fietkau066dae92010-11-07 14:59:39 +01001999 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05302000 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01002001 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07002002 if (ath_mac80211_start_queue(sc, qnum))
2003 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05302004 }
2005 spin_unlock_bh(&txq->axq_lock);
2006}
2007
Sujithc4288392008-11-18 09:09:30 +05302008static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002009{
Sujithcbe61d82009-02-09 13:27:12 +05302010 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002011 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2013 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302014 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002015 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302016 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002017 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002018 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002019
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002020 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2021 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2022 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002023
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002024 for (;;) {
2025 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002026 if (list_empty(&txq->axq_q)) {
2027 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002028 spin_unlock_bh(&txq->axq_lock);
2029 break;
2030 }
2031 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2032
2033 /*
2034 * There is a race condition that a BH gets scheduled
2035 * after sw writes TxE and before hw re-load the last
2036 * descriptor to get the newly chained one.
2037 * Software must keep the last DONE descriptor as a
2038 * holding descriptor - software does so by marking
2039 * it with the STALE flag.
2040 */
2041 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302042 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002043 bf_held = bf;
2044 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302045 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002046 break;
2047 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002048 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302049 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002050 }
2051 }
2052
2053 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302054 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002055
Felix Fietkau29bffa92010-03-29 20:14:23 -07002056 memset(&ts, 0, sizeof(ts));
2057 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002058 if (status == -EINPROGRESS) {
2059 spin_unlock_bh(&txq->axq_lock);
2060 break;
2061 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002062
2063 /*
2064 * Remove ath_buf's of the same transmit unit from txq,
2065 * however leave the last descriptor back as the holding
2066 * descriptor for hw.
2067 */
Sujitha119cc42009-03-30 15:28:38 +05302068 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002070 if (!list_is_singular(&lastbf->list))
2071 list_cut_position(&bf_head,
2072 &txq->axq_q, lastbf->list.prev);
2073
2074 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002075 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002076 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002077 if (bf_held)
2078 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 spin_unlock_bh(&txq->axq_lock);
2080
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002081 if (bf_held)
2082 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002083
Sujithcd3d39a2008-08-11 14:03:34 +05302084 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 /*
2086 * This frame is sent out as a single frame.
2087 * Use hardware retry status for this frame.
2088 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002089 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302090 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002091 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002092 }
Johannes Berge6a98542008-10-21 12:40:02 +02002093
Felix Fietkau066dae92010-11-07 14:59:39 +01002094 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2095
Sujithcd3d39a2008-08-11 14:03:34 +05302096 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002097 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002099 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002100
Felix Fietkau066dae92010-11-07 14:59:39 +01002101 if (txq == sc->tx.txq_map[qnum])
2102 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302103
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002104 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302105 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002106 ath_txq_schedule(sc, txq);
2107 spin_unlock_bh(&txq->axq_lock);
2108 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109}
2110
Sujith305fe472009-07-23 15:32:29 +05302111static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002112{
2113 struct ath_softc *sc = container_of(work, struct ath_softc,
2114 tx_complete_work.work);
2115 struct ath_txq *txq;
2116 int i;
2117 bool needreset = false;
2118
2119 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2120 if (ATH_TXQ_SETUP(sc, i)) {
2121 txq = &sc->tx.txq[i];
2122 spin_lock_bh(&txq->axq_lock);
2123 if (txq->axq_depth) {
2124 if (txq->axq_tx_inprogress) {
2125 needreset = true;
2126 spin_unlock_bh(&txq->axq_lock);
2127 break;
2128 } else {
2129 txq->axq_tx_inprogress = true;
2130 }
2131 }
2132 spin_unlock_bh(&txq->axq_lock);
2133 }
2134
2135 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002136 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2137 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302138 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002139 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302140 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002141 }
2142
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002143 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002144 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2145}
2146
2147
Sujithe8324352009-01-16 21:38:42 +05302148
2149void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002150{
Sujithe8324352009-01-16 21:38:42 +05302151 int i;
2152 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002153
Sujithe8324352009-01-16 21:38:42 +05302154 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002155
2156 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302157 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2158 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002159 }
2160}
2161
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002162void ath_tx_edma_tasklet(struct ath_softc *sc)
2163{
2164 struct ath_tx_status txs;
2165 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2166 struct ath_hw *ah = sc->sc_ah;
2167 struct ath_txq *txq;
2168 struct ath_buf *bf, *lastbf;
2169 struct list_head bf_head;
2170 int status;
2171 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002172 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002173
2174 for (;;) {
2175 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2176 if (status == -EINPROGRESS)
2177 break;
2178 if (status == -EIO) {
2179 ath_print(common, ATH_DBG_XMIT,
2180 "Error processing tx status\n");
2181 break;
2182 }
2183
2184 /* Skip beacon completions */
2185 if (txs.qid == sc->beacon.beaconq)
2186 continue;
2187
2188 txq = &sc->tx.txq[txs.qid];
2189
2190 spin_lock_bh(&txq->axq_lock);
2191 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2192 spin_unlock_bh(&txq->axq_lock);
2193 return;
2194 }
2195
2196 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2197 struct ath_buf, list);
2198 lastbf = bf->bf_lastbf;
2199
2200 INIT_LIST_HEAD(&bf_head);
2201 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2202 &lastbf->list);
2203 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2204 txq->axq_depth--;
2205 txq->axq_tx_inprogress = false;
2206 spin_unlock_bh(&txq->axq_lock);
2207
2208 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2209
2210 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002211 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2212 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002213 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002214 }
2215
Felix Fietkau066dae92010-11-07 14:59:39 +01002216 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2217
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002218 if (bf_isampdu(bf))
2219 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2220 else
2221 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2222 &txs, txok, 0);
2223
Felix Fietkau066dae92010-11-07 14:59:39 +01002224 if (txq == sc->tx.txq_map[qnum])
2225 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002226
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002227 spin_lock_bh(&txq->axq_lock);
2228 if (!list_empty(&txq->txq_fifo_pending)) {
2229 INIT_LIST_HEAD(&bf_head);
2230 bf = list_first_entry(&txq->txq_fifo_pending,
2231 struct ath_buf, list);
2232 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2233 &bf->bf_lastbf->list);
2234 ath_tx_txqaddbuf(sc, txq, &bf_head);
2235 } else if (sc->sc_flags & SC_OP_TXAGGR)
2236 ath_txq_schedule(sc, txq);
2237 spin_unlock_bh(&txq->axq_lock);
2238 }
2239}
2240
Sujithe8324352009-01-16 21:38:42 +05302241/*****************/
2242/* Init, Cleanup */
2243/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002244
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002245static int ath_txstatus_setup(struct ath_softc *sc, int size)
2246{
2247 struct ath_descdma *dd = &sc->txsdma;
2248 u8 txs_len = sc->sc_ah->caps.txs_len;
2249
2250 dd->dd_desc_len = size * txs_len;
2251 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2252 &dd->dd_desc_paddr, GFP_KERNEL);
2253 if (!dd->dd_desc)
2254 return -ENOMEM;
2255
2256 return 0;
2257}
2258
2259static int ath_tx_edma_init(struct ath_softc *sc)
2260{
2261 int err;
2262
2263 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2264 if (!err)
2265 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2266 sc->txsdma.dd_desc_paddr,
2267 ATH_TXSTATUS_RING_SIZE);
2268
2269 return err;
2270}
2271
2272static void ath_tx_edma_cleanup(struct ath_softc *sc)
2273{
2274 struct ath_descdma *dd = &sc->txsdma;
2275
2276 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2277 dd->dd_desc_paddr);
2278}
2279
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002280int ath_tx_init(struct ath_softc *sc, int nbufs)
2281{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002282 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002283 int error = 0;
2284
Sujith797fe5cb2009-03-30 15:28:45 +05302285 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002286
Sujith797fe5cb2009-03-30 15:28:45 +05302287 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002288 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302289 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002290 ath_print(common, ATH_DBG_FATAL,
2291 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302292 goto err;
2293 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002294
Sujith797fe5cb2009-03-30 15:28:45 +05302295 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002296 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302297 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002298 ath_print(common, ATH_DBG_FATAL,
2299 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302300 goto err;
2301 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002302
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002303 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2304
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002305 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2306 error = ath_tx_edma_init(sc);
2307 if (error)
2308 goto err;
2309 }
2310
Sujith797fe5cb2009-03-30 15:28:45 +05302311err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002312 if (error != 0)
2313 ath_tx_cleanup(sc);
2314
2315 return error;
2316}
2317
Sujith797fe5cb2009-03-30 15:28:45 +05302318void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002319{
Sujithb77f4832008-12-07 21:44:03 +05302320 if (sc->beacon.bdma.dd_desc_len != 0)
2321 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002322
Sujithb77f4832008-12-07 21:44:03 +05302323 if (sc->tx.txdma.dd_desc_len != 0)
2324 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002325
2326 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2327 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002328}
2329
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002330void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2331{
Sujithc5170162008-10-29 10:13:59 +05302332 struct ath_atx_tid *tid;
2333 struct ath_atx_ac *ac;
2334 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002335
Sujith8ee5afb2008-12-07 21:43:36 +05302336 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302337 tidno < WME_NUM_TID;
2338 tidno++, tid++) {
2339 tid->an = an;
2340 tid->tidno = tidno;
2341 tid->seq_start = tid->seq_next = 0;
2342 tid->baw_size = WME_MAX_BA;
2343 tid->baw_head = tid->baw_tail = 0;
2344 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302345 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302346 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302347 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302348 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302349 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302350 tid->state &= ~AGGR_ADDBA_COMPLETE;
2351 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302352 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002353
Sujith8ee5afb2008-12-07 21:43:36 +05302354 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302355 acno < WME_NUM_AC; acno++, ac++) {
2356 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002357 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302358 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002359 }
2360}
2361
Sujithb5aa9bf2008-10-29 10:13:31 +05302362void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002363{
Felix Fietkau2b409942010-07-07 19:42:08 +02002364 struct ath_atx_ac *ac;
2365 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002367 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302368
Felix Fietkau2b409942010-07-07 19:42:08 +02002369 for (tidno = 0, tid = &an->tid[tidno];
2370 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371
Felix Fietkau2b409942010-07-07 19:42:08 +02002372 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002373 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002374
Felix Fietkau2b409942010-07-07 19:42:08 +02002375 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002376
Felix Fietkau2b409942010-07-07 19:42:08 +02002377 if (tid->sched) {
2378 list_del(&tid->list);
2379 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002380 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002381
2382 if (ac->sched) {
2383 list_del(&ac->list);
2384 tid->ac->sched = false;
2385 }
2386
2387 ath_tid_drain(sc, txq, tid);
2388 tid->state &= ~AGGR_ADDBA_COMPLETE;
2389 tid->state &= ~AGGR_CLEANUP;
2390
2391 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002392 }
2393}