blob: 87b79ef9dbef9ce58c4fe42743f6d3f5394d52d2 [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,
53 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 Fietkau2d3bcba2010-11-14 15:20:01 +0100141static u16 ath_frame_seqno(struct sk_buff *skb)
142{
143 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
144 return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
145}
146
Sujithe8324352009-01-16 21:38:42 +0530147static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
148{
Felix Fietkau066dae92010-11-07 14:59:39 +0100149 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530150 struct ath_buf *bf;
151 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200152 struct ath_tx_status ts;
153
Sujithe8324352009-01-16 21:38:42 +0530154 INIT_LIST_HEAD(&bf_head);
155
Felix Fietkau90fa5392010-09-20 13:45:38 +0200156 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530157 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530158
159 while (!list_empty(&tid->buf_q)) {
160 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530161 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200162
163 if (bf_isretried(bf)) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100164 ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200165 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
166 } else {
Felix Fietkau82b873a2010-11-11 03:18:37 +0100167 ath_tx_send_normal(sc, txq, tid, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200168 }
Sujithe8324352009-01-16 21:38:42 +0530169 }
170
171 spin_unlock_bh(&txq->axq_lock);
172}
173
174static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
175 int seqno)
176{
177 int index, cindex;
178
179 index = ATH_BA_INDEX(tid->seq_start, seqno);
180 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
181
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200182 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530183
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200184 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530185 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
186 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
187 }
188}
189
190static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100191 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530192{
193 int index, cindex;
194
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100195 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530196 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200197 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530198
199 if (index >= ((tid->baw_tail - tid->baw_head) &
200 (ATH_TID_MAX_BUFS - 1))) {
201 tid->baw_tail = cindex;
202 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
203 }
204}
205
206/*
207 * TODO: For frame(s) that are in the retry state, we will reuse the
208 * sequence number(s) without setting the retry bit. The
209 * alternative is to give up on these and BAR the receiver's window
210 * forward.
211 */
212static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
213 struct ath_atx_tid *tid)
214
215{
216 struct ath_buf *bf;
217 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700218 struct ath_tx_status ts;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100219 u16 bf_seqno;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700220
221 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530222 INIT_LIST_HEAD(&bf_head);
223
224 for (;;) {
225 if (list_empty(&tid->buf_q))
226 break;
Sujithe8324352009-01-16 21:38:42 +0530227
Sujithd43f30152009-01-16 21:38:53 +0530228 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
229 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530230
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100231 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530232 if (bf_isretried(bf))
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100233 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530234
235 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700236 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530237 spin_lock(&txq->axq_lock);
238 }
239
240 tid->seq_next = tid->seq_start;
241 tid->baw_tail = tid->baw_head;
242}
243
Sujithfec247c2009-07-27 12:08:16 +0530244static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
245 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530246{
247 struct sk_buff *skb;
248 struct ieee80211_hdr *hdr;
249
250 bf->bf_state.bf_type |= BUF_RETRY;
251 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530252 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530253
254 skb = bf->bf_mpdu;
255 hdr = (struct ieee80211_hdr *)skb->data;
256 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
257}
258
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200259static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
260{
261 struct ath_buf *bf = NULL;
262
263 spin_lock_bh(&sc->tx.txbuflock);
264
265 if (unlikely(list_empty(&sc->tx.txbuf))) {
266 spin_unlock_bh(&sc->tx.txbuflock);
267 return NULL;
268 }
269
270 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
271 list_del(&bf->list);
272
273 spin_unlock_bh(&sc->tx.txbuflock);
274
275 return bf;
276}
277
278static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
279{
280 spin_lock_bh(&sc->tx.txbuflock);
281 list_add_tail(&bf->list, &sc->tx.txbuf);
282 spin_unlock_bh(&sc->tx.txbuflock);
283}
284
Sujithd43f30152009-01-16 21:38:53 +0530285static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
286{
287 struct ath_buf *tbf;
288
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200289 tbf = ath_tx_get_buffer(sc);
290 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530291 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530292
293 ATH_TXBUF_RESET(tbf);
294
Felix Fietkau827e69b2009-11-15 23:09:25 +0100295 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530296 tbf->bf_mpdu = bf->bf_mpdu;
297 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400298 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530299 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530300
301 return tbf;
302}
303
Felix Fietkaub572d032010-11-14 15:20:07 +0100304static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
305 struct ath_tx_status *ts, int txok,
306 int *nframes, int *nbad)
307{
308 u16 seq_st = 0;
309 u32 ba[WME_BA_BMP_SIZE >> 5];
310 int ba_index;
311 int isaggr = 0;
312
313 *nbad = 0;
314 *nframes = 0;
315
316 if (bf->bf_lastbf->bf_tx_aborted)
317 return;
318
319 isaggr = bf_isaggr(bf);
320 if (isaggr) {
321 seq_st = ts->ts_seqnum;
322 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
323 }
324
325 while (bf) {
326 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
327
328 (*nframes)++;
329 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
330 (*nbad)++;
331
332 bf = bf->bf_next;
333 }
334}
335
336
Sujithd43f30152009-01-16 21:38:53 +0530337static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
338 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700339 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530340{
341 struct ath_node *an = NULL;
342 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530343 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800344 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530345 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800346 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530347 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530348 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530349 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530350 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530351 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530352 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
353 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200354 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100355 u16 bf_seqno;
Björn Smedmanebd02282010-10-10 22:44:39 +0200356 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100357 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530358
Sujitha22be222009-03-30 15:28:36 +0530359 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530360 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530361
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800362 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100363 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800364
Felix Fietkau78c46532010-06-25 01:26:16 +0200365 memcpy(rates, tx_info->control.rates, sizeof(rates));
366
Sujith1286ec62009-01-27 13:30:37 +0530367 rcu_read_lock();
368
Ben Greear686b9cb2010-09-23 09:44:36 -0700369 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530370 if (!sta) {
371 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200372
Felix Fietkau31e79a52010-07-12 23:16:34 +0200373 INIT_LIST_HEAD(&bf_head);
374 while (bf) {
375 bf_next = bf->bf_next;
376
377 bf->bf_state.bf_type |= BUF_XRETRY;
378 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
379 !bf->bf_stale || bf_next != NULL)
380 list_move_tail(&bf->list, &bf_head);
381
Felix Fietkaub572d032010-11-14 15:20:07 +0100382 ath_tx_rc_status(bf, ts, 1, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200383 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
384 0, 0);
385
386 bf = bf_next;
387 }
Sujith1286ec62009-01-27 13:30:37 +0530388 return;
Sujithe8324352009-01-16 21:38:42 +0530389 }
390
Sujith1286ec62009-01-27 13:30:37 +0530391 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100392 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
393 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530394
Felix Fietkaub11b1602010-07-11 12:48:44 +0200395 /*
396 * The hardware occasionally sends a tx status for the wrong TID.
397 * In this case, the BA status cannot be considered valid and all
398 * subframes need to be retransmitted
399 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100400 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200401 txok = false;
402
Sujithe8324352009-01-16 21:38:42 +0530403 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530404 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530405
Sujithd43f30152009-01-16 21:38:53 +0530406 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700407 if (ts->ts_flags & ATH9K_TX_BA) {
408 seq_st = ts->ts_seqnum;
409 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530410 } else {
Sujithd43f30152009-01-16 21:38:53 +0530411 /*
412 * AR5416 can become deaf/mute when BA
413 * issue happens. Chip needs to be reset.
414 * But AP code may have sychronization issues
415 * when perform internal reset in this routine.
416 * Only enable reset in STA mode for now.
417 */
Sujith2660b812009-02-09 13:27:26 +0530418 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530419 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530420 }
421 }
422
423 INIT_LIST_HEAD(&bf_pending);
424 INIT_LIST_HEAD(&bf_head);
425
Felix Fietkaub572d032010-11-14 15:20:07 +0100426 ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
Sujithe8324352009-01-16 21:38:42 +0530427 while (bf) {
428 txfail = txpending = 0;
429 bf_next = bf->bf_next;
430
Felix Fietkau78c46532010-06-25 01:26:16 +0200431 skb = bf->bf_mpdu;
432 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100433 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200434
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100435 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530436 /* transmit completion, subframe is
437 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530438 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530439 } else if (!isaggr && txok) {
440 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530441 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530442 } else {
Sujithe8324352009-01-16 21:38:42 +0530443 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400444 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530445 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530446 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530447 txpending = 1;
448 } else {
449 bf->bf_state.bf_type |= BUF_XRETRY;
450 txfail = 1;
451 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530452 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530453 }
454 } else {
455 /*
456 * cleanup in progress, just fail
457 * the un-acked sub-frames
458 */
459 txfail = 1;
460 }
461 }
462
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400463 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
464 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530465 /*
466 * Make sure the last desc is reclaimed if it
467 * not a holding desc.
468 */
469 if (!bf_last->bf_stale)
470 list_move_tail(&bf->list, &bf_head);
471 else
472 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530473 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700474 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530475 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530476 }
477
Felix Fietkau90fa5392010-09-20 13:45:38 +0200478 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530479 /*
480 * complete the acked-ones/xretried ones; update
481 * block-ack window
482 */
483 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100484 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530485 spin_unlock_bh(&txq->axq_lock);
486
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530487 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200488 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaub572d032010-11-14 15:20:07 +0100489 ath_tx_rc_status(bf, ts, nframes, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530490 rc_update = false;
491 } else {
Felix Fietkaub572d032010-11-14 15:20:07 +0100492 ath_tx_rc_status(bf, ts, nframes, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530493 }
494
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700495 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
496 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530497 } else {
Sujithd43f30152009-01-16 21:38:53 +0530498 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400499 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
500 if (bf->bf_next == NULL && bf_last->bf_stale) {
501 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530502
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400503 tbf = ath_clone_txbuf(sc, bf_last);
504 /*
505 * Update tx baw and complete the
506 * frame with failed status if we
507 * run out of tx buf.
508 */
509 if (!tbf) {
510 spin_lock_bh(&txq->axq_lock);
511 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100512 bf_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;
Sujithe8324352009-01-16 21:38:42 +0530652
653 /* Select standard number of delimiters based on frame length alone */
654 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
655
656 /*
657 * If encryption enabled, hardware requires some more padding between
658 * subframes.
659 * TODO - this could be improved to be dependent on the rate.
660 * The hardware can keep up at lower rates, but not higher rates
661 */
Felix Fietkau952cd692010-11-14 15:20:03 +0100662 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +0530663 ndelim += ATH_AGGR_ENCRYPTDELIM;
664
665 /*
666 * Convert desired mpdu density from microeconds to bytes based
667 * on highest rate in rate series (i.e. first rate) to determine
668 * required minimum length for subframe. Take into account
669 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530670 *
Sujithe8324352009-01-16 21:38:42 +0530671 * If there is no mpdu density restriction, no further calculation
672 * is needed.
673 */
Sujith4ef70842009-07-23 15:32:41 +0530674
675 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530676 return ndelim;
677
678 rix = tx_info->control.rates[0].idx;
679 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530680 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
681 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
682
683 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530684 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530685 else
Sujith4ef70842009-07-23 15:32:41 +0530686 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530687
688 if (nsymbols == 0)
689 nsymbols = 1;
690
Felix Fietkauc6663872010-04-19 19:57:33 +0200691 streams = HT_RC_2_STREAMS(rix);
692 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530693 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
694
Sujithe8324352009-01-16 21:38:42 +0530695 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530696 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
697 ndelim = max(mindelim, ndelim);
698 }
699
700 return ndelim;
701}
702
703static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530704 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530705 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100706 struct list_head *bf_q,
707 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530708{
709#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530710 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
711 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530712 u16 aggr_limit = 0, al = 0, bpad = 0,
713 al_delta, h_baw = tid->baw_size / 2;
714 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200715 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100716 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530717
718 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
719
720 do {
721 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100722 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530723
Sujithd43f30152009-01-16 21:38:53 +0530724 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100725 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530726 status = ATH_AGGR_BAW_CLOSED;
727 break;
728 }
729
730 if (!rl) {
731 aggr_limit = ath_lookup_rate(sc, bf, tid);
732 rl = 1;
733 }
734
Sujithd43f30152009-01-16 21:38:53 +0530735 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530736 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
737
Sujithd43f30152009-01-16 21:38:53 +0530738 if (nframes &&
739 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530740 status = ATH_AGGR_LIMITED;
741 break;
742 }
743
Felix Fietkau0299a502010-10-21 02:47:24 +0200744 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
745 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
746 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
747 break;
748
Sujithd43f30152009-01-16 21:38:53 +0530749 /* do not exceed subframe limit */
750 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530751 status = ATH_AGGR_LIMITED;
752 break;
753 }
Sujithd43f30152009-01-16 21:38:53 +0530754 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530755
Sujithd43f30152009-01-16 21:38:53 +0530756 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530757 al += bpad + al_delta;
758
759 /*
760 * Get the delimiters needed to meet the MPDU
761 * density for this node.
762 */
763 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530764 bpad = PADBYTES(al_delta) + (ndelim << 2);
765
766 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400767 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530768
Sujithd43f30152009-01-16 21:38:53 +0530769 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100770 if (!bf_isretried(bf))
771 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530772 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
773 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530774 if (bf_prev) {
775 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400776 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
777 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530778 }
779 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530780
Sujithe8324352009-01-16 21:38:42 +0530781 } while (!list_empty(&tid->buf_q));
782
Felix Fietkau269c44b2010-11-14 15:20:06 +0100783 *aggr_len = al;
Sujithd43f30152009-01-16 21:38:53 +0530784
Sujithe8324352009-01-16 21:38:42 +0530785 return status;
786#undef PADBYTES
787}
788
789static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
790 struct ath_atx_tid *tid)
791{
Sujithd43f30152009-01-16 21:38:53 +0530792 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530793 enum ATH_AGGR_STATUS status;
794 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100795 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530796
797 do {
798 if (list_empty(&tid->buf_q))
799 return;
800
801 INIT_LIST_HEAD(&bf_q);
802
Felix Fietkau269c44b2010-11-14 15:20:06 +0100803 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530804
805 /*
Sujithd43f30152009-01-16 21:38:53 +0530806 * no frames picked up to be aggregated;
807 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530808 */
809 if (list_empty(&bf_q))
810 break;
811
812 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530813 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530814
Sujithd43f30152009-01-16 21:38:53 +0530815 /* if only one frame, send as non-aggregate */
Felix Fietkaub572d032010-11-14 15:20:07 +0100816 if (bf == bf->bf_lastbf) {
Sujithe8324352009-01-16 21:38:42 +0530817 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530818 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau269c44b2010-11-14 15:20:06 +0100819 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530820 ath_tx_txqaddbuf(sc, txq, &bf_q);
821 continue;
822 }
823
Sujithd43f30152009-01-16 21:38:53 +0530824 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530825 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100826 ath_buf_set_rate(sc, bf, aggr_len);
827 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530828
Sujithd43f30152009-01-16 21:38:53 +0530829 /* anchor last desc of aggregate */
830 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530831
Sujithe8324352009-01-16 21:38:42 +0530832 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530833 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530834
835 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
836 status != ATH_AGGR_BAW_CLOSED);
837}
838
Felix Fietkau231c3a12010-09-20 19:35:28 +0200839int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
840 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530841{
842 struct ath_atx_tid *txtid;
843 struct ath_node *an;
844
845 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530846 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200847
848 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
849 return -EAGAIN;
850
Sujithf83da962009-07-23 15:32:37 +0530851 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200852 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530853 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200854
855 return 0;
Sujithe8324352009-01-16 21:38:42 +0530856}
857
Sujithf83da962009-07-23 15:32:37 +0530858void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530859{
860 struct ath_node *an = (struct ath_node *)sta->drv_priv;
861 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100862 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530863
864 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530865 return;
Sujithe8324352009-01-16 21:38:42 +0530866
867 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530868 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530869 return;
Sujithe8324352009-01-16 21:38:42 +0530870 }
871
Sujithe8324352009-01-16 21:38:42 +0530872 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200873 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200874
875 /*
876 * If frames are still being transmitted for this TID, they will be
877 * cleaned up during tx completion. To prevent race conditions, this
878 * TID can only be reused after all in-progress subframes have been
879 * completed.
880 */
881 if (txtid->baw_head != txtid->baw_tail)
882 txtid->state |= AGGR_CLEANUP;
883 else
884 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530885 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530886
Felix Fietkau90fa5392010-09-20 13:45:38 +0200887 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530888}
889
890void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
891{
892 struct ath_atx_tid *txtid;
893 struct ath_node *an;
894
895 an = (struct ath_node *)sta->drv_priv;
896
897 if (sc->sc_flags & SC_OP_TXAGGR) {
898 txtid = ATH_AN_2_TID(an, tid);
899 txtid->baw_size =
900 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
901 txtid->state |= AGGR_ADDBA_COMPLETE;
902 txtid->state &= ~AGGR_ADDBA_PROGRESS;
903 ath_tx_resume_tid(sc, txtid);
904 }
905}
906
Sujithe8324352009-01-16 21:38:42 +0530907/********************/
908/* Queue Management */
909/********************/
910
Sujithe8324352009-01-16 21:38:42 +0530911static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
912 struct ath_txq *txq)
913{
914 struct ath_atx_ac *ac, *ac_tmp;
915 struct ath_atx_tid *tid, *tid_tmp;
916
917 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
918 list_del(&ac->list);
919 ac->sched = false;
920 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
921 list_del(&tid->list);
922 tid->sched = false;
923 ath_tid_drain(sc, txq, tid);
924 }
925 }
926}
927
928struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
929{
Sujithcbe61d82009-02-09 13:27:12 +0530930 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700931 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530932 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100933 static const int subtype_txq_to_hwq[] = {
934 [WME_AC_BE] = ATH_TXQ_AC_BE,
935 [WME_AC_BK] = ATH_TXQ_AC_BK,
936 [WME_AC_VI] = ATH_TXQ_AC_VI,
937 [WME_AC_VO] = ATH_TXQ_AC_VO,
938 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400939 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530940
941 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100942 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530943 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
944 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
945 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
946 qi.tqi_physCompBuf = 0;
947
948 /*
949 * Enable interrupts only for EOL and DESC conditions.
950 * We mark tx descriptors to receive a DESC interrupt
951 * when a tx queue gets deep; otherwise waiting for the
952 * EOL to reap descriptors. Note that this is done to
953 * reduce interrupt load and this only defers reaping
954 * descriptors, never transmitting frames. Aside from
955 * reducing interrupts this also permits more concurrency.
956 * The only potential downside is if the tx queue backs
957 * up in which case the top half of the kernel may backup
958 * due to a lack of tx descriptors.
959 *
960 * The UAPSD queue is an exception, since we take a desc-
961 * based intr on the EOSP frames.
962 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400963 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
964 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
965 TXQ_FLAG_TXERRINT_ENABLE;
966 } else {
967 if (qtype == ATH9K_TX_QUEUE_UAPSD)
968 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
969 else
970 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
971 TXQ_FLAG_TXDESCINT_ENABLE;
972 }
Sujithe8324352009-01-16 21:38:42 +0530973 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
974 if (qnum == -1) {
975 /*
976 * NB: don't print a message, this happens
977 * normally on parts with too few tx queues
978 */
979 return NULL;
980 }
981 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700982 ath_print(common, ATH_DBG_FATAL,
983 "qnum %u out of range, max %u!\n",
984 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530985 ath9k_hw_releasetxqueue(ah, qnum);
986 return NULL;
987 }
988 if (!ATH_TXQ_SETUP(sc, qnum)) {
989 struct ath_txq *txq = &sc->tx.txq[qnum];
990
991 txq->axq_qnum = qnum;
992 txq->axq_link = NULL;
993 INIT_LIST_HEAD(&txq->axq_q);
994 INIT_LIST_HEAD(&txq->axq_acq);
995 spin_lock_init(&txq->axq_lock);
996 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400997 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530998 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400999
1000 txq->txq_headidx = txq->txq_tailidx = 0;
1001 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
1002 INIT_LIST_HEAD(&txq->txq_fifo[i]);
1003 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +05301004 }
1005 return &sc->tx.txq[qnum];
1006}
1007
Sujithe8324352009-01-16 21:38:42 +05301008int ath_txq_update(struct ath_softc *sc, int qnum,
1009 struct ath9k_tx_queue_info *qinfo)
1010{
Sujithcbe61d82009-02-09 13:27:12 +05301011 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301012 int error = 0;
1013 struct ath9k_tx_queue_info qi;
1014
1015 if (qnum == sc->beacon.beaconq) {
1016 /*
1017 * XXX: for beacon queue, we just save the parameter.
1018 * It will be picked up by ath_beaconq_config when
1019 * it's necessary.
1020 */
1021 sc->beacon.beacon_qi = *qinfo;
1022 return 0;
1023 }
1024
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001025 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301026
1027 ath9k_hw_get_txq_props(ah, qnum, &qi);
1028 qi.tqi_aifs = qinfo->tqi_aifs;
1029 qi.tqi_cwmin = qinfo->tqi_cwmin;
1030 qi.tqi_cwmax = qinfo->tqi_cwmax;
1031 qi.tqi_burstTime = qinfo->tqi_burstTime;
1032 qi.tqi_readyTime = qinfo->tqi_readyTime;
1033
1034 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001035 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1036 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301037 error = -EIO;
1038 } else {
1039 ath9k_hw_resettxqueue(ah, qnum);
1040 }
1041
1042 return error;
1043}
1044
1045int ath_cabq_update(struct ath_softc *sc)
1046{
1047 struct ath9k_tx_queue_info qi;
1048 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301049
1050 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1051 /*
1052 * Ensure the readytime % is within the bounds.
1053 */
Sujith17d79042009-02-09 13:27:03 +05301054 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1055 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1056 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1057 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301058
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001059 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301060 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301061 ath_txq_update(sc, qnum, &qi);
1062
1063 return 0;
1064}
1065
Sujith043a0402009-01-16 21:38:47 +05301066/*
1067 * Drain a given TX queue (could be Beacon or Data)
1068 *
1069 * This assumes output has been stopped and
1070 * we do not need to block ath_tx_tasklet.
1071 */
1072void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301073{
1074 struct ath_buf *bf, *lastbf;
1075 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001076 struct ath_tx_status ts;
1077
1078 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301079 INIT_LIST_HEAD(&bf_head);
1080
Sujithe8324352009-01-16 21:38:42 +05301081 for (;;) {
1082 spin_lock_bh(&txq->axq_lock);
1083
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001084 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1085 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1086 txq->txq_headidx = txq->txq_tailidx = 0;
1087 spin_unlock_bh(&txq->axq_lock);
1088 break;
1089 } else {
1090 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1091 struct ath_buf, list);
1092 }
1093 } else {
1094 if (list_empty(&txq->axq_q)) {
1095 txq->axq_link = NULL;
1096 spin_unlock_bh(&txq->axq_lock);
1097 break;
1098 }
1099 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1100 list);
Sujithe8324352009-01-16 21:38:42 +05301101
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001102 if (bf->bf_stale) {
1103 list_del(&bf->list);
1104 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301105
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001106 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001107 continue;
1108 }
Sujithe8324352009-01-16 21:38:42 +05301109 }
1110
1111 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001112 if (!retry_tx)
1113 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301114
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001115 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1116 list_cut_position(&bf_head,
1117 &txq->txq_fifo[txq->txq_tailidx],
1118 &lastbf->list);
1119 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1120 } else {
1121 /* remove ath_buf's of the same mpdu from txq */
1122 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1123 }
1124
Sujithe8324352009-01-16 21:38:42 +05301125 txq->axq_depth--;
1126
1127 spin_unlock_bh(&txq->axq_lock);
1128
1129 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001130 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301131 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001132 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301133 }
1134
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001135 spin_lock_bh(&txq->axq_lock);
1136 txq->axq_tx_inprogress = false;
1137 spin_unlock_bh(&txq->axq_lock);
1138
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001139 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1140 spin_lock_bh(&txq->axq_lock);
1141 while (!list_empty(&txq->txq_fifo_pending)) {
1142 bf = list_first_entry(&txq->txq_fifo_pending,
1143 struct ath_buf, list);
1144 list_cut_position(&bf_head,
1145 &txq->txq_fifo_pending,
1146 &bf->bf_lastbf->list);
1147 spin_unlock_bh(&txq->axq_lock);
1148
1149 if (bf_isampdu(bf))
1150 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1151 &ts, 0);
1152 else
1153 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1154 &ts, 0, 0);
1155 spin_lock_bh(&txq->axq_lock);
1156 }
1157 spin_unlock_bh(&txq->axq_lock);
1158 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001159
1160 /* flush any pending frames if aggregation is enabled */
1161 if (sc->sc_flags & SC_OP_TXAGGR) {
1162 if (!retry_tx) {
1163 spin_lock_bh(&txq->axq_lock);
1164 ath_txq_drain_pending_buffers(sc, txq);
1165 spin_unlock_bh(&txq->axq_lock);
1166 }
1167 }
Sujithe8324352009-01-16 21:38:42 +05301168}
1169
Sujith043a0402009-01-16 21:38:47 +05301170void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1171{
Sujithcbe61d82009-02-09 13:27:12 +05301172 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001173 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301174 struct ath_txq *txq;
1175 int i, npend = 0;
1176
1177 if (sc->sc_flags & SC_OP_INVALID)
1178 return;
1179
1180 /* Stop beacon queue */
1181 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1182
1183 /* Stop data queues */
1184 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1185 if (ATH_TXQ_SETUP(sc, i)) {
1186 txq = &sc->tx.txq[i];
1187 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1188 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1189 }
1190 }
1191
1192 if (npend) {
1193 int r;
1194
Sujithe8009e92009-12-14 14:57:08 +05301195 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001196 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301197
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001198 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301199 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001200 ath_print(common, ATH_DBG_FATAL,
1201 "Unable to reset hardware; reset status %d\n",
1202 r);
Sujith043a0402009-01-16 21:38:47 +05301203 }
1204
1205 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1206 if (ATH_TXQ_SETUP(sc, i))
1207 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1208 }
1209}
1210
Sujithe8324352009-01-16 21:38:42 +05301211void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1212{
1213 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1214 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1215}
1216
Sujithe8324352009-01-16 21:38:42 +05301217void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1218{
1219 struct ath_atx_ac *ac;
1220 struct ath_atx_tid *tid;
1221
1222 if (list_empty(&txq->axq_acq))
1223 return;
1224
1225 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1226 list_del(&ac->list);
1227 ac->sched = false;
1228
1229 do {
1230 if (list_empty(&ac->tid_q))
1231 return;
1232
1233 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1234 list_del(&tid->list);
1235 tid->sched = false;
1236
1237 if (tid->paused)
1238 continue;
1239
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001240 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301241
1242 /*
1243 * add tid to round-robin queue if more frames
1244 * are pending for the tid
1245 */
1246 if (!list_empty(&tid->buf_q))
1247 ath_tx_queue_tid(txq, tid);
1248
1249 break;
1250 } while (!list_empty(&ac->tid_q));
1251
1252 if (!list_empty(&ac->tid_q)) {
1253 if (!ac->sched) {
1254 ac->sched = true;
1255 list_add_tail(&ac->list, &txq->axq_acq);
1256 }
1257 }
1258}
1259
Sujithe8324352009-01-16 21:38:42 +05301260/***********/
1261/* TX, DMA */
1262/***********/
1263
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001264/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001265 * Insert a chain of ath_buf (descriptors) on a txq and
1266 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001267 */
Sujith102e0572008-10-29 10:15:16 +05301268static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1269 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001270{
Sujithcbe61d82009-02-09 13:27:12 +05301271 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001272 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301274
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001275 /*
1276 * Insert the frame on the outbound list and
1277 * pass it on to the hardware.
1278 */
1279
1280 if (list_empty(head))
1281 return;
1282
1283 bf = list_first_entry(head, struct ath_buf, list);
1284
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001285 ath_print(common, ATH_DBG_QUEUE,
1286 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001287
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001288 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1289 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1290 list_splice_tail_init(head, &txq->txq_fifo_pending);
1291 return;
1292 }
1293 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1294 ath_print(common, ATH_DBG_XMIT,
1295 "Initializing tx fifo %d which "
1296 "is non-empty\n",
1297 txq->txq_headidx);
1298 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1299 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1300 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001301 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001302 ath_print(common, ATH_DBG_XMIT,
1303 "TXDP[%u] = %llx (%p)\n",
1304 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001305 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001306 list_splice_tail_init(head, &txq->axq_q);
1307
1308 if (txq->axq_link == NULL) {
1309 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1310 ath_print(common, ATH_DBG_XMIT,
1311 "TXDP[%u] = %llx (%p)\n",
1312 txq->axq_qnum, ito64(bf->bf_daddr),
1313 bf->bf_desc);
1314 } else {
1315 *txq->axq_link = bf->bf_daddr;
1316 ath_print(common, ATH_DBG_XMIT,
1317 "link[%u] (%p)=%llx (%p)\n",
1318 txq->axq_qnum, txq->axq_link,
1319 ito64(bf->bf_daddr), bf->bf_desc);
1320 }
1321 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1322 &txq->axq_link);
1323 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001324 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001325 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001326}
1327
Sujithe8324352009-01-16 21:38:42 +05301328static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1329 struct list_head *bf_head,
1330 struct ath_tx_control *txctl)
1331{
1332 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001333 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301334
Sujithe8324352009-01-16 21:38:42 +05301335 bf = list_first_entry(bf_head, struct ath_buf, list);
1336 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301337 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001338 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
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 Fietkau2d3bcba2010-11-14 15:20:01 +01001348 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_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 */
Sujithd43f30152009-01-16 21:38:53 +05301354 list_move_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
Sujithe8324352009-01-16 21:38:42 +05301359 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001360 if (!bf_isretried(bf))
1361 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301362
1363 /* Queue to h/w without aggregation */
Sujithd43f30152009-01-16 21:38:53 +05301364 bf->bf_lastbf = bf;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001365 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +05301366 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301367}
1368
Felix Fietkau82b873a2010-11-11 03:18:37 +01001369static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1370 struct ath_atx_tid *tid,
1371 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001372{
Sujithe8324352009-01-16 21:38:42 +05301373 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001374
Sujithe8324352009-01-16 21:38:42 +05301375 bf = list_first_entry(bf_head, struct ath_buf, list);
1376 bf->bf_state.bf_type &= ~BUF_AMPDU;
1377
1378 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001379 if (tid)
1380 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301381
Sujithd43f30152009-01-16 21:38:53 +05301382 bf->bf_lastbf = bf;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001383 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +05301384 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301385 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001386}
1387
Sujith528f0c62008-10-29 10:14:26 +05301388static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001389{
Sujith528f0c62008-10-29 10:14:26 +05301390 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001391 enum ath9k_pkt_type htype;
1392 __le16 fc;
1393
Sujith528f0c62008-10-29 10:14:26 +05301394 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001395 fc = hdr->frame_control;
1396
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001397 if (ieee80211_is_beacon(fc))
1398 htype = ATH9K_PKT_TYPE_BEACON;
1399 else if (ieee80211_is_probe_resp(fc))
1400 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1401 else if (ieee80211_is_atim(fc))
1402 htype = ATH9K_PKT_TYPE_ATIM;
1403 else if (ieee80211_is_pspoll(fc))
1404 htype = ATH9K_PKT_TYPE_PSPOLL;
1405 else
1406 htype = ATH9K_PKT_TYPE_NORMAL;
1407
1408 return htype;
1409}
1410
Sujith528f0c62008-10-29 10:14:26 +05301411static void assign_aggr_tid_seqno(struct sk_buff *skb,
1412 struct ath_buf *bf)
1413{
1414 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1415 struct ieee80211_hdr *hdr;
1416 struct ath_node *an;
1417 struct ath_atx_tid *tid;
1418 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001419 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301420
1421 if (!tx_info->control.sta)
1422 return;
1423
1424 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1425 hdr = (struct ieee80211_hdr *)skb->data;
1426 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001427 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001428
Sujithe8324352009-01-16 21:38:42 +05301429 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001430 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301431 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301432 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001433 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301434 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301435 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301436}
1437
Felix Fietkau82b873a2010-11-11 03:18:37 +01001438static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301439{
1440 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1441 int flags = 0;
1442
1443 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1444 flags |= ATH9K_TXDESC_INTREQ;
1445
1446 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1447 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301448
Felix Fietkau82b873a2010-11-11 03:18:37 +01001449 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001450 flags |= ATH9K_TXDESC_LDPC;
1451
Sujith528f0c62008-10-29 10:14:26 +05301452 return flags;
1453}
1454
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001455/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456 * rix - rate index
1457 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1458 * width - 0 for 20 MHz, 1 for 40 MHz
1459 * half_gi - to use 4us v/s 3.6 us for symbol time
1460 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001461static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301462 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001463{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001465 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301466
1467 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001468 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001469 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001470 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001471 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1472
1473 if (!half_gi)
1474 duration = SYMBOL_TIME(nsymbols);
1475 else
1476 duration = SYMBOL_TIME_HALFGI(nsymbols);
1477
Sujithe63835b2008-11-18 09:07:53 +05301478 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001479 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301480
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001481 return duration;
1482}
1483
Felix Fietkau269c44b2010-11-14 15:20:06 +01001484static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001485{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001486 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301488 struct sk_buff *skb;
1489 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301490 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001491 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301492 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301493 int i, flags = 0;
1494 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301495 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301496
1497 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301498
Sujitha22be222009-03-30 15:28:36 +05301499 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301500 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301501 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301502 hdr = (struct ieee80211_hdr *)skb->data;
1503 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301504
Sujithc89424d2009-01-30 14:29:28 +05301505 /*
1506 * We check if Short Preamble is needed for the CTS rate by
1507 * checking the BSS's global flag.
1508 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1509 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001510 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1511 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301512 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001513 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001514
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001515 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001516 bool is_40, is_sgi, is_sp;
1517 int phy;
1518
Sujithe63835b2008-11-18 09:07:53 +05301519 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001520 continue;
1521
Sujitha8efee42008-11-18 09:07:30 +05301522 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301523 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001524 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001525
Felix Fietkau27032052010-01-17 21:08:50 +01001526 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1527 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301528 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001529 flags |= ATH9K_TXDESC_RTSENA;
1530 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1531 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1532 flags |= ATH9K_TXDESC_CTSENA;
1533 }
1534
Sujithc89424d2009-01-30 14:29:28 +05301535 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1536 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1537 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1538 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001539
Felix Fietkau545750d2009-11-23 22:21:01 +01001540 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1541 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1542 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1543
1544 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1545 /* MCS rates */
1546 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001547 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001548 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001549 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1550 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001551 continue;
1552 }
1553
1554 /* legcay rates */
1555 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1556 !(rate->flags & IEEE80211_RATE_ERP_G))
1557 phy = WLAN_RC_PHY_CCK;
1558 else
1559 phy = WLAN_RC_PHY_OFDM;
1560
1561 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1562 series[i].Rate = rate->hw_value;
1563 if (rate->hw_value_short) {
1564 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1565 series[i].Rate |= rate->hw_value_short;
1566 } else {
1567 is_sp = false;
1568 }
1569
1570 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001571 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001572 }
1573
Felix Fietkau27032052010-01-17 21:08:50 +01001574 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001575 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001576 flags &= ~ATH9K_TXDESC_RTSENA;
1577
1578 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1579 if (flags & ATH9K_TXDESC_RTSENA)
1580 flags &= ~ATH9K_TXDESC_CTSENA;
1581
Sujithe63835b2008-11-18 09:07:53 +05301582 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301583 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1584 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301585 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301586 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301587
Sujith17d79042009-02-09 13:27:03 +05301588 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301589 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001590}
1591
Felix Fietkau82b873a2010-11-11 03:18:37 +01001592static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1593 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301594{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001595 struct ath_wiphy *aphy = hw->priv;
1596 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001597 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301598 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1599 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001600 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301601 int hdrlen;
1602 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001603 int padpos, padsize;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001604
1605 bf = ath_tx_get_buffer(sc);
1606 if (!bf) {
1607 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1608 return NULL;
1609 }
Sujithe8324352009-01-16 21:38:42 +05301610
Sujithe8324352009-01-16 21:38:42 +05301611 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1612 fc = hdr->frame_control;
1613
1614 ATH_TXBUF_RESET(bf);
1615
Felix Fietkau827e69b2009-11-15 23:09:25 +01001616 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001617 bf->bf_frmlen = skb->len + FCS_LEN;
1618 /* Remove the padding size from bf_frmlen, if any */
1619 padpos = ath9k_cmn_padpos(hdr->frame_control);
1620 padsize = padpos & 3;
1621 if (padsize && skb->len>padpos+padsize) {
1622 bf->bf_frmlen -= padsize;
1623 }
Sujithe8324352009-01-16 21:38:42 +05301624
Felix Fietkau82b873a2010-11-11 03:18:37 +01001625 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301626 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001627 if (sc->sc_flags & SC_OP_TXAGGR)
1628 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001629 }
Sujithe8324352009-01-16 21:38:42 +05301630
Felix Fietkau82b873a2010-11-11 03:18:37 +01001631 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301632
Felix Fietkau30170472010-11-14 15:20:05 +01001633 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +05301634 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
Sujithe8324352009-01-16 21:38:42 +05301635
Sujithe8324352009-01-16 21:38:42 +05301636 bf->bf_mpdu = skb;
1637
Ben Greearc1739eb32010-10-14 12:45:29 -07001638 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1639 skb->len, DMA_TO_DEVICE);
1640 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301641 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001642 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001643 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1644 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001645 ath_tx_return_buffer(sc, bf);
1646 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301647 }
1648
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001649 bf->bf_tx_aborted = false;
1650
Felix Fietkau82b873a2010-11-11 03:18:37 +01001651 return bf;
Sujithe8324352009-01-16 21:38:42 +05301652}
1653
1654/* FIXME: tx power */
1655static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1656 struct ath_tx_control *txctl)
1657{
Sujitha22be222009-03-30 15:28:36 +05301658 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301659 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301660 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301661 struct ath_node *an = NULL;
1662 struct list_head bf_head;
1663 struct ath_desc *ds;
1664 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301665 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001666 enum ath9k_key_type keytype;
Felix Fietkau30170472010-11-14 15:20:05 +01001667 u32 keyix;
Sujithe8324352009-01-16 21:38:42 +05301668 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301669 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001670 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301671
1672 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301673 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301674
1675 INIT_LIST_HEAD(&bf_head);
1676 list_add_tail(&bf->list, &bf_head);
1677
1678 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001679 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301680
Felix Fietkau952cd692010-11-14 15:20:03 +01001681 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001682 if (tx_info->control.hw_key)
1683 keyix = tx_info->control.hw_key->hw_key_idx;
1684 else
1685 keyix = ATH9K_TXKEYIX_INVALID;
1686
Sujithe8324352009-01-16 21:38:42 +05301687 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001688 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301689
1690 ath9k_hw_filltxdesc(ah, ds,
1691 skb->len, /* segment length */
1692 true, /* first segment */
1693 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001694 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001695 bf->bf_buf_addr,
1696 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301697
Sujithe8324352009-01-16 21:38:42 +05301698 spin_lock_bh(&txctl->txq->axq_lock);
1699
1700 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1701 tx_info->control.sta) {
1702 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001703 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1704 IEEE80211_QOS_CTL_TID_MASK;
1705 tid = ATH_AN_2_TID(an, tidno);
1706
Sujithe8324352009-01-16 21:38:42 +05301707
Felix Fietkau066dae92010-11-07 14:59:39 +01001708 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001709 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301710 /*
1711 * Try aggregation if it's a unicast data frame
1712 * and the destination is HT capable.
1713 */
1714 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1715 } else {
1716 /*
1717 * Send this frame as regular when ADDBA
1718 * exchange is neither complete nor pending.
1719 */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001720 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301721 }
1722 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001723 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001724 bf->bf_state.bfs_paprd = txctl->paprd;
1725
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001726 if (bf->bf_state.bfs_paprd)
1727 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1728
Felix Fietkau82b873a2010-11-11 03:18:37 +01001729 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301730 }
1731
1732 spin_unlock_bh(&txctl->txq->axq_lock);
1733}
1734
1735/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001736int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301737 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001738{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001739 struct ath_wiphy *aphy = hw->priv;
1740 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001741 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001742 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001743 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744
Felix Fietkau82b873a2010-11-11 03:18:37 +01001745 bf = ath_tx_setup_buffer(hw, skb);
1746 if (unlikely(!bf))
1747 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748
Felix Fietkau066dae92010-11-07 14:59:39 +01001749 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001750 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001751 if (txq == sc->tx.txq_map[q] &&
1752 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1753 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001754 txq->stopped = 1;
1755 }
1756 spin_unlock_bh(&txq->axq_lock);
1757
Sujithe8324352009-01-16 21:38:42 +05301758 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001759
1760 return 0;
1761}
1762
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001763void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001764{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001765 struct ath_wiphy *aphy = hw->priv;
1766 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001767 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001768 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1769 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301770 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1771 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001772
Sujithe8324352009-01-16 21:38:42 +05301773 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001774
Sujithe8324352009-01-16 21:38:42 +05301775 /*
1776 * As a temporary workaround, assign seq# here; this will likely need
1777 * to be cleaned up to work better with Beacon transmission and virtual
1778 * BSSes.
1779 */
1780 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301781 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1782 sc->tx.seq_no += 0x10;
1783 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1784 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001785 }
1786
Sujithe8324352009-01-16 21:38:42 +05301787 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001788 padpos = ath9k_cmn_padpos(hdr->frame_control);
1789 padsize = padpos & 3;
1790 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301791 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001792 ath_print(common, ATH_DBG_XMIT,
1793 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301794 dev_kfree_skb_any(skb);
1795 return;
1796 }
1797 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001798 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001799 }
1800
Sujithe8324352009-01-16 21:38:42 +05301801 txctl.txq = sc->beacon.cabq;
1802
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001803 ath_print(common, ATH_DBG_XMIT,
1804 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301805
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001806 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001807 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301808 goto exit;
1809 }
1810
1811 return;
1812exit:
1813 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001814}
1815
Sujithe8324352009-01-16 21:38:42 +05301816/*****************/
1817/* TX Completion */
1818/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001819
Sujithe8324352009-01-16 21:38:42 +05301820static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001821 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001822 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001823{
Sujithe8324352009-01-16 21:38:42 +05301824 struct ieee80211_hw *hw = sc->hw;
1825 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001826 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001827 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001828 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301829
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001830 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301831
Felix Fietkau827e69b2009-11-15 23:09:25 +01001832 if (aphy)
1833 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301834
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301835 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301836 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301837
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301838 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301839 /* Frame was ACKed */
1840 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1841 }
1842
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001843 padpos = ath9k_cmn_padpos(hdr->frame_control);
1844 padsize = padpos & 3;
1845 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301846 /*
1847 * Remove MAC header padding before giving the frame back to
1848 * mac80211.
1849 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001850 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301851 skb_pull(skb, padsize);
1852 }
1853
Sujith1b04b932010-01-08 10:36:05 +05301854 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1855 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001856 ath_print(common, ATH_DBG_PS,
1857 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001858 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301859 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1860 PS_WAIT_FOR_CAB |
1861 PS_WAIT_FOR_PSPOLL_DATA |
1862 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001863 }
1864
Felix Fietkau61117f02010-11-11 03:18:36 +01001865 if (unlikely(ftype))
1866 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001867 else {
1868 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001869 if (txq == sc->tx.txq_map[q]) {
1870 spin_lock_bh(&txq->axq_lock);
1871 if (WARN_ON(--txq->pending_frames < 0))
1872 txq->pending_frames = 0;
1873 spin_unlock_bh(&txq->axq_lock);
1874 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001875
Felix Fietkau827e69b2009-11-15 23:09:25 +01001876 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001877 }
Sujithe8324352009-01-16 21:38:42 +05301878}
1879
1880static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001881 struct ath_txq *txq, struct list_head *bf_q,
1882 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301883{
1884 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301885 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301886 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301887
Sujithe8324352009-01-16 21:38:42 +05301888 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301889 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301890
1891 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301892 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301893
1894 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301895 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301896 }
1897
Ben Greearc1739eb32010-10-14 12:45:29 -07001898 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001899 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001900
1901 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001902 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001903 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001904 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001905 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001906 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001907 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001908 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1909 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001910 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001911 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1912 * accidentally reference it later.
1913 */
1914 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301915
1916 /*
1917 * Return the list of ath_buf of this mpdu to free queue
1918 */
1919 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1920 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1921 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1922}
1923
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001924static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Felix Fietkaub572d032010-11-14 15:20:07 +01001925 int nframes, int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301926{
Sujitha22be222009-03-30 15:28:36 +05301927 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301928 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301929 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001930 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001931 struct ath_softc *sc = bf->aphy->sc;
1932 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301933 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301934
Sujith95e4acb2009-03-13 08:56:09 +05301935 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001936 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301937
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001938 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301939 WARN_ON(tx_rateindex >= hw->max_rates);
1940
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001941 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301942 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001943 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001944 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301945
Felix Fietkaub572d032010-11-14 15:20:07 +01001946 BUG_ON(nbad > nframes);
Björn Smedmanebd02282010-10-10 22:44:39 +02001947
Felix Fietkaub572d032010-11-14 15:20:07 +01001948 tx_info->status.ampdu_len = nframes;
1949 tx_info->status.ampdu_ack_len = nframes - nbad;
Björn Smedmanebd02282010-10-10 22:44:39 +02001950 }
1951
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001952 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301953 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001954 /*
1955 * If an underrun error is seen assume it as an excessive
1956 * retry only if max frame trigger level has been reached
1957 * (2 KB for single stream, and 4 KB for dual stream).
1958 * Adjust the long retry as if the frame was tried
1959 * hw->max_rate_tries times to affect how rate control updates
1960 * PER for the failed rate.
1961 * In case of congestion on the bus penalizing this type of
1962 * underruns should help hardware actually transmit new frames
1963 * successfully by eventually preferring slower rates.
1964 * This itself should also alleviate congestion on the bus.
1965 */
1966 if (ieee80211_is_data(hdr->frame_control) &&
1967 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1968 ATH9K_TX_DELIM_UNDERRUN)) &&
1969 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1970 tx_info->status.rates[tx_rateindex].count =
1971 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301972 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301973
Felix Fietkau545750d2009-11-23 22:21:01 +01001974 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301975 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001976 tx_info->status.rates[i].idx = -1;
1977 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301978
Felix Fietkau78c46532010-06-25 01:26:16 +02001979 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301980}
1981
Felix Fietkau066dae92010-11-07 14:59:39 +01001982static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301983{
Felix Fietkau066dae92010-11-07 14:59:39 +01001984 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301985
Felix Fietkau066dae92010-11-07 14:59:39 +01001986 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301987 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001988 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001989 if (ath_mac80211_start_queue(sc, qnum))
1990 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301991 }
1992 spin_unlock_bh(&txq->axq_lock);
1993}
1994
Sujithc4288392008-11-18 09:09:30 +05301995static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001996{
Sujithcbe61d82009-02-09 13:27:12 +05301997 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001998 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001999 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2000 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302001 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002002 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302003 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002004 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002005 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002006
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002007 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2008 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2009 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002010
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002011 for (;;) {
2012 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002013 if (list_empty(&txq->axq_q)) {
2014 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002015 spin_unlock_bh(&txq->axq_lock);
2016 break;
2017 }
2018 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2019
2020 /*
2021 * There is a race condition that a BH gets scheduled
2022 * after sw writes TxE and before hw re-load the last
2023 * descriptor to get the newly chained one.
2024 * Software must keep the last DONE descriptor as a
2025 * holding descriptor - software does so by marking
2026 * it with the STALE flag.
2027 */
2028 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302029 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002030 bf_held = bf;
2031 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302032 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002033 break;
2034 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002035 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302036 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002037 }
2038 }
2039
2040 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302041 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002042
Felix Fietkau29bffa92010-03-29 20:14:23 -07002043 memset(&ts, 0, sizeof(ts));
2044 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045 if (status == -EINPROGRESS) {
2046 spin_unlock_bh(&txq->axq_lock);
2047 break;
2048 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049
2050 /*
2051 * Remove ath_buf's of the same transmit unit from txq,
2052 * however leave the last descriptor back as the holding
2053 * descriptor for hw.
2054 */
Sujitha119cc42009-03-30 15:28:38 +05302055 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002056 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002057 if (!list_is_singular(&lastbf->list))
2058 list_cut_position(&bf_head,
2059 &txq->axq_q, lastbf->list.prev);
2060
2061 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002062 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002063 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002064 if (bf_held)
2065 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002066 spin_unlock_bh(&txq->axq_lock);
2067
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002068 if (bf_held)
2069 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002070
Sujithcd3d39a2008-08-11 14:03:34 +05302071 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002072 /*
2073 * This frame is sent out as a single frame.
2074 * Use hardware retry status for this frame.
2075 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002076 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302077 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002078 ath_tx_rc_status(bf, &ts, 1, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 }
Johannes Berge6a98542008-10-21 12:40:02 +02002080
Felix Fietkau066dae92010-11-07 14:59:39 +01002081 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2082
Sujithcd3d39a2008-08-11 14:03:34 +05302083 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002084 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002086 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002087
Felix Fietkau066dae92010-11-07 14:59:39 +01002088 if (txq == sc->tx.txq_map[qnum])
2089 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302090
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002091 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302092 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002093 ath_txq_schedule(sc, txq);
2094 spin_unlock_bh(&txq->axq_lock);
2095 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002096}
2097
Sujith305fe472009-07-23 15:32:29 +05302098static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002099{
2100 struct ath_softc *sc = container_of(work, struct ath_softc,
2101 tx_complete_work.work);
2102 struct ath_txq *txq;
2103 int i;
2104 bool needreset = false;
2105
2106 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2107 if (ATH_TXQ_SETUP(sc, i)) {
2108 txq = &sc->tx.txq[i];
2109 spin_lock_bh(&txq->axq_lock);
2110 if (txq->axq_depth) {
2111 if (txq->axq_tx_inprogress) {
2112 needreset = true;
2113 spin_unlock_bh(&txq->axq_lock);
2114 break;
2115 } else {
2116 txq->axq_tx_inprogress = true;
2117 }
2118 }
2119 spin_unlock_bh(&txq->axq_lock);
2120 }
2121
2122 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002123 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2124 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302125 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002126 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302127 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002128 }
2129
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002130 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002131 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2132}
2133
2134
Sujithe8324352009-01-16 21:38:42 +05302135
2136void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002137{
Sujithe8324352009-01-16 21:38:42 +05302138 int i;
2139 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140
Sujithe8324352009-01-16 21:38:42 +05302141 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002142
2143 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302144 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2145 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002146 }
2147}
2148
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002149void ath_tx_edma_tasklet(struct ath_softc *sc)
2150{
2151 struct ath_tx_status txs;
2152 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2153 struct ath_hw *ah = sc->sc_ah;
2154 struct ath_txq *txq;
2155 struct ath_buf *bf, *lastbf;
2156 struct list_head bf_head;
2157 int status;
2158 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002159 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002160
2161 for (;;) {
2162 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2163 if (status == -EINPROGRESS)
2164 break;
2165 if (status == -EIO) {
2166 ath_print(common, ATH_DBG_XMIT,
2167 "Error processing tx status\n");
2168 break;
2169 }
2170
2171 /* Skip beacon completions */
2172 if (txs.qid == sc->beacon.beaconq)
2173 continue;
2174
2175 txq = &sc->tx.txq[txs.qid];
2176
2177 spin_lock_bh(&txq->axq_lock);
2178 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2179 spin_unlock_bh(&txq->axq_lock);
2180 return;
2181 }
2182
2183 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2184 struct ath_buf, list);
2185 lastbf = bf->bf_lastbf;
2186
2187 INIT_LIST_HEAD(&bf_head);
2188 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2189 &lastbf->list);
2190 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2191 txq->axq_depth--;
2192 txq->axq_tx_inprogress = false;
2193 spin_unlock_bh(&txq->axq_lock);
2194
2195 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2196
2197 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002198 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2199 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkaub572d032010-11-14 15:20:07 +01002200 ath_tx_rc_status(bf, &txs, 1, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002201 }
2202
Felix Fietkau066dae92010-11-07 14:59:39 +01002203 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2204
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002205 if (bf_isampdu(bf))
2206 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2207 else
2208 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2209 &txs, txok, 0);
2210
Felix Fietkau066dae92010-11-07 14:59:39 +01002211 if (txq == sc->tx.txq_map[qnum])
2212 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002213
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002214 spin_lock_bh(&txq->axq_lock);
2215 if (!list_empty(&txq->txq_fifo_pending)) {
2216 INIT_LIST_HEAD(&bf_head);
2217 bf = list_first_entry(&txq->txq_fifo_pending,
2218 struct ath_buf, list);
2219 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2220 &bf->bf_lastbf->list);
2221 ath_tx_txqaddbuf(sc, txq, &bf_head);
2222 } else if (sc->sc_flags & SC_OP_TXAGGR)
2223 ath_txq_schedule(sc, txq);
2224 spin_unlock_bh(&txq->axq_lock);
2225 }
2226}
2227
Sujithe8324352009-01-16 21:38:42 +05302228/*****************/
2229/* Init, Cleanup */
2230/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002231
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002232static int ath_txstatus_setup(struct ath_softc *sc, int size)
2233{
2234 struct ath_descdma *dd = &sc->txsdma;
2235 u8 txs_len = sc->sc_ah->caps.txs_len;
2236
2237 dd->dd_desc_len = size * txs_len;
2238 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2239 &dd->dd_desc_paddr, GFP_KERNEL);
2240 if (!dd->dd_desc)
2241 return -ENOMEM;
2242
2243 return 0;
2244}
2245
2246static int ath_tx_edma_init(struct ath_softc *sc)
2247{
2248 int err;
2249
2250 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2251 if (!err)
2252 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2253 sc->txsdma.dd_desc_paddr,
2254 ATH_TXSTATUS_RING_SIZE);
2255
2256 return err;
2257}
2258
2259static void ath_tx_edma_cleanup(struct ath_softc *sc)
2260{
2261 struct ath_descdma *dd = &sc->txsdma;
2262
2263 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2264 dd->dd_desc_paddr);
2265}
2266
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002267int ath_tx_init(struct ath_softc *sc, int nbufs)
2268{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002269 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002270 int error = 0;
2271
Sujith797fe5cb2009-03-30 15:28:45 +05302272 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002273
Sujith797fe5cb2009-03-30 15:28:45 +05302274 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002275 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302276 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002277 ath_print(common, ATH_DBG_FATAL,
2278 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302279 goto err;
2280 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002281
Sujith797fe5cb2009-03-30 15:28:45 +05302282 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002283 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302284 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002285 ath_print(common, ATH_DBG_FATAL,
2286 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302287 goto err;
2288 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002289
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002290 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2291
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002292 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2293 error = ath_tx_edma_init(sc);
2294 if (error)
2295 goto err;
2296 }
2297
Sujith797fe5cb2009-03-30 15:28:45 +05302298err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002299 if (error != 0)
2300 ath_tx_cleanup(sc);
2301
2302 return error;
2303}
2304
Sujith797fe5cb2009-03-30 15:28:45 +05302305void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002306{
Sujithb77f4832008-12-07 21:44:03 +05302307 if (sc->beacon.bdma.dd_desc_len != 0)
2308 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002309
Sujithb77f4832008-12-07 21:44:03 +05302310 if (sc->tx.txdma.dd_desc_len != 0)
2311 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002312
2313 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2314 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002315}
2316
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002317void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2318{
Sujithc5170162008-10-29 10:13:59 +05302319 struct ath_atx_tid *tid;
2320 struct ath_atx_ac *ac;
2321 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002322
Sujith8ee5afb2008-12-07 21:43:36 +05302323 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302324 tidno < WME_NUM_TID;
2325 tidno++, tid++) {
2326 tid->an = an;
2327 tid->tidno = tidno;
2328 tid->seq_start = tid->seq_next = 0;
2329 tid->baw_size = WME_MAX_BA;
2330 tid->baw_head = tid->baw_tail = 0;
2331 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302332 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302333 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302334 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302335 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302336 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302337 tid->state &= ~AGGR_ADDBA_COMPLETE;
2338 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302339 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002340
Sujith8ee5afb2008-12-07 21:43:36 +05302341 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302342 acno < WME_NUM_AC; acno++, ac++) {
2343 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002344 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302345 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002346 }
2347}
2348
Sujithb5aa9bf2008-10-29 10:13:31 +05302349void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002350{
Felix Fietkau2b409942010-07-07 19:42:08 +02002351 struct ath_atx_ac *ac;
2352 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002353 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002354 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302355
Felix Fietkau2b409942010-07-07 19:42:08 +02002356 for (tidno = 0, tid = &an->tid[tidno];
2357 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002358
Felix Fietkau2b409942010-07-07 19:42:08 +02002359 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002360 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002361
Felix Fietkau2b409942010-07-07 19:42:08 +02002362 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002363
Felix Fietkau2b409942010-07-07 19:42:08 +02002364 if (tid->sched) {
2365 list_del(&tid->list);
2366 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002367 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002368
2369 if (ac->sched) {
2370 list_del(&ac->list);
2371 tid->ac->sched = false;
2372 }
2373
2374 ath_tid_drain(sc, txq, tid);
2375 tid->state &= ~AGGR_ADDBA_COMPLETE;
2376 tid->state &= ~AGGR_CLEANUP;
2377
2378 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002379 }
2380}