blob: aa447770eb2b606ed2ccffed3880b993f9cc3200 [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
Sujithc37452b2009-03-09 09:31:57 +053051static void ath_tx_send_ht_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);
59static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +053060static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070061 struct ath_tx_status *ts, int txok);
62static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +053063 int nbad, int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020064static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
65 int seqno);
Sujithe8324352009-01-16 21:38:42 +053066
Felix Fietkau545750d2009-11-23 22:21:01 +010067enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020068 MCS_HT20,
69 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010070 MCS_HT40,
71 MCS_HT40_SGI,
72};
73
Felix Fietkau0e668cd2010-04-19 19:57:32 +020074static int ath_max_4ms_framelen[4][32] = {
75 [MCS_HT20] = {
76 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
77 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
78 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
79 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
80 },
81 [MCS_HT20_SGI] = {
82 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
83 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
84 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
85 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010086 },
87 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020088 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
89 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
90 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
91 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010092 },
93 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020094 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
95 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
96 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
97 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010098 }
99};
100
Sujithe8324352009-01-16 21:38:42 +0530101/*********************/
102/* Aggregation logic */
103/*********************/
104
Sujithe8324352009-01-16 21:38:42 +0530105static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
106{
107 struct ath_atx_ac *ac = tid->ac;
108
109 if (tid->paused)
110 return;
111
112 if (tid->sched)
113 return;
114
115 tid->sched = true;
116 list_add_tail(&tid->list, &ac->tid_q);
117
118 if (ac->sched)
119 return;
120
121 ac->sched = true;
122 list_add_tail(&ac->list, &txq->axq_acq);
123}
124
Sujithe8324352009-01-16 21:38:42 +0530125static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
126{
127 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
128
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200129 WARN_ON(!tid->paused);
130
Sujithe8324352009-01-16 21:38:42 +0530131 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200132 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530133
134 if (list_empty(&tid->buf_q))
135 goto unlock;
136
137 ath_tx_queue_tid(txq, tid);
138 ath_txq_schedule(sc, txq);
139unlock:
140 spin_unlock_bh(&txq->axq_lock);
141}
142
143static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
144{
145 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
146 struct ath_buf *bf;
147 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200148 struct ath_tx_status ts;
149
Sujithe8324352009-01-16 21:38:42 +0530150 INIT_LIST_HEAD(&bf_head);
151
Felix Fietkau90fa5392010-09-20 13:45:38 +0200152 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530153 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530154
155 while (!list_empty(&tid->buf_q)) {
156 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530157 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200158
159 if (bf_isretried(bf)) {
160 ath_tx_update_baw(sc, tid, bf->bf_seqno);
161 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
162 } else {
163 ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
164 }
Sujithe8324352009-01-16 21:38:42 +0530165 }
166
167 spin_unlock_bh(&txq->axq_lock);
168}
169
170static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
171 int seqno)
172{
173 int index, cindex;
174
175 index = ATH_BA_INDEX(tid->seq_start, seqno);
176 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
177
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200178 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530179
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200180 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530181 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
182 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
183 }
184}
185
186static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
187 struct ath_buf *bf)
188{
189 int index, cindex;
190
191 if (bf_isretried(bf))
192 return;
193
194 index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
195 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200196 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530197
198 if (index >= ((tid->baw_tail - tid->baw_head) &
199 (ATH_TID_MAX_BUFS - 1))) {
200 tid->baw_tail = cindex;
201 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
202 }
203}
204
205/*
206 * TODO: For frame(s) that are in the retry state, we will reuse the
207 * sequence number(s) without setting the retry bit. The
208 * alternative is to give up on these and BAR the receiver's window
209 * forward.
210 */
211static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
212 struct ath_atx_tid *tid)
213
214{
215 struct ath_buf *bf;
216 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700217 struct ath_tx_status ts;
218
219 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530220 INIT_LIST_HEAD(&bf_head);
221
222 for (;;) {
223 if (list_empty(&tid->buf_q))
224 break;
Sujithe8324352009-01-16 21:38:42 +0530225
Sujithd43f30152009-01-16 21:38:53 +0530226 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
227 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530228
229 if (bf_isretried(bf))
230 ath_tx_update_baw(sc, tid, bf->bf_seqno);
231
232 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700233 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530234 spin_lock(&txq->axq_lock);
235 }
236
237 tid->seq_next = tid->seq_start;
238 tid->baw_tail = tid->baw_head;
239}
240
Sujithfec247c2009-07-27 12:08:16 +0530241static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
242 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530243{
244 struct sk_buff *skb;
245 struct ieee80211_hdr *hdr;
246
247 bf->bf_state.bf_type |= BUF_RETRY;
248 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530249 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530250
251 skb = bf->bf_mpdu;
252 hdr = (struct ieee80211_hdr *)skb->data;
253 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
254}
255
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200256static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
257{
258 struct ath_buf *bf = NULL;
259
260 spin_lock_bh(&sc->tx.txbuflock);
261
262 if (unlikely(list_empty(&sc->tx.txbuf))) {
263 spin_unlock_bh(&sc->tx.txbuflock);
264 return NULL;
265 }
266
267 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
268 list_del(&bf->list);
269
270 spin_unlock_bh(&sc->tx.txbuflock);
271
272 return bf;
273}
274
275static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
276{
277 spin_lock_bh(&sc->tx.txbuflock);
278 list_add_tail(&bf->list, &sc->tx.txbuf);
279 spin_unlock_bh(&sc->tx.txbuflock);
280}
281
Sujithd43f30152009-01-16 21:38:53 +0530282static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
283{
284 struct ath_buf *tbf;
285
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200286 tbf = ath_tx_get_buffer(sc);
287 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530288 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530289
290 ATH_TXBUF_RESET(tbf);
291
Felix Fietkau827e69b2009-11-15 23:09:25 +0100292 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530293 tbf->bf_mpdu = bf->bf_mpdu;
294 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400295 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530296 tbf->bf_state = bf->bf_state;
297 tbf->bf_dmacontext = bf->bf_dmacontext;
298
299 return tbf;
300}
301
302static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
303 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700304 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530305{
306 struct ath_node *an = NULL;
307 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530308 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800309 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530310 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800311 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530312 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530313 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530314 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530315 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530316 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530317 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
318 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200319 struct ieee80211_tx_rate rates[4];
Sujithe8324352009-01-16 21:38:42 +0530320
Sujitha22be222009-03-30 15:28:36 +0530321 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530322 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530323
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800324 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100325 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800326
Felix Fietkau78c46532010-06-25 01:26:16 +0200327 memcpy(rates, tx_info->control.rates, sizeof(rates));
328
Sujith1286ec62009-01-27 13:30:37 +0530329 rcu_read_lock();
330
Ben Greear686b9cb2010-09-23 09:44:36 -0700331 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530332 if (!sta) {
333 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200334
Felix Fietkau31e79a52010-07-12 23:16:34 +0200335 INIT_LIST_HEAD(&bf_head);
336 while (bf) {
337 bf_next = bf->bf_next;
338
339 bf->bf_state.bf_type |= BUF_XRETRY;
340 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
341 !bf->bf_stale || bf_next != NULL)
342 list_move_tail(&bf->list, &bf_head);
343
344 ath_tx_rc_status(bf, ts, 0, 0, false);
345 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
346 0, 0);
347
348 bf = bf_next;
349 }
Sujith1286ec62009-01-27 13:30:37 +0530350 return;
Sujithe8324352009-01-16 21:38:42 +0530351 }
352
Sujith1286ec62009-01-27 13:30:37 +0530353 an = (struct ath_node *)sta->drv_priv;
354 tid = ATH_AN_2_TID(an, bf->bf_tidno);
355
Felix Fietkaub11b1602010-07-11 12:48:44 +0200356 /*
357 * The hardware occasionally sends a tx status for the wrong TID.
358 * In this case, the BA status cannot be considered valid and all
359 * subframes need to be retransmitted
360 */
361 if (bf->bf_tidno != ts->tid)
362 txok = false;
363
Sujithe8324352009-01-16 21:38:42 +0530364 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530365 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530366
Sujithd43f30152009-01-16 21:38:53 +0530367 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700368 if (ts->ts_flags & ATH9K_TX_BA) {
369 seq_st = ts->ts_seqnum;
370 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530371 } else {
Sujithd43f30152009-01-16 21:38:53 +0530372 /*
373 * AR5416 can become deaf/mute when BA
374 * issue happens. Chip needs to be reset.
375 * But AP code may have sychronization issues
376 * when perform internal reset in this routine.
377 * Only enable reset in STA mode for now.
378 */
Sujith2660b812009-02-09 13:27:26 +0530379 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530380 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530381 }
382 }
383
384 INIT_LIST_HEAD(&bf_pending);
385 INIT_LIST_HEAD(&bf_head);
386
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700387 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530388 while (bf) {
389 txfail = txpending = 0;
390 bf_next = bf->bf_next;
391
Felix Fietkau78c46532010-06-25 01:26:16 +0200392 skb = bf->bf_mpdu;
393 tx_info = IEEE80211_SKB_CB(skb);
394
Sujithe8324352009-01-16 21:38:42 +0530395 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
396 /* transmit completion, subframe is
397 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530398 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530399 } else if (!isaggr && txok) {
400 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530401 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530402 } else {
Sujithe8324352009-01-16 21:38:42 +0530403 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400404 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530405 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530406 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530407 txpending = 1;
408 } else {
409 bf->bf_state.bf_type |= BUF_XRETRY;
410 txfail = 1;
411 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530412 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530413 }
414 } else {
415 /*
416 * cleanup in progress, just fail
417 * the un-acked sub-frames
418 */
419 txfail = 1;
420 }
421 }
422
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400423 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
424 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530425 /*
426 * Make sure the last desc is reclaimed if it
427 * not a holding desc.
428 */
429 if (!bf_last->bf_stale)
430 list_move_tail(&bf->list, &bf_head);
431 else
432 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530433 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700434 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530435 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530436 }
437
Felix Fietkau90fa5392010-09-20 13:45:38 +0200438 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530439 /*
440 * complete the acked-ones/xretried ones; update
441 * block-ack window
442 */
443 spin_lock_bh(&txq->axq_lock);
444 ath_tx_update_baw(sc, tid, bf->bf_seqno);
445 spin_unlock_bh(&txq->axq_lock);
446
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530447 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200448 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700449 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530450 rc_update = false;
451 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700452 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530453 }
454
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700455 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
456 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530457 } else {
Sujithd43f30152009-01-16 21:38:53 +0530458 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400459 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
460 if (bf->bf_next == NULL && bf_last->bf_stale) {
461 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530462
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400463 tbf = ath_clone_txbuf(sc, bf_last);
464 /*
465 * Update tx baw and complete the
466 * frame with failed status if we
467 * run out of tx buf.
468 */
469 if (!tbf) {
470 spin_lock_bh(&txq->axq_lock);
471 ath_tx_update_baw(sc, tid,
472 bf->bf_seqno);
473 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400474
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400475 bf->bf_state.bf_type |=
476 BUF_XRETRY;
477 ath_tx_rc_status(bf, ts, nbad,
478 0, false);
479 ath_tx_complete_buf(sc, bf, txq,
480 &bf_head,
481 ts, 0, 0);
482 break;
483 }
484
485 ath9k_hw_cleartxdesc(sc->sc_ah,
486 tbf->bf_desc);
487 list_add_tail(&tbf->list, &bf_head);
488 } else {
489 /*
490 * Clear descriptor status words for
491 * software retry
492 */
493 ath9k_hw_cleartxdesc(sc->sc_ah,
494 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400495 }
Sujithe8324352009-01-16 21:38:42 +0530496 }
497
498 /*
499 * Put this buffer to the temporary pending
500 * queue to retain ordering
501 */
502 list_splice_tail_init(&bf_head, &bf_pending);
503 }
504
505 bf = bf_next;
506 }
507
Felix Fietkau4cee7862010-07-23 03:53:16 +0200508 /* prepend un-acked frames to the beginning of the pending frame queue */
509 if (!list_empty(&bf_pending)) {
510 spin_lock_bh(&txq->axq_lock);
511 list_splice(&bf_pending, &tid->buf_q);
512 ath_tx_queue_tid(txq, tid);
513 spin_unlock_bh(&txq->axq_lock);
514 }
515
Sujithe8324352009-01-16 21:38:42 +0530516 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200517 ath_tx_flush_tid(sc, tid);
518
Sujithe8324352009-01-16 21:38:42 +0530519 if (tid->baw_head == tid->baw_tail) {
520 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530521 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530522 }
Sujithe8324352009-01-16 21:38:42 +0530523 }
524
Sujith1286ec62009-01-27 13:30:37 +0530525 rcu_read_unlock();
526
Sujithe8324352009-01-16 21:38:42 +0530527 if (needreset)
528 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530529}
530
531static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
532 struct ath_atx_tid *tid)
533{
Sujithe8324352009-01-16 21:38:42 +0530534 struct sk_buff *skb;
535 struct ieee80211_tx_info *tx_info;
536 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530537 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530538 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530539 int i;
540
Sujitha22be222009-03-30 15:28:36 +0530541 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530542 tx_info = IEEE80211_SKB_CB(skb);
543 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530544
545 /*
546 * Find the lowest frame length among the rate series that will have a
547 * 4ms transmit duration.
548 * TODO - TXOP limit needs to be considered.
549 */
550 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
551
552 for (i = 0; i < 4; i++) {
553 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100554 int modeidx;
555 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530556 legacy = 1;
557 break;
558 }
559
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200560 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100561 modeidx = MCS_HT40;
562 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200563 modeidx = MCS_HT20;
564
565 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
566 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100567
568 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530569 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530570 }
571 }
572
573 /*
574 * limit aggregate size by the minimum rate if rate selected is
575 * not a probe rate, if rate selected is a probe rate then
576 * avoid aggregation of this packet.
577 */
578 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
579 return 0;
580
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530581 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
582 aggr_limit = min((max_4ms_framelen * 3) / 8,
583 (u32)ATH_AMPDU_LIMIT_MAX);
584 else
585 aggr_limit = min(max_4ms_framelen,
586 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530587
588 /*
589 * h/w can accept aggregates upto 16 bit lengths (65535).
590 * The IE, however can hold upto 65536, which shows up here
591 * as zero. Ignore 65536 since we are constrained by hw.
592 */
Sujith4ef70842009-07-23 15:32:41 +0530593 if (tid->an->maxampdu)
594 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530595
596 return aggr_limit;
597}
598
599/*
Sujithd43f30152009-01-16 21:38:53 +0530600 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530601 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530602 */
603static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
604 struct ath_buf *bf, u16 frmlen)
605{
Sujithe8324352009-01-16 21:38:42 +0530606 struct sk_buff *skb = bf->bf_mpdu;
607 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530608 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530609 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100610 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200611 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530612
613 /* Select standard number of delimiters based on frame length alone */
614 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
615
616 /*
617 * If encryption enabled, hardware requires some more padding between
618 * subframes.
619 * TODO - this could be improved to be dependent on the rate.
620 * The hardware can keep up at lower rates, but not higher rates
621 */
622 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
623 ndelim += ATH_AGGR_ENCRYPTDELIM;
624
625 /*
626 * Convert desired mpdu density from microeconds to bytes based
627 * on highest rate in rate series (i.e. first rate) to determine
628 * required minimum length for subframe. Take into account
629 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530630 *
Sujithe8324352009-01-16 21:38:42 +0530631 * If there is no mpdu density restriction, no further calculation
632 * is needed.
633 */
Sujith4ef70842009-07-23 15:32:41 +0530634
635 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530636 return ndelim;
637
638 rix = tx_info->control.rates[0].idx;
639 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530640 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
641 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
642
643 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530644 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530645 else
Sujith4ef70842009-07-23 15:32:41 +0530646 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530647
648 if (nsymbols == 0)
649 nsymbols = 1;
650
Felix Fietkauc6663872010-04-19 19:57:33 +0200651 streams = HT_RC_2_STREAMS(rix);
652 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530653 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
654
Sujithe8324352009-01-16 21:38:42 +0530655 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530656 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
657 ndelim = max(mindelim, ndelim);
658 }
659
660 return ndelim;
661}
662
663static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530664 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530665 struct ath_atx_tid *tid,
666 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530667{
668#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530669 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
670 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530671 u16 aggr_limit = 0, al = 0, bpad = 0,
672 al_delta, h_baw = tid->baw_size / 2;
673 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Sujithe8324352009-01-16 21:38:42 +0530674
675 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
676
677 do {
678 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
679
Sujithd43f30152009-01-16 21:38:53 +0530680 /* do not step over block-ack window */
Sujithe8324352009-01-16 21:38:42 +0530681 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
682 status = ATH_AGGR_BAW_CLOSED;
683 break;
684 }
685
686 if (!rl) {
687 aggr_limit = ath_lookup_rate(sc, bf, tid);
688 rl = 1;
689 }
690
Sujithd43f30152009-01-16 21:38:53 +0530691 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530692 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
693
Sujithd43f30152009-01-16 21:38:53 +0530694 if (nframes &&
695 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530696 status = ATH_AGGR_LIMITED;
697 break;
698 }
699
Sujithd43f30152009-01-16 21:38:53 +0530700 /* do not exceed subframe limit */
701 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530702 status = ATH_AGGR_LIMITED;
703 break;
704 }
Sujithd43f30152009-01-16 21:38:53 +0530705 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530706
Sujithd43f30152009-01-16 21:38:53 +0530707 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530708 al += bpad + al_delta;
709
710 /*
711 * Get the delimiters needed to meet the MPDU
712 * density for this node.
713 */
714 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530715 bpad = PADBYTES(al_delta) + (ndelim << 2);
716
717 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400718 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530719
Sujithd43f30152009-01-16 21:38:53 +0530720 /* link buffers of this frame to the aggregate */
Sujithe8324352009-01-16 21:38:42 +0530721 ath_tx_addto_baw(sc, tid, bf);
Sujithd43f30152009-01-16 21:38:53 +0530722 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
723 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530724 if (bf_prev) {
725 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400726 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
727 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530728 }
729 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530730
Sujithe8324352009-01-16 21:38:42 +0530731 } while (!list_empty(&tid->buf_q));
732
733 bf_first->bf_al = al;
734 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530735
Sujithe8324352009-01-16 21:38:42 +0530736 return status;
737#undef PADBYTES
738}
739
740static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
741 struct ath_atx_tid *tid)
742{
Sujithd43f30152009-01-16 21:38:53 +0530743 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530744 enum ATH_AGGR_STATUS status;
745 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530746
747 do {
748 if (list_empty(&tid->buf_q))
749 return;
750
751 INIT_LIST_HEAD(&bf_q);
752
Sujithfec247c2009-07-27 12:08:16 +0530753 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530754
755 /*
Sujithd43f30152009-01-16 21:38:53 +0530756 * no frames picked up to be aggregated;
757 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530758 */
759 if (list_empty(&bf_q))
760 break;
761
762 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530763 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530764
Sujithd43f30152009-01-16 21:38:53 +0530765 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530766 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530767 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530768 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530769 ath_buf_set_rate(sc, bf);
770 ath_tx_txqaddbuf(sc, txq, &bf_q);
771 continue;
772 }
773
Sujithd43f30152009-01-16 21:38:53 +0530774 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530775 bf->bf_state.bf_type |= BUF_AGGR;
776 ath_buf_set_rate(sc, bf);
777 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
778
Sujithd43f30152009-01-16 21:38:53 +0530779 /* anchor last desc of aggregate */
780 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530781
Sujithe8324352009-01-16 21:38:42 +0530782 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530783 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530784
785 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
786 status != ATH_AGGR_BAW_CLOSED);
787}
788
Felix Fietkau231c3a12010-09-20 19:35:28 +0200789int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
790 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530791{
792 struct ath_atx_tid *txtid;
793 struct ath_node *an;
794
795 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530796 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200797
798 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
799 return -EAGAIN;
800
Sujithf83da962009-07-23 15:32:37 +0530801 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200802 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530803 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200804
805 return 0;
Sujithe8324352009-01-16 21:38:42 +0530806}
807
Sujithf83da962009-07-23 15:32:37 +0530808void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530809{
810 struct ath_node *an = (struct ath_node *)sta->drv_priv;
811 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
812 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
Sujithe8324352009-01-16 21:38:42 +0530813
814 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530815 return;
Sujithe8324352009-01-16 21:38:42 +0530816
817 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530818 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530819 return;
Sujithe8324352009-01-16 21:38:42 +0530820 }
821
Sujithe8324352009-01-16 21:38:42 +0530822 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200823 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200824
825 /*
826 * If frames are still being transmitted for this TID, they will be
827 * cleaned up during tx completion. To prevent race conditions, this
828 * TID can only be reused after all in-progress subframes have been
829 * completed.
830 */
831 if (txtid->baw_head != txtid->baw_tail)
832 txtid->state |= AGGR_CLEANUP;
833 else
834 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530835 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530836
Felix Fietkau90fa5392010-09-20 13:45:38 +0200837 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530838}
839
840void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
841{
842 struct ath_atx_tid *txtid;
843 struct ath_node *an;
844
845 an = (struct ath_node *)sta->drv_priv;
846
847 if (sc->sc_flags & SC_OP_TXAGGR) {
848 txtid = ATH_AN_2_TID(an, tid);
849 txtid->baw_size =
850 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
851 txtid->state |= AGGR_ADDBA_COMPLETE;
852 txtid->state &= ~AGGR_ADDBA_PROGRESS;
853 ath_tx_resume_tid(sc, txtid);
854 }
855}
856
Sujithe8324352009-01-16 21:38:42 +0530857/********************/
858/* Queue Management */
859/********************/
860
Sujithe8324352009-01-16 21:38:42 +0530861static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
862 struct ath_txq *txq)
863{
864 struct ath_atx_ac *ac, *ac_tmp;
865 struct ath_atx_tid *tid, *tid_tmp;
866
867 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
868 list_del(&ac->list);
869 ac->sched = false;
870 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
871 list_del(&tid->list);
872 tid->sched = false;
873 ath_tid_drain(sc, txq, tid);
874 }
875 }
876}
877
878struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
879{
Sujithcbe61d82009-02-09 13:27:12 +0530880 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700881 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530882 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400883 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530884
885 memset(&qi, 0, sizeof(qi));
886 qi.tqi_subtype = subtype;
887 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
888 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
889 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
890 qi.tqi_physCompBuf = 0;
891
892 /*
893 * Enable interrupts only for EOL and DESC conditions.
894 * We mark tx descriptors to receive a DESC interrupt
895 * when a tx queue gets deep; otherwise waiting for the
896 * EOL to reap descriptors. Note that this is done to
897 * reduce interrupt load and this only defers reaping
898 * descriptors, never transmitting frames. Aside from
899 * reducing interrupts this also permits more concurrency.
900 * The only potential downside is if the tx queue backs
901 * up in which case the top half of the kernel may backup
902 * due to a lack of tx descriptors.
903 *
904 * The UAPSD queue is an exception, since we take a desc-
905 * based intr on the EOSP frames.
906 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400907 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
908 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
909 TXQ_FLAG_TXERRINT_ENABLE;
910 } else {
911 if (qtype == ATH9K_TX_QUEUE_UAPSD)
912 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
913 else
914 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
915 TXQ_FLAG_TXDESCINT_ENABLE;
916 }
Sujithe8324352009-01-16 21:38:42 +0530917 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
918 if (qnum == -1) {
919 /*
920 * NB: don't print a message, this happens
921 * normally on parts with too few tx queues
922 */
923 return NULL;
924 }
925 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700926 ath_print(common, ATH_DBG_FATAL,
927 "qnum %u out of range, max %u!\n",
928 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530929 ath9k_hw_releasetxqueue(ah, qnum);
930 return NULL;
931 }
932 if (!ATH_TXQ_SETUP(sc, qnum)) {
933 struct ath_txq *txq = &sc->tx.txq[qnum];
934
Felix Fietkau293f2ba2010-06-12 00:33:49 -0400935 txq->axq_class = subtype;
Sujithe8324352009-01-16 21:38:42 +0530936 txq->axq_qnum = qnum;
937 txq->axq_link = NULL;
938 INIT_LIST_HEAD(&txq->axq_q);
939 INIT_LIST_HEAD(&txq->axq_acq);
940 spin_lock_init(&txq->axq_lock);
941 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400942 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530943 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400944
945 txq->txq_headidx = txq->txq_tailidx = 0;
946 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
947 INIT_LIST_HEAD(&txq->txq_fifo[i]);
948 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530949 }
950 return &sc->tx.txq[qnum];
951}
952
Sujithe8324352009-01-16 21:38:42 +0530953int ath_txq_update(struct ath_softc *sc, int qnum,
954 struct ath9k_tx_queue_info *qinfo)
955{
Sujithcbe61d82009-02-09 13:27:12 +0530956 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530957 int error = 0;
958 struct ath9k_tx_queue_info qi;
959
960 if (qnum == sc->beacon.beaconq) {
961 /*
962 * XXX: for beacon queue, we just save the parameter.
963 * It will be picked up by ath_beaconq_config when
964 * it's necessary.
965 */
966 sc->beacon.beacon_qi = *qinfo;
967 return 0;
968 }
969
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700970 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530971
972 ath9k_hw_get_txq_props(ah, qnum, &qi);
973 qi.tqi_aifs = qinfo->tqi_aifs;
974 qi.tqi_cwmin = qinfo->tqi_cwmin;
975 qi.tqi_cwmax = qinfo->tqi_cwmax;
976 qi.tqi_burstTime = qinfo->tqi_burstTime;
977 qi.tqi_readyTime = qinfo->tqi_readyTime;
978
979 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700980 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
981 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +0530982 error = -EIO;
983 } else {
984 ath9k_hw_resettxqueue(ah, qnum);
985 }
986
987 return error;
988}
989
990int ath_cabq_update(struct ath_softc *sc)
991{
992 struct ath9k_tx_queue_info qi;
993 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +0530994
995 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
996 /*
997 * Ensure the readytime % is within the bounds.
998 */
Sujith17d79042009-02-09 13:27:03 +0530999 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1000 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1001 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1002 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301003
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001004 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301005 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301006 ath_txq_update(sc, qnum, &qi);
1007
1008 return 0;
1009}
1010
Sujith043a0402009-01-16 21:38:47 +05301011/*
1012 * Drain a given TX queue (could be Beacon or Data)
1013 *
1014 * This assumes output has been stopped and
1015 * we do not need to block ath_tx_tasklet.
1016 */
1017void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301018{
1019 struct ath_buf *bf, *lastbf;
1020 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001021 struct ath_tx_status ts;
1022
1023 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301024 INIT_LIST_HEAD(&bf_head);
1025
Sujithe8324352009-01-16 21:38:42 +05301026 for (;;) {
1027 spin_lock_bh(&txq->axq_lock);
1028
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001029 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1030 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1031 txq->txq_headidx = txq->txq_tailidx = 0;
1032 spin_unlock_bh(&txq->axq_lock);
1033 break;
1034 } else {
1035 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1036 struct ath_buf, list);
1037 }
1038 } else {
1039 if (list_empty(&txq->axq_q)) {
1040 txq->axq_link = NULL;
1041 spin_unlock_bh(&txq->axq_lock);
1042 break;
1043 }
1044 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1045 list);
Sujithe8324352009-01-16 21:38:42 +05301046
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001047 if (bf->bf_stale) {
1048 list_del(&bf->list);
1049 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301050
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001051 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001052 continue;
1053 }
Sujithe8324352009-01-16 21:38:42 +05301054 }
1055
1056 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001057 if (!retry_tx)
1058 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301059
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001060 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1061 list_cut_position(&bf_head,
1062 &txq->txq_fifo[txq->txq_tailidx],
1063 &lastbf->list);
1064 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1065 } else {
1066 /* remove ath_buf's of the same mpdu from txq */
1067 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1068 }
1069
Sujithe8324352009-01-16 21:38:42 +05301070 txq->axq_depth--;
1071
1072 spin_unlock_bh(&txq->axq_lock);
1073
1074 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001075 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301076 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001077 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301078 }
1079
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001080 spin_lock_bh(&txq->axq_lock);
1081 txq->axq_tx_inprogress = false;
1082 spin_unlock_bh(&txq->axq_lock);
1083
Sujithe8324352009-01-16 21:38:42 +05301084 /* flush any pending frames if aggregation is enabled */
1085 if (sc->sc_flags & SC_OP_TXAGGR) {
1086 if (!retry_tx) {
1087 spin_lock_bh(&txq->axq_lock);
1088 ath_txq_drain_pending_buffers(sc, txq);
1089 spin_unlock_bh(&txq->axq_lock);
1090 }
1091 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001092
1093 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1094 spin_lock_bh(&txq->axq_lock);
1095 while (!list_empty(&txq->txq_fifo_pending)) {
1096 bf = list_first_entry(&txq->txq_fifo_pending,
1097 struct ath_buf, list);
1098 list_cut_position(&bf_head,
1099 &txq->txq_fifo_pending,
1100 &bf->bf_lastbf->list);
1101 spin_unlock_bh(&txq->axq_lock);
1102
1103 if (bf_isampdu(bf))
1104 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1105 &ts, 0);
1106 else
1107 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1108 &ts, 0, 0);
1109 spin_lock_bh(&txq->axq_lock);
1110 }
1111 spin_unlock_bh(&txq->axq_lock);
1112 }
Sujithe8324352009-01-16 21:38:42 +05301113}
1114
Sujith043a0402009-01-16 21:38:47 +05301115void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1116{
Sujithcbe61d82009-02-09 13:27:12 +05301117 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001118 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301119 struct ath_txq *txq;
1120 int i, npend = 0;
1121
1122 if (sc->sc_flags & SC_OP_INVALID)
1123 return;
1124
1125 /* Stop beacon queue */
1126 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1127
1128 /* Stop data queues */
1129 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1130 if (ATH_TXQ_SETUP(sc, i)) {
1131 txq = &sc->tx.txq[i];
1132 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1133 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1134 }
1135 }
1136
1137 if (npend) {
1138 int r;
1139
Sujithe8009e92009-12-14 14:57:08 +05301140 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001141 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301142
1143 spin_lock_bh(&sc->sc_resetlock);
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001144 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301145 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001146 ath_print(common, ATH_DBG_FATAL,
1147 "Unable to reset hardware; reset status %d\n",
1148 r);
Sujith043a0402009-01-16 21:38:47 +05301149 spin_unlock_bh(&sc->sc_resetlock);
1150 }
1151
1152 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1153 if (ATH_TXQ_SETUP(sc, i))
1154 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1155 }
1156}
1157
Sujithe8324352009-01-16 21:38:42 +05301158void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1159{
1160 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1161 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1162}
1163
Sujithe8324352009-01-16 21:38:42 +05301164void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1165{
1166 struct ath_atx_ac *ac;
1167 struct ath_atx_tid *tid;
1168
1169 if (list_empty(&txq->axq_acq))
1170 return;
1171
1172 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1173 list_del(&ac->list);
1174 ac->sched = false;
1175
1176 do {
1177 if (list_empty(&ac->tid_q))
1178 return;
1179
1180 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1181 list_del(&tid->list);
1182 tid->sched = false;
1183
1184 if (tid->paused)
1185 continue;
1186
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001187 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301188
1189 /*
1190 * add tid to round-robin queue if more frames
1191 * are pending for the tid
1192 */
1193 if (!list_empty(&tid->buf_q))
1194 ath_tx_queue_tid(txq, tid);
1195
1196 break;
1197 } while (!list_empty(&ac->tid_q));
1198
1199 if (!list_empty(&ac->tid_q)) {
1200 if (!ac->sched) {
1201 ac->sched = true;
1202 list_add_tail(&ac->list, &txq->axq_acq);
1203 }
1204 }
1205}
1206
1207int ath_tx_setup(struct ath_softc *sc, int haltype)
1208{
1209 struct ath_txq *txq;
1210
1211 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001212 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1213 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301214 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1215 return 0;
1216 }
1217 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1218 if (txq != NULL) {
1219 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1220 return 1;
1221 } else
1222 return 0;
1223}
1224
1225/***********/
1226/* TX, DMA */
1227/***********/
1228
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001229/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001230 * Insert a chain of ath_buf (descriptors) on a txq and
1231 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001232 */
Sujith102e0572008-10-29 10:15:16 +05301233static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1234 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001235{
Sujithcbe61d82009-02-09 13:27:12 +05301236 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001237 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001238 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301239
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001240 /*
1241 * Insert the frame on the outbound list and
1242 * pass it on to the hardware.
1243 */
1244
1245 if (list_empty(head))
1246 return;
1247
1248 bf = list_first_entry(head, struct ath_buf, list);
1249
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001250 ath_print(common, ATH_DBG_QUEUE,
1251 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001252
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001253 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1254 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1255 list_splice_tail_init(head, &txq->txq_fifo_pending);
1256 return;
1257 }
1258 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1259 ath_print(common, ATH_DBG_XMIT,
1260 "Initializing tx fifo %d which "
1261 "is non-empty\n",
1262 txq->txq_headidx);
1263 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1264 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1265 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001266 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001267 ath_print(common, ATH_DBG_XMIT,
1268 "TXDP[%u] = %llx (%p)\n",
1269 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001270 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001271 list_splice_tail_init(head, &txq->axq_q);
1272
1273 if (txq->axq_link == NULL) {
1274 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1275 ath_print(common, ATH_DBG_XMIT,
1276 "TXDP[%u] = %llx (%p)\n",
1277 txq->axq_qnum, ito64(bf->bf_daddr),
1278 bf->bf_desc);
1279 } else {
1280 *txq->axq_link = bf->bf_daddr;
1281 ath_print(common, ATH_DBG_XMIT,
1282 "link[%u] (%p)=%llx (%p)\n",
1283 txq->axq_qnum, txq->axq_link,
1284 ito64(bf->bf_daddr), bf->bf_desc);
1285 }
1286 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1287 &txq->axq_link);
1288 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001289 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001290 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001291}
1292
Sujithe8324352009-01-16 21:38:42 +05301293static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1294 struct list_head *bf_head,
1295 struct ath_tx_control *txctl)
1296{
1297 struct ath_buf *bf;
1298
Sujithe8324352009-01-16 21:38:42 +05301299 bf = list_first_entry(bf_head, struct ath_buf, list);
1300 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301301 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301302
1303 /*
1304 * Do not queue to h/w when any of the following conditions is true:
1305 * - there are pending frames in software queue
1306 * - the TID is currently paused for ADDBA/BAR request
1307 * - seqno is not within block-ack window
1308 * - h/w queue depth exceeds low water mark
1309 */
1310 if (!list_empty(&tid->buf_q) || tid->paused ||
1311 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1312 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001313 /*
Sujithe8324352009-01-16 21:38:42 +05301314 * Add this frame to software queue for scheduling later
1315 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001316 */
Sujithd43f30152009-01-16 21:38:53 +05301317 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301318 ath_tx_queue_tid(txctl->txq, tid);
1319 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001320 }
1321
Sujithe8324352009-01-16 21:38:42 +05301322 /* Add sub-frame to BAW */
1323 ath_tx_addto_baw(sc, tid, bf);
1324
1325 /* Queue to h/w without aggregation */
1326 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301327 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301328 ath_buf_set_rate(sc, bf);
1329 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301330}
1331
Sujithc37452b2009-03-09 09:31:57 +05301332static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1333 struct ath_atx_tid *tid,
1334 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001335{
Sujithe8324352009-01-16 21:38:42 +05301336 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001337
Sujithe8324352009-01-16 21:38:42 +05301338 bf = list_first_entry(bf_head, struct ath_buf, list);
1339 bf->bf_state.bf_type &= ~BUF_AMPDU;
1340
1341 /* update starting sequence number for subsequent ADDBA request */
1342 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1343
1344 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301345 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301346 ath_buf_set_rate(sc, bf);
1347 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301348 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001349}
1350
Sujithc37452b2009-03-09 09:31:57 +05301351static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1352 struct list_head *bf_head)
1353{
1354 struct ath_buf *bf;
1355
1356 bf = list_first_entry(bf_head, struct ath_buf, list);
1357
1358 bf->bf_lastbf = bf;
1359 bf->bf_nframes = 1;
1360 ath_buf_set_rate(sc, bf);
1361 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301362 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301363}
1364
Sujith528f0c62008-10-29 10:14:26 +05301365static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001366{
Sujith528f0c62008-10-29 10:14:26 +05301367 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001368 enum ath9k_pkt_type htype;
1369 __le16 fc;
1370
Sujith528f0c62008-10-29 10:14:26 +05301371 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001372 fc = hdr->frame_control;
1373
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001374 if (ieee80211_is_beacon(fc))
1375 htype = ATH9K_PKT_TYPE_BEACON;
1376 else if (ieee80211_is_probe_resp(fc))
1377 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1378 else if (ieee80211_is_atim(fc))
1379 htype = ATH9K_PKT_TYPE_ATIM;
1380 else if (ieee80211_is_pspoll(fc))
1381 htype = ATH9K_PKT_TYPE_PSPOLL;
1382 else
1383 htype = ATH9K_PKT_TYPE_NORMAL;
1384
1385 return htype;
1386}
1387
Sujith528f0c62008-10-29 10:14:26 +05301388static void assign_aggr_tid_seqno(struct sk_buff *skb,
1389 struct ath_buf *bf)
1390{
1391 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1392 struct ieee80211_hdr *hdr;
1393 struct ath_node *an;
1394 struct ath_atx_tid *tid;
1395 __le16 fc;
1396 u8 *qc;
1397
1398 if (!tx_info->control.sta)
1399 return;
1400
1401 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1402 hdr = (struct ieee80211_hdr *)skb->data;
1403 fc = hdr->frame_control;
1404
Sujith528f0c62008-10-29 10:14:26 +05301405 if (ieee80211_is_data_qos(fc)) {
1406 qc = ieee80211_get_qos_ctl(hdr);
1407 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301408 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409
Sujithe8324352009-01-16 21:38:42 +05301410 /*
1411 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301412 * We also override seqno set by upper layer with the one
1413 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301414 */
1415 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301416 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301417 bf->bf_seqno = tid->seq_next;
1418 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301419}
1420
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001421static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301422{
1423 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1424 int flags = 0;
1425
1426 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1427 flags |= ATH9K_TXDESC_INTREQ;
1428
1429 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1430 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301431
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001432 if (use_ldpc)
1433 flags |= ATH9K_TXDESC_LDPC;
1434
Sujith528f0c62008-10-29 10:14:26 +05301435 return flags;
1436}
1437
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001438/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439 * rix - rate index
1440 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1441 * width - 0 for 20 MHz, 1 for 40 MHz
1442 * half_gi - to use 4us v/s 3.6 us for symbol time
1443 */
Sujith102e0572008-10-29 10:15:16 +05301444static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1445 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001446{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001447 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001448 int streams, pktlen;
1449
Sujithcd3d39a2008-08-11 14:03:34 +05301450 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301451
1452 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001453 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001454 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001455 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1457
1458 if (!half_gi)
1459 duration = SYMBOL_TIME(nsymbols);
1460 else
1461 duration = SYMBOL_TIME_HALFGI(nsymbols);
1462
Sujithe63835b2008-11-18 09:07:53 +05301463 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301465
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001466 return duration;
1467}
1468
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001469static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1470{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001471 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001472 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301473 struct sk_buff *skb;
1474 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301475 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001476 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301477 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301478 int i, flags = 0;
1479 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301480 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301481
1482 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301483
Sujitha22be222009-03-30 15:28:36 +05301484 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301485 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301486 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301487 hdr = (struct ieee80211_hdr *)skb->data;
1488 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301489
Sujithc89424d2009-01-30 14:29:28 +05301490 /*
1491 * We check if Short Preamble is needed for the CTS rate by
1492 * checking the BSS's global flag.
1493 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1494 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001495 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1496 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301497 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001498 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001499
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001500 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001501 bool is_40, is_sgi, is_sp;
1502 int phy;
1503
Sujithe63835b2008-11-18 09:07:53 +05301504 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 continue;
1506
Sujitha8efee42008-11-18 09:07:30 +05301507 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301508 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001509 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001510
Felix Fietkau27032052010-01-17 21:08:50 +01001511 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1512 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301513 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001514 flags |= ATH9K_TXDESC_RTSENA;
1515 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1516 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1517 flags |= ATH9K_TXDESC_CTSENA;
1518 }
1519
Sujithc89424d2009-01-30 14:29:28 +05301520 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1521 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1522 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1523 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001524
Felix Fietkau545750d2009-11-23 22:21:01 +01001525 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1526 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1527 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1528
1529 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1530 /* MCS rates */
1531 series[i].Rate = rix | 0x80;
1532 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1533 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001534 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1535 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001536 continue;
1537 }
1538
1539 /* legcay rates */
1540 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1541 !(rate->flags & IEEE80211_RATE_ERP_G))
1542 phy = WLAN_RC_PHY_CCK;
1543 else
1544 phy = WLAN_RC_PHY_OFDM;
1545
1546 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1547 series[i].Rate = rate->hw_value;
1548 if (rate->hw_value_short) {
1549 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1550 series[i].Rate |= rate->hw_value_short;
1551 } else {
1552 is_sp = false;
1553 }
1554
1555 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1556 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001557 }
1558
Felix Fietkau27032052010-01-17 21:08:50 +01001559 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1560 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1561 flags &= ~ATH9K_TXDESC_RTSENA;
1562
1563 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1564 if (flags & ATH9K_TXDESC_RTSENA)
1565 flags &= ~ATH9K_TXDESC_CTSENA;
1566
Sujithe63835b2008-11-18 09:07:53 +05301567 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301568 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1569 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301570 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301571 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301572
Sujith17d79042009-02-09 13:27:03 +05301573 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301574 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001575}
1576
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001577static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301578 struct sk_buff *skb,
1579 struct ath_tx_control *txctl)
1580{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001581 struct ath_wiphy *aphy = hw->priv;
1582 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301583 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1584 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301585 int hdrlen;
1586 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001587 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001588 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301589
Felix Fietkau827e69b2009-11-15 23:09:25 +01001590 tx_info->pad[0] = 0;
1591 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001592 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001593 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001594 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001595 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1596 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001597 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001598 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1599 break;
1600 }
Sujithe8324352009-01-16 21:38:42 +05301601 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1602 fc = hdr->frame_control;
1603
1604 ATH_TXBUF_RESET(bf);
1605
Felix Fietkau827e69b2009-11-15 23:09:25 +01001606 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001607 bf->bf_frmlen = skb->len + FCS_LEN;
1608 /* Remove the padding size from bf_frmlen, if any */
1609 padpos = ath9k_cmn_padpos(hdr->frame_control);
1610 padsize = padpos & 3;
1611 if (padsize && skb->len>padpos+padsize) {
1612 bf->bf_frmlen -= padsize;
1613 }
Sujithe8324352009-01-16 21:38:42 +05301614
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001615 if (!txctl->paprd && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301616 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001617 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1618 use_ldpc = true;
1619 }
Sujithe8324352009-01-16 21:38:42 +05301620
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001621 bf->bf_state.bfs_paprd = txctl->paprd;
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001622 if (txctl->paprd)
1623 bf->bf_state.bfs_paprd_timestamp = jiffies;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001624 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301625
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001626 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301627 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1628 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1629 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1630 } else {
1631 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1632 }
1633
Sujith17b182e2009-12-14 14:56:56 +05301634 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1635 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301636 assign_aggr_tid_seqno(skb, bf);
1637
1638 bf->bf_mpdu = skb;
1639
1640 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1641 skb->len, DMA_TO_DEVICE);
1642 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1643 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001644 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1645 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301646 return -ENOMEM;
1647 }
1648
1649 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001650
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001651 bf->bf_tx_aborted = false;
1652
Sujithe8324352009-01-16 21:38:42 +05301653 return 0;
1654}
1655
1656/* FIXME: tx power */
1657static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1658 struct ath_tx_control *txctl)
1659{
Sujitha22be222009-03-30 15:28:36 +05301660 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301661 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301662 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301663 struct ath_node *an = NULL;
1664 struct list_head bf_head;
1665 struct ath_desc *ds;
1666 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301667 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301668 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301669 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301670
1671 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301672 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301673
1674 INIT_LIST_HEAD(&bf_head);
1675 list_add_tail(&bf->list, &bf_head);
1676
1677 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001678 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301679
1680 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1681 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1682
1683 ath9k_hw_filltxdesc(ah, ds,
1684 skb->len, /* segment length */
1685 true, /* first segment */
1686 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001687 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001688 bf->bf_buf_addr,
1689 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301690
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001691 if (bf->bf_state.bfs_paprd)
1692 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1693
Sujithe8324352009-01-16 21:38:42 +05301694 spin_lock_bh(&txctl->txq->axq_lock);
1695
1696 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1697 tx_info->control.sta) {
1698 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1699 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1700
Sujithc37452b2009-03-09 09:31:57 +05301701 if (!ieee80211_is_data_qos(fc)) {
1702 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1703 goto tx_done;
1704 }
1705
Felix Fietkau4fdec032010-03-12 04:02:43 +01001706 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301707 /*
1708 * Try aggregation if it's a unicast data frame
1709 * and the destination is HT capable.
1710 */
1711 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1712 } else {
1713 /*
1714 * Send this frame as regular when ADDBA
1715 * exchange is neither complete nor pending.
1716 */
Sujithc37452b2009-03-09 09:31:57 +05301717 ath_tx_send_ht_normal(sc, txctl->txq,
1718 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301719 }
1720 } else {
Sujithc37452b2009-03-09 09:31:57 +05301721 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301722 }
1723
Sujithc37452b2009-03-09 09:31:57 +05301724tx_done:
Sujithe8324352009-01-16 21:38:42 +05301725 spin_unlock_bh(&txctl->txq->axq_lock);
1726}
1727
1728/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001729int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301730 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001731{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001732 struct ath_wiphy *aphy = hw->priv;
1733 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001734 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001735 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001736 struct ath_buf *bf;
Felix Fietkau97923b12010-06-12 00:33:55 -04001737 int q, r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001738
Sujithe8324352009-01-16 21:38:42 +05301739 bf = ath_tx_get_buffer(sc);
1740 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001741 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301742 return -1;
1743 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001745 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301746 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001747 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748
Sujithe8324352009-01-16 21:38:42 +05301749 /* upon ath_tx_processq() this TX queue will be resumed, we
1750 * guarantee this will happen by knowing beforehand that
1751 * we will at least have to run TX completionon one buffer
1752 * on the queue */
1753 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001754 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001755 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301756 txq->stopped = 1;
1757 }
1758 spin_unlock_bh(&txq->axq_lock);
1759
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001760 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301761
1762 return r;
1763 }
1764
Felix Fietkau97923b12010-06-12 00:33:55 -04001765 q = skb_get_queue_mapping(skb);
1766 if (q >= 4)
1767 q = 0;
1768
1769 spin_lock_bh(&txq->axq_lock);
1770 if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
1771 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1772 txq->stopped = 1;
1773 }
1774 spin_unlock_bh(&txq->axq_lock);
1775
Sujithe8324352009-01-16 21:38:42 +05301776 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001777
1778 return 0;
1779}
1780
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001781void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001782{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001783 struct ath_wiphy *aphy = hw->priv;
1784 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001785 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001786 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1787 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301788 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1789 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001790
Sujithe8324352009-01-16 21:38:42 +05301791 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001792
Sujithe8324352009-01-16 21:38:42 +05301793 /*
1794 * As a temporary workaround, assign seq# here; this will likely need
1795 * to be cleaned up to work better with Beacon transmission and virtual
1796 * BSSes.
1797 */
1798 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301799 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1800 sc->tx.seq_no += 0x10;
1801 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1802 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001803 }
1804
Sujithe8324352009-01-16 21:38:42 +05301805 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001806 padpos = ath9k_cmn_padpos(hdr->frame_control);
1807 padsize = padpos & 3;
1808 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301809 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001810 ath_print(common, ATH_DBG_XMIT,
1811 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301812 dev_kfree_skb_any(skb);
1813 return;
1814 }
1815 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001816 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001817 }
1818
Sujithe8324352009-01-16 21:38:42 +05301819 txctl.txq = sc->beacon.cabq;
1820
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001821 ath_print(common, ATH_DBG_XMIT,
1822 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301823
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001824 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001825 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301826 goto exit;
1827 }
1828
1829 return;
1830exit:
1831 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001832}
1833
Sujithe8324352009-01-16 21:38:42 +05301834/*****************/
1835/* TX Completion */
1836/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001837
Sujithe8324352009-01-16 21:38:42 +05301838static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001839 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001840{
Sujithe8324352009-01-16 21:38:42 +05301841 struct ieee80211_hw *hw = sc->hw;
1842 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001843 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001844 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001845 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301846
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001847 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301848
Felix Fietkau827e69b2009-11-15 23:09:25 +01001849 if (aphy)
1850 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301851
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301852 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301853 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301854
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301855 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301856 /* Frame was ACKed */
1857 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1858 }
1859
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001860 padpos = ath9k_cmn_padpos(hdr->frame_control);
1861 padsize = padpos & 3;
1862 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301863 /*
1864 * Remove MAC header padding before giving the frame back to
1865 * mac80211.
1866 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001867 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301868 skb_pull(skb, padsize);
1869 }
1870
Sujith1b04b932010-01-08 10:36:05 +05301871 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1872 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001873 ath_print(common, ATH_DBG_PS,
1874 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001875 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301876 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1877 PS_WAIT_FOR_CAB |
1878 PS_WAIT_FOR_PSPOLL_DATA |
1879 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001880 }
1881
Felix Fietkau827e69b2009-11-15 23:09:25 +01001882 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001883 ath9k_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001884 else {
1885 q = skb_get_queue_mapping(skb);
1886 if (q >= 4)
1887 q = 0;
1888
1889 if (--sc->tx.pending_frames[q] < 0)
1890 sc->tx.pending_frames[q] = 0;
1891
Felix Fietkau827e69b2009-11-15 23:09:25 +01001892 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001893 }
Sujithe8324352009-01-16 21:38:42 +05301894}
1895
1896static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001897 struct ath_txq *txq, struct list_head *bf_q,
1898 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301899{
1900 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301901 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301902 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301903
Sujithe8324352009-01-16 21:38:42 +05301904 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301905 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301906
1907 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301908 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301909
1910 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301911 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301912 }
1913
1914 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001915
1916 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001917 if (time_after(jiffies,
1918 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001919 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001920 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001921 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001922 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001923 } else {
1924 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
1925 ath_debug_stat_tx(sc, txq, bf, ts);
1926 }
Sujithe8324352009-01-16 21:38:42 +05301927
1928 /*
1929 * Return the list of ath_buf of this mpdu to free queue
1930 */
1931 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1932 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1933 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1934}
1935
1936static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001937 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301938{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001939 u16 seq_st = 0;
1940 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301941 int ba_index;
1942 int nbad = 0;
1943 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001944
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001945 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301946 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301947
Sujithcd3d39a2008-08-11 14:03:34 +05301948 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001949 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001950 seq_st = ts->ts_seqnum;
1951 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001952 }
1953
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001954 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301955 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1956 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1957 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001958
Sujithe8324352009-01-16 21:38:42 +05301959 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001960 }
1961
Sujithe8324352009-01-16 21:38:42 +05301962 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001963}
1964
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001965static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301966 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301967{
Sujitha22be222009-03-30 15:28:36 +05301968 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301969 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301970 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001971 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301972 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301973
Sujith95e4acb2009-03-13 08:56:09 +05301974 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001975 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301976
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001977 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301978 WARN_ON(tx_rateindex >= hw->max_rates);
1979
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001980 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301981 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01001982 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
1983 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301984
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001985 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301986 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05301987 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001988 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01001989 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
1990 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001991 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
1992 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01001993 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
1994 tx_info->status.ampdu_len = bf->bf_nframes;
1995 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05301996 }
1997 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301998
Felix Fietkau545750d2009-11-23 22:21:01 +01001999 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302000 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002001 tx_info->status.rates[i].idx = -1;
2002 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302003
Felix Fietkau78c46532010-06-25 01:26:16 +02002004 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302005}
2006
Sujith059d8062009-01-16 21:38:49 +05302007static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2008{
2009 int qnum;
2010
Felix Fietkau97923b12010-06-12 00:33:55 -04002011 qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
2012 if (qnum == -1)
2013 return;
2014
Sujith059d8062009-01-16 21:38:49 +05302015 spin_lock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04002016 if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07002017 if (ath_mac80211_start_queue(sc, qnum))
2018 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05302019 }
2020 spin_unlock_bh(&txq->axq_lock);
2021}
2022
Sujithc4288392008-11-18 09:09:30 +05302023static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002024{
Sujithcbe61d82009-02-09 13:27:12 +05302025 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002026 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002027 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2028 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302029 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002030 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302031 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002032 int status;
2033
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002034 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2035 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2036 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002037
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002038 for (;;) {
2039 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002040 if (list_empty(&txq->axq_q)) {
2041 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002042 spin_unlock_bh(&txq->axq_lock);
2043 break;
2044 }
2045 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2046
2047 /*
2048 * There is a race condition that a BH gets scheduled
2049 * after sw writes TxE and before hw re-load the last
2050 * descriptor to get the newly chained one.
2051 * Software must keep the last DONE descriptor as a
2052 * holding descriptor - software does so by marking
2053 * it with the STALE flag.
2054 */
2055 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302056 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002057 bf_held = bf;
2058 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302059 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060 break;
2061 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002062 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302063 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002064 }
2065 }
2066
2067 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302068 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069
Felix Fietkau29bffa92010-03-29 20:14:23 -07002070 memset(&ts, 0, sizeof(ts));
2071 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002072 if (status == -EINPROGRESS) {
2073 spin_unlock_bh(&txq->axq_lock);
2074 break;
2075 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076
2077 /*
2078 * Remove ath_buf's of the same transmit unit from txq,
2079 * however leave the last descriptor back as the holding
2080 * descriptor for hw.
2081 */
Sujitha119cc42009-03-30 15:28:38 +05302082 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002083 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084 if (!list_is_singular(&lastbf->list))
2085 list_cut_position(&bf_head,
2086 &txq->axq_q, lastbf->list.prev);
2087
2088 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002089 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002090 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002091 if (bf_held)
2092 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002093 spin_unlock_bh(&txq->axq_lock);
2094
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002095 if (bf_held)
2096 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002097
Sujithcd3d39a2008-08-11 14:03:34 +05302098 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002099 /*
2100 * This frame is sent out as a single frame.
2101 * Use hardware retry status for this frame.
2102 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002103 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302104 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002105 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002106 }
Johannes Berge6a98542008-10-21 12:40:02 +02002107
Sujithcd3d39a2008-08-11 14:03:34 +05302108 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002109 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002110 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002111 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002112
Sujith059d8062009-01-16 21:38:49 +05302113 ath_wake_mac80211_queue(sc, txq);
2114
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002115 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302116 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117 ath_txq_schedule(sc, txq);
2118 spin_unlock_bh(&txq->axq_lock);
2119 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002120}
2121
Sujith305fe472009-07-23 15:32:29 +05302122static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002123{
2124 struct ath_softc *sc = container_of(work, struct ath_softc,
2125 tx_complete_work.work);
2126 struct ath_txq *txq;
2127 int i;
2128 bool needreset = false;
2129
2130 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2131 if (ATH_TXQ_SETUP(sc, i)) {
2132 txq = &sc->tx.txq[i];
2133 spin_lock_bh(&txq->axq_lock);
2134 if (txq->axq_depth) {
2135 if (txq->axq_tx_inprogress) {
2136 needreset = true;
2137 spin_unlock_bh(&txq->axq_lock);
2138 break;
2139 } else {
2140 txq->axq_tx_inprogress = true;
2141 }
2142 }
2143 spin_unlock_bh(&txq->axq_lock);
2144 }
2145
2146 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002147 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2148 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302149 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002150 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302151 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002152 }
2153
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002154 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002155 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2156}
2157
2158
Sujithe8324352009-01-16 21:38:42 +05302159
2160void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002161{
Sujithe8324352009-01-16 21:38:42 +05302162 int i;
2163 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164
Sujithe8324352009-01-16 21:38:42 +05302165 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002166
2167 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302168 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2169 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002170 }
2171}
2172
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002173void ath_tx_edma_tasklet(struct ath_softc *sc)
2174{
2175 struct ath_tx_status txs;
2176 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2177 struct ath_hw *ah = sc->sc_ah;
2178 struct ath_txq *txq;
2179 struct ath_buf *bf, *lastbf;
2180 struct list_head bf_head;
2181 int status;
2182 int txok;
2183
2184 for (;;) {
2185 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2186 if (status == -EINPROGRESS)
2187 break;
2188 if (status == -EIO) {
2189 ath_print(common, ATH_DBG_XMIT,
2190 "Error processing tx status\n");
2191 break;
2192 }
2193
2194 /* Skip beacon completions */
2195 if (txs.qid == sc->beacon.beaconq)
2196 continue;
2197
2198 txq = &sc->tx.txq[txs.qid];
2199
2200 spin_lock_bh(&txq->axq_lock);
2201 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2202 spin_unlock_bh(&txq->axq_lock);
2203 return;
2204 }
2205
2206 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2207 struct ath_buf, list);
2208 lastbf = bf->bf_lastbf;
2209
2210 INIT_LIST_HEAD(&bf_head);
2211 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2212 &lastbf->list);
2213 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2214 txq->axq_depth--;
2215 txq->axq_tx_inprogress = false;
2216 spin_unlock_bh(&txq->axq_lock);
2217
2218 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2219
2220 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002221 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2222 bf->bf_state.bf_type |= BUF_XRETRY;
2223 ath_tx_rc_status(bf, &txs, 0, txok, true);
2224 }
2225
2226 if (bf_isampdu(bf))
2227 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2228 else
2229 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2230 &txs, txok, 0);
2231
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002232 ath_wake_mac80211_queue(sc, txq);
2233
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002234 spin_lock_bh(&txq->axq_lock);
2235 if (!list_empty(&txq->txq_fifo_pending)) {
2236 INIT_LIST_HEAD(&bf_head);
2237 bf = list_first_entry(&txq->txq_fifo_pending,
2238 struct ath_buf, list);
2239 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2240 &bf->bf_lastbf->list);
2241 ath_tx_txqaddbuf(sc, txq, &bf_head);
2242 } else if (sc->sc_flags & SC_OP_TXAGGR)
2243 ath_txq_schedule(sc, txq);
2244 spin_unlock_bh(&txq->axq_lock);
2245 }
2246}
2247
Sujithe8324352009-01-16 21:38:42 +05302248/*****************/
2249/* Init, Cleanup */
2250/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002251
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002252static int ath_txstatus_setup(struct ath_softc *sc, int size)
2253{
2254 struct ath_descdma *dd = &sc->txsdma;
2255 u8 txs_len = sc->sc_ah->caps.txs_len;
2256
2257 dd->dd_desc_len = size * txs_len;
2258 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2259 &dd->dd_desc_paddr, GFP_KERNEL);
2260 if (!dd->dd_desc)
2261 return -ENOMEM;
2262
2263 return 0;
2264}
2265
2266static int ath_tx_edma_init(struct ath_softc *sc)
2267{
2268 int err;
2269
2270 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2271 if (!err)
2272 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2273 sc->txsdma.dd_desc_paddr,
2274 ATH_TXSTATUS_RING_SIZE);
2275
2276 return err;
2277}
2278
2279static void ath_tx_edma_cleanup(struct ath_softc *sc)
2280{
2281 struct ath_descdma *dd = &sc->txsdma;
2282
2283 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2284 dd->dd_desc_paddr);
2285}
2286
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002287int ath_tx_init(struct ath_softc *sc, int nbufs)
2288{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002289 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002290 int error = 0;
2291
Sujith797fe5c2009-03-30 15:28:45 +05302292 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002293
Sujith797fe5c2009-03-30 15:28:45 +05302294 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002295 "tx", nbufs, 1, 1);
Sujith797fe5c2009-03-30 15:28:45 +05302296 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002297 ath_print(common, ATH_DBG_FATAL,
2298 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5c2009-03-30 15:28:45 +05302299 goto err;
2300 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002301
Sujith797fe5c2009-03-30 15:28:45 +05302302 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002303 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5c2009-03-30 15:28:45 +05302304 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002305 ath_print(common, ATH_DBG_FATAL,
2306 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5c2009-03-30 15:28:45 +05302307 goto err;
2308 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002309
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002310 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2311
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002312 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2313 error = ath_tx_edma_init(sc);
2314 if (error)
2315 goto err;
2316 }
2317
Sujith797fe5c2009-03-30 15:28:45 +05302318err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002319 if (error != 0)
2320 ath_tx_cleanup(sc);
2321
2322 return error;
2323}
2324
Sujith797fe5c2009-03-30 15:28:45 +05302325void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002326{
Sujithb77f4832008-12-07 21:44:03 +05302327 if (sc->beacon.bdma.dd_desc_len != 0)
2328 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002329
Sujithb77f4832008-12-07 21:44:03 +05302330 if (sc->tx.txdma.dd_desc_len != 0)
2331 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002332
2333 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2334 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002335}
2336
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002337void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2338{
Sujithc5170162008-10-29 10:13:59 +05302339 struct ath_atx_tid *tid;
2340 struct ath_atx_ac *ac;
2341 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002342
Sujith8ee5afb2008-12-07 21:43:36 +05302343 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302344 tidno < WME_NUM_TID;
2345 tidno++, tid++) {
2346 tid->an = an;
2347 tid->tidno = tidno;
2348 tid->seq_start = tid->seq_next = 0;
2349 tid->baw_size = WME_MAX_BA;
2350 tid->baw_head = tid->baw_tail = 0;
2351 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302352 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302353 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302354 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302355 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302356 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302357 tid->state &= ~AGGR_ADDBA_COMPLETE;
2358 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302359 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002360
Sujith8ee5afb2008-12-07 21:43:36 +05302361 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302362 acno < WME_NUM_AC; acno++, ac++) {
2363 ac->sched = false;
Felix Fietkau1d2231e2010-06-12 00:33:51 -04002364 ac->qnum = sc->tx.hwq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302365 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366 }
2367}
2368
Sujithb5aa9bf2008-10-29 10:13:31 +05302369void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002370{
Felix Fietkau2b409942010-07-07 19:42:08 +02002371 struct ath_atx_ac *ac;
2372 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002373 struct ath_txq *txq;
Felix Fietkau2b409942010-07-07 19:42:08 +02002374 int i, tidno;
Sujithe8324352009-01-16 21:38:42 +05302375
Felix Fietkau2b409942010-07-07 19:42:08 +02002376 for (tidno = 0, tid = &an->tid[tidno];
2377 tidno < WME_NUM_TID; tidno++, tid++) {
2378 i = tid->ac->qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002379
Felix Fietkau2b409942010-07-07 19:42:08 +02002380 if (!ATH_TXQ_SETUP(sc, i))
2381 continue;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002382
Felix Fietkau2b409942010-07-07 19:42:08 +02002383 txq = &sc->tx.txq[i];
2384 ac = tid->ac;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002385
Felix Fietkau2b409942010-07-07 19:42:08 +02002386 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002387
Felix Fietkau2b409942010-07-07 19:42:08 +02002388 if (tid->sched) {
2389 list_del(&tid->list);
2390 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002391 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002392
2393 if (ac->sched) {
2394 list_del(&ac->list);
2395 tid->ac->sched = false;
2396 }
2397
2398 ath_tid_drain(sc, txq, tid);
2399 tid->state &= ~AGGR_ADDBA_COMPLETE;
2400 tid->state &= ~AGGR_CLEANUP;
2401
2402 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002403 }
2404}