blob: c63e283ff97f2154ee41bcbb5084c21a3e86f020 [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 Fietkau2d42efc2010-11-14 15:20:13 +010053 struct list_head *bf_head);
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 Fietkau2d42efc2010-11-14 15:20:13 +0100141static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
Felix Fietkau76e45222010-11-14 15:20:08 +0100142{
143 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100144 BUILD_BUG_ON(sizeof(struct ath_frame_info) >
145 sizeof(tx_info->rate_driver_data));
146 return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
Felix Fietkau76e45222010-11-14 15:20:08 +0100147}
148
Sujithe8324352009-01-16 21:38:42 +0530149static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
150{
Felix Fietkau066dae92010-11-07 14:59:39 +0100151 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530152 struct ath_buf *bf;
153 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200154 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100155 struct ath_frame_info *fi;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200156
Sujithe8324352009-01-16 21:38:42 +0530157 INIT_LIST_HEAD(&bf_head);
158
Felix Fietkau90fa5392010-09-20 13:45:38 +0200159 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530160 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530161
162 while (!list_empty(&tid->buf_q)) {
163 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530164 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200165
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100166 fi = get_frame_info(bf->bf_mpdu);
167 if (fi->retries) {
168 ath_tx_update_baw(sc, tid, fi->seqno);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200169 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
170 } else {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100171 ath_tx_send_normal(sc, txq, tid, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200172 }
Sujithe8324352009-01-16 21:38:42 +0530173 }
174
175 spin_unlock_bh(&txq->axq_lock);
176}
177
178static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
179 int seqno)
180{
181 int index, cindex;
182
183 index = ATH_BA_INDEX(tid->seq_start, seqno);
184 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
185
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200186 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530187
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200188 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530189 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
190 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
191 }
192}
193
194static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100195 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530196{
197 int index, cindex;
198
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100199 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530200 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200201 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530202
203 if (index >= ((tid->baw_tail - tid->baw_head) &
204 (ATH_TID_MAX_BUFS - 1))) {
205 tid->baw_tail = cindex;
206 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
207 }
208}
209
210/*
211 * TODO: For frame(s) that are in the retry state, we will reuse the
212 * sequence number(s) without setting the retry bit. The
213 * alternative is to give up on these and BAR the receiver's window
214 * forward.
215 */
216static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
217 struct ath_atx_tid *tid)
218
219{
220 struct ath_buf *bf;
221 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700222 struct ath_tx_status ts;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100223 struct ath_frame_info *fi;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700224
225 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530226 INIT_LIST_HEAD(&bf_head);
227
228 for (;;) {
229 if (list_empty(&tid->buf_q))
230 break;
Sujithe8324352009-01-16 21:38:42 +0530231
Sujithd43f30152009-01-16 21:38:53 +0530232 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
233 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530234
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100235 fi = get_frame_info(bf->bf_mpdu);
236 if (fi->retries)
237 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530238
239 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700240 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530241 spin_lock(&txq->axq_lock);
242 }
243
244 tid->seq_next = tid->seq_start;
245 tid->baw_tail = tid->baw_head;
246}
247
Sujithfec247c2009-07-27 12:08:16 +0530248static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100249 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +0530250{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100251 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithe8324352009-01-16 21:38:42 +0530252 struct ieee80211_hdr *hdr;
253
Sujithfec247c2009-07-27 12:08:16 +0530254 TX_STAT_INC(txq->axq_qnum, a_retries);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100255 if (tx_info->control.rates[4].count++ > 0)
256 return;
Sujithe8324352009-01-16 21:38:42 +0530257
Sujithe8324352009-01-16 21:38:42 +0530258 hdr = (struct ieee80211_hdr *)skb->data;
259 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
260}
261
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200262static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
263{
264 struct ath_buf *bf = NULL;
265
266 spin_lock_bh(&sc->tx.txbuflock);
267
268 if (unlikely(list_empty(&sc->tx.txbuf))) {
269 spin_unlock_bh(&sc->tx.txbuflock);
270 return NULL;
271 }
272
273 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
274 list_del(&bf->list);
275
276 spin_unlock_bh(&sc->tx.txbuflock);
277
278 return bf;
279}
280
281static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
282{
283 spin_lock_bh(&sc->tx.txbuflock);
284 list_add_tail(&bf->list, &sc->tx.txbuf);
285 spin_unlock_bh(&sc->tx.txbuflock);
286}
287
Sujithd43f30152009-01-16 21:38:53 +0530288static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
289{
290 struct ath_buf *tbf;
291
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200292 tbf = ath_tx_get_buffer(sc);
293 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530294 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530295
296 ATH_TXBUF_RESET(tbf);
297
Felix Fietkau827e69b2009-11-15 23:09:25 +0100298 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530299 tbf->bf_mpdu = bf->bf_mpdu;
300 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400301 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530302 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530303
304 return tbf;
305}
306
Felix Fietkaub572d032010-11-14 15:20:07 +0100307static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
308 struct ath_tx_status *ts, int txok,
309 int *nframes, int *nbad)
310{
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100311 struct ath_frame_info *fi;
Felix Fietkaub572d032010-11-14 15:20:07 +0100312 u16 seq_st = 0;
313 u32 ba[WME_BA_BMP_SIZE >> 5];
314 int ba_index;
315 int isaggr = 0;
316
317 *nbad = 0;
318 *nframes = 0;
319
Felix Fietkaub572d032010-11-14 15:20:07 +0100320 isaggr = bf_isaggr(bf);
321 if (isaggr) {
322 seq_st = ts->ts_seqnum;
323 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
324 }
325
326 while (bf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100327 fi = get_frame_info(bf->bf_mpdu);
328 ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
Felix Fietkaub572d032010-11-14 15:20:07 +0100329
330 (*nframes)++;
331 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
332 (*nbad)++;
333
334 bf = bf->bf_next;
335 }
336}
337
338
Sujithd43f30152009-01-16 21:38:53 +0530339static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
340 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkauc5992612010-11-14 15:20:09 +0100341 struct ath_tx_status *ts, int txok, bool retry)
Sujithe8324352009-01-16 21:38:42 +0530342{
343 struct ath_node *an = NULL;
344 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530345 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800346 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530347 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800348 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530349 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530350 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530351 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530352 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530353 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530354 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
355 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200356 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100357 struct ath_frame_info *fi;
Björn Smedmanebd02282010-10-10 22:44:39 +0200358 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100359 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530360
Sujitha22be222009-03-30 15:28:36 +0530361 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530362 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530363
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800364 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100365 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800366
Felix Fietkau78c46532010-06-25 01:26:16 +0200367 memcpy(rates, tx_info->control.rates, sizeof(rates));
368
Sujith1286ec62009-01-27 13:30:37 +0530369 rcu_read_lock();
370
Ben Greear686b9cb2010-09-23 09:44:36 -0700371 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530372 if (!sta) {
373 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200374
Felix Fietkau31e79a52010-07-12 23:16:34 +0200375 INIT_LIST_HEAD(&bf_head);
376 while (bf) {
377 bf_next = bf->bf_next;
378
379 bf->bf_state.bf_type |= BUF_XRETRY;
380 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
381 !bf->bf_stale || bf_next != NULL)
382 list_move_tail(&bf->list, &bf_head);
383
Felix Fietkaub572d032010-11-14 15:20:07 +0100384 ath_tx_rc_status(bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200385 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
386 0, 0);
387
388 bf = bf_next;
389 }
Sujith1286ec62009-01-27 13:30:37 +0530390 return;
Sujithe8324352009-01-16 21:38:42 +0530391 }
392
Sujith1286ec62009-01-27 13:30:37 +0530393 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100394 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
395 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530396
Felix Fietkaub11b1602010-07-11 12:48:44 +0200397 /*
398 * The hardware occasionally sends a tx status for the wrong TID.
399 * In this case, the BA status cannot be considered valid and all
400 * subframes need to be retransmitted
401 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100402 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200403 txok = false;
404
Sujithe8324352009-01-16 21:38:42 +0530405 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530406 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530407
Sujithd43f30152009-01-16 21:38:53 +0530408 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700409 if (ts->ts_flags & ATH9K_TX_BA) {
410 seq_st = ts->ts_seqnum;
411 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530412 } else {
Sujithd43f30152009-01-16 21:38:53 +0530413 /*
414 * AR5416 can become deaf/mute when BA
415 * issue happens. Chip needs to be reset.
416 * But AP code may have sychronization issues
417 * when perform internal reset in this routine.
418 * Only enable reset in STA mode for now.
419 */
Sujith2660b812009-02-09 13:27:26 +0530420 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530421 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530422 }
423 }
424
425 INIT_LIST_HEAD(&bf_pending);
426 INIT_LIST_HEAD(&bf_head);
427
Felix Fietkaub572d032010-11-14 15:20:07 +0100428 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530429 while (bf) {
430 txfail = txpending = 0;
431 bf_next = bf->bf_next;
432
Felix Fietkau78c46532010-06-25 01:26:16 +0200433 skb = bf->bf_mpdu;
434 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100435 fi = get_frame_info(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200436
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100437 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530438 /* transmit completion, subframe is
439 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530440 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530441 } else if (!isaggr && txok) {
442 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530443 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530444 } else {
Felix Fietkauc5992612010-11-14 15:20:09 +0100445 if (!(tid->state & AGGR_CLEANUP) && retry) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100446 if (fi->retries < ATH_MAX_SW_RETRIES) {
447 ath_tx_set_retry(sc, txq, bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530448 txpending = 1;
449 } else {
450 bf->bf_state.bf_type |= BUF_XRETRY;
451 txfail = 1;
452 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530453 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530454 }
455 } else {
456 /*
457 * cleanup in progress, just fail
458 * the un-acked sub-frames
459 */
460 txfail = 1;
461 }
462 }
463
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400464 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
465 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530466 /*
467 * Make sure the last desc is reclaimed if it
468 * not a holding desc.
469 */
470 if (!bf_last->bf_stale)
471 list_move_tail(&bf->list, &bf_head);
472 else
473 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530474 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700475 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530476 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530477 }
478
Felix Fietkau90fa5392010-09-20 13:45:38 +0200479 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530480 /*
481 * complete the acked-ones/xretried ones; update
482 * block-ack window
483 */
484 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100485 ath_tx_update_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +0530486 spin_unlock_bh(&txq->axq_lock);
487
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530488 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200489 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaub572d032010-11-14 15:20:07 +0100490 ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530491 rc_update = false;
492 } else {
Felix Fietkaub572d032010-11-14 15:20:07 +0100493 ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530494 }
495
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700496 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
497 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530498 } else {
Sujithd43f30152009-01-16 21:38:53 +0530499 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400500 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
501 if (bf->bf_next == NULL && bf_last->bf_stale) {
502 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530503
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400504 tbf = ath_clone_txbuf(sc, bf_last);
505 /*
506 * Update tx baw and complete the
507 * frame with failed status if we
508 * run out of tx buf.
509 */
510 if (!tbf) {
511 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100512 ath_tx_update_baw(sc, tid, fi->seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400513 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400514
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400515 bf->bf_state.bf_type |=
516 BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +0100517 ath_tx_rc_status(bf, ts, nframes,
518 nbad, 0, false);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400519 ath_tx_complete_buf(sc, bf, txq,
520 &bf_head,
521 ts, 0, 0);
522 break;
523 }
524
525 ath9k_hw_cleartxdesc(sc->sc_ah,
526 tbf->bf_desc);
527 list_add_tail(&tbf->list, &bf_head);
528 } else {
529 /*
530 * Clear descriptor status words for
531 * software retry
532 */
533 ath9k_hw_cleartxdesc(sc->sc_ah,
534 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400535 }
Sujithe8324352009-01-16 21:38:42 +0530536 }
537
538 /*
539 * Put this buffer to the temporary pending
540 * queue to retain ordering
541 */
542 list_splice_tail_init(&bf_head, &bf_pending);
543 }
544
545 bf = bf_next;
546 }
547
Felix Fietkau4cee7862010-07-23 03:53:16 +0200548 /* prepend un-acked frames to the beginning of the pending frame queue */
549 if (!list_empty(&bf_pending)) {
550 spin_lock_bh(&txq->axq_lock);
551 list_splice(&bf_pending, &tid->buf_q);
552 ath_tx_queue_tid(txq, tid);
553 spin_unlock_bh(&txq->axq_lock);
554 }
555
Sujithe8324352009-01-16 21:38:42 +0530556 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200557 ath_tx_flush_tid(sc, tid);
558
Sujithe8324352009-01-16 21:38:42 +0530559 if (tid->baw_head == tid->baw_tail) {
560 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530561 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530562 }
Sujithe8324352009-01-16 21:38:42 +0530563 }
564
Sujith1286ec62009-01-27 13:30:37 +0530565 rcu_read_unlock();
566
Sujithe8324352009-01-16 21:38:42 +0530567 if (needreset)
568 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530569}
570
571static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
572 struct ath_atx_tid *tid)
573{
Sujithe8324352009-01-16 21:38:42 +0530574 struct sk_buff *skb;
575 struct ieee80211_tx_info *tx_info;
576 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530577 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530578 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530579 int i;
580
Sujitha22be222009-03-30 15:28:36 +0530581 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530582 tx_info = IEEE80211_SKB_CB(skb);
583 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530584
585 /*
586 * Find the lowest frame length among the rate series that will have a
587 * 4ms transmit duration.
588 * TODO - TXOP limit needs to be considered.
589 */
590 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
591
592 for (i = 0; i < 4; i++) {
593 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100594 int modeidx;
595 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530596 legacy = 1;
597 break;
598 }
599
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200600 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100601 modeidx = MCS_HT40;
602 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200603 modeidx = MCS_HT20;
604
605 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
606 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100607
608 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530609 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530610 }
611 }
612
613 /*
614 * limit aggregate size by the minimum rate if rate selected is
615 * not a probe rate, if rate selected is a probe rate then
616 * avoid aggregation of this packet.
617 */
618 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
619 return 0;
620
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530621 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
622 aggr_limit = min((max_4ms_framelen * 3) / 8,
623 (u32)ATH_AMPDU_LIMIT_MAX);
624 else
625 aggr_limit = min(max_4ms_framelen,
626 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530627
628 /*
629 * h/w can accept aggregates upto 16 bit lengths (65535).
630 * The IE, however can hold upto 65536, which shows up here
631 * as zero. Ignore 65536 since we are constrained by hw.
632 */
Sujith4ef70842009-07-23 15:32:41 +0530633 if (tid->an->maxampdu)
634 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530635
636 return aggr_limit;
637}
638
639/*
Sujithd43f30152009-01-16 21:38:53 +0530640 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530641 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530642 */
643static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
644 struct ath_buf *bf, u16 frmlen)
645{
Sujithe8324352009-01-16 21:38:42 +0530646 struct sk_buff *skb = bf->bf_mpdu;
647 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530648 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530649 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100650 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200651 int width, streams, half_gi, ndelim, mindelim;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100652 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530653
654 /* Select standard number of delimiters based on frame length alone */
655 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
656
657 /*
658 * If encryption enabled, hardware requires some more padding between
659 * subframes.
660 * TODO - this could be improved to be dependent on the rate.
661 * The hardware can keep up at lower rates, but not higher rates
662 */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100663 if (fi->keyix != ATH9K_TXKEYIX_INVALID)
Sujithe8324352009-01-16 21:38:42 +0530664 ndelim += ATH_AGGR_ENCRYPTDELIM;
665
666 /*
667 * Convert desired mpdu density from microeconds to bytes based
668 * on highest rate in rate series (i.e. first rate) to determine
669 * required minimum length for subframe. Take into account
670 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530671 *
Sujithe8324352009-01-16 21:38:42 +0530672 * If there is no mpdu density restriction, no further calculation
673 * is needed.
674 */
Sujith4ef70842009-07-23 15:32:41 +0530675
676 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530677 return ndelim;
678
679 rix = tx_info->control.rates[0].idx;
680 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530681 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
682 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
683
684 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530685 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530686 else
Sujith4ef70842009-07-23 15:32:41 +0530687 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530688
689 if (nsymbols == 0)
690 nsymbols = 1;
691
Felix Fietkauc6663872010-04-19 19:57:33 +0200692 streams = HT_RC_2_STREAMS(rix);
693 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530694 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
695
Sujithe8324352009-01-16 21:38:42 +0530696 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530697 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
698 ndelim = max(mindelim, ndelim);
699 }
700
701 return ndelim;
702}
703
704static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530705 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530706 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100707 struct list_head *bf_q,
708 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530709{
710#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530711 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
712 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530713 u16 aggr_limit = 0, al = 0, bpad = 0,
714 al_delta, h_baw = tid->baw_size / 2;
715 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200716 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100717 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530718
719 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
720
721 do {
722 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100723 fi = get_frame_info(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530724
Sujithd43f30152009-01-16 21:38:53 +0530725 /* do not step over block-ack window */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100726 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530727 status = ATH_AGGR_BAW_CLOSED;
728 break;
729 }
730
731 if (!rl) {
732 aggr_limit = ath_lookup_rate(sc, bf, tid);
733 rl = 1;
734 }
735
Sujithd43f30152009-01-16 21:38:53 +0530736 /* do not exceed aggregation limit */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100737 al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
Sujithe8324352009-01-16 21:38:42 +0530738
Sujithd43f30152009-01-16 21:38:53 +0530739 if (nframes &&
740 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530741 status = ATH_AGGR_LIMITED;
742 break;
743 }
744
Felix Fietkau0299a502010-10-21 02:47:24 +0200745 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
746 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
747 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
748 break;
749
Sujithd43f30152009-01-16 21:38:53 +0530750 /* do not exceed subframe limit */
751 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530752 status = ATH_AGGR_LIMITED;
753 break;
754 }
Sujithd43f30152009-01-16 21:38:53 +0530755 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530756
Sujithd43f30152009-01-16 21:38:53 +0530757 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530758 al += bpad + al_delta;
759
760 /*
761 * Get the delimiters needed to meet the MPDU
762 * density for this node.
763 */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100764 ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +0530765 bpad = PADBYTES(al_delta) + (ndelim << 2);
766
767 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400768 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530769
Sujithd43f30152009-01-16 21:38:53 +0530770 /* link buffers of this frame to the aggregate */
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100771 if (!fi->retries)
772 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithd43f30152009-01-16 21:38:53 +0530773 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
774 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530775 if (bf_prev) {
776 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400777 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
778 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530779 }
780 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530781
Sujithe8324352009-01-16 21:38:42 +0530782 } while (!list_empty(&tid->buf_q));
783
Felix Fietkau269c44b2010-11-14 15:20:06 +0100784 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530785
Sujithe8324352009-01-16 21:38:42 +0530786 return status;
787#undef PADBYTES
788}
789
790static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
791 struct ath_atx_tid *tid)
792{
Sujithd43f30152009-01-16 21:38:53 +0530793 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530794 enum ATH_AGGR_STATUS status;
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100795 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +0530796 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100797 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530798
799 do {
800 if (list_empty(&tid->buf_q))
801 return;
802
803 INIT_LIST_HEAD(&bf_q);
804
Felix Fietkau269c44b2010-11-14 15:20:06 +0100805 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530806
807 /*
Sujithd43f30152009-01-16 21:38:53 +0530808 * no frames picked up to be aggregated;
809 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530810 */
811 if (list_empty(&bf_q))
812 break;
813
814 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530815 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530816
Sujithd43f30152009-01-16 21:38:53 +0530817 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100818 if (bf == bf->bf_lastbf) {
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100819 fi = get_frame_info(bf->bf_mpdu);
820
Sujithe8324352009-01-16 21:38:42 +0530821 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530822 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau2d42efc2010-11-14 15:20:13 +0100823 ath_buf_set_rate(sc, bf, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +0530824 ath_tx_txqaddbuf(sc, txq, &bf_q);
825 continue;
826 }
827
Sujithd43f30152009-01-16 21:38:53 +0530828 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530829 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100830 ath_buf_set_rate(sc, bf, aggr_len);
831 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530832
Sujithd43f30152009-01-16 21:38:53 +0530833 /* anchor last desc of aggregate */
834 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530835
Sujithe8324352009-01-16 21:38:42 +0530836 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530837 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530838
839 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
840 status != ATH_AGGR_BAW_CLOSED);
841}
842
Felix Fietkau231c3a12010-09-20 19:35:28 +0200843int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
844 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530845{
846 struct ath_atx_tid *txtid;
847 struct ath_node *an;
848
849 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530850 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200851
852 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
853 return -EAGAIN;
854
Sujithf83da962009-07-23 15:32:37 +0530855 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200856 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530857 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200858
859 return 0;
Sujithe8324352009-01-16 21:38:42 +0530860}
861
Sujithf83da962009-07-23 15:32:37 +0530862void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530863{
864 struct ath_node *an = (struct ath_node *)sta->drv_priv;
865 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100866 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530867
868 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530869 return;
Sujithe8324352009-01-16 21:38:42 +0530870
871 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530872 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530873 return;
Sujithe8324352009-01-16 21:38:42 +0530874 }
875
Sujithe8324352009-01-16 21:38:42 +0530876 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200877 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200878
879 /*
880 * If frames are still being transmitted for this TID, they will be
881 * cleaned up during tx completion. To prevent race conditions, this
882 * TID can only be reused after all in-progress subframes have been
883 * completed.
884 */
885 if (txtid->baw_head != txtid->baw_tail)
886 txtid->state |= AGGR_CLEANUP;
887 else
888 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530889 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530890
Felix Fietkau90fa5392010-09-20 13:45:38 +0200891 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530892}
893
894void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
895{
896 struct ath_atx_tid *txtid;
897 struct ath_node *an;
898
899 an = (struct ath_node *)sta->drv_priv;
900
901 if (sc->sc_flags & SC_OP_TXAGGR) {
902 txtid = ATH_AN_2_TID(an, tid);
903 txtid->baw_size =
904 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
905 txtid->state |= AGGR_ADDBA_COMPLETE;
906 txtid->state &= ~AGGR_ADDBA_PROGRESS;
907 ath_tx_resume_tid(sc, txtid);
908 }
909}
910
Sujithe8324352009-01-16 21:38:42 +0530911/********************/
912/* Queue Management */
913/********************/
914
Sujithe8324352009-01-16 21:38:42 +0530915static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
916 struct ath_txq *txq)
917{
918 struct ath_atx_ac *ac, *ac_tmp;
919 struct ath_atx_tid *tid, *tid_tmp;
920
921 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
922 list_del(&ac->list);
923 ac->sched = false;
924 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
925 list_del(&tid->list);
926 tid->sched = false;
927 ath_tid_drain(sc, txq, tid);
928 }
929 }
930}
931
932struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
933{
Sujithcbe61d82009-02-09 13:27:12 +0530934 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700935 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530936 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100937 static const int subtype_txq_to_hwq[] = {
938 [WME_AC_BE] = ATH_TXQ_AC_BE,
939 [WME_AC_BK] = ATH_TXQ_AC_BK,
940 [WME_AC_VI] = ATH_TXQ_AC_VI,
941 [WME_AC_VO] = ATH_TXQ_AC_VO,
942 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400943 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530944
945 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100946 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530947 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
948 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
949 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
950 qi.tqi_physCompBuf = 0;
951
952 /*
953 * Enable interrupts only for EOL and DESC conditions.
954 * We mark tx descriptors to receive a DESC interrupt
955 * when a tx queue gets deep; otherwise waiting for the
956 * EOL to reap descriptors. Note that this is done to
957 * reduce interrupt load and this only defers reaping
958 * descriptors, never transmitting frames. Aside from
959 * reducing interrupts this also permits more concurrency.
960 * The only potential downside is if the tx queue backs
961 * up in which case the top half of the kernel may backup
962 * due to a lack of tx descriptors.
963 *
964 * The UAPSD queue is an exception, since we take a desc-
965 * based intr on the EOSP frames.
966 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400967 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
968 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
969 TXQ_FLAG_TXERRINT_ENABLE;
970 } else {
971 if (qtype == ATH9K_TX_QUEUE_UAPSD)
972 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
973 else
974 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
975 TXQ_FLAG_TXDESCINT_ENABLE;
976 }
Sujithe8324352009-01-16 21:38:42 +0530977 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
978 if (qnum == -1) {
979 /*
980 * NB: don't print a message, this happens
981 * normally on parts with too few tx queues
982 */
983 return NULL;
984 }
985 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700986 ath_print(common, ATH_DBG_FATAL,
987 "qnum %u out of range, max %u!\n",
988 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530989 ath9k_hw_releasetxqueue(ah, qnum);
990 return NULL;
991 }
992 if (!ATH_TXQ_SETUP(sc, qnum)) {
993 struct ath_txq *txq = &sc->tx.txq[qnum];
994
995 txq->axq_qnum = qnum;
996 txq->axq_link = NULL;
997 INIT_LIST_HEAD(&txq->axq_q);
998 INIT_LIST_HEAD(&txq->axq_acq);
999 spin_lock_init(&txq->axq_lock);
1000 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001001 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +05301002 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001003
1004 txq->txq_headidx = txq->txq_tailidx = 0;
1005 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1006 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1007 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301008 }
1009 return &sc->tx.txq[qnum];
1010}
1011
Sujithe8324352009-01-16 21:38:42 +05301012int ath_txq_update(struct ath_softc *sc, int qnum,
1013 struct ath9k_tx_queue_info *qinfo)
1014{
Sujithcbe61d82009-02-09 13:27:12 +05301015 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301016 int error = 0;
1017 struct ath9k_tx_queue_info qi;
1018
1019 if (qnum == sc->beacon.beaconq) {
1020 /*
1021 * XXX: for beacon queue, we just save the parameter.
1022 * It will be picked up by ath_beaconq_config when
1023 * it's necessary.
1024 */
1025 sc->beacon.beacon_qi = *qinfo;
1026 return 0;
1027 }
1028
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001029 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301030
1031 ath9k_hw_get_txq_props(ah, qnum, &qi);
1032 qi.tqi_aifs = qinfo->tqi_aifs;
1033 qi.tqi_cwmin = qinfo->tqi_cwmin;
1034 qi.tqi_cwmax = qinfo->tqi_cwmax;
1035 qi.tqi_burstTime = qinfo->tqi_burstTime;
1036 qi.tqi_readyTime = qinfo->tqi_readyTime;
1037
1038 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001039 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1040 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301041 error = -EIO;
1042 } else {
1043 ath9k_hw_resettxqueue(ah, qnum);
1044 }
1045
1046 return error;
1047}
1048
1049int ath_cabq_update(struct ath_softc *sc)
1050{
1051 struct ath9k_tx_queue_info qi;
1052 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301053
1054 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1055 /*
1056 * Ensure the readytime % is within the bounds.
1057 */
Sujith17d79042009-02-09 13:27:03 +05301058 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1059 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1060 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1061 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301062
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001063 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301064 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301065 ath_txq_update(sc, qnum, &qi);
1066
1067 return 0;
1068}
1069
Sujith043a0402009-01-16 21:38:47 +05301070/*
1071 * Drain a given TX queue (could be Beacon or Data)
1072 *
1073 * This assumes output has been stopped and
1074 * we do not need to block ath_tx_tasklet.
1075 */
1076void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301077{
1078 struct ath_buf *bf, *lastbf;
1079 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001080 struct ath_tx_status ts;
1081
1082 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301083 INIT_LIST_HEAD(&bf_head);
1084
Sujithe8324352009-01-16 21:38:42 +05301085 for (;;) {
1086 spin_lock_bh(&txq->axq_lock);
1087
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001088 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1089 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1090 txq->txq_headidx = txq->txq_tailidx = 0;
1091 spin_unlock_bh(&txq->axq_lock);
1092 break;
1093 } else {
1094 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1095 struct ath_buf, list);
1096 }
1097 } else {
1098 if (list_empty(&txq->axq_q)) {
1099 txq->axq_link = NULL;
1100 spin_unlock_bh(&txq->axq_lock);
1101 break;
1102 }
1103 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1104 list);
Sujithe8324352009-01-16 21:38:42 +05301105
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001106 if (bf->bf_stale) {
1107 list_del(&bf->list);
1108 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301109
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001110 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001111 continue;
1112 }
Sujithe8324352009-01-16 21:38:42 +05301113 }
1114
1115 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05301116
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001117 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1118 list_cut_position(&bf_head,
1119 &txq->txq_fifo[txq->txq_tailidx],
1120 &lastbf->list);
1121 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1122 } else {
1123 /* remove ath_buf's of the same mpdu from txq */
1124 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1125 }
1126
Sujithe8324352009-01-16 21:38:42 +05301127 txq->axq_depth--;
1128
1129 spin_unlock_bh(&txq->axq_lock);
1130
1131 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01001132 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
1133 retry_tx);
Sujithe8324352009-01-16 21:38:42 +05301134 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001135 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301136 }
1137
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001138 spin_lock_bh(&txq->axq_lock);
1139 txq->axq_tx_inprogress = false;
1140 spin_unlock_bh(&txq->axq_lock);
1141
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001142 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1143 spin_lock_bh(&txq->axq_lock);
1144 while (!list_empty(&txq->txq_fifo_pending)) {
1145 bf = list_first_entry(&txq->txq_fifo_pending,
1146 struct ath_buf, list);
1147 list_cut_position(&bf_head,
1148 &txq->txq_fifo_pending,
1149 &bf->bf_lastbf->list);
1150 spin_unlock_bh(&txq->axq_lock);
1151
1152 if (bf_isampdu(bf))
1153 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
Felix Fietkauc5992612010-11-14 15:20:09 +01001154 &ts, 0, retry_tx);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001155 else
1156 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1157 &ts, 0, 0);
1158 spin_lock_bh(&txq->axq_lock);
1159 }
1160 spin_unlock_bh(&txq->axq_lock);
1161 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001162
1163 /* flush any pending frames if aggregation is enabled */
1164 if (sc->sc_flags & SC_OP_TXAGGR) {
1165 if (!retry_tx) {
1166 spin_lock_bh(&txq->axq_lock);
1167 ath_txq_drain_pending_buffers(sc, txq);
1168 spin_unlock_bh(&txq->axq_lock);
1169 }
1170 }
Sujithe8324352009-01-16 21:38:42 +05301171}
1172
Sujith043a0402009-01-16 21:38:47 +05301173void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1174{
Sujithcbe61d82009-02-09 13:27:12 +05301175 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001176 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301177 struct ath_txq *txq;
1178 int i, npend = 0;
1179
1180 if (sc->sc_flags & SC_OP_INVALID)
1181 return;
1182
1183 /* Stop beacon queue */
1184 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1185
1186 /* Stop data queues */
1187 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1188 if (ATH_TXQ_SETUP(sc, i)) {
1189 txq = &sc->tx.txq[i];
1190 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1191 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1192 }
1193 }
1194
1195 if (npend) {
1196 int r;
1197
Sujithe8009e92009-12-14 14:57:08 +05301198 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001199 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301200
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001201 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301202 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001203 ath_print(common, ATH_DBG_FATAL,
1204 "Unable to reset hardware; reset status %d\n",
1205 r);
Sujith043a0402009-01-16 21:38:47 +05301206 }
1207
1208 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1209 if (ATH_TXQ_SETUP(sc, i))
1210 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1211 }
1212}
1213
Sujithe8324352009-01-16 21:38:42 +05301214void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1215{
1216 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1217 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1218}
1219
Sujithe8324352009-01-16 21:38:42 +05301220void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1221{
1222 struct ath_atx_ac *ac;
1223 struct ath_atx_tid *tid;
1224
1225 if (list_empty(&txq->axq_acq))
1226 return;
1227
1228 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1229 list_del(&ac->list);
1230 ac->sched = false;
1231
1232 do {
1233 if (list_empty(&ac->tid_q))
1234 return;
1235
1236 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1237 list_del(&tid->list);
1238 tid->sched = false;
1239
1240 if (tid->paused)
1241 continue;
1242
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001243 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301244
1245 /*
1246 * add tid to round-robin queue if more frames
1247 * are pending for the tid
1248 */
1249 if (!list_empty(&tid->buf_q))
1250 ath_tx_queue_tid(txq, tid);
1251
1252 break;
1253 } while (!list_empty(&ac->tid_q));
1254
1255 if (!list_empty(&ac->tid_q)) {
1256 if (!ac->sched) {
1257 ac->sched = true;
1258 list_add_tail(&ac->list, &txq->axq_acq);
1259 }
1260 }
1261}
1262
Sujithe8324352009-01-16 21:38:42 +05301263/***********/
1264/* TX, DMA */
1265/***********/
1266
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001267/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001268 * Insert a chain of ath_buf (descriptors) on a txq and
1269 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001270 */
Sujith102e0572008-10-29 10:15:16 +05301271static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1272 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273{
Sujithcbe61d82009-02-09 13:27:12 +05301274 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001275 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001276 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301277
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001278 /*
1279 * Insert the frame on the outbound list and
1280 * pass it on to the hardware.
1281 */
1282
1283 if (list_empty(head))
1284 return;
1285
1286 bf = list_first_entry(head, struct ath_buf, list);
1287
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001288 ath_print(common, ATH_DBG_QUEUE,
1289 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001290
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001291 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1292 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1293 list_splice_tail_init(head, &txq->txq_fifo_pending);
1294 return;
1295 }
1296 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1297 ath_print(common, ATH_DBG_XMIT,
1298 "Initializing tx fifo %d which "
1299 "is non-empty\n",
1300 txq->txq_headidx);
1301 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1302 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1303 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001304 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001305 ath_print(common, ATH_DBG_XMIT,
1306 "TXDP[%u] = %llx (%p)\n",
1307 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001308 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001309 list_splice_tail_init(head, &txq->axq_q);
1310
1311 if (txq->axq_link == NULL) {
1312 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1313 ath_print(common, ATH_DBG_XMIT,
1314 "TXDP[%u] = %llx (%p)\n",
1315 txq->axq_qnum, ito64(bf->bf_daddr),
1316 bf->bf_desc);
1317 } else {
1318 *txq->axq_link = bf->bf_daddr;
1319 ath_print(common, ATH_DBG_XMIT,
1320 "link[%u] (%p)=%llx (%p)\n",
1321 txq->axq_qnum, txq->axq_link,
1322 ito64(bf->bf_daddr), bf->bf_desc);
1323 }
1324 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1325 &txq->axq_link);
1326 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001327 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001328 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001329}
1330
Sujithe8324352009-01-16 21:38:42 +05301331static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau04caf862010-11-14 15:20:12 +01001332 struct ath_buf *bf, struct ath_tx_control *txctl)
Sujithe8324352009-01-16 21:38:42 +05301333{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001334 struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
Felix Fietkau04caf862010-11-14 15:20:12 +01001335 struct list_head bf_head;
Sujithe8324352009-01-16 21:38:42 +05301336
Sujithe8324352009-01-16 21:38:42 +05301337 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301338 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301339
1340 /*
1341 * Do not queue to h/w when any of the following conditions is true:
1342 * - there are pending frames in software queue
1343 * - the TID is currently paused for ADDBA/BAR request
1344 * - seqno is not within block-ack window
1345 * - h/w queue depth exceeds low water mark
1346 */
1347 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001348 !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301349 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001350 /*
Sujithe8324352009-01-16 21:38:42 +05301351 * Add this frame to software queue for scheduling later
1352 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001353 */
Felix Fietkau04caf862010-11-14 15:20:12 +01001354 list_add_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301355 ath_tx_queue_tid(txctl->txq, tid);
1356 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001357 }
1358
Felix Fietkau04caf862010-11-14 15:20:12 +01001359 INIT_LIST_HEAD(&bf_head);
1360 list_add(&bf->list, &bf_head);
1361
Sujithe8324352009-01-16 21:38:42 +05301362 /* Add sub-frame to BAW */
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001363 if (!fi->retries)
1364 ath_tx_addto_baw(sc, tid, fi->seqno);
Sujithe8324352009-01-16 21:38:42 +05301365
1366 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301367 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001368 ath_buf_set_rate(sc, bf, fi->framelen);
Felix Fietkau04caf862010-11-14 15:20:12 +01001369 ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
Sujithc4288392008-11-18 09:09:30 +05301370}
1371
Felix Fietkau82b873a2010-11-11 03:18:37 +01001372static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1373 struct ath_atx_tid *tid,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001374 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001375{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001376 struct ath_frame_info *fi;
Sujithe8324352009-01-16 21:38:42 +05301377 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001378
Sujithe8324352009-01-16 21:38:42 +05301379 bf = list_first_entry(bf_head, struct ath_buf, list);
1380 bf->bf_state.bf_type &= ~BUF_AMPDU;
1381
1382 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001383 if (tid)
1384 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301385
Sujithd43f30152009-01-16 21:38:53 +05301386 bf->bf_lastbf = bf;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001387 fi = get_frame_info(bf->bf_mpdu);
1388 ath_buf_set_rate(sc, bf, fi->framelen);
Sujithe8324352009-01-16 21:38:42 +05301389 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301390 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001391}
1392
Sujith528f0c62008-10-29 10:14:26 +05301393static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001394{
Sujith528f0c62008-10-29 10:14:26 +05301395 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001396 enum ath9k_pkt_type htype;
1397 __le16 fc;
1398
Sujith528f0c62008-10-29 10:14:26 +05301399 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001400 fc = hdr->frame_control;
1401
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001402 if (ieee80211_is_beacon(fc))
1403 htype = ATH9K_PKT_TYPE_BEACON;
1404 else if (ieee80211_is_probe_resp(fc))
1405 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1406 else if (ieee80211_is_atim(fc))
1407 htype = ATH9K_PKT_TYPE_ATIM;
1408 else if (ieee80211_is_pspoll(fc))
1409 htype = ATH9K_PKT_TYPE_PSPOLL;
1410 else
1411 htype = ATH9K_PKT_TYPE_NORMAL;
1412
1413 return htype;
1414}
1415
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001416static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
1417 int framelen)
Sujith528f0c62008-10-29 10:14:26 +05301418{
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001419 struct ath_wiphy *aphy = hw->priv;
1420 struct ath_softc *sc = aphy->sc;
Sujith528f0c62008-10-29 10:14:26 +05301421 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001422 struct ieee80211_sta *sta = tx_info->control.sta;
1423 struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
Sujith528f0c62008-10-29 10:14:26 +05301424 struct ieee80211_hdr *hdr;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001425 struct ath_frame_info *fi = get_frame_info(skb);
Sujith528f0c62008-10-29 10:14:26 +05301426 struct ath_node *an;
1427 struct ath_atx_tid *tid;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001428 enum ath9k_key_type keytype;
1429 u16 seqno = 0;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001430 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301431
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001432 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujith528f0c62008-10-29 10:14:26 +05301433
Sujith528f0c62008-10-29 10:14:26 +05301434 hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001435 if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
1436 conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001437
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001438 an = (struct ath_node *) sta->drv_priv;
1439 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
1440
1441 /*
1442 * Override seqno set by upper layer with the one
1443 * in tx aggregation state.
1444 */
1445 tid = ATH_AN_2_TID(an, tidno);
1446 seqno = tid->seq_next;
1447 hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
1448 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
1449 }
1450
1451 memset(fi, 0, sizeof(*fi));
1452 if (hw_key)
1453 fi->keyix = hw_key->hw_key_idx;
1454 else
1455 fi->keyix = ATH9K_TXKEYIX_INVALID;
1456 fi->keytype = keytype;
1457 fi->framelen = framelen;
1458 fi->seqno = seqno;
Sujith528f0c62008-10-29 10:14:26 +05301459}
1460
Felix Fietkau82b873a2010-11-11 03:18:37 +01001461static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301462{
1463 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1464 int flags = 0;
1465
1466 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1467 flags |= ATH9K_TXDESC_INTREQ;
1468
1469 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1470 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301471
Felix Fietkau82b873a2010-11-11 03:18:37 +01001472 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001473 flags |= ATH9K_TXDESC_LDPC;
1474
Sujith528f0c62008-10-29 10:14:26 +05301475 return flags;
1476}
1477
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001478/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001479 * rix - rate index
1480 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1481 * width - 0 for 20 MHz, 1 for 40 MHz
1482 * half_gi - to use 4us v/s 3.6 us for symbol time
1483 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001484static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301485 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001486{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001488 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301489
1490 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001491 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001492 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001493 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001494 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1495
1496 if (!half_gi)
1497 duration = SYMBOL_TIME(nsymbols);
1498 else
1499 duration = SYMBOL_TIME_HALFGI(nsymbols);
1500
Sujithe63835b2008-11-18 09:07:53 +05301501 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001502 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301503
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001504 return duration;
1505}
1506
Felix Fietkau269c44b2010-11-14 15:20:06 +01001507static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001508{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001509 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001510 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301511 struct sk_buff *skb;
1512 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301513 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001514 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301515 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301516 int i, flags = 0;
1517 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301518 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301519
1520 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301521
Sujitha22be222009-03-30 15:28:36 +05301522 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301523 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301524 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301525 hdr = (struct ieee80211_hdr *)skb->data;
1526 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301527
Sujithc89424d2009-01-30 14:29:28 +05301528 /*
1529 * We check if Short Preamble is needed for the CTS rate by
1530 * checking the BSS's global flag.
1531 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1532 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001533 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1534 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301535 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001536 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001537
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001538 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001539 bool is_40, is_sgi, is_sp;
1540 int phy;
1541
Sujithe63835b2008-11-18 09:07:53 +05301542 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001543 continue;
1544
Sujitha8efee42008-11-18 09:07:30 +05301545 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301546 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001547 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001548
Felix Fietkau27032052010-01-17 21:08:50 +01001549 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1550 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301551 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001552 flags |= ATH9K_TXDESC_RTSENA;
1553 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1554 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1555 flags |= ATH9K_TXDESC_CTSENA;
1556 }
1557
Sujithc89424d2009-01-30 14:29:28 +05301558 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1559 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1560 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1561 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001562
Felix Fietkau545750d2009-11-23 22:21:01 +01001563 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1564 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1565 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1566
1567 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1568 /* MCS rates */
1569 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001570 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001571 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001572 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1573 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001574 continue;
1575 }
1576
1577 /* legcay rates */
1578 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1579 !(rate->flags & IEEE80211_RATE_ERP_G))
1580 phy = WLAN_RC_PHY_CCK;
1581 else
1582 phy = WLAN_RC_PHY_OFDM;
1583
1584 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1585 series[i].Rate = rate->hw_value;
1586 if (rate->hw_value_short) {
1587 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1588 series[i].Rate |= rate->hw_value_short;
1589 } else {
1590 is_sp = false;
1591 }
1592
1593 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001594 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001595 }
1596
Felix Fietkau27032052010-01-17 21:08:50 +01001597 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001598 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001599 flags &= ~ATH9K_TXDESC_RTSENA;
1600
1601 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1602 if (flags & ATH9K_TXDESC_RTSENA)
1603 flags &= ~ATH9K_TXDESC_CTSENA;
1604
Sujithe63835b2008-11-18 09:07:53 +05301605 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301606 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1607 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301608 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301609 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301610
Sujith17d79042009-02-09 13:27:03 +05301611 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301612 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001613}
1614
Felix Fietkau82b873a2010-11-11 03:18:37 +01001615static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
Felix Fietkau04caf862010-11-14 15:20:12 +01001616 struct ath_txq *txq,
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001617 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301618{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001619 struct ath_wiphy *aphy = hw->priv;
1620 struct ath_softc *sc = aphy->sc;
Felix Fietkau04caf862010-11-14 15:20:12 +01001621 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001622 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001623 struct ath_frame_info *fi = get_frame_info(skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001624 struct ath_buf *bf;
Felix Fietkau04caf862010-11-14 15:20:12 +01001625 struct ath_desc *ds;
Felix Fietkau04caf862010-11-14 15:20:12 +01001626 int frm_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001627
1628 bf = ath_tx_get_buffer(sc);
1629 if (!bf) {
1630 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1631 return NULL;
1632 }
Sujithe8324352009-01-16 21:38:42 +05301633
Sujithe8324352009-01-16 21:38:42 +05301634 ATH_TXBUF_RESET(bf);
1635
Felix Fietkau827e69b2009-11-15 23:09:25 +01001636 bf->aphy = aphy;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001637 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301638 bf->bf_mpdu = skb;
1639
Ben Greearc1739eb32010-10-14 12:45:29 -07001640 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1641 skb->len, DMA_TO_DEVICE);
1642 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301643 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001644 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001645 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1646 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001647 ath_tx_return_buffer(sc, bf);
1648 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301649 }
1650
Sujithe8324352009-01-16 21:38:42 +05301651 frm_type = get_hw_packet_type(skb);
Sujithe8324352009-01-16 21:38:42 +05301652
1653 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001654 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301655
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001656 ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
1657 fi->keyix, fi->keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301658
1659 ath9k_hw_filltxdesc(ah, ds,
1660 skb->len, /* segment length */
1661 true, /* first segment */
1662 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001663 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001664 bf->bf_buf_addr,
Felix Fietkau04caf862010-11-14 15:20:12 +01001665 txq->axq_qnum);
1666
1667
1668 return bf;
1669}
1670
1671/* FIXME: tx power */
1672static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1673 struct ath_tx_control *txctl)
1674{
1675 struct sk_buff *skb = bf->bf_mpdu;
1676 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1677 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau04caf862010-11-14 15:20:12 +01001678 struct list_head bf_head;
1679 struct ath_atx_tid *tid;
1680 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301681
Sujithe8324352009-01-16 21:38:42 +05301682 spin_lock_bh(&txctl->txq->axq_lock);
1683
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001684 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && txctl->an) {
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001685 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1686 IEEE80211_QOS_CTL_TID_MASK;
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001687 tid = ATH_AN_2_TID(txctl->an, tidno);
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001688
Felix Fietkau066dae92010-11-07 14:59:39 +01001689 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau04caf862010-11-14 15:20:12 +01001690 /*
1691 * Try aggregation if it's a unicast data frame
1692 * and the destination is HT capable.
1693 */
1694 ath_tx_send_ampdu(sc, tid, bf, txctl);
Sujithe8324352009-01-16 21:38:42 +05301695 } else {
Felix Fietkau04caf862010-11-14 15:20:12 +01001696 INIT_LIST_HEAD(&bf_head);
1697 list_add_tail(&bf->list, &bf_head);
1698
Felix Fietkau61117f012010-11-11 03:18:36 +01001699 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001700 bf->bf_state.bfs_paprd = txctl->paprd;
1701
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001702 if (bf->bf_state.bfs_paprd)
Felix Fietkau04caf862010-11-14 15:20:12 +01001703 ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
1704 bf->bf_state.bfs_paprd);
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001705
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001706 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301707 }
1708
1709 spin_unlock_bh(&txctl->txq->axq_lock);
1710}
1711
1712/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001713int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301714 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001715{
Felix Fietkau28d16702010-11-14 15:20:10 +01001716 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1717 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001718 struct ieee80211_sta *sta = info->control.sta;
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001719 struct ath_wiphy *aphy = hw->priv;
1720 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001721 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001722 struct ath_buf *bf;
Felix Fietkau28d16702010-11-14 15:20:10 +01001723 int padpos, padsize;
Felix Fietkau04caf862010-11-14 15:20:12 +01001724 int frmlen = skb->len + FCS_LEN;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001725 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001726
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001727 txctl->an = (struct ath_node *)sta->drv_priv;
Felix Fietkau04caf862010-11-14 15:20:12 +01001728 if (info->control.hw_key)
1729 frmlen += info->control.hw_key->icv_len;
1730
Felix Fietkau28d16702010-11-14 15:20:10 +01001731 /*
1732 * As a temporary workaround, assign seq# here; this will likely need
1733 * to be cleaned up to work better with Beacon transmission and virtual
1734 * BSSes.
1735 */
1736 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
1737 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1738 sc->tx.seq_no += 0x10;
1739 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1740 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
1741 }
1742
1743 /* Add the padding after the header if this is not already done */
1744 padpos = ath9k_cmn_padpos(hdr->frame_control);
1745 padsize = padpos & 3;
1746 if (padsize && skb->len > padpos) {
1747 if (skb_headroom(skb) < padsize)
1748 return -ENOMEM;
1749
1750 skb_push(skb, padsize);
1751 memmove(skb->data, skb->data + padsize, padpos);
1752 }
1753
Felix Fietkau2d42efc2010-11-14 15:20:13 +01001754 setup_frame_info(hw, skb, frmlen);
1755
1756 /*
1757 * At this point, the vif, hw_key and sta pointers in the tx control
1758 * info are no longer valid (overwritten by the ath_frame_info data.
1759 */
1760
1761 bf = ath_tx_setup_buffer(hw, txctl->txq, skb);
Felix Fietkau82b873a2010-11-11 03:18:37 +01001762 if (unlikely(!bf))
1763 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001764
Felix Fietkau066dae92010-11-07 14:59:39 +01001765 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001766 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001767 if (txq == sc->tx.txq_map[q] &&
1768 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1769 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001770 txq->stopped = 1;
1771 }
1772 spin_unlock_bh(&txq->axq_lock);
1773
Sujithe8324352009-01-16 21:38:42 +05301774 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001775
1776 return 0;
1777}
1778
Sujithe8324352009-01-16 21:38:42 +05301779/*****************/
1780/* TX Completion */
1781/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001782
Sujithe8324352009-01-16 21:38:42 +05301783static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f012010-11-11 03:18:36 +01001784 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001785 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001786{
Sujithe8324352009-01-16 21:38:42 +05301787 struct ieee80211_hw *hw = sc->hw;
1788 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001789 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001790 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001791 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301792
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001793 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301794
Felix Fietkau827e69b2009-11-15 23:09:25 +01001795 if (aphy)
1796 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301797
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301798 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301799 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301800
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301801 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301802 /* Frame was ACKed */
1803 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1804 }
1805
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001806 padpos = ath9k_cmn_padpos(hdr->frame_control);
1807 padsize = padpos & 3;
1808 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301809 /*
1810 * Remove MAC header padding before giving the frame back to
1811 * mac80211.
1812 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001813 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301814 skb_pull(skb, padsize);
1815 }
1816
Sujith1b04b932010-01-08 10:36:05 +05301817 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1818 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001819 ath_print(common, ATH_DBG_PS,
1820 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001821 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301822 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1823 PS_WAIT_FOR_CAB |
1824 PS_WAIT_FOR_PSPOLL_DATA |
1825 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001826 }
1827
Felix Fietkau61117f012010-11-11 03:18:36 +01001828 if (unlikely(ftype))
1829 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001830 else {
1831 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001832 if (txq == sc->tx.txq_map[q]) {
1833 spin_lock_bh(&txq->axq_lock);
1834 if (WARN_ON(--txq->pending_frames < 0))
1835 txq->pending_frames = 0;
1836 spin_unlock_bh(&txq->axq_lock);
1837 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001838
Felix Fietkau827e69b2009-11-15 23:09:25 +01001839 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001840 }
Sujithe8324352009-01-16 21:38:42 +05301841}
1842
1843static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001844 struct ath_txq *txq, struct list_head *bf_q,
1845 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301846{
1847 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301848 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301849 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301850
Sujithe8324352009-01-16 21:38:42 +05301851 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301852 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301853
1854 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301855 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301856
1857 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301858 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301859 }
1860
Ben Greearc1739eb32010-10-14 12:45:29 -07001861 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001862 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001863
1864 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001865 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001866 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001867 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001868 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001869 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001870 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f012010-11-11 03:18:36 +01001871 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1872 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001873 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001874 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1875 * accidentally reference it later.
1876 */
1877 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301878
1879 /*
1880 * Return the list of ath_buf of this mpdu to free queue
1881 */
1882 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1883 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1884 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1885}
1886
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001887static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001888 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301889{
Sujitha22be222009-03-30 15:28:36 +05301890 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301891 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301892 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001893 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001894 struct ath_softc *sc = bf->aphy->sc;
1895 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301896 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301897
Sujith95e4acb2009-03-13 08:56:09 +05301898 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001899 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301900
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001901 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301902 WARN_ON(tx_rateindex >= hw->max_rates);
1903
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001904 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301905 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001906 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001907 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301908
Felix Fietkaub572d032010-11-14 15:20:07 +01001909 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001910
Felix Fietkaub572d032010-11-14 15:20:07 +01001911 tx_info->status.ampdu_len = nframes;
1912 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001913 }
1914
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001915 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301916 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001917 /*
1918 * If an underrun error is seen assume it as an excessive
1919 * retry only if max frame trigger level has been reached
1920 * (2 KB for single stream, and 4 KB for dual stream).
1921 * Adjust the long retry as if the frame was tried
1922 * hw->max_rate_tries times to affect how rate control updates
1923 * PER for the failed rate.
1924 * In case of congestion on the bus penalizing this type of
1925 * underruns should help hardware actually transmit new frames
1926 * successfully by eventually preferring slower rates.
1927 * This itself should also alleviate congestion on the bus.
1928 */
1929 if (ieee80211_is_data(hdr->frame_control) &&
1930 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1931 ATH9K_TX_DELIM_UNDERRUN)) &&
1932 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1933 tx_info->status.rates[tx_rateindex].count =
1934 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301935 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301936
Felix Fietkau545750d2009-11-23 22:21:01 +01001937 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301938 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001939 tx_info->status.rates[i].idx = -1;
1940 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301941
Felix Fietkau78c46532010-06-25 01:26:16 +02001942 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301943}
1944
Felix Fietkau066dae92010-11-07 14:59:39 +01001945static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301946{
Felix Fietkau066dae92010-11-07 14:59:39 +01001947 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301948
Felix Fietkau066dae92010-11-07 14:59:39 +01001949 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301950 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001951 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001952 if (ath_mac80211_start_queue(sc, qnum))
1953 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301954 }
1955 spin_unlock_bh(&txq->axq_lock);
1956}
1957
Sujithc4288392008-11-18 09:09:30 +05301958static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001959{
Sujithcbe61d82009-02-09 13:27:12 +05301960 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001961 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001962 struct ath_buf *bf, *lastbf, *bf_held = NULL;
1963 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05301964 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07001965 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05301966 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001967 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01001968 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001969
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001970 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
1971 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
1972 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001973
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001974 for (;;) {
1975 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001976 if (list_empty(&txq->axq_q)) {
1977 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001978 spin_unlock_bh(&txq->axq_lock);
1979 break;
1980 }
1981 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
1982
1983 /*
1984 * There is a race condition that a BH gets scheduled
1985 * after sw writes TxE and before hw re-load the last
1986 * descriptor to get the newly chained one.
1987 * Software must keep the last DONE descriptor as a
1988 * holding descriptor - software does so by marking
1989 * it with the STALE flag.
1990 */
1991 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05301992 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001993 bf_held = bf;
1994 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05301995 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001996 break;
1997 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001998 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05301999 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002000 }
2001 }
2002
2003 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302004 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002005
Felix Fietkau29bffa92010-03-29 20:14:23 -07002006 memset(&ts, 0, sizeof(ts));
2007 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002008 if (status == -EINPROGRESS) {
2009 spin_unlock_bh(&txq->axq_lock);
2010 break;
2011 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012
2013 /*
2014 * Remove ath_buf's of the same transmit unit from txq,
2015 * however leave the last descriptor back as the holding
2016 * descriptor for hw.
2017 */
Sujitha119cc42009-03-30 15:28:38 +05302018 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002019 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002020 if (!list_is_singular(&lastbf->list))
2021 list_cut_position(&bf_head,
2022 &txq->axq_q, lastbf->list.prev);
2023
2024 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002025 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002026 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002027 if (bf_held)
2028 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002029 spin_unlock_bh(&txq->axq_lock);
2030
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002031 if (bf_held)
2032 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002033
Sujithcd3d39a2008-08-11 14:03:34 +05302034 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002035 /*
2036 * This frame is sent out as a single frame.
2037 * Use hardware retry status for this frame.
2038 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002039 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302040 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002041 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002042 }
Johannes Berge6a98542008-10-21 12:40:02 +02002043
Felix Fietkau066dae92010-11-07 14:59:39 +01002044 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2045
Sujithcd3d39a2008-08-11 14:03:34 +05302046 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002047 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
2048 true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002050 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002051
Felix Fietkau066dae92010-11-07 14:59:39 +01002052 if (txq == sc->tx.txq_map[qnum])
2053 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302054
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002055 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302056 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002057 ath_txq_schedule(sc, txq);
2058 spin_unlock_bh(&txq->axq_lock);
2059 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060}
2061
Sujith305fe472009-07-23 15:32:29 +05302062static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002063{
2064 struct ath_softc *sc = container_of(work, struct ath_softc,
2065 tx_complete_work.work);
2066 struct ath_txq *txq;
2067 int i;
2068 bool needreset = false;
2069
2070 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2071 if (ATH_TXQ_SETUP(sc, i)) {
2072 txq = &sc->tx.txq[i];
2073 spin_lock_bh(&txq->axq_lock);
2074 if (txq->axq_depth) {
2075 if (txq->axq_tx_inprogress) {
2076 needreset = true;
2077 spin_unlock_bh(&txq->axq_lock);
2078 break;
2079 } else {
2080 txq->axq_tx_inprogress = true;
2081 }
2082 }
2083 spin_unlock_bh(&txq->axq_lock);
2084 }
2085
2086 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002087 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2088 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302089 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002090 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302091 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002092 }
2093
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002094 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002095 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2096}
2097
2098
Sujithe8324352009-01-16 21:38:42 +05302099
2100void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002101{
Sujithe8324352009-01-16 21:38:42 +05302102 int i;
2103 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002104
Sujithe8324352009-01-16 21:38:42 +05302105 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002106
2107 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302108 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2109 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002110 }
2111}
2112
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002113void ath_tx_edma_tasklet(struct ath_softc *sc)
2114{
2115 struct ath_tx_status txs;
2116 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2117 struct ath_hw *ah = sc->sc_ah;
2118 struct ath_txq *txq;
2119 struct ath_buf *bf, *lastbf;
2120 struct list_head bf_head;
2121 int status;
2122 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002123 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002124
2125 for (;;) {
2126 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2127 if (status == -EINPROGRESS)
2128 break;
2129 if (status == -EIO) {
2130 ath_print(common, ATH_DBG_XMIT,
2131 "Error processing tx status\n");
2132 break;
2133 }
2134
2135 /* Skip beacon completions */
2136 if (txs.qid == sc->beacon.beaconq)
2137 continue;
2138
2139 txq = &sc->tx.txq[txs.qid];
2140
2141 spin_lock_bh(&txq->axq_lock);
2142 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2143 spin_unlock_bh(&txq->axq_lock);
2144 return;
2145 }
2146
2147 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2148 struct ath_buf, list);
2149 lastbf = bf->bf_lastbf;
2150
2151 INIT_LIST_HEAD(&bf_head);
2152 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2153 &lastbf->list);
2154 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2155 txq->axq_depth--;
2156 txq->axq_tx_inprogress = false;
2157 spin_unlock_bh(&txq->axq_lock);
2158
2159 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2160
2161 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002162 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2163 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002164 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002165 }
2166
Felix Fietkau066dae92010-11-07 14:59:39 +01002167 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2168
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002169 if (bf_isampdu(bf))
Felix Fietkauc5992612010-11-14 15:20:09 +01002170 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
2171 txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002172 else
2173 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2174 &txs, txok, 0);
2175
Felix Fietkau066dae92010-11-07 14:59:39 +01002176 if (txq == sc->tx.txq_map[qnum])
2177 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002178
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002179 spin_lock_bh(&txq->axq_lock);
2180 if (!list_empty(&txq->txq_fifo_pending)) {
2181 INIT_LIST_HEAD(&bf_head);
2182 bf = list_first_entry(&txq->txq_fifo_pending,
2183 struct ath_buf, list);
2184 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2185 &bf->bf_lastbf->list);
2186 ath_tx_txqaddbuf(sc, txq, &bf_head);
2187 } else if (sc->sc_flags & SC_OP_TXAGGR)
2188 ath_txq_schedule(sc, txq);
2189 spin_unlock_bh(&txq->axq_lock);
2190 }
2191}
2192
Sujithe8324352009-01-16 21:38:42 +05302193/*****************/
2194/* Init, Cleanup */
2195/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002196
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002197static int ath_txstatus_setup(struct ath_softc *sc, int size)
2198{
2199 struct ath_descdma *dd = &sc->txsdma;
2200 u8 txs_len = sc->sc_ah->caps.txs_len;
2201
2202 dd->dd_desc_len = size * txs_len;
2203 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2204 &dd->dd_desc_paddr, GFP_KERNEL);
2205 if (!dd->dd_desc)
2206 return -ENOMEM;
2207
2208 return 0;
2209}
2210
2211static int ath_tx_edma_init(struct ath_softc *sc)
2212{
2213 int err;
2214
2215 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2216 if (!err)
2217 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2218 sc->txsdma.dd_desc_paddr,
2219 ATH_TXSTATUS_RING_SIZE);
2220
2221 return err;
2222}
2223
2224static void ath_tx_edma_cleanup(struct ath_softc *sc)
2225{
2226 struct ath_descdma *dd = &sc->txsdma;
2227
2228 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2229 dd->dd_desc_paddr);
2230}
2231
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002232int ath_tx_init(struct ath_softc *sc, int nbufs)
2233{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002234 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002235 int error = 0;
2236
Sujith797fe5cb2009-03-30 15:28:45 +05302237 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002238
Sujith797fe5cb2009-03-30 15:28:45 +05302239 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002240 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302241 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002242 ath_print(common, ATH_DBG_FATAL,
2243 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302244 goto err;
2245 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002246
Sujith797fe5cb2009-03-30 15:28:45 +05302247 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002248 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302249 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002250 ath_print(common, ATH_DBG_FATAL,
2251 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302252 goto err;
2253 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002254
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002255 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2256
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002257 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2258 error = ath_tx_edma_init(sc);
2259 if (error)
2260 goto err;
2261 }
2262
Sujith797fe5cb2009-03-30 15:28:45 +05302263err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002264 if (error != 0)
2265 ath_tx_cleanup(sc);
2266
2267 return error;
2268}
2269
Sujith797fe5cb2009-03-30 15:28:45 +05302270void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002271{
Sujithb77f4832008-12-07 21:44:03 +05302272 if (sc->beacon.bdma.dd_desc_len != 0)
2273 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002274
Sujithb77f4832008-12-07 21:44:03 +05302275 if (sc->tx.txdma.dd_desc_len != 0)
2276 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002277
2278 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2279 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002280}
2281
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002282void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2283{
Sujithc5170162008-10-29 10:13:59 +05302284 struct ath_atx_tid *tid;
2285 struct ath_atx_ac *ac;
2286 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002287
Sujith8ee5afb2008-12-07 21:43:36 +05302288 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302289 tidno < WME_NUM_TID;
2290 tidno++, tid++) {
2291 tid->an = an;
2292 tid->tidno = tidno;
2293 tid->seq_start = tid->seq_next = 0;
2294 tid->baw_size = WME_MAX_BA;
2295 tid->baw_head = tid->baw_tail = 0;
2296 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302297 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302298 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302299 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302300 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302301 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302302 tid->state &= ~AGGR_ADDBA_COMPLETE;
2303 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302304 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002305
Sujith8ee5afb2008-12-07 21:43:36 +05302306 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302307 acno < WME_NUM_AC; acno++, ac++) {
2308 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002309 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302310 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002311 }
2312}
2313
Sujithb5aa9bf2008-10-29 10:13:31 +05302314void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002315{
Felix Fietkau2b409942010-07-07 19:42:08 +02002316 struct ath_atx_ac *ac;
2317 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002318 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002319 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302320
Felix Fietkau2b409942010-07-07 19:42:08 +02002321 for (tidno = 0, tid = &an->tid[tidno];
2322 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002323
Felix Fietkau2b409942010-07-07 19:42:08 +02002324 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002325 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002326
Felix Fietkau2b409942010-07-07 19:42:08 +02002327 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002328
Felix Fietkau2b409942010-07-07 19:42:08 +02002329 if (tid->sched) {
2330 list_del(&tid->list);
2331 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002332 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002333
2334 if (ac->sched) {
2335 list_del(&ac->list);
2336 tid->ac->sched = false;
2337 }
2338
2339 ath_tid_drain(sc, txq, tid);
2340 tid->state &= ~AGGR_ADDBA_COMPLETE;
2341 tid->state &= ~AGGR_CLEANUP;
2342
2343 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002344 }
2345}