blob: 5eeffaea551e03161611417fbfcecaffd1f6ea47 [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,
Felix Fietkau04caf862010-11-14 15:20:12 +01001347 struct ath_buf *bf, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301348{
Felix Fietkau04caf862010-11-14 15:20:12 +01001349 struct list_head bf_head;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001350 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301351
Sujithe8324352009-01-16 21:38:42 +05301352 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301353 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001354 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301355
1356 /*
1357 * Do not queue to h/w when any of the following conditions is true:
1358 * - there are pending frames in software queue
1359 * - the TID is currently paused for ADDBA/BAR request
1360 * - seqno is not within block-ack window
1361 * - h/w queue depth exceeds low water mark
1362 */
1363 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001364 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301365 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001366 /*
Sujithe8324352009-01-16 21:38:42 +05301367 * Add this frame to software queue for scheduling later
1368 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001369 */
Felix Fietkau04caf862010-11-14 15:20:12 +01001370 list_add_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301371 ath_tx_queue_tid(txctl->txq, tid);
1372 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001373 }
1374
Felix Fietkau04caf862010-11-14 15:20:12 +01001375 INIT_LIST_HEAD(&bf_head);
1376 list_add(&bf->list, &bf_head);
1377
Sujithe8324352009-01-16 21:38:42 +05301378 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001379 if (!bf_isretried(bf))
1380 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301381
1382 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301383 bf->bf_lastbf = bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001384 ath_buf_set_rate(sc, bf, txctl->frmlen);
1385 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
Sujithc4288392008-11-18 09:09:30 +05301386}
1387
Felix Fietkau82b873a2010-11-11 03:18:37 +01001388static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1389 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +01001390 struct list_head *bf_head, int frmlen)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001391{
Sujithe8324352009-01-16 21:38:42 +05301392 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001393
Sujithe8324352009-01-16 21:38:42 +05301394 bf = list_first_entry(bf_head, struct ath_buf, list);
1395 bf->bf_state.bf_type &= ~BUF_AMPDU;
1396
1397 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001398 if (tid)
1399 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301400
Sujithd43f30152009-01-16 21:38:53 +05301401 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001402 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301403 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301404 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001405}
1406
Sujith528f0c62008-10-29 10:14:26 +05301407static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001408{
Sujith528f0c62008-10-29 10:14:26 +05301409 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001410 enum ath9k_pkt_type htype;
1411 __le16 fc;
1412
Sujith528f0c62008-10-29 10:14:26 +05301413 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001414 fc = hdr->frame_control;
1415
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001416 if (ieee80211_is_beacon(fc))
1417 htype = ATH9K_PKT_TYPE_BEACON;
1418 else if (ieee80211_is_probe_resp(fc))
1419 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1420 else if (ieee80211_is_atim(fc))
1421 htype = ATH9K_PKT_TYPE_ATIM;
1422 else if (ieee80211_is_pspoll(fc))
1423 htype = ATH9K_PKT_TYPE_PSPOLL;
1424 else
1425 htype = ATH9K_PKT_TYPE_NORMAL;
1426
1427 return htype;
1428}
1429
Felix Fietkau04caf862010-11-14 15:20:12 +01001430static void assign_aggr_tid_seqno(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301431{
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,
Felix Fietkau04caf862010-11-14 15:20:12 +01001611 struct ath_txq *txq,
1612 struct sk_buff *skb, int frmlen)
Sujithe8324352009-01-16 21:38:42 +05301613{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001614 struct ath_wiphy *aphy = hw->priv;
1615 struct ath_softc *sc = aphy->sc;
Felix Fietkau04caf862010-11-14 15:20:12 +01001616 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001617 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau04caf862010-11-14 15:20:12 +01001618 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1619 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001620 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001621 struct ath_desc *ds;
1622 enum ath9k_key_type keytype;
1623 u32 keyix;
1624 int frm_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001625
1626 bf = ath_tx_get_buffer(sc);
1627 if (!bf) {
1628 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1629 return NULL;
1630 }
Sujithe8324352009-01-16 21:38:42 +05301631
Sujithe8324352009-01-16 21:38:42 +05301632 ATH_TXBUF_RESET(bf);
1633
Felix Fietkau04caf862010-11-14 15:20:12 +01001634 if (ieee80211_is_data_qos(hdr->frame_control) &&
1635 conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR))
1636 assign_aggr_tid_seqno(skb);
1637
Felix Fietkau827e69b2009-11-15 23:09:25 +01001638 bf->aphy = aphy;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001639 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301640 bf->bf_mpdu = skb;
1641
Ben Greearc1739eb32010-10-14 12:45:29 -07001642 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1643 skb->len, DMA_TO_DEVICE);
1644 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301645 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001646 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001647 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1648 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001649 ath_tx_return_buffer(sc, bf);
1650 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301651 }
1652
Sujithe8324352009-01-16 21:38:42 +05301653 frm_type = get_hw_packet_type(skb);
Sujithe8324352009-01-16 21:38:42 +05301654
1655 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001656 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301657
Felix Fietkau952cd692010-11-14 15:20:03 +01001658 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001659 if (tx_info->control.hw_key)
1660 keyix = tx_info->control.hw_key->hw_key_idx;
1661 else
1662 keyix = ATH9K_TXKEYIX_INVALID;
1663
Felix Fietkau76e45222010-11-14 15:20:08 +01001664 ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001665 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301666
1667 ath9k_hw_filltxdesc(ah, ds,
1668 skb->len, /* segment length */
1669 true, /* first segment */
1670 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001671 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001672 bf->bf_buf_addr,
Felix Fietkau04caf862010-11-14 15:20:12 +01001673 txq->axq_qnum);
1674
1675
1676 return bf;
1677}
1678
1679/* FIXME: tx power */
1680static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1681 struct ath_tx_control *txctl)
1682{
1683 struct sk_buff *skb = bf->bf_mpdu;
1684 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1685 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1686 struct ath_node *an = NULL;
1687 struct list_head bf_head;
1688 struct ath_atx_tid *tid;
1689 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301690
Sujithe8324352009-01-16 21:38:42 +05301691 spin_lock_bh(&txctl->txq->axq_lock);
1692
Felix Fietkau04caf862010-11-14 15:20:12 +01001693 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) {
Sujithe8324352009-01-16 21:38:42 +05301694 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001695 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1696 IEEE80211_QOS_CTL_TID_MASK;
1697 tid = ATH_AN_2_TID(an, tidno);
1698
Felix Fietkau066dae92010-11-07 14:59:39 +01001699 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau04caf862010-11-14 15:20:12 +01001700 /*
1701 * Try aggregation if it's a unicast data frame
1702 * and the destination is HT capable.
1703 */
1704 ath_tx_send_ampdu(sc, tid, bf, txctl);
Sujithe8324352009-01-16 21:38:42 +05301705 } else {
Felix Fietkau04caf862010-11-14 15:20:12 +01001706 INIT_LIST_HEAD(&bf_head);
1707 list_add_tail(&bf->list, &bf_head);
1708
Felix Fietkau61117f02010-11-11 03:18:36 +01001709 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001710 bf->bf_state.bfs_paprd = txctl->paprd;
1711
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001712 if (bf->bf_state.bfs_paprd)
Felix Fietkau04caf862010-11-14 15:20:12 +01001713 ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
1714 bf->bf_state.bfs_paprd);
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001715
Felix Fietkau04caf862010-11-14 15:20:12 +01001716 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen);
Sujithe8324352009-01-16 21:38:42 +05301717 }
1718
1719 spin_unlock_bh(&txctl->txq->axq_lock);
1720}
1721
1722/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001723int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301724 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001725{
Felix Fietkau28d16702010-11-14 15:20:10 +01001726 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1727 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001728 struct ath_wiphy *aphy = hw->priv;
1729 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001730 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001731 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001732 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001733 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001734 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001735
Felix Fietkau04caf862010-11-14 15:20:12 +01001736 if (info->control.hw_key)
1737 frmlen += info->control.hw_key->icv_len;
1738
1739 txctl->frmlen = frmlen;
1740
Felix Fietkau28d16702010-11-14 15:20:10 +01001741 /*
1742 * As a temporary workaround, assign seq# here; this will likely need
1743 * to be cleaned up to work better with Beacon transmission and virtual
1744 * BSSes.
1745 */
1746 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1747 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1748 sc->tx.seq_no += 0x10;
1749 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1750 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1751 }
1752
1753 /* Add the padding after the header if this is not already done */
1754 padpos = ath9k_cmn_padpos(hdr->frame_control);
1755 padsize = padpos & 3;
1756 if (padsize && skb->len > padpos) {
1757 if (skb_headroom(skb) < padsize)
1758 return -ENOMEM;
1759
1760 skb_push(skb, padsize);
1761 memmove(skb->data, skb->data + padsize, padpos);
1762 }
1763
Felix Fietkau04caf862010-11-14 15:20:12 +01001764 bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001765 if (unlikely(!bf))
1766 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001767
Felix Fietkau066dae92010-11-07 14:59:39 +01001768 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001769 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001770 if (txq == sc->tx.txq_map[q] &&
1771 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1772 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001773 txq->stopped = 1;
1774 }
1775 spin_unlock_bh(&txq->axq_lock);
1776
Sujithe8324352009-01-16 21:38:42 +05301777 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001778
1779 return 0;
1780}
1781
Sujithe8324352009-01-16 21:38:42 +05301782/*****************/
1783/* TX Completion */
1784/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001785
Sujithe8324352009-01-16 21:38:42 +05301786static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001787 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001788 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001789{
Sujithe8324352009-01-16 21:38:42 +05301790 struct ieee80211_hw *hw = sc->hw;
1791 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001792 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001793 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001794 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301795
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001796 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301797
Felix Fietkau827e69b2009-11-15 23:09:25 +01001798 if (aphy)
1799 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301800
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301801 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301802 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301803
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301804 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301805 /* Frame was ACKed */
1806 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1807 }
1808
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001809 padpos = ath9k_cmn_padpos(hdr->frame_control);
1810 padsize = padpos & 3;
1811 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301812 /*
1813 * Remove MAC header padding before giving the frame back to
1814 * mac80211.
1815 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001816 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301817 skb_pull(skb, padsize);
1818 }
1819
Sujith1b04b932010-01-08 10:36:05 +05301820 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1821 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001822 ath_print(common, ATH_DBG_PS,
1823 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001824 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301825 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1826 PS_WAIT_FOR_CAB |
1827 PS_WAIT_FOR_PSPOLL_DATA |
1828 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001829 }
1830
Felix Fietkau61117f02010-11-11 03:18:36 +01001831 if (unlikely(ftype))
1832 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001833 else {
1834 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001835 if (txq == sc->tx.txq_map[q]) {
1836 spin_lock_bh(&txq->axq_lock);
1837 if (WARN_ON(--txq->pending_frames < 0))
1838 txq->pending_frames = 0;
1839 spin_unlock_bh(&txq->axq_lock);
1840 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001841
Felix Fietkau827e69b2009-11-15 23:09:25 +01001842 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001843 }
Sujithe8324352009-01-16 21:38:42 +05301844}
1845
1846static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001847 struct ath_txq *txq, struct list_head *bf_q,
1848 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301849{
1850 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301851 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301852 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301853
Sujithe8324352009-01-16 21:38:42 +05301854 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301855 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301856
1857 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301858 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301859
1860 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301861 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301862 }
1863
Ben Greearc1739eb32010-10-14 12:45:29 -07001864 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001865 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001866
1867 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001868 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001869 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001870 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001871 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001872 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001873 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001874 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1875 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001876 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001877 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1878 * accidentally reference it later.
1879 */
1880 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301881
1882 /*
1883 * Return the list of ath_buf of this mpdu to free queue
1884 */
1885 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1886 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1887 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1888}
1889
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001890static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001891 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301892{
Sujitha22be222009-03-30 15:28:36 +05301893 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301894 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301895 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001896 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001897 struct ath_softc *sc = bf->aphy->sc;
1898 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301899 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301900
Sujith95e4acb2009-03-13 08:56:09 +05301901 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001902 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301903
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001904 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301905 WARN_ON(tx_rateindex >= hw->max_rates);
1906
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001907 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301908 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001909 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001910 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301911
Felix Fietkaub572d032010-11-14 15:20:07 +01001912 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001913
Felix Fietkaub572d032010-11-14 15:20:07 +01001914 tx_info->status.ampdu_len = nframes;
1915 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001916 }
1917
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001918 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301919 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001920 /*
1921 * If an underrun error is seen assume it as an excessive
1922 * retry only if max frame trigger level has been reached
1923 * (2 KB for single stream, and 4 KB for dual stream).
1924 * Adjust the long retry as if the frame was tried
1925 * hw->max_rate_tries times to affect how rate control updates
1926 * PER for the failed rate.
1927 * In case of congestion on the bus penalizing this type of
1928 * underruns should help hardware actually transmit new frames
1929 * successfully by eventually preferring slower rates.
1930 * This itself should also alleviate congestion on the bus.
1931 */
1932 if (ieee80211_is_data(hdr->frame_control) &&
1933 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1934 ATH9K_TX_DELIM_UNDERRUN)) &&
1935 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1936 tx_info->status.rates[tx_rateindex].count =
1937 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301938 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301939
Felix Fietkau545750d2009-11-23 22:21:01 +01001940 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301941 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001942 tx_info->status.rates[i].idx = -1;
1943 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301944
Felix Fietkau78c46532010-06-25 01:26:16 +02001945 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301946}
1947
Felix Fietkau066dae92010-11-07 14:59:39 +01001948static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301949{
Felix Fietkau066dae92010-11-07 14:59:39 +01001950 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301951
Felix Fietkau066dae92010-11-07 14:59:39 +01001952 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301953 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001954 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001955 if (ath_mac80211_start_queue(sc, qnum))
1956 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301957 }
1958 spin_unlock_bh(&txq->axq_lock);
1959}
1960
Sujithc4288392008-11-18 09:09:30 +05301961static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001962{
Sujithcbe61d82009-02-09 13:27:12 +05301963 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001964 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001965 struct ath_buf *bf, *lastbf, *bf_held = NULL;
1966 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05301967 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07001968 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05301969 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001970 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01001971 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001972
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001973 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
1974 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
1975 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001976
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001977 for (;;) {
1978 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001979 if (list_empty(&txq->axq_q)) {
1980 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001981 spin_unlock_bh(&txq->axq_lock);
1982 break;
1983 }
1984 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
1985
1986 /*
1987 * There is a race condition that a BH gets scheduled
1988 * after sw writes TxE and before hw re-load the last
1989 * descriptor to get the newly chained one.
1990 * Software must keep the last DONE descriptor as a
1991 * holding descriptor - software does so by marking
1992 * it with the STALE flag.
1993 */
1994 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05301995 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001996 bf_held = bf;
1997 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05301998 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001999 break;
2000 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002001 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302002 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002003 }
2004 }
2005
2006 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302007 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002008
Felix Fietkau29bffa92010-03-29 20:14:23 -07002009 memset(&ts, 0, sizeof(ts));
2010 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002011 if (status == -EINPROGRESS) {
2012 spin_unlock_bh(&txq->axq_lock);
2013 break;
2014 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002015
2016 /*
2017 * Remove ath_buf's of the same transmit unit from txq,
2018 * however leave the last descriptor back as the holding
2019 * descriptor for hw.
2020 */
Sujitha119cc42009-03-30 15:28:38 +05302021 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002022 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002023 if (!list_is_singular(&lastbf->list))
2024 list_cut_position(&bf_head,
2025 &txq->axq_q, lastbf->list.prev);
2026
2027 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002028 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002029 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002030 if (bf_held)
2031 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002032 spin_unlock_bh(&txq->axq_lock);
2033
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002034 if (bf_held)
2035 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002036
Sujithcd3d39a2008-08-11 14:03:34 +05302037 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002038 /*
2039 * This frame is sent out as a single frame.
2040 * Use hardware retry status for this frame.
2041 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002042 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302043 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002044 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045 }
Johannes Berge6a98542008-10-21 12:40:02 +02002046
Felix Fietkau066dae92010-11-07 14:59:39 +01002047 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2048
Sujithcd3d39a2008-08-11 14:03:34 +05302049 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002050 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
2051 true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002052 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002053 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002054
Felix Fietkau066dae92010-11-07 14:59:39 +01002055 if (txq == sc->tx.txq_map[qnum])
2056 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302057
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002058 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302059 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060 ath_txq_schedule(sc, txq);
2061 spin_unlock_bh(&txq->axq_lock);
2062 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002063}
2064
Sujith305fe472009-07-23 15:32:29 +05302065static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002066{
2067 struct ath_softc *sc = container_of(work, struct ath_softc,
2068 tx_complete_work.work);
2069 struct ath_txq *txq;
2070 int i;
2071 bool needreset = false;
2072
2073 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2074 if (ATH_TXQ_SETUP(sc, i)) {
2075 txq = &sc->tx.txq[i];
2076 spin_lock_bh(&txq->axq_lock);
2077 if (txq->axq_depth) {
2078 if (txq->axq_tx_inprogress) {
2079 needreset = true;
2080 spin_unlock_bh(&txq->axq_lock);
2081 break;
2082 } else {
2083 txq->axq_tx_inprogress = true;
2084 }
2085 }
2086 spin_unlock_bh(&txq->axq_lock);
2087 }
2088
2089 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002090 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2091 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302092 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002093 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302094 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002095 }
2096
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002097 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002098 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2099}
2100
2101
Sujithe8324352009-01-16 21:38:42 +05302102
2103void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002104{
Sujithe8324352009-01-16 21:38:42 +05302105 int i;
2106 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002107
Sujithe8324352009-01-16 21:38:42 +05302108 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109
2110 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302111 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2112 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002113 }
2114}
2115
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002116void ath_tx_edma_tasklet(struct ath_softc *sc)
2117{
2118 struct ath_tx_status txs;
2119 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2120 struct ath_hw *ah = sc->sc_ah;
2121 struct ath_txq *txq;
2122 struct ath_buf *bf, *lastbf;
2123 struct list_head bf_head;
2124 int status;
2125 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002126 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002127
2128 for (;;) {
2129 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2130 if (status == -EINPROGRESS)
2131 break;
2132 if (status == -EIO) {
2133 ath_print(common, ATH_DBG_XMIT,
2134 "Error processing tx status\n");
2135 break;
2136 }
2137
2138 /* Skip beacon completions */
2139 if (txs.qid == sc->beacon.beaconq)
2140 continue;
2141
2142 txq = &sc->tx.txq[txs.qid];
2143
2144 spin_lock_bh(&txq->axq_lock);
2145 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2146 spin_unlock_bh(&txq->axq_lock);
2147 return;
2148 }
2149
2150 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2151 struct ath_buf, list);
2152 lastbf = bf->bf_lastbf;
2153
2154 INIT_LIST_HEAD(&bf_head);
2155 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2156 &lastbf->list);
2157 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2158 txq->axq_depth--;
2159 txq->axq_tx_inprogress = false;
2160 spin_unlock_bh(&txq->axq_lock);
2161
2162 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2163
2164 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002165 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2166 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002167 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002168 }
2169
Felix Fietkau066dae92010-11-07 14:59:39 +01002170 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2171
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002172 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002173 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
2174 txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002175 else
2176 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2177 &txs, txok, 0);
2178
Felix Fietkau066dae92010-11-07 14:59:39 +01002179 if (txq == sc->tx.txq_map[qnum])
2180 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002181
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002182 spin_lock_bh(&txq->axq_lock);
2183 if (!list_empty(&txq->txq_fifo_pending)) {
2184 INIT_LIST_HEAD(&bf_head);
2185 bf = list_first_entry(&txq->txq_fifo_pending,
2186 struct ath_buf, list);
2187 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2188 &bf->bf_lastbf->list);
2189 ath_tx_txqaddbuf(sc, txq, &bf_head);
2190 } else if (sc->sc_flags & SC_OP_TXAGGR)
2191 ath_txq_schedule(sc, txq);
2192 spin_unlock_bh(&txq->axq_lock);
2193 }
2194}
2195
Sujithe8324352009-01-16 21:38:42 +05302196/*****************/
2197/* Init, Cleanup */
2198/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002199
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002200static int ath_txstatus_setup(struct ath_softc *sc, int size)
2201{
2202 struct ath_descdma *dd = &sc->txsdma;
2203 u8 txs_len = sc->sc_ah->caps.txs_len;
2204
2205 dd->dd_desc_len = size * txs_len;
2206 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2207 &dd->dd_desc_paddr, GFP_KERNEL);
2208 if (!dd->dd_desc)
2209 return -ENOMEM;
2210
2211 return 0;
2212}
2213
2214static int ath_tx_edma_init(struct ath_softc *sc)
2215{
2216 int err;
2217
2218 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2219 if (!err)
2220 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2221 sc->txsdma.dd_desc_paddr,
2222 ATH_TXSTATUS_RING_SIZE);
2223
2224 return err;
2225}
2226
2227static void ath_tx_edma_cleanup(struct ath_softc *sc)
2228{
2229 struct ath_descdma *dd = &sc->txsdma;
2230
2231 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2232 dd->dd_desc_paddr);
2233}
2234
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002235int ath_tx_init(struct ath_softc *sc, int nbufs)
2236{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002237 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002238 int error = 0;
2239
Sujith797fe5cb2009-03-30 15:28:45 +05302240 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002241
Sujith797fe5cb2009-03-30 15:28:45 +05302242 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002243 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302244 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002245 ath_print(common, ATH_DBG_FATAL,
2246 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302247 goto err;
2248 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002249
Sujith797fe5cb2009-03-30 15:28:45 +05302250 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002251 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302252 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002253 ath_print(common, ATH_DBG_FATAL,
2254 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302255 goto err;
2256 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002257
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002258 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2259
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002260 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2261 error = ath_tx_edma_init(sc);
2262 if (error)
2263 goto err;
2264 }
2265
Sujith797fe5cb2009-03-30 15:28:45 +05302266err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002267 if (error != 0)
2268 ath_tx_cleanup(sc);
2269
2270 return error;
2271}
2272
Sujith797fe5cb2009-03-30 15:28:45 +05302273void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002274{
Sujithb77f4832008-12-07 21:44:03 +05302275 if (sc->beacon.bdma.dd_desc_len != 0)
2276 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002277
Sujithb77f4832008-12-07 21:44:03 +05302278 if (sc->tx.txdma.dd_desc_len != 0)
2279 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002280
2281 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2282 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002283}
2284
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002285void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2286{
Sujithc5170162008-10-29 10:13:59 +05302287 struct ath_atx_tid *tid;
2288 struct ath_atx_ac *ac;
2289 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002290
Sujith8ee5afb2008-12-07 21:43:36 +05302291 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302292 tidno < WME_NUM_TID;
2293 tidno++, tid++) {
2294 tid->an = an;
2295 tid->tidno = tidno;
2296 tid->seq_start = tid->seq_next = 0;
2297 tid->baw_size = WME_MAX_BA;
2298 tid->baw_head = tid->baw_tail = 0;
2299 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302300 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302301 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302302 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302303 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302304 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302305 tid->state &= ~AGGR_ADDBA_COMPLETE;
2306 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302307 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002308
Sujith8ee5afb2008-12-07 21:43:36 +05302309 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302310 acno < WME_NUM_AC; acno++, ac++) {
2311 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002312 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302313 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002314 }
2315}
2316
Sujithb5aa9bf2008-10-29 10:13:31 +05302317void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002318{
Felix Fietkau2b409942010-07-07 19:42:08 +02002319 struct ath_atx_ac *ac;
2320 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002321 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002322 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302323
Felix Fietkau2b409942010-07-07 19:42:08 +02002324 for (tidno = 0, tid = &an->tid[tidno];
2325 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002326
Felix Fietkau2b409942010-07-07 19:42:08 +02002327 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002328 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002329
Felix Fietkau2b409942010-07-07 19:42:08 +02002330 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002331
Felix Fietkau2b409942010-07-07 19:42:08 +02002332 if (tid->sched) {
2333 list_del(&tid->list);
2334 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002335 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002336
2337 if (ac->sched) {
2338 list_del(&ac->list);
2339 tid->ac->sched = false;
2340 }
2341
2342 ath_tid_drain(sc, txq, tid);
2343 tid->state &= ~AGGR_ADDBA_COMPLETE;
2344 tid->state &= ~AGGR_CLEANUP;
2345
2346 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002347 }
2348}