blob: c35033f1a5e08dbd4b7a5e83fdd72b09993d0edd [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
Felix Fietkaub572d032010-11-14 15:20:07 +0100337 isaggr = bf_isaggr(bf);
338 if (isaggr) {
339 seq_st = ts->ts_seqnum;
340 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
341 }
342
343 while (bf) {
344 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
345
346 (*nframes)++;
347 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
348 (*nbad)++;
349
350 bf = bf->bf_next;
351 }
352}
353
354
Sujithd43f30152009-01-16 21:38:53 +0530355static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
356 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100357 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530358{
359 struct ath_node *an = NULL;
360 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530361 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800362 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530363 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800364 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530365 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530366 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530367 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530368 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530369 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530370 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
371 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200372 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100373 u16 bf_seqno;
Björn Smedmanebd02282010-10-10 22:44:39 +0200374 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100375 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530376
Sujitha22be222009-03-30 15:28:36 +0530377 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530378 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530379
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800380 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100381 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800382
Felix Fietkau78c46532010-06-25 01:26:16 +0200383 memcpy(rates, tx_info->control.rates, sizeof(rates));
384
Sujith1286ec62009-01-27 13:30:37 +0530385 rcu_read_lock();
386
Ben Greear686b9cb2010-09-23 09:44:36 -0700387 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530388 if (!sta) {
389 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200390
Felix Fietkau31e79a52010-07-12 23:16:34 +0200391 INIT_LIST_HEAD(&bf_head);
392 while (bf) {
393 bf_next = bf->bf_next;
394
395 bf->bf_state.bf_type |= BUF_XRETRY;
396 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
397 !bf->bf_stale || bf_next != NULL)
398 list_move_tail(&bf->list, &bf_head);
399
Felix Fietkaub572d032010-11-14 15:20:07 +0100400 ath_tx_rc_status(bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200401 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
402 0, 0);
403
404 bf = bf_next;
405 }
Sujith1286ec62009-01-27 13:30:37 +0530406 return;
Sujithe8324352009-01-16 21:38:42 +0530407 }
408
Sujith1286ec62009-01-27 13:30:37 +0530409 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100410 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
411 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530412
Felix Fietkaub11b1602010-07-11 12:48:44 +0200413 /*
414 * The hardware occasionally sends a tx status for the wrong TID.
415 * In this case, the BA status cannot be considered valid and all
416 * subframes need to be retransmitted
417 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100418 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200419 txok = false;
420
Sujithe8324352009-01-16 21:38:42 +0530421 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530422 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530423
Sujithd43f30152009-01-16 21:38:53 +0530424 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700425 if (ts->ts_flags & ATH9K_TX_BA) {
426 seq_st = ts->ts_seqnum;
427 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530428 } else {
Sujithd43f30152009-01-16 21:38:53 +0530429 /*
430 * AR5416 can become deaf/mute when BA
431 * issue happens. Chip needs to be reset.
432 * But AP code may have sychronization issues
433 * when perform internal reset in this routine.
434 * Only enable reset in STA mode for now.
435 */
Sujith2660b812009-02-09 13:27:26 +0530436 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530437 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530438 }
439 }
440
441 INIT_LIST_HEAD(&bf_pending);
442 INIT_LIST_HEAD(&bf_head);
443
Felix Fietkaub572d032010-11-14 15:20:07 +0100444 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530445 while (bf) {
446 txfail = txpending = 0;
447 bf_next = bf->bf_next;
448
Felix Fietkau78c46532010-06-25 01:26:16 +0200449 skb = bf->bf_mpdu;
450 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100451 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200452
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100453 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530454 /* transmit completion, subframe is
455 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530456 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530457 } else if (!isaggr && txok) {
458 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530459 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530460 } else {
Felix Fietkauc5992612010-11-14 15:20:09 +0100461 if (!(tid->state & AGGR_CLEANUP) && retry) {
Sujithe8324352009-01-16 21:38:42 +0530462 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530463 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530464 txpending = 1;
465 } else {
466 bf->bf_state.bf_type |= BUF_XRETRY;
467 txfail = 1;
468 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530469 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530470 }
471 } else {
472 /*
473 * cleanup in progress, just fail
474 * the un-acked sub-frames
475 */
476 txfail = 1;
477 }
478 }
479
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400480 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
481 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530482 /*
483 * Make sure the last desc is reclaimed if it
484 * not a holding desc.
485 */
486 if (!bf_last->bf_stale)
487 list_move_tail(&bf->list, &bf_head);
488 else
489 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530490 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700491 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530492 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530493 }
494
Felix Fietkau90fa5392010-09-20 13:45:38 +0200495 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530496 /*
497 * complete the acked-ones/xretried ones; update
498 * block-ack window
499 */
500 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100501 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530502 spin_unlock_bh(&txq->axq_lock);
503
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530504 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200505 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaub572d032010-11-14 15:20:07 +0100506 ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530507 rc_update = false;
508 } else {
Felix Fietkaub572d032010-11-14 15:20:07 +0100509 ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530510 }
511
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700512 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
513 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530514 } else {
Sujithd43f30152009-01-16 21:38:53 +0530515 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400516 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
517 if (bf->bf_next == NULL && bf_last->bf_stale) {
518 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530519
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400520 tbf = ath_clone_txbuf(sc, bf_last);
521 /*
522 * Update tx baw and complete the
523 * frame with failed status if we
524 * run out of tx buf.
525 */
526 if (!tbf) {
527 spin_lock_bh(&txq->axq_lock);
528 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100529 bf_seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400530 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400531
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400532 bf->bf_state.bf_type |=
533 BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +0100534 ath_tx_rc_status(bf, ts, nframes,
535 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400536 ath_tx_complete_buf(sc, bf, txq,
537 &bf_head,
538 ts, 0, 0);
539 break;
540 }
541
542 ath9k_hw_cleartxdesc(sc->sc_ah,
543 tbf->bf_desc);
544 list_add_tail(&tbf->list, &bf_head);
545 } else {
546 /*
547 * Clear descriptor status words for
548 * software retry
549 */
550 ath9k_hw_cleartxdesc(sc->sc_ah,
551 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400552 }
Sujithe8324352009-01-16 21:38:42 +0530553 }
554
555 /*
556 * Put this buffer to the temporary pending
557 * queue to retain ordering
558 */
559 list_splice_tail_init(&bf_head, &bf_pending);
560 }
561
562 bf = bf_next;
563 }
564
Felix Fietkau4cee7862010-07-23 03:53:16 +0200565 /* prepend un-acked frames to the beginning of the pending frame queue */
566 if (!list_empty(&bf_pending)) {
567 spin_lock_bh(&txq->axq_lock);
568 list_splice(&bf_pending, &tid->buf_q);
569 ath_tx_queue_tid(txq, tid);
570 spin_unlock_bh(&txq->axq_lock);
571 }
572
Sujithe8324352009-01-16 21:38:42 +0530573 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200574 ath_tx_flush_tid(sc, tid);
575
Sujithe8324352009-01-16 21:38:42 +0530576 if (tid->baw_head == tid->baw_tail) {
577 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530578 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530579 }
Sujithe8324352009-01-16 21:38:42 +0530580 }
581
Sujith1286ec62009-01-27 13:30:37 +0530582 rcu_read_unlock();
583
Sujithe8324352009-01-16 21:38:42 +0530584 if (needreset)
585 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530586}
587
588static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
589 struct ath_atx_tid *tid)
590{
Sujithe8324352009-01-16 21:38:42 +0530591 struct sk_buff *skb;
592 struct ieee80211_tx_info *tx_info;
593 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530594 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530595 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530596 int i;
597
Sujitha22be222009-03-30 15:28:36 +0530598 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530599 tx_info = IEEE80211_SKB_CB(skb);
600 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530601
602 /*
603 * Find the lowest frame length among the rate series that will have a
604 * 4ms transmit duration.
605 * TODO - TXOP limit needs to be considered.
606 */
607 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
608
609 for (i = 0; i < 4; i++) {
610 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100611 int modeidx;
612 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530613 legacy = 1;
614 break;
615 }
616
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200617 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100618 modeidx = MCS_HT40;
619 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200620 modeidx = MCS_HT20;
621
622 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
623 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100624
625 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530626 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530627 }
628 }
629
630 /*
631 * limit aggregate size by the minimum rate if rate selected is
632 * not a probe rate, if rate selected is a probe rate then
633 * avoid aggregation of this packet.
634 */
635 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
636 return 0;
637
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530638 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
639 aggr_limit = min((max_4ms_framelen * 3) / 8,
640 (u32)ATH_AMPDU_LIMIT_MAX);
641 else
642 aggr_limit = min(max_4ms_framelen,
643 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530644
645 /*
646 * h/w can accept aggregates upto 16 bit lengths (65535).
647 * The IE, however can hold upto 65536, which shows up here
648 * as zero. Ignore 65536 since we are constrained by hw.
649 */
Sujith4ef70842009-07-23 15:32:41 +0530650 if (tid->an->maxampdu)
651 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530652
653 return aggr_limit;
654}
655
656/*
Sujithd43f30152009-01-16 21:38:53 +0530657 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530658 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530659 */
660static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
661 struct ath_buf *bf, u16 frmlen)
662{
Sujithe8324352009-01-16 21:38:42 +0530663 struct sk_buff *skb = bf->bf_mpdu;
664 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530665 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530666 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100667 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200668 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530669
670 /* Select standard number of delimiters based on frame length alone */
671 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
672
673 /*
674 * If encryption enabled, hardware requires some more padding between
675 * subframes.
676 * TODO - this could be improved to be dependent on the rate.
677 * The hardware can keep up at lower rates, but not higher rates
678 */
Felix Fietkau952cd692010-11-14 15:20:03 +0100679 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +0530680 ndelim += ATH_AGGR_ENCRYPTDELIM;
681
682 /*
683 * Convert desired mpdu density from microeconds to bytes based
684 * on highest rate in rate series (i.e. first rate) to determine
685 * required minimum length for subframe. Take into account
686 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530687 *
Sujithe8324352009-01-16 21:38:42 +0530688 * If there is no mpdu density restriction, no further calculation
689 * is needed.
690 */
Sujith4ef70842009-07-23 15:32:41 +0530691
692 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530693 return ndelim;
694
695 rix = tx_info->control.rates[0].idx;
696 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530697 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
698 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
699
700 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530701 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530702 else
Sujith4ef70842009-07-23 15:32:41 +0530703 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530704
705 if (nsymbols == 0)
706 nsymbols = 1;
707
Felix Fietkauc6663872010-04-19 19:57:33 +0200708 streams = HT_RC_2_STREAMS(rix);
709 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530710 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
711
Sujithe8324352009-01-16 21:38:42 +0530712 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530713 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
714 ndelim = max(mindelim, ndelim);
715 }
716
717 return ndelim;
718}
719
720static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530721 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530722 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100723 struct list_head *bf_q,
724 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530725{
726#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530727 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
728 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530729 u16 aggr_limit = 0, al = 0, bpad = 0,
730 al_delta, h_baw = tid->baw_size / 2;
731 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200732 struct ieee80211_tx_info *tx_info;
Felix Fietkau76e45222010-11-14 15:20:08 +0100733 int frmlen;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100734 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530735
736 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
737
738 do {
739 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100740 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530741
Sujithd43f30152009-01-16 21:38:53 +0530742 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100743 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530744 status = ATH_AGGR_BAW_CLOSED;
745 break;
746 }
747
748 if (!rl) {
749 aggr_limit = ath_lookup_rate(sc, bf, tid);
750 rl = 1;
751 }
752
Sujithd43f30152009-01-16 21:38:53 +0530753 /* do not exceed aggregation limit */
Felix Fietkau76e45222010-11-14 15:20:08 +0100754 frmlen = ath_frame_len(bf->bf_mpdu);
755 al_delta = ATH_AGGR_DELIM_SZ + frmlen;
Sujithe8324352009-01-16 21:38:42 +0530756
Sujithd43f30152009-01-16 21:38:53 +0530757 if (nframes &&
758 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530759 status = ATH_AGGR_LIMITED;
760 break;
761 }
762
Felix Fietkau0299a502010-10-21 02:47:24 +0200763 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
764 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
765 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
766 break;
767
Sujithd43f30152009-01-16 21:38:53 +0530768 /* do not exceed subframe limit */
769 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530770 status = ATH_AGGR_LIMITED;
771 break;
772 }
Sujithd43f30152009-01-16 21:38:53 +0530773 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530774
Sujithd43f30152009-01-16 21:38:53 +0530775 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530776 al += bpad + al_delta;
777
778 /*
779 * Get the delimiters needed to meet the MPDU
780 * density for this node.
781 */
Felix Fietkau76e45222010-11-14 15:20:08 +0100782 ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530783 bpad = PADBYTES(al_delta) + (ndelim << 2);
784
785 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400786 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530787
Sujithd43f30152009-01-16 21:38:53 +0530788 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100789 if (!bf_isretried(bf))
790 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530791 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
792 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530793 if (bf_prev) {
794 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400795 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
796 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530797 }
798 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530799
Sujithe8324352009-01-16 21:38:42 +0530800 } while (!list_empty(&tid->buf_q));
801
Felix Fietkau269c44b2010-11-14 15:20:06 +0100802 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530803
Sujithe8324352009-01-16 21:38:42 +0530804 return status;
805#undef PADBYTES
806}
807
808static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
809 struct ath_atx_tid *tid)
810{
Sujithd43f30152009-01-16 21:38:53 +0530811 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530812 enum ATH_AGGR_STATUS status;
813 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100814 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530815
816 do {
817 if (list_empty(&tid->buf_q))
818 return;
819
820 INIT_LIST_HEAD(&bf_q);
821
Felix Fietkau269c44b2010-11-14 15:20:06 +0100822 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530823
824 /*
Sujithd43f30152009-01-16 21:38:53 +0530825 * no frames picked up to be aggregated;
826 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530827 */
828 if (list_empty(&bf_q))
829 break;
830
831 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530832 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530833
Sujithd43f30152009-01-16 21:38:53 +0530834 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100835 if (bf == bf->bf_lastbf) {
Sujithe8324352009-01-16 21:38:42 +0530836 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530837 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau76e45222010-11-14 15:20:08 +0100838 ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +0530839 ath_tx_txqaddbuf(sc, txq, &bf_q);
840 continue;
841 }
842
Sujithd43f30152009-01-16 21:38:53 +0530843 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530844 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100845 ath_buf_set_rate(sc, bf, aggr_len);
846 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530847
Sujithd43f30152009-01-16 21:38:53 +0530848 /* anchor last desc of aggregate */
849 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530850
Sujithe8324352009-01-16 21:38:42 +0530851 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530852 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530853
854 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
855 status != ATH_AGGR_BAW_CLOSED);
856}
857
Felix Fietkau231c3a12010-09-20 19:35:28 +0200858int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
859 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530860{
861 struct ath_atx_tid *txtid;
862 struct ath_node *an;
863
864 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530865 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200866
867 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
868 return -EAGAIN;
869
Sujithf83da962009-07-23 15:32:37 +0530870 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200871 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530872 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200873
874 return 0;
Sujithe8324352009-01-16 21:38:42 +0530875}
876
Sujithf83da962009-07-23 15:32:37 +0530877void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530878{
879 struct ath_node *an = (struct ath_node *)sta->drv_priv;
880 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100881 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530882
883 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530884 return;
Sujithe8324352009-01-16 21:38:42 +0530885
886 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530887 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530888 return;
Sujithe8324352009-01-16 21:38:42 +0530889 }
890
Sujithe8324352009-01-16 21:38:42 +0530891 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200892 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200893
894 /*
895 * If frames are still being transmitted for this TID, they will be
896 * cleaned up during tx completion. To prevent race conditions, this
897 * TID can only be reused after all in-progress subframes have been
898 * completed.
899 */
900 if (txtid->baw_head != txtid->baw_tail)
901 txtid->state |= AGGR_CLEANUP;
902 else
903 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530904 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530905
Felix Fietkau90fa5392010-09-20 13:45:38 +0200906 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530907}
908
909void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
910{
911 struct ath_atx_tid *txtid;
912 struct ath_node *an;
913
914 an = (struct ath_node *)sta->drv_priv;
915
916 if (sc->sc_flags & SC_OP_TXAGGR) {
917 txtid = ATH_AN_2_TID(an, tid);
918 txtid->baw_size =
919 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
920 txtid->state |= AGGR_ADDBA_COMPLETE;
921 txtid->state &= ~AGGR_ADDBA_PROGRESS;
922 ath_tx_resume_tid(sc, txtid);
923 }
924}
925
Sujithe8324352009-01-16 21:38:42 +0530926/********************/
927/* Queue Management */
928/********************/
929
Sujithe8324352009-01-16 21:38:42 +0530930static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
931 struct ath_txq *txq)
932{
933 struct ath_atx_ac *ac, *ac_tmp;
934 struct ath_atx_tid *tid, *tid_tmp;
935
936 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
937 list_del(&ac->list);
938 ac->sched = false;
939 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
940 list_del(&tid->list);
941 tid->sched = false;
942 ath_tid_drain(sc, txq, tid);
943 }
944 }
945}
946
947struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
948{
Sujithcbe61d82009-02-09 13:27:12 +0530949 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700950 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530951 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100952 static const int subtype_txq_to_hwq[] = {
953 [WME_AC_BE] = ATH_TXQ_AC_BE,
954 [WME_AC_BK] = ATH_TXQ_AC_BK,
955 [WME_AC_VI] = ATH_TXQ_AC_VI,
956 [WME_AC_VO] = ATH_TXQ_AC_VO,
957 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400958 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530959
960 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100961 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530962 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
963 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
964 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
965 qi.tqi_physCompBuf = 0;
966
967 /*
968 * Enable interrupts only for EOL and DESC conditions.
969 * We mark tx descriptors to receive a DESC interrupt
970 * when a tx queue gets deep; otherwise waiting for the
971 * EOL to reap descriptors. Note that this is done to
972 * reduce interrupt load and this only defers reaping
973 * descriptors, never transmitting frames. Aside from
974 * reducing interrupts this also permits more concurrency.
975 * The only potential downside is if the tx queue backs
976 * up in which case the top half of the kernel may backup
977 * due to a lack of tx descriptors.
978 *
979 * The UAPSD queue is an exception, since we take a desc-
980 * based intr on the EOSP frames.
981 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400982 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
983 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
984 TXQ_FLAG_TXERRINT_ENABLE;
985 } else {
986 if (qtype == ATH9K_TX_QUEUE_UAPSD)
987 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
988 else
989 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
990 TXQ_FLAG_TXDESCINT_ENABLE;
991 }
Sujithe8324352009-01-16 21:38:42 +0530992 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
993 if (qnum == -1) {
994 /*
995 * NB: don't print a message, this happens
996 * normally on parts with too few tx queues
997 */
998 return NULL;
999 }
1000 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001001 ath_print(common, ATH_DBG_FATAL,
1002 "qnum %u out of range, max %u!\n",
1003 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +05301004 ath9k_hw_releasetxqueue(ah, qnum);
1005 return NULL;
1006 }
1007 if (!ATH_TXQ_SETUP(sc, qnum)) {
1008 struct ath_txq *txq = &sc->tx.txq[qnum];
1009
1010 txq->axq_qnum = qnum;
1011 txq->axq_link = NULL;
1012 INIT_LIST_HEAD(&txq->axq_q);
1013 INIT_LIST_HEAD(&txq->axq_acq);
1014 spin_lock_init(&txq->axq_lock);
1015 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001016 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +05301017 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001018
1019 txq->txq_headidx = txq->txq_tailidx = 0;
1020 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1021 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1022 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301023 }
1024 return &sc->tx.txq[qnum];
1025}
1026
Sujithe8324352009-01-16 21:38:42 +05301027int ath_txq_update(struct ath_softc *sc, int qnum,
1028 struct ath9k_tx_queue_info *qinfo)
1029{
Sujithcbe61d82009-02-09 13:27:12 +05301030 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301031 int error = 0;
1032 struct ath9k_tx_queue_info qi;
1033
1034 if (qnum == sc->beacon.beaconq) {
1035 /*
1036 * XXX: for beacon queue, we just save the parameter.
1037 * It will be picked up by ath_beaconq_config when
1038 * it's necessary.
1039 */
1040 sc->beacon.beacon_qi = *qinfo;
1041 return 0;
1042 }
1043
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001044 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301045
1046 ath9k_hw_get_txq_props(ah, qnum, &qi);
1047 qi.tqi_aifs = qinfo->tqi_aifs;
1048 qi.tqi_cwmin = qinfo->tqi_cwmin;
1049 qi.tqi_cwmax = qinfo->tqi_cwmax;
1050 qi.tqi_burstTime = qinfo->tqi_burstTime;
1051 qi.tqi_readyTime = qinfo->tqi_readyTime;
1052
1053 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001054 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1055 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301056 error = -EIO;
1057 } else {
1058 ath9k_hw_resettxqueue(ah, qnum);
1059 }
1060
1061 return error;
1062}
1063
1064int ath_cabq_update(struct ath_softc *sc)
1065{
1066 struct ath9k_tx_queue_info qi;
1067 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301068
1069 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1070 /*
1071 * Ensure the readytime % is within the bounds.
1072 */
Sujith17d79042009-02-09 13:27:03 +05301073 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1074 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1075 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1076 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301077
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001078 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301079 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301080 ath_txq_update(sc, qnum, &qi);
1081
1082 return 0;
1083}
1084
Sujith043a0402009-01-16 21:38:47 +05301085/*
1086 * Drain a given TX queue (could be Beacon or Data)
1087 *
1088 * This assumes output has been stopped and
1089 * we do not need to block ath_tx_tasklet.
1090 */
1091void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301092{
1093 struct ath_buf *bf, *lastbf;
1094 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001095 struct ath_tx_status ts;
1096
1097 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301098 INIT_LIST_HEAD(&bf_head);
1099
Sujithe8324352009-01-16 21:38:42 +05301100 for (;;) {
1101 spin_lock_bh(&txq->axq_lock);
1102
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001103 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1104 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1105 txq->txq_headidx = txq->txq_tailidx = 0;
1106 spin_unlock_bh(&txq->axq_lock);
1107 break;
1108 } else {
1109 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1110 struct ath_buf, list);
1111 }
1112 } else {
1113 if (list_empty(&txq->axq_q)) {
1114 txq->axq_link = NULL;
1115 spin_unlock_bh(&txq->axq_lock);
1116 break;
1117 }
1118 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1119 list);
Sujithe8324352009-01-16 21:38:42 +05301120
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001121 if (bf->bf_stale) {
1122 list_del(&bf->list);
1123 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301124
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001125 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001126 continue;
1127 }
Sujithe8324352009-01-16 21:38:42 +05301128 }
1129
1130 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05301131
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001132 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1133 list_cut_position(&bf_head,
1134 &txq->txq_fifo[txq->txq_tailidx],
1135 &lastbf->list);
1136 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1137 } else {
1138 /* remove ath_buf's of the same mpdu from txq */
1139 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1140 }
1141
Sujithe8324352009-01-16 21:38:42 +05301142 txq->axq_depth--;
1143
1144 spin_unlock_bh(&txq->axq_lock);
1145
1146 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001147 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1148 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301149 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001150 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301151 }
1152
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001153 spin_lock_bh(&txq->axq_lock);
1154 txq->axq_tx_inprogress = false;
1155 spin_unlock_bh(&txq->axq_lock);
1156
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001157 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1158 spin_lock_bh(&txq->axq_lock);
1159 while (!list_empty(&txq->txq_fifo_pending)) {
1160 bf = list_first_entry(&txq->txq_fifo_pending,
1161 struct ath_buf, list);
1162 list_cut_position(&bf_head,
1163 &txq->txq_fifo_pending,
1164 &bf->bf_lastbf->list);
1165 spin_unlock_bh(&txq->axq_lock);
1166
1167 if (bf_isampdu(bf))
1168 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
Felix Fietkauc5992612010-11-14 15:20:09 +01001169 &ts, 0, retry_tx);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001170 else
1171 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1172 &ts, 0, 0);
1173 spin_lock_bh(&txq->axq_lock);
1174 }
1175 spin_unlock_bh(&txq->axq_lock);
1176 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001177
1178 /* flush any pending frames if aggregation is enabled */
1179 if (sc->sc_flags & SC_OP_TXAGGR) {
1180 if (!retry_tx) {
1181 spin_lock_bh(&txq->axq_lock);
1182 ath_txq_drain_pending_buffers(sc, txq);
1183 spin_unlock_bh(&txq->axq_lock);
1184 }
1185 }
Sujithe8324352009-01-16 21:38:42 +05301186}
1187
Sujith043a0402009-01-16 21:38:47 +05301188void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1189{
Sujithcbe61d82009-02-09 13:27:12 +05301190 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001191 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301192 struct ath_txq *txq;
1193 int i, npend = 0;
1194
1195 if (sc->sc_flags & SC_OP_INVALID)
1196 return;
1197
1198 /* Stop beacon queue */
1199 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1200
1201 /* Stop data queues */
1202 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1203 if (ATH_TXQ_SETUP(sc, i)) {
1204 txq = &sc->tx.txq[i];
1205 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1206 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1207 }
1208 }
1209
1210 if (npend) {
1211 int r;
1212
Sujithe8009e92009-12-14 14:57:08 +05301213 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001214 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301215
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001216 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301217 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001218 ath_print(common, ATH_DBG_FATAL,
1219 "Unable to reset hardware; reset status %d\n",
1220 r);
Sujith043a0402009-01-16 21:38:47 +05301221 }
1222
1223 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1224 if (ATH_TXQ_SETUP(sc, i))
1225 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1226 }
1227}
1228
Sujithe8324352009-01-16 21:38:42 +05301229void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1230{
1231 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1232 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1233}
1234
Sujithe8324352009-01-16 21:38:42 +05301235void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1236{
1237 struct ath_atx_ac *ac;
1238 struct ath_atx_tid *tid;
1239
1240 if (list_empty(&txq->axq_acq))
1241 return;
1242
1243 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1244 list_del(&ac->list);
1245 ac->sched = false;
1246
1247 do {
1248 if (list_empty(&ac->tid_q))
1249 return;
1250
1251 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1252 list_del(&tid->list);
1253 tid->sched = false;
1254
1255 if (tid->paused)
1256 continue;
1257
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001258 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301259
1260 /*
1261 * add tid to round-robin queue if more frames
1262 * are pending for the tid
1263 */
1264 if (!list_empty(&tid->buf_q))
1265 ath_tx_queue_tid(txq, tid);
1266
1267 break;
1268 } while (!list_empty(&ac->tid_q));
1269
1270 if (!list_empty(&ac->tid_q)) {
1271 if (!ac->sched) {
1272 ac->sched = true;
1273 list_add_tail(&ac->list, &txq->axq_acq);
1274 }
1275 }
1276}
1277
Sujithe8324352009-01-16 21:38:42 +05301278/***********/
1279/* TX, DMA */
1280/***********/
1281
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001282/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001283 * Insert a chain of ath_buf (descriptors) on a txq and
1284 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001285 */
Sujith102e0572008-10-29 10:15:16 +05301286static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1287 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001288{
Sujithcbe61d82009-02-09 13:27:12 +05301289 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001290 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001291 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301292
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001293 /*
1294 * Insert the frame on the outbound list and
1295 * pass it on to the hardware.
1296 */
1297
1298 if (list_empty(head))
1299 return;
1300
1301 bf = list_first_entry(head, struct ath_buf, list);
1302
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001303 ath_print(common, ATH_DBG_QUEUE,
1304 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001305
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001306 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1307 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1308 list_splice_tail_init(head, &txq->txq_fifo_pending);
1309 return;
1310 }
1311 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1312 ath_print(common, ATH_DBG_XMIT,
1313 "Initializing tx fifo %d which "
1314 "is non-empty\n",
1315 txq->txq_headidx);
1316 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1317 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1318 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001319 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001320 ath_print(common, ATH_DBG_XMIT,
1321 "TXDP[%u] = %llx (%p)\n",
1322 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001323 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001324 list_splice_tail_init(head, &txq->axq_q);
1325
1326 if (txq->axq_link == NULL) {
1327 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1328 ath_print(common, ATH_DBG_XMIT,
1329 "TXDP[%u] = %llx (%p)\n",
1330 txq->axq_qnum, ito64(bf->bf_daddr),
1331 bf->bf_desc);
1332 } else {
1333 *txq->axq_link = bf->bf_daddr;
1334 ath_print(common, ATH_DBG_XMIT,
1335 "link[%u] (%p)=%llx (%p)\n",
1336 txq->axq_qnum, txq->axq_link,
1337 ito64(bf->bf_daddr), bf->bf_desc);
1338 }
1339 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1340 &txq->axq_link);
1341 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001342 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001343 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001344}
1345
Sujithe8324352009-01-16 21:38:42 +05301346static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1347 struct list_head *bf_head,
Felix Fietkau76e45222010-11-14 15:20:08 +01001348 struct ath_tx_control *txctl, int frmlen)
Sujithe8324352009-01-16 21:38:42 +05301349{
1350 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001351 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301352
Sujithe8324352009-01-16 21:38:42 +05301353 bf = list_first_entry(bf_head, struct ath_buf, list);
1354 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301355 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001356 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301357
1358 /*
1359 * Do not queue to h/w when any of the following conditions is true:
1360 * - there are pending frames in software queue
1361 * - the TID is currently paused for ADDBA/BAR request
1362 * - seqno is not within block-ack window
1363 * - h/w queue depth exceeds low water mark
1364 */
1365 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001366 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301367 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001368 /*
Sujithe8324352009-01-16 21:38:42 +05301369 * Add this frame to software queue for scheduling later
1370 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001371 */
Sujithd43f30152009-01-16 21:38:53 +05301372 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301373 ath_tx_queue_tid(txctl->txq, tid);
1374 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001375 }
1376
Sujithe8324352009-01-16 21:38:42 +05301377 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001378 if (!bf_isretried(bf))
1379 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301380
1381 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301382 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001383 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301384 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301385}
1386
Felix Fietkau82b873a2010-11-11 03:18:37 +01001387static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1388 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +01001389 struct list_head *bf_head, int frmlen)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001390{
Sujithe8324352009-01-16 21:38:42 +05301391 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001392
Sujithe8324352009-01-16 21:38:42 +05301393 bf = list_first_entry(bf_head, struct ath_buf, list);
1394 bf->bf_state.bf_type &= ~BUF_AMPDU;
1395
1396 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001397 if (tid)
1398 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301399
Sujithd43f30152009-01-16 21:38:53 +05301400 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001401 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301402 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301403 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001404}
1405
Sujith528f0c62008-10-29 10:14:26 +05301406static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001407{
Sujith528f0c62008-10-29 10:14:26 +05301408 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409 enum ath9k_pkt_type htype;
1410 __le16 fc;
1411
Sujith528f0c62008-10-29 10:14:26 +05301412 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001413 fc = hdr->frame_control;
1414
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001415 if (ieee80211_is_beacon(fc))
1416 htype = ATH9K_PKT_TYPE_BEACON;
1417 else if (ieee80211_is_probe_resp(fc))
1418 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1419 else if (ieee80211_is_atim(fc))
1420 htype = ATH9K_PKT_TYPE_ATIM;
1421 else if (ieee80211_is_pspoll(fc))
1422 htype = ATH9K_PKT_TYPE_PSPOLL;
1423 else
1424 htype = ATH9K_PKT_TYPE_NORMAL;
1425
1426 return htype;
1427}
1428
Sujith528f0c62008-10-29 10:14:26 +05301429static void assign_aggr_tid_seqno(struct sk_buff *skb,
1430 struct ath_buf *bf)
1431{
1432 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1433 struct ieee80211_hdr *hdr;
1434 struct ath_node *an;
1435 struct ath_atx_tid *tid;
1436 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001437 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301438
1439 if (!tx_info->control.sta)
1440 return;
1441
1442 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1443 hdr = (struct ieee80211_hdr *)skb->data;
1444 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001445 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001446
Sujithe8324352009-01-16 21:38:42 +05301447 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001448 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301449 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301450 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001451 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301452 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301453 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301454}
1455
Felix Fietkau82b873a2010-11-11 03:18:37 +01001456static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301457{
1458 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1459 int flags = 0;
1460
1461 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1462 flags |= ATH9K_TXDESC_INTREQ;
1463
1464 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1465 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301466
Felix Fietkau82b873a2010-11-11 03:18:37 +01001467 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001468 flags |= ATH9K_TXDESC_LDPC;
1469
Sujith528f0c62008-10-29 10:14:26 +05301470 return flags;
1471}
1472
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001473/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001474 * rix - rate index
1475 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1476 * width - 0 for 20 MHz, 1 for 40 MHz
1477 * half_gi - to use 4us v/s 3.6 us for symbol time
1478 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001479static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301480 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001481{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001482 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001483 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301484
1485 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001486 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001488 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001489 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1490
1491 if (!half_gi)
1492 duration = SYMBOL_TIME(nsymbols);
1493 else
1494 duration = SYMBOL_TIME_HALFGI(nsymbols);
1495
Sujithe63835b2008-11-18 09:07:53 +05301496 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301498
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499 return duration;
1500}
1501
Felix Fietkau269c44b2010-11-14 15:20:06 +01001502static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001503{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001504 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301506 struct sk_buff *skb;
1507 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301508 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001509 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301510 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301511 int i, flags = 0;
1512 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301513 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301514
1515 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301516
Sujitha22be222009-03-30 15:28:36 +05301517 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301518 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301519 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301520 hdr = (struct ieee80211_hdr *)skb->data;
1521 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301522
Sujithc89424d2009-01-30 14:29:28 +05301523 /*
1524 * We check if Short Preamble is needed for the CTS rate by
1525 * checking the BSS's global flag.
1526 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1527 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001528 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1529 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301530 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001531 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001532
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001533 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001534 bool is_40, is_sgi, is_sp;
1535 int phy;
1536
Sujithe63835b2008-11-18 09:07:53 +05301537 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001538 continue;
1539
Sujitha8efee42008-11-18 09:07:30 +05301540 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301541 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001542 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001543
Felix Fietkau27032052010-01-17 21:08:50 +01001544 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1545 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301546 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001547 flags |= ATH9K_TXDESC_RTSENA;
1548 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1549 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1550 flags |= ATH9K_TXDESC_CTSENA;
1551 }
1552
Sujithc89424d2009-01-30 14:29:28 +05301553 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1554 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1555 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1556 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001557
Felix Fietkau545750d2009-11-23 22:21:01 +01001558 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1559 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1560 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1561
1562 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1563 /* MCS rates */
1564 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001565 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001566 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001567 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1568 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001569 continue;
1570 }
1571
1572 /* legcay rates */
1573 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1574 !(rate->flags & IEEE80211_RATE_ERP_G))
1575 phy = WLAN_RC_PHY_CCK;
1576 else
1577 phy = WLAN_RC_PHY_OFDM;
1578
1579 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1580 series[i].Rate = rate->hw_value;
1581 if (rate->hw_value_short) {
1582 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1583 series[i].Rate |= rate->hw_value_short;
1584 } else {
1585 is_sp = false;
1586 }
1587
1588 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001589 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001590 }
1591
Felix Fietkau27032052010-01-17 21:08:50 +01001592 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001593 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001594 flags &= ~ATH9K_TXDESC_RTSENA;
1595
1596 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1597 if (flags & ATH9K_TXDESC_RTSENA)
1598 flags &= ~ATH9K_TXDESC_CTSENA;
1599
Sujithe63835b2008-11-18 09:07:53 +05301600 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301601 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1602 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301603 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301604 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301605
Sujith17d79042009-02-09 13:27:03 +05301606 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301607 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001608}
1609
Felix Fietkau82b873a2010-11-11 03:18:37 +01001610static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1611 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301612{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001613 struct ath_wiphy *aphy = hw->priv;
1614 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001615 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301616 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001617 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301618 int hdrlen;
1619 __le16 fc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001620
1621 bf = ath_tx_get_buffer(sc);
1622 if (!bf) {
1623 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1624 return NULL;
1625 }
Sujithe8324352009-01-16 21:38:42 +05301626
Sujithe8324352009-01-16 21:38:42 +05301627 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1628 fc = hdr->frame_control;
1629
1630 ATH_TXBUF_RESET(bf);
1631
Felix Fietkau827e69b2009-11-15 23:09:25 +01001632 bf->aphy = aphy;
Sujithe8324352009-01-16 21:38:42 +05301633
Felix Fietkau82b873a2010-11-11 03:18:37 +01001634 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301635 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001636 if (sc->sc_flags & SC_OP_TXAGGR)
1637 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001638 }
Sujithe8324352009-01-16 21:38:42 +05301639
Felix Fietkau82b873a2010-11-11 03:18:37 +01001640 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301641
Sujithe8324352009-01-16 21:38:42 +05301642 bf->bf_mpdu = skb;
1643
Ben Greearc1739eb32010-10-14 12:45:29 -07001644 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1645 skb->len, DMA_TO_DEVICE);
1646 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301647 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001648 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001649 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1650 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001651 ath_tx_return_buffer(sc, bf);
1652 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301653 }
1654
Felix Fietkau82b873a2010-11-11 03:18:37 +01001655 return bf;
Sujithe8324352009-01-16 21:38:42 +05301656}
1657
1658/* FIXME: tx power */
1659static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1660 struct ath_tx_control *txctl)
1661{
Sujitha22be222009-03-30 15:28:36 +05301662 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301663 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301664 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301665 struct ath_node *an = NULL;
1666 struct list_head bf_head;
1667 struct ath_desc *ds;
1668 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301669 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001670 enum ath9k_key_type keytype;
Felix Fietkau30170472010-11-14 15:20:05 +01001671 u32 keyix;
Sujithe8324352009-01-16 21:38:42 +05301672 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301673 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001674 u8 tidno;
Felix Fietkau76e45222010-11-14 15:20:08 +01001675 int frmlen;
Sujithe8324352009-01-16 21:38:42 +05301676
1677 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301678 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301679
1680 INIT_LIST_HEAD(&bf_head);
1681 list_add_tail(&bf->list, &bf_head);
1682
1683 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001684 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301685
Felix Fietkau952cd692010-11-14 15:20:03 +01001686 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001687 if (tx_info->control.hw_key)
1688 keyix = tx_info->control.hw_key->hw_key_idx;
1689 else
1690 keyix = ATH9K_TXKEYIX_INVALID;
1691
Felix Fietkau76e45222010-11-14 15:20:08 +01001692 frmlen = ath_frame_len(bf->bf_mpdu);
1693 ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001694 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301695
1696 ath9k_hw_filltxdesc(ah, ds,
1697 skb->len, /* segment length */
1698 true, /* first segment */
1699 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001700 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001701 bf->bf_buf_addr,
1702 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301703
Sujithe8324352009-01-16 21:38:42 +05301704 spin_lock_bh(&txctl->txq->axq_lock);
1705
1706 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1707 tx_info->control.sta) {
1708 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001709 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1710 IEEE80211_QOS_CTL_TID_MASK;
1711 tid = ATH_AN_2_TID(an, tidno);
1712
Sujithe8324352009-01-16 21:38:42 +05301713
Felix Fietkau066dae92010-11-07 14:59:39 +01001714 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001715 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301716 /*
1717 * Try aggregation if it's a unicast data frame
1718 * and the destination is HT capable.
1719 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001720 ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301721 } else {
1722 /*
1723 * Send this frame as regular when ADDBA
1724 * exchange is neither complete nor pending.
1725 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001726 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301727 }
1728 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001729 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001730 bf->bf_state.bfs_paprd = txctl->paprd;
1731
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001732 if (bf->bf_state.bfs_paprd)
1733 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1734
Felix Fietkau76e45222010-11-14 15:20:08 +01001735 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301736 }
1737
1738 spin_unlock_bh(&txctl->txq->axq_lock);
1739}
1740
1741/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001742int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301743 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001745 struct ath_wiphy *aphy = hw->priv;
1746 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001747 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001749 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001750
Felix Fietkau82b873a2010-11-11 03:18:37 +01001751 bf = ath_tx_setup_buffer(hw, skb);
1752 if (unlikely(!bf))
1753 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001754
Felix Fietkau066dae92010-11-07 14:59:39 +01001755 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001756 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001757 if (txq == sc->tx.txq_map[q] &&
1758 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1759 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001760 txq->stopped = 1;
1761 }
1762 spin_unlock_bh(&txq->axq_lock);
1763
Sujithe8324352009-01-16 21:38:42 +05301764 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001765
1766 return 0;
1767}
1768
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001769void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001770{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001771 struct ath_wiphy *aphy = hw->priv;
1772 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001773 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001774 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1775 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301776 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1777 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001778
Sujithe8324352009-01-16 21:38:42 +05301779 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001780
Sujithe8324352009-01-16 21:38:42 +05301781 /*
1782 * As a temporary workaround, assign seq# here; this will likely need
1783 * to be cleaned up to work better with Beacon transmission and virtual
1784 * BSSes.
1785 */
1786 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301787 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1788 sc->tx.seq_no += 0x10;
1789 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1790 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001791 }
1792
Sujithe8324352009-01-16 21:38:42 +05301793 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001794 padpos = ath9k_cmn_padpos(hdr->frame_control);
1795 padsize = padpos & 3;
1796 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301797 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001798 ath_print(common, ATH_DBG_XMIT,
1799 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301800 dev_kfree_skb_any(skb);
1801 return;
1802 }
1803 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001804 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001805 }
1806
Sujithe8324352009-01-16 21:38:42 +05301807 txctl.txq = sc->beacon.cabq;
1808
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001809 ath_print(common, ATH_DBG_XMIT,
1810 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301811
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001812 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001813 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301814 goto exit;
1815 }
1816
1817 return;
1818exit:
1819 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001820}
1821
Sujithe8324352009-01-16 21:38:42 +05301822/*****************/
1823/* TX Completion */
1824/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001825
Sujithe8324352009-01-16 21:38:42 +05301826static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001827 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001828 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001829{
Sujithe8324352009-01-16 21:38:42 +05301830 struct ieee80211_hw *hw = sc->hw;
1831 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001832 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001833 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001834 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301835
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001836 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301837
Felix Fietkau827e69b2009-11-15 23:09:25 +01001838 if (aphy)
1839 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301840
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301841 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301842 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301843
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301844 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301845 /* Frame was ACKed */
1846 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1847 }
1848
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001849 padpos = ath9k_cmn_padpos(hdr->frame_control);
1850 padsize = padpos & 3;
1851 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301852 /*
1853 * Remove MAC header padding before giving the frame back to
1854 * mac80211.
1855 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001856 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301857 skb_pull(skb, padsize);
1858 }
1859
Sujith1b04b932010-01-08 10:36:05 +05301860 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1861 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001862 ath_print(common, ATH_DBG_PS,
1863 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001864 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301865 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1866 PS_WAIT_FOR_CAB |
1867 PS_WAIT_FOR_PSPOLL_DATA |
1868 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001869 }
1870
Felix Fietkau61117f02010-11-11 03:18:36 +01001871 if (unlikely(ftype))
1872 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001873 else {
1874 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001875 if (txq == sc->tx.txq_map[q]) {
1876 spin_lock_bh(&txq->axq_lock);
1877 if (WARN_ON(--txq->pending_frames < 0))
1878 txq->pending_frames = 0;
1879 spin_unlock_bh(&txq->axq_lock);
1880 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001881
Felix Fietkau827e69b2009-11-15 23:09:25 +01001882 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001883 }
Sujithe8324352009-01-16 21:38:42 +05301884}
1885
1886static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001887 struct ath_txq *txq, struct list_head *bf_q,
1888 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301889{
1890 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301891 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301892 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301893
Sujithe8324352009-01-16 21:38:42 +05301894 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301895 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301896
1897 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301898 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301899
1900 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301901 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301902 }
1903
Ben Greearc1739eb32010-10-14 12:45:29 -07001904 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001905 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001906
1907 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001908 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001909 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001910 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001911 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001912 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001913 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001914 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1915 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001916 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001917 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1918 * accidentally reference it later.
1919 */
1920 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301921
1922 /*
1923 * Return the list of ath_buf of this mpdu to free queue
1924 */
1925 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1926 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1927 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1928}
1929
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001930static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001931 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301932{
Sujitha22be222009-03-30 15:28:36 +05301933 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301934 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301935 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001936 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001937 struct ath_softc *sc = bf->aphy->sc;
1938 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301939 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301940
Sujith95e4acb2009-03-13 08:56:09 +05301941 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001942 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301943
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001944 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301945 WARN_ON(tx_rateindex >= hw->max_rates);
1946
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001947 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301948 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001949 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001950 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301951
Felix Fietkaub572d032010-11-14 15:20:07 +01001952 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001953
Felix Fietkaub572d032010-11-14 15:20:07 +01001954 tx_info->status.ampdu_len = nframes;
1955 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001956 }
1957
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001958 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301959 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001960 /*
1961 * If an underrun error is seen assume it as an excessive
1962 * retry only if max frame trigger level has been reached
1963 * (2 KB for single stream, and 4 KB for dual stream).
1964 * Adjust the long retry as if the frame was tried
1965 * hw->max_rate_tries times to affect how rate control updates
1966 * PER for the failed rate.
1967 * In case of congestion on the bus penalizing this type of
1968 * underruns should help hardware actually transmit new frames
1969 * successfully by eventually preferring slower rates.
1970 * This itself should also alleviate congestion on the bus.
1971 */
1972 if (ieee80211_is_data(hdr->frame_control) &&
1973 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1974 ATH9K_TX_DELIM_UNDERRUN)) &&
1975 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1976 tx_info->status.rates[tx_rateindex].count =
1977 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301978 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301979
Felix Fietkau545750d2009-11-23 22:21:01 +01001980 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301981 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001982 tx_info->status.rates[i].idx = -1;
1983 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301984
Felix Fietkau78c46532010-06-25 01:26:16 +02001985 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301986}
1987
Felix Fietkau066dae92010-11-07 14:59:39 +01001988static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301989{
Felix Fietkau066dae92010-11-07 14:59:39 +01001990 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301991
Felix Fietkau066dae92010-11-07 14:59:39 +01001992 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301993 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001994 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001995 if (ath_mac80211_start_queue(sc, qnum))
1996 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301997 }
1998 spin_unlock_bh(&txq->axq_lock);
1999}
2000
Sujithc4288392008-11-18 09:09:30 +05302001static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002002{
Sujithcbe61d82009-02-09 13:27:12 +05302003 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002004 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002005 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2006 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302007 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002008 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302009 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002010 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002011 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002013 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2014 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2015 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002016
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002017 for (;;) {
2018 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002019 if (list_empty(&txq->axq_q)) {
2020 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002021 spin_unlock_bh(&txq->axq_lock);
2022 break;
2023 }
2024 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2025
2026 /*
2027 * There is a race condition that a BH gets scheduled
2028 * after sw writes TxE and before hw re-load the last
2029 * descriptor to get the newly chained one.
2030 * Software must keep the last DONE descriptor as a
2031 * holding descriptor - software does so by marking
2032 * it with the STALE flag.
2033 */
2034 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302035 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002036 bf_held = bf;
2037 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302038 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002039 break;
2040 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002041 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302042 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002043 }
2044 }
2045
2046 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302047 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002048
Felix Fietkau29bffa92010-03-29 20:14:23 -07002049 memset(&ts, 0, sizeof(ts));
2050 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002051 if (status == -EINPROGRESS) {
2052 spin_unlock_bh(&txq->axq_lock);
2053 break;
2054 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002055
2056 /*
2057 * Remove ath_buf's of the same transmit unit from txq,
2058 * however leave the last descriptor back as the holding
2059 * descriptor for hw.
2060 */
Sujitha119cc42009-03-30 15:28:38 +05302061 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002062 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002063 if (!list_is_singular(&lastbf->list))
2064 list_cut_position(&bf_head,
2065 &txq->axq_q, lastbf->list.prev);
2066
2067 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002068 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002069 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002070 if (bf_held)
2071 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002072 spin_unlock_bh(&txq->axq_lock);
2073
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002074 if (bf_held)
2075 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076
Sujithcd3d39a2008-08-11 14:03:34 +05302077 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002078 /*
2079 * This frame is sent out as a single frame.
2080 * Use hardware retry status for this frame.
2081 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002082 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302083 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002084 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 }
Johannes Berge6a98542008-10-21 12:40:02 +02002086
Felix Fietkau066dae92010-11-07 14:59:39 +01002087 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2088
Sujithcd3d39a2008-08-11 14:03:34 +05302089 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002090 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
2091 true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002092 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002093 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094
Felix Fietkau066dae92010-11-07 14:59:39 +01002095 if (txq == sc->tx.txq_map[qnum])
2096 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302097
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302099 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002100 ath_txq_schedule(sc, txq);
2101 spin_unlock_bh(&txq->axq_lock);
2102 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002103}
2104
Sujith305fe472009-07-23 15:32:29 +05302105static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002106{
2107 struct ath_softc *sc = container_of(work, struct ath_softc,
2108 tx_complete_work.work);
2109 struct ath_txq *txq;
2110 int i;
2111 bool needreset = false;
2112
2113 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2114 if (ATH_TXQ_SETUP(sc, i)) {
2115 txq = &sc->tx.txq[i];
2116 spin_lock_bh(&txq->axq_lock);
2117 if (txq->axq_depth) {
2118 if (txq->axq_tx_inprogress) {
2119 needreset = true;
2120 spin_unlock_bh(&txq->axq_lock);
2121 break;
2122 } else {
2123 txq->axq_tx_inprogress = true;
2124 }
2125 }
2126 spin_unlock_bh(&txq->axq_lock);
2127 }
2128
2129 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002130 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2131 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302132 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002133 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302134 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002135 }
2136
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002137 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002138 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2139}
2140
2141
Sujithe8324352009-01-16 21:38:42 +05302142
2143void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002144{
Sujithe8324352009-01-16 21:38:42 +05302145 int i;
2146 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002147
Sujithe8324352009-01-16 21:38:42 +05302148 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002149
2150 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302151 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2152 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002153 }
2154}
2155
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002156void ath_tx_edma_tasklet(struct ath_softc *sc)
2157{
2158 struct ath_tx_status txs;
2159 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2160 struct ath_hw *ah = sc->sc_ah;
2161 struct ath_txq *txq;
2162 struct ath_buf *bf, *lastbf;
2163 struct list_head bf_head;
2164 int status;
2165 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002166 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002167
2168 for (;;) {
2169 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2170 if (status == -EINPROGRESS)
2171 break;
2172 if (status == -EIO) {
2173 ath_print(common, ATH_DBG_XMIT,
2174 "Error processing tx status\n");
2175 break;
2176 }
2177
2178 /* Skip beacon completions */
2179 if (txs.qid == sc->beacon.beaconq)
2180 continue;
2181
2182 txq = &sc->tx.txq[txs.qid];
2183
2184 spin_lock_bh(&txq->axq_lock);
2185 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2186 spin_unlock_bh(&txq->axq_lock);
2187 return;
2188 }
2189
2190 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2191 struct ath_buf, list);
2192 lastbf = bf->bf_lastbf;
2193
2194 INIT_LIST_HEAD(&bf_head);
2195 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2196 &lastbf->list);
2197 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2198 txq->axq_depth--;
2199 txq->axq_tx_inprogress = false;
2200 spin_unlock_bh(&txq->axq_lock);
2201
2202 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2203
2204 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002205 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2206 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002207 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002208 }
2209
Felix Fietkau066dae92010-11-07 14:59:39 +01002210 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2211
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002212 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002213 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
2214 txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002215 else
2216 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2217 &txs, txok, 0);
2218
Felix Fietkau066dae92010-11-07 14:59:39 +01002219 if (txq == sc->tx.txq_map[qnum])
2220 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002221
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002222 spin_lock_bh(&txq->axq_lock);
2223 if (!list_empty(&txq->txq_fifo_pending)) {
2224 INIT_LIST_HEAD(&bf_head);
2225 bf = list_first_entry(&txq->txq_fifo_pending,
2226 struct ath_buf, list);
2227 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2228 &bf->bf_lastbf->list);
2229 ath_tx_txqaddbuf(sc, txq, &bf_head);
2230 } else if (sc->sc_flags & SC_OP_TXAGGR)
2231 ath_txq_schedule(sc, txq);
2232 spin_unlock_bh(&txq->axq_lock);
2233 }
2234}
2235
Sujithe8324352009-01-16 21:38:42 +05302236/*****************/
2237/* Init, Cleanup */
2238/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002239
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002240static int ath_txstatus_setup(struct ath_softc *sc, int size)
2241{
2242 struct ath_descdma *dd = &sc->txsdma;
2243 u8 txs_len = sc->sc_ah->caps.txs_len;
2244
2245 dd->dd_desc_len = size * txs_len;
2246 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2247 &dd->dd_desc_paddr, GFP_KERNEL);
2248 if (!dd->dd_desc)
2249 return -ENOMEM;
2250
2251 return 0;
2252}
2253
2254static int ath_tx_edma_init(struct ath_softc *sc)
2255{
2256 int err;
2257
2258 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2259 if (!err)
2260 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2261 sc->txsdma.dd_desc_paddr,
2262 ATH_TXSTATUS_RING_SIZE);
2263
2264 return err;
2265}
2266
2267static void ath_tx_edma_cleanup(struct ath_softc *sc)
2268{
2269 struct ath_descdma *dd = &sc->txsdma;
2270
2271 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2272 dd->dd_desc_paddr);
2273}
2274
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002275int ath_tx_init(struct ath_softc *sc, int nbufs)
2276{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002277 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002278 int error = 0;
2279
Sujith797fe5cb2009-03-30 15:28:45 +05302280 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002281
Sujith797fe5cb2009-03-30 15:28:45 +05302282 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002283 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302284 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002285 ath_print(common, ATH_DBG_FATAL,
2286 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302287 goto err;
2288 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002289
Sujith797fe5cb2009-03-30 15:28:45 +05302290 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002291 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302292 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002293 ath_print(common, ATH_DBG_FATAL,
2294 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302295 goto err;
2296 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002297
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002298 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2299
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002300 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2301 error = ath_tx_edma_init(sc);
2302 if (error)
2303 goto err;
2304 }
2305
Sujith797fe5cb2009-03-30 15:28:45 +05302306err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002307 if (error != 0)
2308 ath_tx_cleanup(sc);
2309
2310 return error;
2311}
2312
Sujith797fe5cb2009-03-30 15:28:45 +05302313void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002314{
Sujithb77f4832008-12-07 21:44:03 +05302315 if (sc->beacon.bdma.dd_desc_len != 0)
2316 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002317
Sujithb77f4832008-12-07 21:44:03 +05302318 if (sc->tx.txdma.dd_desc_len != 0)
2319 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002320
2321 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2322 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002323}
2324
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002325void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2326{
Sujithc5170162008-10-29 10:13:59 +05302327 struct ath_atx_tid *tid;
2328 struct ath_atx_ac *ac;
2329 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002330
Sujith8ee5afb2008-12-07 21:43:36 +05302331 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302332 tidno < WME_NUM_TID;
2333 tidno++, tid++) {
2334 tid->an = an;
2335 tid->tidno = tidno;
2336 tid->seq_start = tid->seq_next = 0;
2337 tid->baw_size = WME_MAX_BA;
2338 tid->baw_head = tid->baw_tail = 0;
2339 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302340 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302341 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302342 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302343 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302344 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302345 tid->state &= ~AGGR_ADDBA_COMPLETE;
2346 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302347 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002348
Sujith8ee5afb2008-12-07 21:43:36 +05302349 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302350 acno < WME_NUM_AC; acno++, ac++) {
2351 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002352 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302353 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354 }
2355}
2356
Sujithb5aa9bf2008-10-29 10:13:31 +05302357void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002358{
Felix Fietkau2b409942010-07-07 19:42:08 +02002359 struct ath_atx_ac *ac;
2360 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002361 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002362 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302363
Felix Fietkau2b409942010-07-07 19:42:08 +02002364 for (tidno = 0, tid = &an->tid[tidno];
2365 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366
Felix Fietkau2b409942010-07-07 19:42:08 +02002367 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002368 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002369
Felix Fietkau2b409942010-07-07 19:42:08 +02002370 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371
Felix Fietkau2b409942010-07-07 19:42:08 +02002372 if (tid->sched) {
2373 list_del(&tid->list);
2374 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002375 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002376
2377 if (ac->sched) {
2378 list_del(&ac->list);
2379 tid->ac->sched = false;
2380 }
2381
2382 ath_tid_drain(sc, txq, tid);
2383 tid->state &= ~AGGR_ADDBA_COMPLETE;
2384 tid->state &= ~AGGR_CLEANUP;
2385
2386 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002387 }
2388}