blob: f3f0d1c6ad0a70eab56dcbe0b1a27110455891ae [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Sujith394cf0a2009-02-09 13:26:54 +053017#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040018#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070019
20#define BITS_PER_BYTE 8
21#define OFDM_PLCP_BITS 22
Felix Fietkau7817e4c2010-04-19 19:57:31 +020022#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070023#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
24#define L_STF 8
25#define L_LTF 8
26#define L_SIG 4
27#define HT_SIG 8
28#define HT_STF 4
29#define HT_LTF(_ns) (4 * (_ns))
30#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
31#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
32#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
33#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
34
35#define OFDM_SIFS_TIME 16
36
Felix Fietkauc6663872010-04-19 19:57:33 +020037static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070038 /* 20MHz 40MHz */
39 { 26, 54 }, /* 0: BPSK */
40 { 52, 108 }, /* 1: QPSK 1/2 */
41 { 78, 162 }, /* 2: QPSK 3/4 */
42 { 104, 216 }, /* 3: 16-QAM 1/2 */
43 { 156, 324 }, /* 4: 16-QAM 3/4 */
44 { 208, 432 }, /* 5: 64-QAM 2/3 */
45 { 234, 486 }, /* 6: 64-QAM 3/4 */
46 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070047};
48
49#define IS_HT_RATE(_rate) ((_rate) & 0x80)
50
Felix Fietkau82b873a2010-11-11 03:18:37 +010051static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
52 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +010053 struct list_head *bf_head, int frmlen);
Sujithe8324352009-01-16 21:38:42 +053054static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070055 struct ath_txq *txq, struct list_head *bf_q,
56 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053057static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
58 struct list_head *head);
Felix Fietkau269c44b2010-11-14 15:20:06 +010059static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
Felix Fietkaudb1a0522010-03-29 20:07:11 -070060static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +010061 int nframes, int nbad, int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020062static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
63 int seqno);
Sujithe8324352009-01-16 21:38:42 +053064
Felix Fietkau545750d2009-11-23 22:21:01 +010065enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020066 MCS_HT20,
67 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010068 MCS_HT40,
69 MCS_HT40_SGI,
70};
71
Felix Fietkau0e668cd2010-04-19 19:57:32 +020072static int ath_max_4ms_framelen[4][32] = {
73 [MCS_HT20] = {
74 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
75 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
76 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
77 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
78 },
79 [MCS_HT20_SGI] = {
80 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
81 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
82 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
83 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010084 },
85 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020086 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
87 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
88 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
89 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010090 },
91 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020092 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
93 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
94 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
95 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010096 }
97};
98
Sujithe8324352009-01-16 21:38:42 +053099/*********************/
100/* Aggregation logic */
101/*********************/
102
Sujithe8324352009-01-16 21:38:42 +0530103static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
104{
105 struct ath_atx_ac *ac = tid->ac;
106
107 if (tid->paused)
108 return;
109
110 if (tid->sched)
111 return;
112
113 tid->sched = true;
114 list_add_tail(&tid->list, &ac->tid_q);
115
116 if (ac->sched)
117 return;
118
119 ac->sched = true;
120 list_add_tail(&ac->list, &txq->axq_acq);
121}
122
Sujithe8324352009-01-16 21:38:42 +0530123static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
124{
Felix Fietkau066dae92010-11-07 14:59:39 +0100125 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530126
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200127 WARN_ON(!tid->paused);
128
Sujithe8324352009-01-16 21:38:42 +0530129 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200130 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530131
132 if (list_empty(&tid->buf_q))
133 goto unlock;
134
135 ath_tx_queue_tid(txq, tid);
136 ath_txq_schedule(sc, txq);
137unlock:
138 spin_unlock_bh(&txq->axq_lock);
139}
140
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100141static u16 ath_frame_seqno(struct sk_buff *skb)
142{
143 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
144 return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
145}
146
Felix Fietkau76e45222010-11-14 15:20:08 +0100147static int ath_frame_len(struct sk_buff *skb)
148{
149 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
150 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
151 int frmlen = skb->len + FCS_LEN;
152 int padpos, padsize;
153
154 /* Remove the padding size, if any */
155 padpos = ath9k_cmn_padpos(hdr->frame_control);
156 padsize = padpos & 3;
157
158 if (padsize && skb->len > padpos + padsize)
159 frmlen -= padsize;
160
161 if (tx_info->control.hw_key)
162 frmlen += tx_info->control.hw_key->icv_len;
163
164 return frmlen;
165}
166
Sujithe8324352009-01-16 21:38:42 +0530167static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
168{
Felix Fietkau066dae92010-11-07 14:59:39 +0100169 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530170 struct ath_buf *bf;
171 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200172 struct ath_tx_status ts;
173
Sujithe8324352009-01-16 21:38:42 +0530174 INIT_LIST_HEAD(&bf_head);
175
Felix Fietkau90fa5392010-09-20 13:45:38 +0200176 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530177 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530178
179 while (!list_empty(&tid->buf_q)) {
180 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530181 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200182
183 if (bf_isretried(bf)) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100184 ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200185 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
186 } else {
Felix Fietkau76e45222010-11-14 15:20:08 +0100187 ath_tx_send_normal(sc, txq, tid, &bf_head,
188 ath_frame_len(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200189 }
Sujithe8324352009-01-16 21:38:42 +0530190 }
191
192 spin_unlock_bh(&txq->axq_lock);
193}
194
195static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
196 int seqno)
197{
198 int index, cindex;
199
200 index = ATH_BA_INDEX(tid->seq_start, seqno);
201 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
202
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200203 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530204
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200205 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530206 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
207 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
208 }
209}
210
211static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100212 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530213{
214 int index, cindex;
215
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100216 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530217 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200218 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530219
220 if (index >= ((tid->baw_tail - tid->baw_head) &
221 (ATH_TID_MAX_BUFS - 1))) {
222 tid->baw_tail = cindex;
223 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
224 }
225}
226
227/*
228 * TODO: For frame(s) that are in the retry state, we will reuse the
229 * sequence number(s) without setting the retry bit. The
230 * alternative is to give up on these and BAR the receiver's window
231 * forward.
232 */
233static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
234 struct ath_atx_tid *tid)
235
236{
237 struct ath_buf *bf;
238 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700239 struct ath_tx_status ts;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100240 u16 bf_seqno;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700241
242 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530243 INIT_LIST_HEAD(&bf_head);
244
245 for (;;) {
246 if (list_empty(&tid->buf_q))
247 break;
Sujithe8324352009-01-16 21:38:42 +0530248
Sujithd43f30152009-01-16 21:38:53 +0530249 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
250 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530251
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100252 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530253 if (bf_isretried(bf))
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100254 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530255
256 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700257 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530258 spin_lock(&txq->axq_lock);
259 }
260
261 tid->seq_next = tid->seq_start;
262 tid->baw_tail = tid->baw_head;
263}
264
Sujithfec247c2009-07-27 12:08:16 +0530265static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
266 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530267{
268 struct sk_buff *skb;
269 struct ieee80211_hdr *hdr;
270
271 bf->bf_state.bf_type |= BUF_RETRY;
272 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530273 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530274
275 skb = bf->bf_mpdu;
276 hdr = (struct ieee80211_hdr *)skb->data;
277 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
278}
279
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200280static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
281{
282 struct ath_buf *bf = NULL;
283
284 spin_lock_bh(&sc->tx.txbuflock);
285
286 if (unlikely(list_empty(&sc->tx.txbuf))) {
287 spin_unlock_bh(&sc->tx.txbuflock);
288 return NULL;
289 }
290
291 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
292 list_del(&bf->list);
293
294 spin_unlock_bh(&sc->tx.txbuflock);
295
296 return bf;
297}
298
299static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
300{
301 spin_lock_bh(&sc->tx.txbuflock);
302 list_add_tail(&bf->list, &sc->tx.txbuf);
303 spin_unlock_bh(&sc->tx.txbuflock);
304}
305
Sujithd43f30152009-01-16 21:38:53 +0530306static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
307{
308 struct ath_buf *tbf;
309
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200310 tbf = ath_tx_get_buffer(sc);
311 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530312 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530313
314 ATH_TXBUF_RESET(tbf);
315
Felix Fietkau827e69b2009-11-15 23:09:25 +0100316 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530317 tbf->bf_mpdu = bf->bf_mpdu;
318 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400319 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530320 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530321
322 return tbf;
323}
324
Felix Fietkaub572d032010-11-14 15:20:07 +0100325static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
326 struct ath_tx_status *ts, int txok,
327 int *nframes, int *nbad)
328{
329 u16 seq_st = 0;
330 u32 ba[WME_BA_BMP_SIZE >> 5];
331 int ba_index;
332 int isaggr = 0;
333
334 *nbad = 0;
335 *nframes = 0;
336
Felix Fietkaub572d032010-11-14 15:20:07 +0100337 isaggr = bf_isaggr(bf);
338 if (isaggr) {
339 seq_st = ts->ts_seqnum;
340 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
341 }
342
343 while (bf) {
344 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
345
346 (*nframes)++;
347 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
348 (*nbad)++;
349
350 bf = bf->bf_next;
351 }
352}
353
354
Sujithd43f30152009-01-16 21:38:53 +0530355static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
356 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100357 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530358{
359 struct ath_node *an = NULL;
360 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530361 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800362 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530363 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800364 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530365 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530366 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530367 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530368 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530369 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530370 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
371 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200372 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100373 u16 bf_seqno;
Björn Smedmanebd02282010-10-10 22:44:39 +0200374 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100375 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530376
Sujitha22be222009-03-30 15:28:36 +0530377 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530378 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530379
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800380 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100381 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800382
Felix Fietkau78c46532010-06-25 01:26:16 +0200383 memcpy(rates, tx_info->control.rates, sizeof(rates));
384
Sujith1286ec62009-01-27 13:30:37 +0530385 rcu_read_lock();
386
Ben Greear686b9cb2010-09-23 09:44:36 -0700387 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530388 if (!sta) {
389 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200390
Felix Fietkau31e79a52010-07-12 23:16:34 +0200391 INIT_LIST_HEAD(&bf_head);
392 while (bf) {
393 bf_next = bf->bf_next;
394
395 bf->bf_state.bf_type |= BUF_XRETRY;
396 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
397 !bf->bf_stale || bf_next != NULL)
398 list_move_tail(&bf->list, &bf_head);
399
Felix Fietkaub572d032010-11-14 15:20:07 +0100400 ath_tx_rc_status(bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200401 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
402 0, 0);
403
404 bf = bf_next;
405 }
Sujith1286ec62009-01-27 13:30:37 +0530406 return;
Sujithe8324352009-01-16 21:38:42 +0530407 }
408
Sujith1286ec62009-01-27 13:30:37 +0530409 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100410 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
411 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530412
Felix Fietkaub11b1602010-07-11 12:48:44 +0200413 /*
414 * The hardware occasionally sends a tx status for the wrong TID.
415 * In this case, the BA status cannot be considered valid and all
416 * subframes need to be retransmitted
417 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100418 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200419 txok = false;
420
Sujithe8324352009-01-16 21:38:42 +0530421 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530422 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530423
Sujithd43f30152009-01-16 21:38:53 +0530424 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700425 if (ts->ts_flags & ATH9K_TX_BA) {
426 seq_st = ts->ts_seqnum;
427 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530428 } else {
Sujithd43f30152009-01-16 21:38:53 +0530429 /*
430 * AR5416 can become deaf/mute when BA
431 * issue happens. Chip needs to be reset.
432 * But AP code may have sychronization issues
433 * when perform internal reset in this routine.
434 * Only enable reset in STA mode for now.
435 */
Sujith2660b812009-02-09 13:27:26 +0530436 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530437 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530438 }
439 }
440
441 INIT_LIST_HEAD(&bf_pending);
442 INIT_LIST_HEAD(&bf_head);
443
Felix Fietkaub572d032010-11-14 15:20:07 +0100444 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530445 while (bf) {
446 txfail = txpending = 0;
447 bf_next = bf->bf_next;
448
Felix Fietkau78c46532010-06-25 01:26:16 +0200449 skb = bf->bf_mpdu;
450 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100451 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200452
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100453 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530454 /* transmit completion, subframe is
455 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530456 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530457 } else if (!isaggr && txok) {
458 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530459 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530460 } else {
Felix Fietkauc5992612010-11-14 15:20:09 +0100461 if (!(tid->state & AGGR_CLEANUP) && retry) {
Sujithe8324352009-01-16 21:38:42 +0530462 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530463 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530464 txpending = 1;
465 } else {
466 bf->bf_state.bf_type |= BUF_XRETRY;
467 txfail = 1;
468 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530469 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530470 }
471 } else {
472 /*
473 * cleanup in progress, just fail
474 * the un-acked sub-frames
475 */
476 txfail = 1;
477 }
478 }
479
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400480 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
481 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530482 /*
483 * Make sure the last desc is reclaimed if it
484 * not a holding desc.
485 */
486 if (!bf_last->bf_stale)
487 list_move_tail(&bf->list, &bf_head);
488 else
489 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530490 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700491 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530492 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530493 }
494
Felix Fietkau90fa5392010-09-20 13:45:38 +0200495 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530496 /*
497 * complete the acked-ones/xretried ones; update
498 * block-ack window
499 */
500 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100501 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530502 spin_unlock_bh(&txq->axq_lock);
503
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530504 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200505 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaub572d032010-11-14 15:20:07 +0100506 ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530507 rc_update = false;
508 } else {
Felix Fietkaub572d032010-11-14 15:20:07 +0100509 ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530510 }
511
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700512 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
513 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530514 } else {
Sujithd43f30152009-01-16 21:38:53 +0530515 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400516 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
517 if (bf->bf_next == NULL && bf_last->bf_stale) {
518 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530519
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400520 tbf = ath_clone_txbuf(sc, bf_last);
521 /*
522 * Update tx baw and complete the
523 * frame with failed status if we
524 * run out of tx buf.
525 */
526 if (!tbf) {
527 spin_lock_bh(&txq->axq_lock);
528 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100529 bf_seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400530 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400531
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400532 bf->bf_state.bf_type |=
533 BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +0100534 ath_tx_rc_status(bf, ts, nframes,
535 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400536 ath_tx_complete_buf(sc, bf, txq,
537 &bf_head,
538 ts, 0, 0);
539 break;
540 }
541
542 ath9k_hw_cleartxdesc(sc->sc_ah,
543 tbf->bf_desc);
544 list_add_tail(&tbf->list, &bf_head);
545 } else {
546 /*
547 * Clear descriptor status words for
548 * software retry
549 */
550 ath9k_hw_cleartxdesc(sc->sc_ah,
551 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400552 }
Sujithe8324352009-01-16 21:38:42 +0530553 }
554
555 /*
556 * Put this buffer to the temporary pending
557 * queue to retain ordering
558 */
559 list_splice_tail_init(&bf_head, &bf_pending);
560 }
561
562 bf = bf_next;
563 }
564
Felix Fietkau4cee7862010-07-23 03:53:16 +0200565 /* prepend un-acked frames to the beginning of the pending frame queue */
566 if (!list_empty(&bf_pending)) {
567 spin_lock_bh(&txq->axq_lock);
568 list_splice(&bf_pending, &tid->buf_q);
569 ath_tx_queue_tid(txq, tid);
570 spin_unlock_bh(&txq->axq_lock);
571 }
572
Sujithe8324352009-01-16 21:38:42 +0530573 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200574 ath_tx_flush_tid(sc, tid);
575
Sujithe8324352009-01-16 21:38:42 +0530576 if (tid->baw_head == tid->baw_tail) {
577 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530578 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530579 }
Sujithe8324352009-01-16 21:38:42 +0530580 }
581
Sujith1286ec62009-01-27 13:30:37 +0530582 rcu_read_unlock();
583
Sujithe8324352009-01-16 21:38:42 +0530584 if (needreset)
585 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530586}
587
588static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
589 struct ath_atx_tid *tid)
590{
Sujithe8324352009-01-16 21:38:42 +0530591 struct sk_buff *skb;
592 struct ieee80211_tx_info *tx_info;
593 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530594 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530595 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530596 int i;
597
Sujitha22be222009-03-30 15:28:36 +0530598 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530599 tx_info = IEEE80211_SKB_CB(skb);
600 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530601
602 /*
603 * Find the lowest frame length among the rate series that will have a
604 * 4ms transmit duration.
605 * TODO - TXOP limit needs to be considered.
606 */
607 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
608
609 for (i = 0; i < 4; i++) {
610 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100611 int modeidx;
612 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530613 legacy = 1;
614 break;
615 }
616
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200617 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100618 modeidx = MCS_HT40;
619 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200620 modeidx = MCS_HT20;
621
622 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
623 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100624
625 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530626 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530627 }
628 }
629
630 /*
631 * limit aggregate size by the minimum rate if rate selected is
632 * not a probe rate, if rate selected is a probe rate then
633 * avoid aggregation of this packet.
634 */
635 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
636 return 0;
637
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530638 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
639 aggr_limit = min((max_4ms_framelen * 3) / 8,
640 (u32)ATH_AMPDU_LIMIT_MAX);
641 else
642 aggr_limit = min(max_4ms_framelen,
643 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530644
645 /*
646 * h/w can accept aggregates upto 16 bit lengths (65535).
647 * The IE, however can hold upto 65536, which shows up here
648 * as zero. Ignore 65536 since we are constrained by hw.
649 */
Sujith4ef70842009-07-23 15:32:41 +0530650 if (tid->an->maxampdu)
651 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530652
653 return aggr_limit;
654}
655
656/*
Sujithd43f30152009-01-16 21:38:53 +0530657 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530658 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530659 */
660static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
661 struct ath_buf *bf, u16 frmlen)
662{
Sujithe8324352009-01-16 21:38:42 +0530663 struct sk_buff *skb = bf->bf_mpdu;
664 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530665 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530666 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100667 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200668 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530669
670 /* Select standard number of delimiters based on frame length alone */
671 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
672
673 /*
674 * If encryption enabled, hardware requires some more padding between
675 * subframes.
676 * TODO - this could be improved to be dependent on the rate.
677 * The hardware can keep up at lower rates, but not higher rates
678 */
Felix Fietkau952cd692010-11-14 15:20:03 +0100679 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +0530680 ndelim += ATH_AGGR_ENCRYPTDELIM;
681
682 /*
683 * Convert desired mpdu density from microeconds to bytes based
684 * on highest rate in rate series (i.e. first rate) to determine
685 * required minimum length for subframe. Take into account
686 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530687 *
Sujithe8324352009-01-16 21:38:42 +0530688 * If there is no mpdu density restriction, no further calculation
689 * is needed.
690 */
Sujith4ef70842009-07-23 15:32:41 +0530691
692 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530693 return ndelim;
694
695 rix = tx_info->control.rates[0].idx;
696 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530697 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
698 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
699
700 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530701 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530702 else
Sujith4ef70842009-07-23 15:32:41 +0530703 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530704
705 if (nsymbols == 0)
706 nsymbols = 1;
707
Felix Fietkauc6663872010-04-19 19:57:33 +0200708 streams = HT_RC_2_STREAMS(rix);
709 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530710 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
711
Sujithe8324352009-01-16 21:38:42 +0530712 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530713 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
714 ndelim = max(mindelim, ndelim);
715 }
716
717 return ndelim;
718}
719
720static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530721 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530722 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100723 struct list_head *bf_q,
724 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530725{
726#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530727 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
728 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530729 u16 aggr_limit = 0, al = 0, bpad = 0,
730 al_delta, h_baw = tid->baw_size / 2;
731 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200732 struct ieee80211_tx_info *tx_info;
Felix Fietkau76e45222010-11-14 15:20:08 +0100733 int frmlen;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100734 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530735
736 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
737
738 do {
739 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100740 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530741
Sujithd43f30152009-01-16 21:38:53 +0530742 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100743 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530744 status = ATH_AGGR_BAW_CLOSED;
745 break;
746 }
747
748 if (!rl) {
749 aggr_limit = ath_lookup_rate(sc, bf, tid);
750 rl = 1;
751 }
752
Sujithd43f30152009-01-16 21:38:53 +0530753 /* do not exceed aggregation limit */
Felix Fietkau76e45222010-11-14 15:20:08 +0100754 frmlen = ath_frame_len(bf->bf_mpdu);
755 al_delta = ATH_AGGR_DELIM_SZ + frmlen;
Sujithe8324352009-01-16 21:38:42 +0530756
Sujithd43f30152009-01-16 21:38:53 +0530757 if (nframes &&
758 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530759 status = ATH_AGGR_LIMITED;
760 break;
761 }
762
Felix Fietkau0299a502010-10-21 02:47:24 +0200763 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
764 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
765 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
766 break;
767
Sujithd43f30152009-01-16 21:38:53 +0530768 /* do not exceed subframe limit */
769 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530770 status = ATH_AGGR_LIMITED;
771 break;
772 }
Sujithd43f30152009-01-16 21:38:53 +0530773 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530774
Sujithd43f30152009-01-16 21:38:53 +0530775 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530776 al += bpad + al_delta;
777
778 /*
779 * Get the delimiters needed to meet the MPDU
780 * density for this node.
781 */
Felix Fietkau76e45222010-11-14 15:20:08 +0100782 ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530783 bpad = PADBYTES(al_delta) + (ndelim << 2);
784
785 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400786 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530787
Sujithd43f30152009-01-16 21:38:53 +0530788 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100789 if (!bf_isretried(bf))
790 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530791 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
792 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530793 if (bf_prev) {
794 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400795 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
796 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530797 }
798 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530799
Sujithe8324352009-01-16 21:38:42 +0530800 } while (!list_empty(&tid->buf_q));
801
Felix Fietkau269c44b2010-11-14 15:20:06 +0100802 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530803
Sujithe8324352009-01-16 21:38:42 +0530804 return status;
805#undef PADBYTES
806}
807
808static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
809 struct ath_atx_tid *tid)
810{
Sujithd43f30152009-01-16 21:38:53 +0530811 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530812 enum ATH_AGGR_STATUS status;
813 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100814 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530815
816 do {
817 if (list_empty(&tid->buf_q))
818 return;
819
820 INIT_LIST_HEAD(&bf_q);
821
Felix Fietkau269c44b2010-11-14 15:20:06 +0100822 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530823
824 /*
Sujithd43f30152009-01-16 21:38:53 +0530825 * no frames picked up to be aggregated;
826 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530827 */
828 if (list_empty(&bf_q))
829 break;
830
831 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530832 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530833
Sujithd43f30152009-01-16 21:38:53 +0530834 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100835 if (bf == bf->bf_lastbf) {
Sujithe8324352009-01-16 21:38:42 +0530836 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530837 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau76e45222010-11-14 15:20:08 +0100838 ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +0530839 ath_tx_txqaddbuf(sc, txq, &bf_q);
840 continue;
841 }
842
Sujithd43f30152009-01-16 21:38:53 +0530843 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530844 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100845 ath_buf_set_rate(sc, bf, aggr_len);
846 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530847
Sujithd43f30152009-01-16 21:38:53 +0530848 /* anchor last desc of aggregate */
849 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530850
Sujithe8324352009-01-16 21:38:42 +0530851 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530852 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530853
854 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
855 status != ATH_AGGR_BAW_CLOSED);
856}
857
Felix Fietkau231c3a12010-09-20 19:35:28 +0200858int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
859 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530860{
861 struct ath_atx_tid *txtid;
862 struct ath_node *an;
863
864 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530865 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200866
867 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
868 return -EAGAIN;
869
Sujithf83da962009-07-23 15:32:37 +0530870 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200871 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530872 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200873
874 return 0;
Sujithe8324352009-01-16 21:38:42 +0530875}
876
Sujithf83da962009-07-23 15:32:37 +0530877void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530878{
879 struct ath_node *an = (struct ath_node *)sta->drv_priv;
880 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100881 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530882
883 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530884 return;
Sujithe8324352009-01-16 21:38:42 +0530885
886 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530887 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530888 return;
Sujithe8324352009-01-16 21:38:42 +0530889 }
890
Sujithe8324352009-01-16 21:38:42 +0530891 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200892 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200893
894 /*
895 * If frames are still being transmitted for this TID, they will be
896 * cleaned up during tx completion. To prevent race conditions, this
897 * TID can only be reused after all in-progress subframes have been
898 * completed.
899 */
900 if (txtid->baw_head != txtid->baw_tail)
901 txtid->state |= AGGR_CLEANUP;
902 else
903 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530904 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530905
Felix Fietkau90fa5392010-09-20 13:45:38 +0200906 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530907}
908
909void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
910{
911 struct ath_atx_tid *txtid;
912 struct ath_node *an;
913
914 an = (struct ath_node *)sta->drv_priv;
915
916 if (sc->sc_flags & SC_OP_TXAGGR) {
917 txtid = ATH_AN_2_TID(an, tid);
918 txtid->baw_size =
919 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
920 txtid->state |= AGGR_ADDBA_COMPLETE;
921 txtid->state &= ~AGGR_ADDBA_PROGRESS;
922 ath_tx_resume_tid(sc, txtid);
923 }
924}
925
Sujithe8324352009-01-16 21:38:42 +0530926/********************/
927/* Queue Management */
928/********************/
929
Sujithe8324352009-01-16 21:38:42 +0530930static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
931 struct ath_txq *txq)
932{
933 struct ath_atx_ac *ac, *ac_tmp;
934 struct ath_atx_tid *tid, *tid_tmp;
935
936 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
937 list_del(&ac->list);
938 ac->sched = false;
939 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
940 list_del(&tid->list);
941 tid->sched = false;
942 ath_tid_drain(sc, txq, tid);
943 }
944 }
945}
946
947struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
948{
Sujithcbe61d82009-02-09 13:27:12 +0530949 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700950 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530951 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100952 static const int subtype_txq_to_hwq[] = {
953 [WME_AC_BE] = ATH_TXQ_AC_BE,
954 [WME_AC_BK] = ATH_TXQ_AC_BK,
955 [WME_AC_VI] = ATH_TXQ_AC_VI,
956 [WME_AC_VO] = ATH_TXQ_AC_VO,
957 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400958 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530959
960 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100961 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530962 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
963 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
964 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
965 qi.tqi_physCompBuf = 0;
966
967 /*
968 * Enable interrupts only for EOL and DESC conditions.
969 * We mark tx descriptors to receive a DESC interrupt
970 * when a tx queue gets deep; otherwise waiting for the
971 * EOL to reap descriptors. Note that this is done to
972 * reduce interrupt load and this only defers reaping
973 * descriptors, never transmitting frames. Aside from
974 * reducing interrupts this also permits more concurrency.
975 * The only potential downside is if the tx queue backs
976 * up in which case the top half of the kernel may backup
977 * due to a lack of tx descriptors.
978 *
979 * The UAPSD queue is an exception, since we take a desc-
980 * based intr on the EOSP frames.
981 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400982 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
983 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
984 TXQ_FLAG_TXERRINT_ENABLE;
985 } else {
986 if (qtype == ATH9K_TX_QUEUE_UAPSD)
987 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
988 else
989 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
990 TXQ_FLAG_TXDESCINT_ENABLE;
991 }
Sujithe8324352009-01-16 21:38:42 +0530992 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
993 if (qnum == -1) {
994 /*
995 * NB: don't print a message, this happens
996 * normally on parts with too few tx queues
997 */
998 return NULL;
999 }
1000 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001001 ath_print(common, ATH_DBG_FATAL,
1002 "qnum %u out of range, max %u!\n",
1003 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +05301004 ath9k_hw_releasetxqueue(ah, qnum);
1005 return NULL;
1006 }
1007 if (!ATH_TXQ_SETUP(sc, qnum)) {
1008 struct ath_txq *txq = &sc->tx.txq[qnum];
1009
1010 txq->axq_qnum = qnum;
1011 txq->axq_link = NULL;
1012 INIT_LIST_HEAD(&txq->axq_q);
1013 INIT_LIST_HEAD(&txq->axq_acq);
1014 spin_lock_init(&txq->axq_lock);
1015 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001016 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +05301017 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001018
1019 txq->txq_headidx = txq->txq_tailidx = 0;
1020 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1021 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1022 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301023 }
1024 return &sc->tx.txq[qnum];
1025}
1026
Sujithe8324352009-01-16 21:38:42 +05301027int ath_txq_update(struct ath_softc *sc, int qnum,
1028 struct ath9k_tx_queue_info *qinfo)
1029{
Sujithcbe61d82009-02-09 13:27:12 +05301030 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301031 int error = 0;
1032 struct ath9k_tx_queue_info qi;
1033
1034 if (qnum == sc->beacon.beaconq) {
1035 /*
1036 * XXX: for beacon queue, we just save the parameter.
1037 * It will be picked up by ath_beaconq_config when
1038 * it's necessary.
1039 */
1040 sc->beacon.beacon_qi = *qinfo;
1041 return 0;
1042 }
1043
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001044 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301045
1046 ath9k_hw_get_txq_props(ah, qnum, &qi);
1047 qi.tqi_aifs = qinfo->tqi_aifs;
1048 qi.tqi_cwmin = qinfo->tqi_cwmin;
1049 qi.tqi_cwmax = qinfo->tqi_cwmax;
1050 qi.tqi_burstTime = qinfo->tqi_burstTime;
1051 qi.tqi_readyTime = qinfo->tqi_readyTime;
1052
1053 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001054 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1055 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301056 error = -EIO;
1057 } else {
1058 ath9k_hw_resettxqueue(ah, qnum);
1059 }
1060
1061 return error;
1062}
1063
1064int ath_cabq_update(struct ath_softc *sc)
1065{
1066 struct ath9k_tx_queue_info qi;
1067 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301068
1069 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1070 /*
1071 * Ensure the readytime % is within the bounds.
1072 */
Sujith17d79042009-02-09 13:27:03 +05301073 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1074 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1075 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1076 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301077
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001078 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301079 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301080 ath_txq_update(sc, qnum, &qi);
1081
1082 return 0;
1083}
1084
Sujith043a0402009-01-16 21:38:47 +05301085/*
1086 * Drain a given TX queue (could be Beacon or Data)
1087 *
1088 * This assumes output has been stopped and
1089 * we do not need to block ath_tx_tasklet.
1090 */
1091void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301092{
1093 struct ath_buf *bf, *lastbf;
1094 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001095 struct ath_tx_status ts;
1096
1097 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301098 INIT_LIST_HEAD(&bf_head);
1099
Sujithe8324352009-01-16 21:38:42 +05301100 for (;;) {
1101 spin_lock_bh(&txq->axq_lock);
1102
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001103 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1104 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1105 txq->txq_headidx = txq->txq_tailidx = 0;
1106 spin_unlock_bh(&txq->axq_lock);
1107 break;
1108 } else {
1109 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1110 struct ath_buf, list);
1111 }
1112 } else {
1113 if (list_empty(&txq->axq_q)) {
1114 txq->axq_link = NULL;
1115 spin_unlock_bh(&txq->axq_lock);
1116 break;
1117 }
1118 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1119 list);
Sujithe8324352009-01-16 21:38:42 +05301120
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001121 if (bf->bf_stale) {
1122 list_del(&bf->list);
1123 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301124
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001125 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001126 continue;
1127 }
Sujithe8324352009-01-16 21:38:42 +05301128 }
1129
1130 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05301131
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001132 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1133 list_cut_position(&bf_head,
1134 &txq->txq_fifo[txq->txq_tailidx],
1135 &lastbf->list);
1136 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1137 } else {
1138 /* remove ath_buf's of the same mpdu from txq */
1139 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1140 }
1141
Sujithe8324352009-01-16 21:38:42 +05301142 txq->axq_depth--;
1143
1144 spin_unlock_bh(&txq->axq_lock);
1145
1146 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001147 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1148 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301149 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001150 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301151 }
1152
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001153 spin_lock_bh(&txq->axq_lock);
1154 txq->axq_tx_inprogress = false;
1155 spin_unlock_bh(&txq->axq_lock);
1156
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001157 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1158 spin_lock_bh(&txq->axq_lock);
1159 while (!list_empty(&txq->txq_fifo_pending)) {
1160 bf = list_first_entry(&txq->txq_fifo_pending,
1161 struct ath_buf, list);
1162 list_cut_position(&bf_head,
1163 &txq->txq_fifo_pending,
1164 &bf->bf_lastbf->list);
1165 spin_unlock_bh(&txq->axq_lock);
1166
1167 if (bf_isampdu(bf))
1168 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
Felix Fietkauc5992612010-11-14 15:20:09 +01001169 &ts, 0, retry_tx);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001170 else
1171 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1172 &ts, 0, 0);
1173 spin_lock_bh(&txq->axq_lock);
1174 }
1175 spin_unlock_bh(&txq->axq_lock);
1176 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001177
1178 /* flush any pending frames if aggregation is enabled */
1179 if (sc->sc_flags & SC_OP_TXAGGR) {
1180 if (!retry_tx) {
1181 spin_lock_bh(&txq->axq_lock);
1182 ath_txq_drain_pending_buffers(sc, txq);
1183 spin_unlock_bh(&txq->axq_lock);
1184 }
1185 }
Sujithe8324352009-01-16 21:38:42 +05301186}
1187
Sujith043a0402009-01-16 21:38:47 +05301188void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1189{
Sujithcbe61d82009-02-09 13:27:12 +05301190 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001191 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301192 struct ath_txq *txq;
1193 int i, npend = 0;
1194
1195 if (sc->sc_flags & SC_OP_INVALID)
1196 return;
1197
1198 /* Stop beacon queue */
1199 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1200
1201 /* Stop data queues */
1202 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1203 if (ATH_TXQ_SETUP(sc, i)) {
1204 txq = &sc->tx.txq[i];
1205 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1206 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1207 }
1208 }
1209
1210 if (npend) {
1211 int r;
1212
Sujithe8009e92009-12-14 14:57:08 +05301213 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001214 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301215
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001216 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301217 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001218 ath_print(common, ATH_DBG_FATAL,
1219 "Unable to reset hardware; reset status %d\n",
1220 r);
Sujith043a0402009-01-16 21:38:47 +05301221 }
1222
1223 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1224 if (ATH_TXQ_SETUP(sc, i))
1225 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1226 }
1227}
1228
Sujithe8324352009-01-16 21:38:42 +05301229void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1230{
1231 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1232 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1233}
1234
Sujithe8324352009-01-16 21:38:42 +05301235void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1236{
1237 struct ath_atx_ac *ac;
1238 struct ath_atx_tid *tid;
1239
1240 if (list_empty(&txq->axq_acq))
1241 return;
1242
1243 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1244 list_del(&ac->list);
1245 ac->sched = false;
1246
1247 do {
1248 if (list_empty(&ac->tid_q))
1249 return;
1250
1251 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1252 list_del(&tid->list);
1253 tid->sched = false;
1254
1255 if (tid->paused)
1256 continue;
1257
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001258 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301259
1260 /*
1261 * add tid to round-robin queue if more frames
1262 * are pending for the tid
1263 */
1264 if (!list_empty(&tid->buf_q))
1265 ath_tx_queue_tid(txq, tid);
1266
1267 break;
1268 } while (!list_empty(&ac->tid_q));
1269
1270 if (!list_empty(&ac->tid_q)) {
1271 if (!ac->sched) {
1272 ac->sched = true;
1273 list_add_tail(&ac->list, &txq->axq_acq);
1274 }
1275 }
1276}
1277
Sujithe8324352009-01-16 21:38:42 +05301278/***********/
1279/* TX, DMA */
1280/***********/
1281
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001282/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001283 * Insert a chain of ath_buf (descriptors) on a txq and
1284 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001285 */
Sujith102e0572008-10-29 10:15:16 +05301286static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1287 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001288{
Sujithcbe61d82009-02-09 13:27:12 +05301289 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001290 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001291 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301292
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001293 /*
1294 * Insert the frame on the outbound list and
1295 * pass it on to the hardware.
1296 */
1297
1298 if (list_empty(head))
1299 return;
1300
1301 bf = list_first_entry(head, struct ath_buf, list);
1302
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001303 ath_print(common, ATH_DBG_QUEUE,
1304 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001305
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001306 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1307 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1308 list_splice_tail_init(head, &txq->txq_fifo_pending);
1309 return;
1310 }
1311 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1312 ath_print(common, ATH_DBG_XMIT,
1313 "Initializing tx fifo %d which "
1314 "is non-empty\n",
1315 txq->txq_headidx);
1316 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1317 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1318 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001319 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001320 ath_print(common, ATH_DBG_XMIT,
1321 "TXDP[%u] = %llx (%p)\n",
1322 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001323 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001324 list_splice_tail_init(head, &txq->axq_q);
1325
1326 if (txq->axq_link == NULL) {
1327 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1328 ath_print(common, ATH_DBG_XMIT,
1329 "TXDP[%u] = %llx (%p)\n",
1330 txq->axq_qnum, ito64(bf->bf_daddr),
1331 bf->bf_desc);
1332 } else {
1333 *txq->axq_link = bf->bf_daddr;
1334 ath_print(common, ATH_DBG_XMIT,
1335 "link[%u] (%p)=%llx (%p)\n",
1336 txq->axq_qnum, txq->axq_link,
1337 ito64(bf->bf_daddr), bf->bf_desc);
1338 }
1339 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1340 &txq->axq_link);
1341 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001342 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001343 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001344}
1345
Sujithe8324352009-01-16 21:38:42 +05301346static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1347 struct list_head *bf_head,
Felix Fietkau76e45222010-11-14 15:20:08 +01001348 struct ath_tx_control *txctl, int frmlen)
Sujithe8324352009-01-16 21:38:42 +05301349{
1350 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001351 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301352
Sujithe8324352009-01-16 21:38:42 +05301353 bf = list_first_entry(bf_head, struct ath_buf, list);
1354 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301355 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001356 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301357
1358 /*
1359 * Do not queue to h/w when any of the following conditions is true:
1360 * - there are pending frames in software queue
1361 * - the TID is currently paused for ADDBA/BAR request
1362 * - seqno is not within block-ack window
1363 * - h/w queue depth exceeds low water mark
1364 */
1365 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001366 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301367 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001368 /*
Sujithe8324352009-01-16 21:38:42 +05301369 * Add this frame to software queue for scheduling later
1370 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001371 */
Sujithd43f30152009-01-16 21:38:53 +05301372 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301373 ath_tx_queue_tid(txctl->txq, tid);
1374 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001375 }
1376
Sujithe8324352009-01-16 21:38:42 +05301377 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001378 if (!bf_isretried(bf))
1379 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301380
1381 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301382 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001383 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301384 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301385}
1386
Felix Fietkau82b873a2010-11-11 03:18:37 +01001387static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1388 struct ath_atx_tid *tid,
Felix Fietkau76e45222010-11-14 15:20:08 +01001389 struct list_head *bf_head, int frmlen)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001390{
Sujithe8324352009-01-16 21:38:42 +05301391 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001392
Sujithe8324352009-01-16 21:38:42 +05301393 bf = list_first_entry(bf_head, struct ath_buf, list);
1394 bf->bf_state.bf_type &= ~BUF_AMPDU;
1395
1396 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001397 if (tid)
1398 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301399
Sujithd43f30152009-01-16 21:38:53 +05301400 bf->bf_lastbf = bf;
Felix Fietkau76e45222010-11-14 15:20:08 +01001401 ath_buf_set_rate(sc, bf, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301402 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301403 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001404}
1405
Sujith528f0c62008-10-29 10:14:26 +05301406static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001407{
Sujith528f0c62008-10-29 10:14:26 +05301408 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409 enum ath9k_pkt_type htype;
1410 __le16 fc;
1411
Sujith528f0c62008-10-29 10:14:26 +05301412 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001413 fc = hdr->frame_control;
1414
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001415 if (ieee80211_is_beacon(fc))
1416 htype = ATH9K_PKT_TYPE_BEACON;
1417 else if (ieee80211_is_probe_resp(fc))
1418 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1419 else if (ieee80211_is_atim(fc))
1420 htype = ATH9K_PKT_TYPE_ATIM;
1421 else if (ieee80211_is_pspoll(fc))
1422 htype = ATH9K_PKT_TYPE_PSPOLL;
1423 else
1424 htype = ATH9K_PKT_TYPE_NORMAL;
1425
1426 return htype;
1427}
1428
Sujith528f0c62008-10-29 10:14:26 +05301429static void assign_aggr_tid_seqno(struct sk_buff *skb,
1430 struct ath_buf *bf)
1431{
1432 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1433 struct ieee80211_hdr *hdr;
1434 struct ath_node *an;
1435 struct ath_atx_tid *tid;
1436 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001437 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301438
1439 if (!tx_info->control.sta)
1440 return;
1441
1442 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1443 hdr = (struct ieee80211_hdr *)skb->data;
1444 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001445 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001446
Sujithe8324352009-01-16 21:38:42 +05301447 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001448 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301449 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301450 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001451 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301452 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301453 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301454}
1455
Felix Fietkau82b873a2010-11-11 03:18:37 +01001456static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301457{
1458 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1459 int flags = 0;
1460
1461 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1462 flags |= ATH9K_TXDESC_INTREQ;
1463
1464 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1465 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301466
Felix Fietkau82b873a2010-11-11 03:18:37 +01001467 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001468 flags |= ATH9K_TXDESC_LDPC;
1469
Sujith528f0c62008-10-29 10:14:26 +05301470 return flags;
1471}
1472
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001473/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001474 * rix - rate index
1475 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1476 * width - 0 for 20 MHz, 1 for 40 MHz
1477 * half_gi - to use 4us v/s 3.6 us for symbol time
1478 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001479static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301480 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001481{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001482 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001483 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301484
1485 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001486 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001488 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001489 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1490
1491 if (!half_gi)
1492 duration = SYMBOL_TIME(nsymbols);
1493 else
1494 duration = SYMBOL_TIME_HALFGI(nsymbols);
1495
Sujithe63835b2008-11-18 09:07:53 +05301496 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301498
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499 return duration;
1500}
1501
Felix Fietkau269c44b2010-11-14 15:20:06 +01001502static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001503{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001504 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301506 struct sk_buff *skb;
1507 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301508 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001509 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301510 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301511 int i, flags = 0;
1512 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301513 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301514
1515 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301516
Sujitha22be222009-03-30 15:28:36 +05301517 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301518 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301519 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301520 hdr = (struct ieee80211_hdr *)skb->data;
1521 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301522
Sujithc89424d2009-01-30 14:29:28 +05301523 /*
1524 * We check if Short Preamble is needed for the CTS rate by
1525 * checking the BSS's global flag.
1526 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1527 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001528 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1529 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301530 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001531 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001532
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001533 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001534 bool is_40, is_sgi, is_sp;
1535 int phy;
1536
Sujithe63835b2008-11-18 09:07:53 +05301537 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001538 continue;
1539
Sujitha8efee42008-11-18 09:07:30 +05301540 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301541 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001542 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001543
Felix Fietkau27032052010-01-17 21:08:50 +01001544 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1545 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301546 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001547 flags |= ATH9K_TXDESC_RTSENA;
1548 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1549 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1550 flags |= ATH9K_TXDESC_CTSENA;
1551 }
1552
Sujithc89424d2009-01-30 14:29:28 +05301553 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1554 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1555 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1556 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001557
Felix Fietkau545750d2009-11-23 22:21:01 +01001558 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1559 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1560 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1561
1562 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1563 /* MCS rates */
1564 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001565 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001566 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001567 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1568 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001569 continue;
1570 }
1571
1572 /* legcay rates */
1573 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1574 !(rate->flags & IEEE80211_RATE_ERP_G))
1575 phy = WLAN_RC_PHY_CCK;
1576 else
1577 phy = WLAN_RC_PHY_OFDM;
1578
1579 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1580 series[i].Rate = rate->hw_value;
1581 if (rate->hw_value_short) {
1582 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1583 series[i].Rate |= rate->hw_value_short;
1584 } else {
1585 is_sp = false;
1586 }
1587
1588 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001589 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001590 }
1591
Felix Fietkau27032052010-01-17 21:08:50 +01001592 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001593 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001594 flags &= ~ATH9K_TXDESC_RTSENA;
1595
1596 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1597 if (flags & ATH9K_TXDESC_RTSENA)
1598 flags &= ~ATH9K_TXDESC_CTSENA;
1599
Sujithe63835b2008-11-18 09:07:53 +05301600 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301601 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1602 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301603 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301604 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301605
Sujith17d79042009-02-09 13:27:03 +05301606 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301607 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001608}
1609
Felix Fietkau82b873a2010-11-11 03:18:37 +01001610static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1611 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301612{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001613 struct ath_wiphy *aphy = hw->priv;
1614 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001615 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301616 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001617 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301618 int hdrlen;
1619 __le16 fc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001620
1621 bf = ath_tx_get_buffer(sc);
1622 if (!bf) {
1623 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1624 return NULL;
1625 }
Sujithe8324352009-01-16 21:38:42 +05301626
Sujithe8324352009-01-16 21:38:42 +05301627 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1628 fc = hdr->frame_control;
1629
1630 ATH_TXBUF_RESET(bf);
1631
Felix Fietkau827e69b2009-11-15 23:09:25 +01001632 bf->aphy = aphy;
Sujithe8324352009-01-16 21:38:42 +05301633
Felix Fietkau82b873a2010-11-11 03:18:37 +01001634 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301635 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001636 if (sc->sc_flags & SC_OP_TXAGGR)
1637 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001638 }
Sujithe8324352009-01-16 21:38:42 +05301639
Felix Fietkau82b873a2010-11-11 03:18:37 +01001640 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301641
Sujithe8324352009-01-16 21:38:42 +05301642 bf->bf_mpdu = skb;
1643
Ben Greearc1739eb32010-10-14 12:45:29 -07001644 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1645 skb->len, DMA_TO_DEVICE);
1646 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301647 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001648 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001649 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1650 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001651 ath_tx_return_buffer(sc, bf);
1652 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301653 }
1654
Felix Fietkau82b873a2010-11-11 03:18:37 +01001655 return bf;
Sujithe8324352009-01-16 21:38:42 +05301656}
1657
1658/* FIXME: tx power */
1659static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1660 struct ath_tx_control *txctl)
1661{
Sujitha22be222009-03-30 15:28:36 +05301662 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301663 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301664 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301665 struct ath_node *an = NULL;
1666 struct list_head bf_head;
1667 struct ath_desc *ds;
1668 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301669 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001670 enum ath9k_key_type keytype;
Felix Fietkau30170472010-11-14 15:20:05 +01001671 u32 keyix;
Sujithe8324352009-01-16 21:38:42 +05301672 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301673 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001674 u8 tidno;
Felix Fietkau76e45222010-11-14 15:20:08 +01001675 int frmlen;
Sujithe8324352009-01-16 21:38:42 +05301676
1677 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301678 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301679
1680 INIT_LIST_HEAD(&bf_head);
1681 list_add_tail(&bf->list, &bf_head);
1682
1683 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001684 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301685
Felix Fietkau952cd692010-11-14 15:20:03 +01001686 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001687 if (tx_info->control.hw_key)
1688 keyix = tx_info->control.hw_key->hw_key_idx;
1689 else
1690 keyix = ATH9K_TXKEYIX_INVALID;
1691
Felix Fietkau76e45222010-11-14 15:20:08 +01001692 frmlen = ath_frame_len(bf->bf_mpdu);
1693 ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001694 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301695
1696 ath9k_hw_filltxdesc(ah, ds,
1697 skb->len, /* segment length */
1698 true, /* first segment */
1699 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001700 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001701 bf->bf_buf_addr,
1702 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301703
Sujithe8324352009-01-16 21:38:42 +05301704 spin_lock_bh(&txctl->txq->axq_lock);
1705
1706 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1707 tx_info->control.sta) {
1708 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001709 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1710 IEEE80211_QOS_CTL_TID_MASK;
1711 tid = ATH_AN_2_TID(an, tidno);
1712
Sujithe8324352009-01-16 21:38:42 +05301713
Felix Fietkau066dae92010-11-07 14:59:39 +01001714 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001715 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301716 /*
1717 * Try aggregation if it's a unicast data frame
1718 * and the destination is HT capable.
1719 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001720 ath_tx_send_ampdu(sc, tid, &bf_head, txctl, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301721 } else {
1722 /*
1723 * Send this frame as regular when ADDBA
1724 * exchange is neither complete nor pending.
1725 */
Felix Fietkau76e45222010-11-14 15:20:08 +01001726 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301727 }
1728 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001729 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001730 bf->bf_state.bfs_paprd = txctl->paprd;
1731
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001732 if (bf->bf_state.bfs_paprd)
1733 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1734
Felix Fietkau76e45222010-11-14 15:20:08 +01001735 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, frmlen);
Sujithe8324352009-01-16 21:38:42 +05301736 }
1737
1738 spin_unlock_bh(&txctl->txq->axq_lock);
1739}
1740
1741/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001742int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301743 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744{
Felix Fietkau28d16702010-11-14 15:20:10 +01001745 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1746 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001747 struct ath_wiphy *aphy = hw->priv;
1748 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001749 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001750 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001751 int padpos, padsize;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001752 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001753
Felix Fietkau28d16702010-11-14 15:20:10 +01001754 /*
1755 * As a temporary workaround, assign seq# here; this will likely need
1756 * to be cleaned up to work better with Beacon transmission and virtual
1757 * BSSes.
1758 */
1759 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1760 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1761 sc->tx.seq_no += 0x10;
1762 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1763 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1764 }
1765
1766 /* Add the padding after the header if this is not already done */
1767 padpos = ath9k_cmn_padpos(hdr->frame_control);
1768 padsize = padpos & 3;
1769 if (padsize && skb->len > padpos) {
1770 if (skb_headroom(skb) < padsize)
1771 return -ENOMEM;
1772
1773 skb_push(skb, padsize);
1774 memmove(skb->data, skb->data + padsize, padpos);
1775 }
1776
Felix Fietkau82b873a2010-11-11 03:18:37 +01001777 bf = ath_tx_setup_buffer(hw, skb);
1778 if (unlikely(!bf))
1779 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001780
Felix Fietkau066dae92010-11-07 14:59:39 +01001781 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001782 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001783 if (txq == sc->tx.txq_map[q] &&
1784 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1785 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001786 txq->stopped = 1;
1787 }
1788 spin_unlock_bh(&txq->axq_lock);
1789
Sujithe8324352009-01-16 21:38:42 +05301790 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001791
1792 return 0;
1793}
1794
Sujithe8324352009-01-16 21:38:42 +05301795/*****************/
1796/* TX Completion */
1797/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001798
Sujithe8324352009-01-16 21:38:42 +05301799static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001800 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001801 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001802{
Sujithe8324352009-01-16 21:38:42 +05301803 struct ieee80211_hw *hw = sc->hw;
1804 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001805 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001806 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001807 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301808
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001809 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301810
Felix Fietkau827e69b2009-11-15 23:09:25 +01001811 if (aphy)
1812 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301813
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301814 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301815 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301816
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301817 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301818 /* Frame was ACKed */
1819 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1820 }
1821
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001822 padpos = ath9k_cmn_padpos(hdr->frame_control);
1823 padsize = padpos & 3;
1824 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301825 /*
1826 * Remove MAC header padding before giving the frame back to
1827 * mac80211.
1828 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001829 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301830 skb_pull(skb, padsize);
1831 }
1832
Sujith1b04b932010-01-08 10:36:05 +05301833 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1834 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001835 ath_print(common, ATH_DBG_PS,
1836 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001837 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301838 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1839 PS_WAIT_FOR_CAB |
1840 PS_WAIT_FOR_PSPOLL_DATA |
1841 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001842 }
1843
Felix Fietkau61117f02010-11-11 03:18:36 +01001844 if (unlikely(ftype))
1845 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001846 else {
1847 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001848 if (txq == sc->tx.txq_map[q]) {
1849 spin_lock_bh(&txq->axq_lock);
1850 if (WARN_ON(--txq->pending_frames < 0))
1851 txq->pending_frames = 0;
1852 spin_unlock_bh(&txq->axq_lock);
1853 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001854
Felix Fietkau827e69b2009-11-15 23:09:25 +01001855 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001856 }
Sujithe8324352009-01-16 21:38:42 +05301857}
1858
1859static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001860 struct ath_txq *txq, struct list_head *bf_q,
1861 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301862{
1863 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301864 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301865 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301866
Sujithe8324352009-01-16 21:38:42 +05301867 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301868 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301869
1870 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301871 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301872
1873 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301874 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301875 }
1876
Ben Greearc1739eb32010-10-14 12:45:29 -07001877 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001878 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001879
1880 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001881 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001882 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001883 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001884 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001885 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001886 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001887 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1888 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001889 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001890 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1891 * accidentally reference it later.
1892 */
1893 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301894
1895 /*
1896 * Return the list of ath_buf of this mpdu to free queue
1897 */
1898 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1899 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1900 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1901}
1902
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001903static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001904 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301905{
Sujitha22be222009-03-30 15:28:36 +05301906 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301907 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301908 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001909 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001910 struct ath_softc *sc = bf->aphy->sc;
1911 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301912 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301913
Sujith95e4acb2009-03-13 08:56:09 +05301914 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001915 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301916
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001917 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301918 WARN_ON(tx_rateindex >= hw->max_rates);
1919
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001920 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301921 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001922 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001923 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301924
Felix Fietkaub572d032010-11-14 15:20:07 +01001925 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001926
Felix Fietkaub572d032010-11-14 15:20:07 +01001927 tx_info->status.ampdu_len = nframes;
1928 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001929 }
1930
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001931 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301932 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001933 /*
1934 * If an underrun error is seen assume it as an excessive
1935 * retry only if max frame trigger level has been reached
1936 * (2 KB for single stream, and 4 KB for dual stream).
1937 * Adjust the long retry as if the frame was tried
1938 * hw->max_rate_tries times to affect how rate control updates
1939 * PER for the failed rate.
1940 * In case of congestion on the bus penalizing this type of
1941 * underruns should help hardware actually transmit new frames
1942 * successfully by eventually preferring slower rates.
1943 * This itself should also alleviate congestion on the bus.
1944 */
1945 if (ieee80211_is_data(hdr->frame_control) &&
1946 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1947 ATH9K_TX_DELIM_UNDERRUN)) &&
1948 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1949 tx_info->status.rates[tx_rateindex].count =
1950 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301951 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301952
Felix Fietkau545750d2009-11-23 22:21:01 +01001953 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301954 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001955 tx_info->status.rates[i].idx = -1;
1956 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301957
Felix Fietkau78c46532010-06-25 01:26:16 +02001958 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301959}
1960
Felix Fietkau066dae92010-11-07 14:59:39 +01001961static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301962{
Felix Fietkau066dae92010-11-07 14:59:39 +01001963 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301964
Felix Fietkau066dae92010-11-07 14:59:39 +01001965 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301966 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001967 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001968 if (ath_mac80211_start_queue(sc, qnum))
1969 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301970 }
1971 spin_unlock_bh(&txq->axq_lock);
1972}
1973
Sujithc4288392008-11-18 09:09:30 +05301974static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001975{
Sujithcbe61d82009-02-09 13:27:12 +05301976 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001977 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001978 struct ath_buf *bf, *lastbf, *bf_held = NULL;
1979 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05301980 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07001981 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05301982 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001983 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01001984 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001985
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001986 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
1987 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
1988 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001989
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001990 for (;;) {
1991 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001992 if (list_empty(&txq->axq_q)) {
1993 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001994 spin_unlock_bh(&txq->axq_lock);
1995 break;
1996 }
1997 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
1998
1999 /*
2000 * There is a race condition that a BH gets scheduled
2001 * after sw writes TxE and before hw re-load the last
2002 * descriptor to get the newly chained one.
2003 * Software must keep the last DONE descriptor as a
2004 * holding descriptor - software does so by marking
2005 * it with the STALE flag.
2006 */
2007 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302008 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002009 bf_held = bf;
2010 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302011 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012 break;
2013 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002014 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302015 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002016 }
2017 }
2018
2019 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302020 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002021
Felix Fietkau29bffa92010-03-29 20:14:23 -07002022 memset(&ts, 0, sizeof(ts));
2023 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002024 if (status == -EINPROGRESS) {
2025 spin_unlock_bh(&txq->axq_lock);
2026 break;
2027 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002028
2029 /*
2030 * Remove ath_buf's of the same transmit unit from txq,
2031 * however leave the last descriptor back as the holding
2032 * descriptor for hw.
2033 */
Sujitha119cc42009-03-30 15:28:38 +05302034 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002035 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002036 if (!list_is_singular(&lastbf->list))
2037 list_cut_position(&bf_head,
2038 &txq->axq_q, lastbf->list.prev);
2039
2040 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002041 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002042 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002043 if (bf_held)
2044 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045 spin_unlock_bh(&txq->axq_lock);
2046
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002047 if (bf_held)
2048 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049
Sujithcd3d39a2008-08-11 14:03:34 +05302050 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002051 /*
2052 * This frame is sent out as a single frame.
2053 * Use hardware retry status for this frame.
2054 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002055 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302056 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002057 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002058 }
Johannes Berge6a98542008-10-21 12:40:02 +02002059
Felix Fietkau066dae92010-11-07 14:59:39 +01002060 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2061
Sujithcd3d39a2008-08-11 14:03:34 +05302062 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002063 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
2064 true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002065 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002066 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002067
Felix Fietkau066dae92010-11-07 14:59:39 +01002068 if (txq == sc->tx.txq_map[qnum])
2069 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302070
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002071 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302072 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002073 ath_txq_schedule(sc, txq);
2074 spin_unlock_bh(&txq->axq_lock);
2075 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076}
2077
Sujith305fe472009-07-23 15:32:29 +05302078static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002079{
2080 struct ath_softc *sc = container_of(work, struct ath_softc,
2081 tx_complete_work.work);
2082 struct ath_txq *txq;
2083 int i;
2084 bool needreset = false;
2085
2086 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2087 if (ATH_TXQ_SETUP(sc, i)) {
2088 txq = &sc->tx.txq[i];
2089 spin_lock_bh(&txq->axq_lock);
2090 if (txq->axq_depth) {
2091 if (txq->axq_tx_inprogress) {
2092 needreset = true;
2093 spin_unlock_bh(&txq->axq_lock);
2094 break;
2095 } else {
2096 txq->axq_tx_inprogress = true;
2097 }
2098 }
2099 spin_unlock_bh(&txq->axq_lock);
2100 }
2101
2102 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002103 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2104 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302105 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002106 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302107 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002108 }
2109
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002110 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002111 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2112}
2113
2114
Sujithe8324352009-01-16 21:38:42 +05302115
2116void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117{
Sujithe8324352009-01-16 21:38:42 +05302118 int i;
2119 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002120
Sujithe8324352009-01-16 21:38:42 +05302121 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002122
2123 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302124 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2125 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002126 }
2127}
2128
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002129void ath_tx_edma_tasklet(struct ath_softc *sc)
2130{
2131 struct ath_tx_status txs;
2132 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2133 struct ath_hw *ah = sc->sc_ah;
2134 struct ath_txq *txq;
2135 struct ath_buf *bf, *lastbf;
2136 struct list_head bf_head;
2137 int status;
2138 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002139 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002140
2141 for (;;) {
2142 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2143 if (status == -EINPROGRESS)
2144 break;
2145 if (status == -EIO) {
2146 ath_print(common, ATH_DBG_XMIT,
2147 "Error processing tx status\n");
2148 break;
2149 }
2150
2151 /* Skip beacon completions */
2152 if (txs.qid == sc->beacon.beaconq)
2153 continue;
2154
2155 txq = &sc->tx.txq[txs.qid];
2156
2157 spin_lock_bh(&txq->axq_lock);
2158 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2159 spin_unlock_bh(&txq->axq_lock);
2160 return;
2161 }
2162
2163 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2164 struct ath_buf, list);
2165 lastbf = bf->bf_lastbf;
2166
2167 INIT_LIST_HEAD(&bf_head);
2168 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2169 &lastbf->list);
2170 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2171 txq->axq_depth--;
2172 txq->axq_tx_inprogress = false;
2173 spin_unlock_bh(&txq->axq_lock);
2174
2175 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2176
2177 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002178 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2179 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002180 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002181 }
2182
Felix Fietkau066dae92010-11-07 14:59:39 +01002183 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2184
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002185 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002186 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
2187 txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002188 else
2189 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2190 &txs, txok, 0);
2191
Felix Fietkau066dae92010-11-07 14:59:39 +01002192 if (txq == sc->tx.txq_map[qnum])
2193 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002194
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002195 spin_lock_bh(&txq->axq_lock);
2196 if (!list_empty(&txq->txq_fifo_pending)) {
2197 INIT_LIST_HEAD(&bf_head);
2198 bf = list_first_entry(&txq->txq_fifo_pending,
2199 struct ath_buf, list);
2200 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2201 &bf->bf_lastbf->list);
2202 ath_tx_txqaddbuf(sc, txq, &bf_head);
2203 } else if (sc->sc_flags & SC_OP_TXAGGR)
2204 ath_txq_schedule(sc, txq);
2205 spin_unlock_bh(&txq->axq_lock);
2206 }
2207}
2208
Sujithe8324352009-01-16 21:38:42 +05302209/*****************/
2210/* Init, Cleanup */
2211/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002212
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002213static int ath_txstatus_setup(struct ath_softc *sc, int size)
2214{
2215 struct ath_descdma *dd = &sc->txsdma;
2216 u8 txs_len = sc->sc_ah->caps.txs_len;
2217
2218 dd->dd_desc_len = size * txs_len;
2219 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2220 &dd->dd_desc_paddr, GFP_KERNEL);
2221 if (!dd->dd_desc)
2222 return -ENOMEM;
2223
2224 return 0;
2225}
2226
2227static int ath_tx_edma_init(struct ath_softc *sc)
2228{
2229 int err;
2230
2231 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2232 if (!err)
2233 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2234 sc->txsdma.dd_desc_paddr,
2235 ATH_TXSTATUS_RING_SIZE);
2236
2237 return err;
2238}
2239
2240static void ath_tx_edma_cleanup(struct ath_softc *sc)
2241{
2242 struct ath_descdma *dd = &sc->txsdma;
2243
2244 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2245 dd->dd_desc_paddr);
2246}
2247
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002248int ath_tx_init(struct ath_softc *sc, int nbufs)
2249{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002250 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002251 int error = 0;
2252
Sujith797fe5cb2009-03-30 15:28:45 +05302253 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002254
Sujith797fe5cb2009-03-30 15:28:45 +05302255 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002256 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302257 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002258 ath_print(common, ATH_DBG_FATAL,
2259 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302260 goto err;
2261 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002262
Sujith797fe5cb2009-03-30 15:28:45 +05302263 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002264 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302265 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002266 ath_print(common, ATH_DBG_FATAL,
2267 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302268 goto err;
2269 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002270
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002271 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2272
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002273 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2274 error = ath_tx_edma_init(sc);
2275 if (error)
2276 goto err;
2277 }
2278
Sujith797fe5cb2009-03-30 15:28:45 +05302279err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002280 if (error != 0)
2281 ath_tx_cleanup(sc);
2282
2283 return error;
2284}
2285
Sujith797fe5cb2009-03-30 15:28:45 +05302286void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002287{
Sujithb77f4832008-12-07 21:44:03 +05302288 if (sc->beacon.bdma.dd_desc_len != 0)
2289 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002290
Sujithb77f4832008-12-07 21:44:03 +05302291 if (sc->tx.txdma.dd_desc_len != 0)
2292 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002293
2294 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2295 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002296}
2297
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002298void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2299{
Sujithc5170162008-10-29 10:13:59 +05302300 struct ath_atx_tid *tid;
2301 struct ath_atx_ac *ac;
2302 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002303
Sujith8ee5afb2008-12-07 21:43:36 +05302304 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302305 tidno < WME_NUM_TID;
2306 tidno++, tid++) {
2307 tid->an = an;
2308 tid->tidno = tidno;
2309 tid->seq_start = tid->seq_next = 0;
2310 tid->baw_size = WME_MAX_BA;
2311 tid->baw_head = tid->baw_tail = 0;
2312 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302313 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302314 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302315 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302316 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302317 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302318 tid->state &= ~AGGR_ADDBA_COMPLETE;
2319 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302320 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002321
Sujith8ee5afb2008-12-07 21:43:36 +05302322 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302323 acno < WME_NUM_AC; acno++, ac++) {
2324 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002325 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302326 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002327 }
2328}
2329
Sujithb5aa9bf2008-10-29 10:13:31 +05302330void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002331{
Felix Fietkau2b409942010-07-07 19:42:08 +02002332 struct ath_atx_ac *ac;
2333 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002334 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002335 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302336
Felix Fietkau2b409942010-07-07 19:42:08 +02002337 for (tidno = 0, tid = &an->tid[tidno];
2338 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002339
Felix Fietkau2b409942010-07-07 19:42:08 +02002340 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002341 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002342
Felix Fietkau2b409942010-07-07 19:42:08 +02002343 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002344
Felix Fietkau2b409942010-07-07 19:42:08 +02002345 if (tid->sched) {
2346 list_del(&tid->list);
2347 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002348 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002349
2350 if (ac->sched) {
2351 list_del(&ac->list);
2352 tid->ac->sched = false;
2353 }
2354
2355 ath_tid_drain(sc, txq, tid);
2356 tid->state &= ~AGGR_ADDBA_COMPLETE;
2357 tid->state &= ~AGGR_CLEANUP;
2358
2359 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002360 }
2361}