blob: ec124fbe817727883c7482ccc52601350b32409c [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);
Sujithe8324352009-01-16 21:38:42 +053064
Felix Fietkau545750d2009-11-23 22:21:01 +010065enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020066 MCS_HT20,
67 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010068 MCS_HT40,
69 MCS_HT40_SGI,
70};
71
Felix Fietkau0e668cd2010-04-19 19:57:32 +020072static int ath_max_4ms_framelen[4][32] = {
73 [MCS_HT20] = {
74 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
75 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
76 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
77 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
78 },
79 [MCS_HT20_SGI] = {
80 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
81 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
82 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
83 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010084 },
85 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020086 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
87 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
88 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
89 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010090 },
91 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020092 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
93 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
94 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
95 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010096 }
97};
98
Sujithe8324352009-01-16 21:38:42 +053099/*********************/
100/* Aggregation logic */
101/*********************/
102
Sujithe8324352009-01-16 21:38:42 +0530103static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
104{
105 struct ath_atx_ac *ac = tid->ac;
106
107 if (tid->paused)
108 return;
109
110 if (tid->sched)
111 return;
112
113 tid->sched = true;
114 list_add_tail(&tid->list, &ac->tid_q);
115
116 if (ac->sched)
117 return;
118
119 ac->sched = true;
120 list_add_tail(&ac->list, &txq->axq_acq);
121}
122
123static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
124{
125 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
126
127 spin_lock_bh(&txq->axq_lock);
128 tid->paused++;
129 spin_unlock_bh(&txq->axq_lock);
130}
131
132static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
133{
134 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
135
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700136 BUG_ON(tid->paused <= 0);
Sujithe8324352009-01-16 21:38:42 +0530137 spin_lock_bh(&txq->axq_lock);
138
139 tid->paused--;
140
141 if (tid->paused > 0)
142 goto unlock;
143
144 if (list_empty(&tid->buf_q))
145 goto unlock;
146
147 ath_tx_queue_tid(txq, tid);
148 ath_txq_schedule(sc, txq);
149unlock:
150 spin_unlock_bh(&txq->axq_lock);
151}
152
153static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
154{
155 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
156 struct ath_buf *bf;
157 struct list_head bf_head;
158 INIT_LIST_HEAD(&bf_head);
159
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700160 BUG_ON(tid->paused <= 0);
Sujithe8324352009-01-16 21:38:42 +0530161 spin_lock_bh(&txq->axq_lock);
162
163 tid->paused--;
164
165 if (tid->paused > 0) {
166 spin_unlock_bh(&txq->axq_lock);
167 return;
168 }
169
170 while (!list_empty(&tid->buf_q)) {
171 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700172 BUG_ON(bf_isretried(bf));
Sujithd43f30152009-01-16 21:38:53 +0530173 list_move_tail(&bf->list, &bf_head);
Sujithc37452b2009-03-09 09:31:57 +0530174 ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530175 }
176
177 spin_unlock_bh(&txq->axq_lock);
178}
179
180static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
181 int seqno)
182{
183 int index, cindex;
184
185 index = ATH_BA_INDEX(tid->seq_start, seqno);
186 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
187
188 tid->tx_buf[cindex] = NULL;
189
190 while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
191 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
192 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
193 }
194}
195
196static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
197 struct ath_buf *bf)
198{
199 int index, cindex;
200
201 if (bf_isretried(bf))
202 return;
203
204 index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
205 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
206
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700207 BUG_ON(tid->tx_buf[cindex] != NULL);
Sujithe8324352009-01-16 21:38:42 +0530208 tid->tx_buf[cindex] = bf;
209
210 if (index >= ((tid->baw_tail - tid->baw_head) &
211 (ATH_TID_MAX_BUFS - 1))) {
212 tid->baw_tail = cindex;
213 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
214 }
215}
216
217/*
218 * TODO: For frame(s) that are in the retry state, we will reuse the
219 * sequence number(s) without setting the retry bit. The
220 * alternative is to give up on these and BAR the receiver's window
221 * forward.
222 */
223static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
224 struct ath_atx_tid *tid)
225
226{
227 struct ath_buf *bf;
228 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700229 struct ath_tx_status ts;
230
231 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530232 INIT_LIST_HEAD(&bf_head);
233
234 for (;;) {
235 if (list_empty(&tid->buf_q))
236 break;
Sujithe8324352009-01-16 21:38:42 +0530237
Sujithd43f30152009-01-16 21:38:53 +0530238 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
239 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530240
241 if (bf_isretried(bf))
242 ath_tx_update_baw(sc, tid, bf->bf_seqno);
243
244 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700245 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530246 spin_lock(&txq->axq_lock);
247 }
248
249 tid->seq_next = tid->seq_start;
250 tid->baw_tail = tid->baw_head;
251}
252
Sujithfec247c2009-07-27 12:08:16 +0530253static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
254 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530255{
256 struct sk_buff *skb;
257 struct ieee80211_hdr *hdr;
258
259 bf->bf_state.bf_type |= BUF_RETRY;
260 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530261 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530262
263 skb = bf->bf_mpdu;
264 hdr = (struct ieee80211_hdr *)skb->data;
265 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
266}
267
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200268static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
269{
270 struct ath_buf *bf = NULL;
271
272 spin_lock_bh(&sc->tx.txbuflock);
273
274 if (unlikely(list_empty(&sc->tx.txbuf))) {
275 spin_unlock_bh(&sc->tx.txbuflock);
276 return NULL;
277 }
278
279 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
280 list_del(&bf->list);
281
282 spin_unlock_bh(&sc->tx.txbuflock);
283
284 return bf;
285}
286
287static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
288{
289 spin_lock_bh(&sc->tx.txbuflock);
290 list_add_tail(&bf->list, &sc->tx.txbuf);
291 spin_unlock_bh(&sc->tx.txbuflock);
292}
293
Sujithd43f30152009-01-16 21:38:53 +0530294static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
295{
296 struct ath_buf *tbf;
297
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200298 tbf = ath_tx_get_buffer(sc);
299 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530300 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530301
302 ATH_TXBUF_RESET(tbf);
303
Felix Fietkau827e69b2009-11-15 23:09:25 +0100304 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530305 tbf->bf_mpdu = bf->bf_mpdu;
306 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400307 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530308 tbf->bf_state = bf->bf_state;
309 tbf->bf_dmacontext = bf->bf_dmacontext;
310
311 return tbf;
312}
313
314static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
315 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700316 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530317{
318 struct ath_node *an = NULL;
319 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530320 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800321 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530322 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800323 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530324 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530325 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530326 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530327 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530328 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530329 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
330 bool rc_update = true;
Sujithe8324352009-01-16 21:38:42 +0530331
Sujitha22be222009-03-30 15:28:36 +0530332 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530333 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530334
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800335 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100336 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800337
Sujith1286ec62009-01-27 13:30:37 +0530338 rcu_read_lock();
339
Johannes Berg5ed176e2009-11-04 14:42:28 +0100340 /* XXX: use ieee80211_find_sta! */
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800341 sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
Sujith1286ec62009-01-27 13:30:37 +0530342 if (!sta) {
343 rcu_read_unlock();
344 return;
Sujithe8324352009-01-16 21:38:42 +0530345 }
346
Sujith1286ec62009-01-27 13:30:37 +0530347 an = (struct ath_node *)sta->drv_priv;
348 tid = ATH_AN_2_TID(an, bf->bf_tidno);
349
Sujithe8324352009-01-16 21:38:42 +0530350 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530351 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530352
Sujithd43f30152009-01-16 21:38:53 +0530353 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700354 if (ts->ts_flags & ATH9K_TX_BA) {
355 seq_st = ts->ts_seqnum;
356 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530357 } else {
Sujithd43f30152009-01-16 21:38:53 +0530358 /*
359 * AR5416 can become deaf/mute when BA
360 * issue happens. Chip needs to be reset.
361 * But AP code may have sychronization issues
362 * when perform internal reset in this routine.
363 * Only enable reset in STA mode for now.
364 */
Sujith2660b812009-02-09 13:27:26 +0530365 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530366 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530367 }
368 }
369
370 INIT_LIST_HEAD(&bf_pending);
371 INIT_LIST_HEAD(&bf_head);
372
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700373 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530374 while (bf) {
375 txfail = txpending = 0;
376 bf_next = bf->bf_next;
377
378 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
379 /* transmit completion, subframe is
380 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530381 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530382 } else if (!isaggr && txok) {
383 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530384 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530385 } else {
Sujithe8324352009-01-16 21:38:42 +0530386 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400387 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530388 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530389 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530390 txpending = 1;
391 } else {
392 bf->bf_state.bf_type |= BUF_XRETRY;
393 txfail = 1;
394 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530395 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530396 }
397 } else {
398 /*
399 * cleanup in progress, just fail
400 * the un-acked sub-frames
401 */
402 txfail = 1;
403 }
404 }
405
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400406 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
407 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530408 /*
409 * Make sure the last desc is reclaimed if it
410 * not a holding desc.
411 */
412 if (!bf_last->bf_stale)
413 list_move_tail(&bf->list, &bf_head);
414 else
415 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530416 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700417 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530418 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530419 }
420
421 if (!txpending) {
422 /*
423 * complete the acked-ones/xretried ones; update
424 * block-ack window
425 */
426 spin_lock_bh(&txq->axq_lock);
427 ath_tx_update_baw(sc, tid, bf->bf_seqno);
428 spin_unlock_bh(&txq->axq_lock);
429
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530430 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700431 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530432 rc_update = false;
433 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700434 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530435 }
436
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700437 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
438 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530439 } else {
Sujithd43f30152009-01-16 21:38:53 +0530440 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400441 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
442 if (bf->bf_next == NULL && bf_last->bf_stale) {
443 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530444
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400445 tbf = ath_clone_txbuf(sc, bf_last);
446 /*
447 * Update tx baw and complete the
448 * frame with failed status if we
449 * run out of tx buf.
450 */
451 if (!tbf) {
452 spin_lock_bh(&txq->axq_lock);
453 ath_tx_update_baw(sc, tid,
454 bf->bf_seqno);
455 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400456
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400457 bf->bf_state.bf_type |=
458 BUF_XRETRY;
459 ath_tx_rc_status(bf, ts, nbad,
460 0, false);
461 ath_tx_complete_buf(sc, bf, txq,
462 &bf_head,
463 ts, 0, 0);
464 break;
465 }
466
467 ath9k_hw_cleartxdesc(sc->sc_ah,
468 tbf->bf_desc);
469 list_add_tail(&tbf->list, &bf_head);
470 } else {
471 /*
472 * Clear descriptor status words for
473 * software retry
474 */
475 ath9k_hw_cleartxdesc(sc->sc_ah,
476 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400477 }
Sujithe8324352009-01-16 21:38:42 +0530478 }
479
480 /*
481 * Put this buffer to the temporary pending
482 * queue to retain ordering
483 */
484 list_splice_tail_init(&bf_head, &bf_pending);
485 }
486
487 bf = bf_next;
488 }
489
490 if (tid->state & AGGR_CLEANUP) {
Sujithe8324352009-01-16 21:38:42 +0530491 if (tid->baw_head == tid->baw_tail) {
492 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530493 tid->state &= ~AGGR_CLEANUP;
494
495 /* send buffered frames as singles */
496 ath_tx_flush_tid(sc, tid);
Sujithd43f30152009-01-16 21:38:53 +0530497 }
Sujith1286ec62009-01-27 13:30:37 +0530498 rcu_read_unlock();
Sujithe8324352009-01-16 21:38:42 +0530499 return;
500 }
501
Sujithd43f30152009-01-16 21:38:53 +0530502 /* prepend un-acked frames to the beginning of the pending frame queue */
Sujithe8324352009-01-16 21:38:42 +0530503 if (!list_empty(&bf_pending)) {
504 spin_lock_bh(&txq->axq_lock);
505 list_splice(&bf_pending, &tid->buf_q);
506 ath_tx_queue_tid(txq, tid);
507 spin_unlock_bh(&txq->axq_lock);
508 }
509
Sujith1286ec62009-01-27 13:30:37 +0530510 rcu_read_unlock();
511
Sujithe8324352009-01-16 21:38:42 +0530512 if (needreset)
513 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530514}
515
516static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
517 struct ath_atx_tid *tid)
518{
Sujithe8324352009-01-16 21:38:42 +0530519 struct sk_buff *skb;
520 struct ieee80211_tx_info *tx_info;
521 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530522 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530523 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530524 int i;
525
Sujitha22be222009-03-30 15:28:36 +0530526 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530527 tx_info = IEEE80211_SKB_CB(skb);
528 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530529
530 /*
531 * Find the lowest frame length among the rate series that will have a
532 * 4ms transmit duration.
533 * TODO - TXOP limit needs to be considered.
534 */
535 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
536
537 for (i = 0; i < 4; i++) {
538 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100539 int modeidx;
540 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530541 legacy = 1;
542 break;
543 }
544
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200545 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100546 modeidx = MCS_HT40;
547 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200548 modeidx = MCS_HT20;
549
550 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
551 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100552
553 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530554 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530555 }
556 }
557
558 /*
559 * limit aggregate size by the minimum rate if rate selected is
560 * not a probe rate, if rate selected is a probe rate then
561 * avoid aggregation of this packet.
562 */
563 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
564 return 0;
565
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530566 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
567 aggr_limit = min((max_4ms_framelen * 3) / 8,
568 (u32)ATH_AMPDU_LIMIT_MAX);
569 else
570 aggr_limit = min(max_4ms_framelen,
571 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530572
573 /*
574 * h/w can accept aggregates upto 16 bit lengths (65535).
575 * The IE, however can hold upto 65536, which shows up here
576 * as zero. Ignore 65536 since we are constrained by hw.
577 */
Sujith4ef70842009-07-23 15:32:41 +0530578 if (tid->an->maxampdu)
579 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530580
581 return aggr_limit;
582}
583
584/*
Sujithd43f30152009-01-16 21:38:53 +0530585 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530586 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530587 */
588static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
589 struct ath_buf *bf, u16 frmlen)
590{
Sujithe8324352009-01-16 21:38:42 +0530591 struct sk_buff *skb = bf->bf_mpdu;
592 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530593 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530594 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100595 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200596 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530597
598 /* Select standard number of delimiters based on frame length alone */
599 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
600
601 /*
602 * If encryption enabled, hardware requires some more padding between
603 * subframes.
604 * TODO - this could be improved to be dependent on the rate.
605 * The hardware can keep up at lower rates, but not higher rates
606 */
607 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
608 ndelim += ATH_AGGR_ENCRYPTDELIM;
609
610 /*
611 * Convert desired mpdu density from microeconds to bytes based
612 * on highest rate in rate series (i.e. first rate) to determine
613 * required minimum length for subframe. Take into account
614 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530615 *
Sujithe8324352009-01-16 21:38:42 +0530616 * If there is no mpdu density restriction, no further calculation
617 * is needed.
618 */
Sujith4ef70842009-07-23 15:32:41 +0530619
620 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530621 return ndelim;
622
623 rix = tx_info->control.rates[0].idx;
624 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530625 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
626 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
627
628 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530629 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530630 else
Sujith4ef70842009-07-23 15:32:41 +0530631 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530632
633 if (nsymbols == 0)
634 nsymbols = 1;
635
Felix Fietkauc6663872010-04-19 19:57:33 +0200636 streams = HT_RC_2_STREAMS(rix);
637 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530638 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
639
Sujithe8324352009-01-16 21:38:42 +0530640 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530641 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
642 ndelim = max(mindelim, ndelim);
643 }
644
645 return ndelim;
646}
647
648static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530649 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530650 struct ath_atx_tid *tid,
651 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530652{
653#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530654 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
655 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530656 u16 aggr_limit = 0, al = 0, bpad = 0,
657 al_delta, h_baw = tid->baw_size / 2;
658 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Sujithe8324352009-01-16 21:38:42 +0530659
660 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
661
662 do {
663 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
664
Sujithd43f30152009-01-16 21:38:53 +0530665 /* do not step over block-ack window */
Sujithe8324352009-01-16 21:38:42 +0530666 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
667 status = ATH_AGGR_BAW_CLOSED;
668 break;
669 }
670
671 if (!rl) {
672 aggr_limit = ath_lookup_rate(sc, bf, tid);
673 rl = 1;
674 }
675
Sujithd43f30152009-01-16 21:38:53 +0530676 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530677 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
678
Sujithd43f30152009-01-16 21:38:53 +0530679 if (nframes &&
680 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530681 status = ATH_AGGR_LIMITED;
682 break;
683 }
684
Sujithd43f30152009-01-16 21:38:53 +0530685 /* do not exceed subframe limit */
686 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530687 status = ATH_AGGR_LIMITED;
688 break;
689 }
Sujithd43f30152009-01-16 21:38:53 +0530690 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530691
Sujithd43f30152009-01-16 21:38:53 +0530692 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530693 al += bpad + al_delta;
694
695 /*
696 * Get the delimiters needed to meet the MPDU
697 * density for this node.
698 */
699 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530700 bpad = PADBYTES(al_delta) + (ndelim << 2);
701
702 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400703 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530704
Sujithd43f30152009-01-16 21:38:53 +0530705 /* link buffers of this frame to the aggregate */
Sujithe8324352009-01-16 21:38:42 +0530706 ath_tx_addto_baw(sc, tid, bf);
Sujithd43f30152009-01-16 21:38:53 +0530707 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
708 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530709 if (bf_prev) {
710 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400711 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
712 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530713 }
714 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530715
Sujithe8324352009-01-16 21:38:42 +0530716 } while (!list_empty(&tid->buf_q));
717
718 bf_first->bf_al = al;
719 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530720
Sujithe8324352009-01-16 21:38:42 +0530721 return status;
722#undef PADBYTES
723}
724
725static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
726 struct ath_atx_tid *tid)
727{
Sujithd43f30152009-01-16 21:38:53 +0530728 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530729 enum ATH_AGGR_STATUS status;
730 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530731
732 do {
733 if (list_empty(&tid->buf_q))
734 return;
735
736 INIT_LIST_HEAD(&bf_q);
737
Sujithfec247c2009-07-27 12:08:16 +0530738 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530739
740 /*
Sujithd43f30152009-01-16 21:38:53 +0530741 * no frames picked up to be aggregated;
742 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530743 */
744 if (list_empty(&bf_q))
745 break;
746
747 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530748 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530749
Sujithd43f30152009-01-16 21:38:53 +0530750 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530751 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530752 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530753 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530754 ath_buf_set_rate(sc, bf);
755 ath_tx_txqaddbuf(sc, txq, &bf_q);
756 continue;
757 }
758
Sujithd43f30152009-01-16 21:38:53 +0530759 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530760 bf->bf_state.bf_type |= BUF_AGGR;
761 ath_buf_set_rate(sc, bf);
762 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
763
Sujithd43f30152009-01-16 21:38:53 +0530764 /* anchor last desc of aggregate */
765 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530766
Sujithe8324352009-01-16 21:38:42 +0530767 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530768 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530769
770 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
771 status != ATH_AGGR_BAW_CLOSED);
772}
773
Sujithf83da962009-07-23 15:32:37 +0530774void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
775 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530776{
777 struct ath_atx_tid *txtid;
778 struct ath_node *an;
779
780 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530781 txtid = ATH_AN_2_TID(an, tid);
782 txtid->state |= AGGR_ADDBA_PROGRESS;
783 ath_tx_pause_tid(sc, txtid);
784 *ssn = txtid->seq_start;
Sujithe8324352009-01-16 21:38:42 +0530785}
786
Sujithf83da962009-07-23 15:32:37 +0530787void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530788{
789 struct ath_node *an = (struct ath_node *)sta->drv_priv;
790 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
791 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700792 struct ath_tx_status ts;
Sujithe8324352009-01-16 21:38:42 +0530793 struct ath_buf *bf;
794 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700795
796 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530797 INIT_LIST_HEAD(&bf_head);
798
799 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530800 return;
Sujithe8324352009-01-16 21:38:42 +0530801
802 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530803 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530804 return;
Sujithe8324352009-01-16 21:38:42 +0530805 }
806
807 ath_tx_pause_tid(sc, txtid);
808
809 /* drop all software retried frames and mark this TID */
810 spin_lock_bh(&txq->axq_lock);
811 while (!list_empty(&txtid->buf_q)) {
812 bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
813 if (!bf_isretried(bf)) {
814 /*
815 * NB: it's based on the assumption that
816 * software retried frame will always stay
817 * at the head of software queue.
818 */
819 break;
820 }
Sujithd43f30152009-01-16 21:38:53 +0530821 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530822 ath_tx_update_baw(sc, txtid, bf->bf_seqno);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700823 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530824 }
Sujithd43f30152009-01-16 21:38:53 +0530825 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530826
827 if (txtid->baw_head != txtid->baw_tail) {
Sujithe8324352009-01-16 21:38:42 +0530828 txtid->state |= AGGR_CLEANUP;
829 } else {
830 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530831 ath_tx_flush_tid(sc, txtid);
832 }
Sujithe8324352009-01-16 21:38:42 +0530833}
834
835void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
836{
837 struct ath_atx_tid *txtid;
838 struct ath_node *an;
839
840 an = (struct ath_node *)sta->drv_priv;
841
842 if (sc->sc_flags & SC_OP_TXAGGR) {
843 txtid = ATH_AN_2_TID(an, tid);
844 txtid->baw_size =
845 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
846 txtid->state |= AGGR_ADDBA_COMPLETE;
847 txtid->state &= ~AGGR_ADDBA_PROGRESS;
848 ath_tx_resume_tid(sc, txtid);
849 }
850}
851
852bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
853{
854 struct ath_atx_tid *txtid;
855
856 if (!(sc->sc_flags & SC_OP_TXAGGR))
857 return false;
858
859 txtid = ATH_AN_2_TID(an, tidno);
860
Vasanthakumar Thiagarajanc3d8f022009-06-10 17:50:08 +0530861 if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
Sujithe8324352009-01-16 21:38:42 +0530862 return true;
Sujithe8324352009-01-16 21:38:42 +0530863 return false;
864}
865
866/********************/
867/* Queue Management */
868/********************/
869
Sujithe8324352009-01-16 21:38:42 +0530870static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
871 struct ath_txq *txq)
872{
873 struct ath_atx_ac *ac, *ac_tmp;
874 struct ath_atx_tid *tid, *tid_tmp;
875
876 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
877 list_del(&ac->list);
878 ac->sched = false;
879 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
880 list_del(&tid->list);
881 tid->sched = false;
882 ath_tid_drain(sc, txq, tid);
883 }
884 }
885}
886
887struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
888{
Sujithcbe61d82009-02-09 13:27:12 +0530889 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700890 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530891 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400892 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530893
894 memset(&qi, 0, sizeof(qi));
895 qi.tqi_subtype = subtype;
896 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
897 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
898 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
899 qi.tqi_physCompBuf = 0;
900
901 /*
902 * Enable interrupts only for EOL and DESC conditions.
903 * We mark tx descriptors to receive a DESC interrupt
904 * when a tx queue gets deep; otherwise waiting for the
905 * EOL to reap descriptors. Note that this is done to
906 * reduce interrupt load and this only defers reaping
907 * descriptors, never transmitting frames. Aside from
908 * reducing interrupts this also permits more concurrency.
909 * The only potential downside is if the tx queue backs
910 * up in which case the top half of the kernel may backup
911 * due to a lack of tx descriptors.
912 *
913 * The UAPSD queue is an exception, since we take a desc-
914 * based intr on the EOSP frames.
915 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400916 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
917 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
918 TXQ_FLAG_TXERRINT_ENABLE;
919 } else {
920 if (qtype == ATH9K_TX_QUEUE_UAPSD)
921 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
922 else
923 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
924 TXQ_FLAG_TXDESCINT_ENABLE;
925 }
Sujithe8324352009-01-16 21:38:42 +0530926 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
927 if (qnum == -1) {
928 /*
929 * NB: don't print a message, this happens
930 * normally on parts with too few tx queues
931 */
932 return NULL;
933 }
934 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700935 ath_print(common, ATH_DBG_FATAL,
936 "qnum %u out of range, max %u!\n",
937 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530938 ath9k_hw_releasetxqueue(ah, qnum);
939 return NULL;
940 }
941 if (!ATH_TXQ_SETUP(sc, qnum)) {
942 struct ath_txq *txq = &sc->tx.txq[qnum];
943
Felix Fietkau293f2ba2010-06-12 00:33:49 -0400944 txq->axq_class = subtype;
Sujithe8324352009-01-16 21:38:42 +0530945 txq->axq_qnum = qnum;
946 txq->axq_link = NULL;
947 INIT_LIST_HEAD(&txq->axq_q);
948 INIT_LIST_HEAD(&txq->axq_acq);
949 spin_lock_init(&txq->axq_lock);
950 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400951 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530952 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400953
954 txq->txq_headidx = txq->txq_tailidx = 0;
955 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
956 INIT_LIST_HEAD(&txq->txq_fifo[i]);
957 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530958 }
959 return &sc->tx.txq[qnum];
960}
961
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530962int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
Sujithe8324352009-01-16 21:38:42 +0530963{
964 int qnum;
965
966 switch (qtype) {
967 case ATH9K_TX_QUEUE_DATA:
968 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700969 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
970 "HAL AC %u out of range, max %zu!\n",
971 haltype, ARRAY_SIZE(sc->tx.hwq_map));
Sujithe8324352009-01-16 21:38:42 +0530972 return -1;
973 }
974 qnum = sc->tx.hwq_map[haltype];
975 break;
976 case ATH9K_TX_QUEUE_BEACON:
977 qnum = sc->beacon.beaconq;
978 break;
979 case ATH9K_TX_QUEUE_CAB:
980 qnum = sc->beacon.cabq->axq_qnum;
981 break;
982 default:
983 qnum = -1;
984 }
985 return qnum;
986}
987
Sujithe8324352009-01-16 21:38:42 +0530988int ath_txq_update(struct ath_softc *sc, int qnum,
989 struct ath9k_tx_queue_info *qinfo)
990{
Sujithcbe61d82009-02-09 13:27:12 +0530991 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530992 int error = 0;
993 struct ath9k_tx_queue_info qi;
994
995 if (qnum == sc->beacon.beaconq) {
996 /*
997 * XXX: for beacon queue, we just save the parameter.
998 * It will be picked up by ath_beaconq_config when
999 * it's necessary.
1000 */
1001 sc->beacon.beacon_qi = *qinfo;
1002 return 0;
1003 }
1004
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001005 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301006
1007 ath9k_hw_get_txq_props(ah, qnum, &qi);
1008 qi.tqi_aifs = qinfo->tqi_aifs;
1009 qi.tqi_cwmin = qinfo->tqi_cwmin;
1010 qi.tqi_cwmax = qinfo->tqi_cwmax;
1011 qi.tqi_burstTime = qinfo->tqi_burstTime;
1012 qi.tqi_readyTime = qinfo->tqi_readyTime;
1013
1014 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001015 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1016 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301017 error = -EIO;
1018 } else {
1019 ath9k_hw_resettxqueue(ah, qnum);
1020 }
1021
1022 return error;
1023}
1024
1025int ath_cabq_update(struct ath_softc *sc)
1026{
1027 struct ath9k_tx_queue_info qi;
1028 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301029
1030 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1031 /*
1032 * Ensure the readytime % is within the bounds.
1033 */
Sujith17d79042009-02-09 13:27:03 +05301034 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1035 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1036 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1037 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301038
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001039 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301040 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301041 ath_txq_update(sc, qnum, &qi);
1042
1043 return 0;
1044}
1045
Sujith043a0402009-01-16 21:38:47 +05301046/*
1047 * Drain a given TX queue (could be Beacon or Data)
1048 *
1049 * This assumes output has been stopped and
1050 * we do not need to block ath_tx_tasklet.
1051 */
1052void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301053{
1054 struct ath_buf *bf, *lastbf;
1055 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001056 struct ath_tx_status ts;
1057
1058 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301059 INIT_LIST_HEAD(&bf_head);
1060
Sujithe8324352009-01-16 21:38:42 +05301061 for (;;) {
1062 spin_lock_bh(&txq->axq_lock);
1063
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001064 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1065 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1066 txq->txq_headidx = txq->txq_tailidx = 0;
1067 spin_unlock_bh(&txq->axq_lock);
1068 break;
1069 } else {
1070 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1071 struct ath_buf, list);
1072 }
1073 } else {
1074 if (list_empty(&txq->axq_q)) {
1075 txq->axq_link = NULL;
1076 spin_unlock_bh(&txq->axq_lock);
1077 break;
1078 }
1079 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1080 list);
Sujithe8324352009-01-16 21:38:42 +05301081
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001082 if (bf->bf_stale) {
1083 list_del(&bf->list);
1084 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301085
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001086 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001087 continue;
1088 }
Sujithe8324352009-01-16 21:38:42 +05301089 }
1090
1091 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001092 if (!retry_tx)
1093 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301094
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001095 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1096 list_cut_position(&bf_head,
1097 &txq->txq_fifo[txq->txq_tailidx],
1098 &lastbf->list);
1099 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1100 } else {
1101 /* remove ath_buf's of the same mpdu from txq */
1102 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1103 }
1104
Sujithe8324352009-01-16 21:38:42 +05301105 txq->axq_depth--;
1106
1107 spin_unlock_bh(&txq->axq_lock);
1108
1109 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001110 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301111 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001112 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301113 }
1114
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001115 spin_lock_bh(&txq->axq_lock);
1116 txq->axq_tx_inprogress = false;
1117 spin_unlock_bh(&txq->axq_lock);
1118
Sujithe8324352009-01-16 21:38:42 +05301119 /* flush any pending frames if aggregation is enabled */
1120 if (sc->sc_flags & SC_OP_TXAGGR) {
1121 if (!retry_tx) {
1122 spin_lock_bh(&txq->axq_lock);
1123 ath_txq_drain_pending_buffers(sc, txq);
1124 spin_unlock_bh(&txq->axq_lock);
1125 }
1126 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001127
1128 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1129 spin_lock_bh(&txq->axq_lock);
1130 while (!list_empty(&txq->txq_fifo_pending)) {
1131 bf = list_first_entry(&txq->txq_fifo_pending,
1132 struct ath_buf, list);
1133 list_cut_position(&bf_head,
1134 &txq->txq_fifo_pending,
1135 &bf->bf_lastbf->list);
1136 spin_unlock_bh(&txq->axq_lock);
1137
1138 if (bf_isampdu(bf))
1139 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1140 &ts, 0);
1141 else
1142 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1143 &ts, 0, 0);
1144 spin_lock_bh(&txq->axq_lock);
1145 }
1146 spin_unlock_bh(&txq->axq_lock);
1147 }
Sujithe8324352009-01-16 21:38:42 +05301148}
1149
Sujith043a0402009-01-16 21:38:47 +05301150void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1151{
Sujithcbe61d82009-02-09 13:27:12 +05301152 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001153 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301154 struct ath_txq *txq;
1155 int i, npend = 0;
1156
1157 if (sc->sc_flags & SC_OP_INVALID)
1158 return;
1159
1160 /* Stop beacon queue */
1161 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1162
1163 /* Stop data queues */
1164 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1165 if (ATH_TXQ_SETUP(sc, i)) {
1166 txq = &sc->tx.txq[i];
1167 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1168 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1169 }
1170 }
1171
1172 if (npend) {
1173 int r;
1174
Sujithe8009e92009-12-14 14:57:08 +05301175 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001176 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301177
1178 spin_lock_bh(&sc->sc_resetlock);
Sujithe8009e92009-12-14 14:57:08 +05301179 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
Sujith043a0402009-01-16 21:38:47 +05301180 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001181 ath_print(common, ATH_DBG_FATAL,
1182 "Unable to reset hardware; reset status %d\n",
1183 r);
Sujith043a0402009-01-16 21:38:47 +05301184 spin_unlock_bh(&sc->sc_resetlock);
1185 }
1186
1187 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1188 if (ATH_TXQ_SETUP(sc, i))
1189 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1190 }
1191}
1192
Sujithe8324352009-01-16 21:38:42 +05301193void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1194{
1195 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1196 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1197}
1198
Sujithe8324352009-01-16 21:38:42 +05301199void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1200{
1201 struct ath_atx_ac *ac;
1202 struct ath_atx_tid *tid;
1203
1204 if (list_empty(&txq->axq_acq))
1205 return;
1206
1207 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1208 list_del(&ac->list);
1209 ac->sched = false;
1210
1211 do {
1212 if (list_empty(&ac->tid_q))
1213 return;
1214
1215 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1216 list_del(&tid->list);
1217 tid->sched = false;
1218
1219 if (tid->paused)
1220 continue;
1221
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001222 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301223
1224 /*
1225 * add tid to round-robin queue if more frames
1226 * are pending for the tid
1227 */
1228 if (!list_empty(&tid->buf_q))
1229 ath_tx_queue_tid(txq, tid);
1230
1231 break;
1232 } while (!list_empty(&ac->tid_q));
1233
1234 if (!list_empty(&ac->tid_q)) {
1235 if (!ac->sched) {
1236 ac->sched = true;
1237 list_add_tail(&ac->list, &txq->axq_acq);
1238 }
1239 }
1240}
1241
1242int ath_tx_setup(struct ath_softc *sc, int haltype)
1243{
1244 struct ath_txq *txq;
1245
1246 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001247 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1248 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301249 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1250 return 0;
1251 }
1252 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1253 if (txq != NULL) {
1254 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1255 return 1;
1256 } else
1257 return 0;
1258}
1259
1260/***********/
1261/* TX, DMA */
1262/***********/
1263
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001264/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001265 * Insert a chain of ath_buf (descriptors) on a txq and
1266 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001267 */
Sujith102e0572008-10-29 10:15:16 +05301268static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1269 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001270{
Sujithcbe61d82009-02-09 13:27:12 +05301271 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001272 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301274
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001275 /*
1276 * Insert the frame on the outbound list and
1277 * pass it on to the hardware.
1278 */
1279
1280 if (list_empty(head))
1281 return;
1282
1283 bf = list_first_entry(head, struct ath_buf, list);
1284
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001285 ath_print(common, ATH_DBG_QUEUE,
1286 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001287
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001288 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1289 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1290 list_splice_tail_init(head, &txq->txq_fifo_pending);
1291 return;
1292 }
1293 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1294 ath_print(common, ATH_DBG_XMIT,
1295 "Initializing tx fifo %d which "
1296 "is non-empty\n",
1297 txq->txq_headidx);
1298 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1299 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1300 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001301 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001302 ath_print(common, ATH_DBG_XMIT,
1303 "TXDP[%u] = %llx (%p)\n",
1304 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001305 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001306 list_splice_tail_init(head, &txq->axq_q);
1307
1308 if (txq->axq_link == NULL) {
1309 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1310 ath_print(common, ATH_DBG_XMIT,
1311 "TXDP[%u] = %llx (%p)\n",
1312 txq->axq_qnum, ito64(bf->bf_daddr),
1313 bf->bf_desc);
1314 } else {
1315 *txq->axq_link = bf->bf_daddr;
1316 ath_print(common, ATH_DBG_XMIT,
1317 "link[%u] (%p)=%llx (%p)\n",
1318 txq->axq_qnum, txq->axq_link,
1319 ito64(bf->bf_daddr), bf->bf_desc);
1320 }
1321 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1322 &txq->axq_link);
1323 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001324 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001325 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001326}
1327
Sujithe8324352009-01-16 21:38:42 +05301328static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1329 struct list_head *bf_head,
1330 struct ath_tx_control *txctl)
1331{
1332 struct ath_buf *bf;
1333
Sujithe8324352009-01-16 21:38:42 +05301334 bf = list_first_entry(bf_head, struct ath_buf, list);
1335 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301336 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301337
1338 /*
1339 * Do not queue to h/w when any of the following conditions is true:
1340 * - there are pending frames in software queue
1341 * - the TID is currently paused for ADDBA/BAR request
1342 * - seqno is not within block-ack window
1343 * - h/w queue depth exceeds low water mark
1344 */
1345 if (!list_empty(&tid->buf_q) || tid->paused ||
1346 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1347 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001348 /*
Sujithe8324352009-01-16 21:38:42 +05301349 * Add this frame to software queue for scheduling later
1350 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001351 */
Sujithd43f30152009-01-16 21:38:53 +05301352 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301353 ath_tx_queue_tid(txctl->txq, tid);
1354 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001355 }
1356
Sujithe8324352009-01-16 21:38:42 +05301357 /* Add sub-frame to BAW */
1358 ath_tx_addto_baw(sc, tid, bf);
1359
1360 /* Queue to h/w without aggregation */
1361 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301362 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301363 ath_buf_set_rate(sc, bf);
1364 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301365}
1366
Sujithc37452b2009-03-09 09:31:57 +05301367static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1368 struct ath_atx_tid *tid,
1369 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001370{
Sujithe8324352009-01-16 21:38:42 +05301371 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001372
Sujithe8324352009-01-16 21:38:42 +05301373 bf = list_first_entry(bf_head, struct ath_buf, list);
1374 bf->bf_state.bf_type &= ~BUF_AMPDU;
1375
1376 /* update starting sequence number for subsequent ADDBA request */
1377 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1378
1379 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301380 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301381 ath_buf_set_rate(sc, bf);
1382 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301383 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001384}
1385
Sujithc37452b2009-03-09 09:31:57 +05301386static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1387 struct list_head *bf_head)
1388{
1389 struct ath_buf *bf;
1390
1391 bf = list_first_entry(bf_head, struct ath_buf, list);
1392
1393 bf->bf_lastbf = bf;
1394 bf->bf_nframes = 1;
1395 ath_buf_set_rate(sc, bf);
1396 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301397 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301398}
1399
Sujith528f0c62008-10-29 10:14:26 +05301400static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001401{
Sujith528f0c62008-10-29 10:14:26 +05301402 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001403 enum ath9k_pkt_type htype;
1404 __le16 fc;
1405
Sujith528f0c62008-10-29 10:14:26 +05301406 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001407 fc = hdr->frame_control;
1408
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409 if (ieee80211_is_beacon(fc))
1410 htype = ATH9K_PKT_TYPE_BEACON;
1411 else if (ieee80211_is_probe_resp(fc))
1412 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1413 else if (ieee80211_is_atim(fc))
1414 htype = ATH9K_PKT_TYPE_ATIM;
1415 else if (ieee80211_is_pspoll(fc))
1416 htype = ATH9K_PKT_TYPE_PSPOLL;
1417 else
1418 htype = ATH9K_PKT_TYPE_NORMAL;
1419
1420 return htype;
1421}
1422
Sujith528f0c62008-10-29 10:14:26 +05301423static int get_hw_crypto_keytype(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001424{
Sujith528f0c62008-10-29 10:14:26 +05301425 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1426
1427 if (tx_info->control.hw_key) {
1428 if (tx_info->control.hw_key->alg == ALG_WEP)
1429 return ATH9K_KEY_TYPE_WEP;
1430 else if (tx_info->control.hw_key->alg == ALG_TKIP)
1431 return ATH9K_KEY_TYPE_TKIP;
1432 else if (tx_info->control.hw_key->alg == ALG_CCMP)
1433 return ATH9K_KEY_TYPE_AES;
1434 }
1435
1436 return ATH9K_KEY_TYPE_CLEAR;
1437}
1438
Sujith528f0c62008-10-29 10:14:26 +05301439static void assign_aggr_tid_seqno(struct sk_buff *skb,
1440 struct ath_buf *bf)
1441{
1442 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1443 struct ieee80211_hdr *hdr;
1444 struct ath_node *an;
1445 struct ath_atx_tid *tid;
1446 __le16 fc;
1447 u8 *qc;
1448
1449 if (!tx_info->control.sta)
1450 return;
1451
1452 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1453 hdr = (struct ieee80211_hdr *)skb->data;
1454 fc = hdr->frame_control;
1455
Sujith528f0c62008-10-29 10:14:26 +05301456 if (ieee80211_is_data_qos(fc)) {
1457 qc = ieee80211_get_qos_ctl(hdr);
1458 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301459 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001460
Sujithe8324352009-01-16 21:38:42 +05301461 /*
1462 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301463 * We also override seqno set by upper layer with the one
1464 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301465 */
1466 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301467 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301468 bf->bf_seqno = tid->seq_next;
1469 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301470}
1471
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001472static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301473{
1474 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1475 int flags = 0;
1476
1477 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1478 flags |= ATH9K_TXDESC_INTREQ;
1479
1480 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1481 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301482
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001483 if (use_ldpc)
1484 flags |= ATH9K_TXDESC_LDPC;
1485
Sujith528f0c62008-10-29 10:14:26 +05301486 return flags;
1487}
1488
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001489/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001490 * rix - rate index
1491 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1492 * width - 0 for 20 MHz, 1 for 40 MHz
1493 * half_gi - to use 4us v/s 3.6 us for symbol time
1494 */
Sujith102e0572008-10-29 10:15:16 +05301495static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1496 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001498 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499 int streams, pktlen;
1500
Sujithcd3d39a2008-08-11 14:03:34 +05301501 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301502
1503 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001504 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001506 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001507 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1508
1509 if (!half_gi)
1510 duration = SYMBOL_TIME(nsymbols);
1511 else
1512 duration = SYMBOL_TIME_HALFGI(nsymbols);
1513
Sujithe63835b2008-11-18 09:07:53 +05301514 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001515 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301516
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001517 return duration;
1518}
1519
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001520static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1521{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001522 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001523 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301524 struct sk_buff *skb;
1525 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301526 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001527 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301528 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301529 int i, flags = 0;
1530 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301531 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301532
1533 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301534
Sujitha22be222009-03-30 15:28:36 +05301535 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301536 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301537 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301538 hdr = (struct ieee80211_hdr *)skb->data;
1539 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301540
Sujithc89424d2009-01-30 14:29:28 +05301541 /*
1542 * We check if Short Preamble is needed for the CTS rate by
1543 * checking the BSS's global flag.
1544 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1545 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001546 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1547 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301548 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001549 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001550
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001551 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001552 bool is_40, is_sgi, is_sp;
1553 int phy;
1554
Sujithe63835b2008-11-18 09:07:53 +05301555 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001556 continue;
1557
Sujitha8efee42008-11-18 09:07:30 +05301558 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301559 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001560 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001561
Felix Fietkau27032052010-01-17 21:08:50 +01001562 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1563 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301564 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001565 flags |= ATH9K_TXDESC_RTSENA;
1566 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1567 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1568 flags |= ATH9K_TXDESC_CTSENA;
1569 }
1570
Sujithc89424d2009-01-30 14:29:28 +05301571 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1572 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1573 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1574 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001575
Felix Fietkau545750d2009-11-23 22:21:01 +01001576 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1577 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1578 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1579
1580 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1581 /* MCS rates */
1582 series[i].Rate = rix | 0x80;
1583 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1584 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001585 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1586 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001587 continue;
1588 }
1589
1590 /* legcay rates */
1591 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1592 !(rate->flags & IEEE80211_RATE_ERP_G))
1593 phy = WLAN_RC_PHY_CCK;
1594 else
1595 phy = WLAN_RC_PHY_OFDM;
1596
1597 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1598 series[i].Rate = rate->hw_value;
1599 if (rate->hw_value_short) {
1600 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1601 series[i].Rate |= rate->hw_value_short;
1602 } else {
1603 is_sp = false;
1604 }
1605
1606 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1607 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001608 }
1609
Felix Fietkau27032052010-01-17 21:08:50 +01001610 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1611 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1612 flags &= ~ATH9K_TXDESC_RTSENA;
1613
1614 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1615 if (flags & ATH9K_TXDESC_RTSENA)
1616 flags &= ~ATH9K_TXDESC_CTSENA;
1617
Sujithe63835b2008-11-18 09:07:53 +05301618 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301619 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1620 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301621 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301622 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301623
Sujith17d79042009-02-09 13:27:03 +05301624 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301625 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001626}
1627
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001628static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301629 struct sk_buff *skb,
1630 struct ath_tx_control *txctl)
1631{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001632 struct ath_wiphy *aphy = hw->priv;
1633 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301634 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1635 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301636 int hdrlen;
1637 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001638 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001639 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301640
Felix Fietkau827e69b2009-11-15 23:09:25 +01001641 tx_info->pad[0] = 0;
1642 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001643 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001644 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001645 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001646 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1647 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001648 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001649 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1650 break;
1651 }
Sujithe8324352009-01-16 21:38:42 +05301652 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1653 fc = hdr->frame_control;
1654
1655 ATH_TXBUF_RESET(bf);
1656
Felix Fietkau827e69b2009-11-15 23:09:25 +01001657 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001658 bf->bf_frmlen = skb->len + FCS_LEN;
1659 /* Remove the padding size from bf_frmlen, if any */
1660 padpos = ath9k_cmn_padpos(hdr->frame_control);
1661 padsize = padpos & 3;
1662 if (padsize && skb->len>padpos+padsize) {
1663 bf->bf_frmlen -= padsize;
1664 }
Sujithe8324352009-01-16 21:38:42 +05301665
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001666 if (conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301667 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001668 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1669 use_ldpc = true;
1670 }
Sujithe8324352009-01-16 21:38:42 +05301671
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001672 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301673
1674 bf->bf_keytype = get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301675 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1676 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1677 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1678 } else {
1679 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1680 }
1681
Sujith17b182e2009-12-14 14:56:56 +05301682 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1683 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301684 assign_aggr_tid_seqno(skb, bf);
1685
1686 bf->bf_mpdu = skb;
1687
1688 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1689 skb->len, DMA_TO_DEVICE);
1690 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1691 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001692 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1693 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301694 return -ENOMEM;
1695 }
1696
1697 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001698
1699 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1700 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1701 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301702 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001703 } else
1704 bf->bf_isnullfunc = false;
1705
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001706 bf->bf_tx_aborted = false;
1707
Sujithe8324352009-01-16 21:38:42 +05301708 return 0;
1709}
1710
1711/* FIXME: tx power */
1712static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1713 struct ath_tx_control *txctl)
1714{
Sujitha22be222009-03-30 15:28:36 +05301715 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301716 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301717 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301718 struct ath_node *an = NULL;
1719 struct list_head bf_head;
1720 struct ath_desc *ds;
1721 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301722 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301723 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301724 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301725
1726 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301727 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301728
1729 INIT_LIST_HEAD(&bf_head);
1730 list_add_tail(&bf->list, &bf_head);
1731
1732 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001733 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301734
1735 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1736 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1737
1738 ath9k_hw_filltxdesc(ah, ds,
1739 skb->len, /* segment length */
1740 true, /* first segment */
1741 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001742 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001743 bf->bf_buf_addr,
1744 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301745
Sujithe8324352009-01-16 21:38:42 +05301746 spin_lock_bh(&txctl->txq->axq_lock);
1747
1748 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1749 tx_info->control.sta) {
1750 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1751 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1752
Sujithc37452b2009-03-09 09:31:57 +05301753 if (!ieee80211_is_data_qos(fc)) {
1754 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1755 goto tx_done;
1756 }
1757
Felix Fietkau4fdec032010-03-12 04:02:43 +01001758 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301759 /*
1760 * Try aggregation if it's a unicast data frame
1761 * and the destination is HT capable.
1762 */
1763 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1764 } else {
1765 /*
1766 * Send this frame as regular when ADDBA
1767 * exchange is neither complete nor pending.
1768 */
Sujithc37452b2009-03-09 09:31:57 +05301769 ath_tx_send_ht_normal(sc, txctl->txq,
1770 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301771 }
1772 } else {
Sujithc37452b2009-03-09 09:31:57 +05301773 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301774 }
1775
Sujithc37452b2009-03-09 09:31:57 +05301776tx_done:
Sujithe8324352009-01-16 21:38:42 +05301777 spin_unlock_bh(&txctl->txq->axq_lock);
1778}
1779
1780/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001781int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301782 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001783{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001784 struct ath_wiphy *aphy = hw->priv;
1785 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001786 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001787 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001788 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301789 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001790
Sujithe8324352009-01-16 21:38:42 +05301791 bf = ath_tx_get_buffer(sc);
1792 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001793 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301794 return -1;
1795 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001796
Felix Fietkau84642d62010-06-01 21:33:13 +02001797 bf->txq = txctl->txq;
1798 spin_lock_bh(&bf->txq->axq_lock);
1799 if (++bf->txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1800 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1801 txq->stopped = 1;
1802 }
1803 spin_unlock_bh(&bf->txq->axq_lock);
1804
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001805 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301806 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001807 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001808
Sujithe8324352009-01-16 21:38:42 +05301809 /* upon ath_tx_processq() this TX queue will be resumed, we
1810 * guarantee this will happen by knowing beforehand that
1811 * we will at least have to run TX completionon one buffer
1812 * on the queue */
1813 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001814 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001815 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301816 txq->stopped = 1;
1817 }
1818 spin_unlock_bh(&txq->axq_lock);
1819
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001820 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301821
1822 return r;
1823 }
1824
1825 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001826
1827 return 0;
1828}
1829
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001830void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001831{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001832 struct ath_wiphy *aphy = hw->priv;
1833 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001834 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001835 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1836 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301837 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1838 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001839
Sujithe8324352009-01-16 21:38:42 +05301840 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001841
Sujithe8324352009-01-16 21:38:42 +05301842 /*
1843 * As a temporary workaround, assign seq# here; this will likely need
1844 * to be cleaned up to work better with Beacon transmission and virtual
1845 * BSSes.
1846 */
1847 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301848 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1849 sc->tx.seq_no += 0x10;
1850 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1851 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001852 }
1853
Sujithe8324352009-01-16 21:38:42 +05301854 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001855 padpos = ath9k_cmn_padpos(hdr->frame_control);
1856 padsize = padpos & 3;
1857 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301858 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001859 ath_print(common, ATH_DBG_XMIT,
1860 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301861 dev_kfree_skb_any(skb);
1862 return;
1863 }
1864 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001865 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001866 }
1867
Sujithe8324352009-01-16 21:38:42 +05301868 txctl.txq = sc->beacon.cabq;
1869
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001870 ath_print(common, ATH_DBG_XMIT,
1871 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301872
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001873 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001874 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301875 goto exit;
1876 }
1877
1878 return;
1879exit:
1880 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001881}
1882
Sujithe8324352009-01-16 21:38:42 +05301883/*****************/
1884/* TX Completion */
1885/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001886
Sujithe8324352009-01-16 21:38:42 +05301887static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001888 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001889{
Sujithe8324352009-01-16 21:38:42 +05301890 struct ieee80211_hw *hw = sc->hw;
1891 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001892 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001893 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
1894 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301895
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001896 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301897
Felix Fietkau827e69b2009-11-15 23:09:25 +01001898 if (aphy)
1899 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301900
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301901 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301902 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301903
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301904 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301905 /* Frame was ACKed */
1906 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1907 }
1908
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001909 padpos = ath9k_cmn_padpos(hdr->frame_control);
1910 padsize = padpos & 3;
1911 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301912 /*
1913 * Remove MAC header padding before giving the frame back to
1914 * mac80211.
1915 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001916 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301917 skb_pull(skb, padsize);
1918 }
1919
Sujith1b04b932010-01-08 10:36:05 +05301920 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1921 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001922 ath_print(common, ATH_DBG_PS,
1923 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001924 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301925 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1926 PS_WAIT_FOR_CAB |
1927 PS_WAIT_FOR_PSPOLL_DATA |
1928 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001929 }
1930
Felix Fietkau827e69b2009-11-15 23:09:25 +01001931 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001932 ath9k_tx_status(hw, skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001933 else
1934 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301935}
1936
1937static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001938 struct ath_txq *txq, struct list_head *bf_q,
1939 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301940{
1941 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301942 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301943 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301944
Sujithe8324352009-01-16 21:38:42 +05301945 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301946 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301947
1948 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301949 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301950
1951 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301952 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301953 }
1954
Felix Fietkau84642d62010-06-01 21:33:13 +02001955 if (bf->txq) {
1956 spin_lock_bh(&bf->txq->axq_lock);
1957 bf->txq->pending_frames--;
1958 spin_unlock_bh(&bf->txq->axq_lock);
1959 bf->txq = NULL;
1960 }
1961
Sujithe8324352009-01-16 21:38:42 +05301962 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001963 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001964 ath_debug_stat_tx(sc, txq, bf, ts);
Sujithe8324352009-01-16 21:38:42 +05301965
1966 /*
1967 * Return the list of ath_buf of this mpdu to free queue
1968 */
1969 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1970 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1971 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1972}
1973
1974static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001975 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301976{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001977 u16 seq_st = 0;
1978 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301979 int ba_index;
1980 int nbad = 0;
1981 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001982
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001983 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301984 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301985
Sujithcd3d39a2008-08-11 14:03:34 +05301986 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001987 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001988 seq_st = ts->ts_seqnum;
1989 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001990 }
1991
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001992 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301993 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1994 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1995 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001996
Sujithe8324352009-01-16 21:38:42 +05301997 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001998 }
1999
Sujithe8324352009-01-16 21:38:42 +05302000 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002001}
2002
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002003static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302004 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302005{
Sujitha22be222009-03-30 15:28:36 +05302006 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302007 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302008 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01002009 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302010 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302011
Sujith95e4acb2009-03-13 08:56:09 +05302012 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002013 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302014
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002015 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302016 WARN_ON(tx_rateindex >= hw->max_rates);
2017
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002018 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302019 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01002020 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
2021 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302022
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002023 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302024 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05302025 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002026 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01002027 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
2028 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002029 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2030 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002031 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2032 tx_info->status.ampdu_len = bf->bf_nframes;
2033 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302034 }
2035 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302036
Felix Fietkau545750d2009-11-23 22:21:01 +01002037 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302038 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002039 tx_info->status.rates[i].idx = -1;
2040 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302041
2042 tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
Sujithc4288392008-11-18 09:09:30 +05302043}
2044
Sujith059d8062009-01-16 21:38:49 +05302045static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2046{
2047 int qnum;
2048
2049 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02002050 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Felix Fietkau293f2ba2010-06-12 00:33:49 -04002051 qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
Sujith059d8062009-01-16 21:38:49 +05302052 if (qnum != -1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08002053 ath_mac80211_start_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302054 txq->stopped = 0;
2055 }
2056 }
2057 spin_unlock_bh(&txq->axq_lock);
2058}
2059
Sujithc4288392008-11-18 09:09:30 +05302060static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002061{
Sujithcbe61d82009-02-09 13:27:12 +05302062 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002063 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002064 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2065 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302066 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002067 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302068 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069 int status;
2070
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002071 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2072 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2073 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002074
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002075 for (;;) {
2076 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002077 if (list_empty(&txq->axq_q)) {
2078 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 spin_unlock_bh(&txq->axq_lock);
2080 break;
2081 }
2082 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2083
2084 /*
2085 * There is a race condition that a BH gets scheduled
2086 * after sw writes TxE and before hw re-load the last
2087 * descriptor to get the newly chained one.
2088 * Software must keep the last DONE descriptor as a
2089 * holding descriptor - software does so by marking
2090 * it with the STALE flag.
2091 */
2092 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302093 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094 bf_held = bf;
2095 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302096 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002097 break;
2098 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002099 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302100 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002101 }
2102 }
2103
2104 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302105 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002106
Felix Fietkau29bffa92010-03-29 20:14:23 -07002107 memset(&ts, 0, sizeof(ts));
2108 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109 if (status == -EINPROGRESS) {
2110 spin_unlock_bh(&txq->axq_lock);
2111 break;
2112 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002113
2114 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002115 * We now know the nullfunc frame has been ACKed so we
2116 * can disable RX.
2117 */
2118 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002119 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302120 if ((sc->ps_flags & PS_ENABLED))
2121 ath9k_enable_ps(sc);
2122 else
Sujith1b04b932010-01-08 10:36:05 +05302123 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002124 }
2125
2126 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002127 * Remove ath_buf's of the same transmit unit from txq,
2128 * however leave the last descriptor back as the holding
2129 * descriptor for hw.
2130 */
Sujitha119cc42009-03-30 15:28:38 +05302131 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002132 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002133 if (!list_is_singular(&lastbf->list))
2134 list_cut_position(&bf_head,
2135 &txq->axq_q, lastbf->list.prev);
2136
2137 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002138 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002139 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002140 if (bf_held)
2141 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002142 spin_unlock_bh(&txq->axq_lock);
2143
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002144 if (bf_held)
2145 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002146
Sujithcd3d39a2008-08-11 14:03:34 +05302147 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002148 /*
2149 * This frame is sent out as a single frame.
2150 * Use hardware retry status for this frame.
2151 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002152 bf->bf_retries = ts.ts_longretry;
2153 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302154 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002155 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002156 }
Johannes Berge6a98542008-10-21 12:40:02 +02002157
Sujithcd3d39a2008-08-11 14:03:34 +05302158 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002159 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002160 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002161 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002162
Sujith059d8062009-01-16 21:38:49 +05302163 ath_wake_mac80211_queue(sc, txq);
2164
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002165 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302166 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002167 ath_txq_schedule(sc, txq);
2168 spin_unlock_bh(&txq->axq_lock);
2169 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002170}
2171
Sujith305fe472009-07-23 15:32:29 +05302172static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002173{
2174 struct ath_softc *sc = container_of(work, struct ath_softc,
2175 tx_complete_work.work);
2176 struct ath_txq *txq;
2177 int i;
2178 bool needreset = false;
2179
2180 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2181 if (ATH_TXQ_SETUP(sc, i)) {
2182 txq = &sc->tx.txq[i];
2183 spin_lock_bh(&txq->axq_lock);
2184 if (txq->axq_depth) {
2185 if (txq->axq_tx_inprogress) {
2186 needreset = true;
2187 spin_unlock_bh(&txq->axq_lock);
2188 break;
2189 } else {
2190 txq->axq_tx_inprogress = true;
2191 }
2192 }
2193 spin_unlock_bh(&txq->axq_lock);
2194 }
2195
2196 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002197 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2198 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302199 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002200 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302201 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002202 }
2203
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002204 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002205 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2206}
2207
2208
Sujithe8324352009-01-16 21:38:42 +05302209
2210void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002211{
Sujithe8324352009-01-16 21:38:42 +05302212 int i;
2213 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002214
Sujithe8324352009-01-16 21:38:42 +05302215 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002216
2217 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302218 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2219 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002220 }
2221}
2222
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002223void ath_tx_edma_tasklet(struct ath_softc *sc)
2224{
2225 struct ath_tx_status txs;
2226 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2227 struct ath_hw *ah = sc->sc_ah;
2228 struct ath_txq *txq;
2229 struct ath_buf *bf, *lastbf;
2230 struct list_head bf_head;
2231 int status;
2232 int txok;
2233
2234 for (;;) {
2235 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2236 if (status == -EINPROGRESS)
2237 break;
2238 if (status == -EIO) {
2239 ath_print(common, ATH_DBG_XMIT,
2240 "Error processing tx status\n");
2241 break;
2242 }
2243
2244 /* Skip beacon completions */
2245 if (txs.qid == sc->beacon.beaconq)
2246 continue;
2247
2248 txq = &sc->tx.txq[txs.qid];
2249
2250 spin_lock_bh(&txq->axq_lock);
2251 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2252 spin_unlock_bh(&txq->axq_lock);
2253 return;
2254 }
2255
2256 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2257 struct ath_buf, list);
2258 lastbf = bf->bf_lastbf;
2259
2260 INIT_LIST_HEAD(&bf_head);
2261 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2262 &lastbf->list);
2263 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2264 txq->axq_depth--;
2265 txq->axq_tx_inprogress = false;
2266 spin_unlock_bh(&txq->axq_lock);
2267
2268 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2269
Vasanthakumar Thiagarajande0f6482010-05-17 18:57:54 -07002270 /*
2271 * Make sure null func frame is acked before configuring
2272 * hw into ps mode.
2273 */
2274 if (bf->bf_isnullfunc && txok) {
2275 if ((sc->ps_flags & PS_ENABLED))
2276 ath9k_enable_ps(sc);
2277 else
2278 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
2279 }
2280
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002281 if (!bf_isampdu(bf)) {
2282 bf->bf_retries = txs.ts_longretry;
2283 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2284 bf->bf_state.bf_type |= BUF_XRETRY;
2285 ath_tx_rc_status(bf, &txs, 0, txok, true);
2286 }
2287
2288 if (bf_isampdu(bf))
2289 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2290 else
2291 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2292 &txs, txok, 0);
2293
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002294 ath_wake_mac80211_queue(sc, txq);
2295
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002296 spin_lock_bh(&txq->axq_lock);
2297 if (!list_empty(&txq->txq_fifo_pending)) {
2298 INIT_LIST_HEAD(&bf_head);
2299 bf = list_first_entry(&txq->txq_fifo_pending,
2300 struct ath_buf, list);
2301 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2302 &bf->bf_lastbf->list);
2303 ath_tx_txqaddbuf(sc, txq, &bf_head);
2304 } else if (sc->sc_flags & SC_OP_TXAGGR)
2305 ath_txq_schedule(sc, txq);
2306 spin_unlock_bh(&txq->axq_lock);
2307 }
2308}
2309
Sujithe8324352009-01-16 21:38:42 +05302310/*****************/
2311/* Init, Cleanup */
2312/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002313
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002314static int ath_txstatus_setup(struct ath_softc *sc, int size)
2315{
2316 struct ath_descdma *dd = &sc->txsdma;
2317 u8 txs_len = sc->sc_ah->caps.txs_len;
2318
2319 dd->dd_desc_len = size * txs_len;
2320 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2321 &dd->dd_desc_paddr, GFP_KERNEL);
2322 if (!dd->dd_desc)
2323 return -ENOMEM;
2324
2325 return 0;
2326}
2327
2328static int ath_tx_edma_init(struct ath_softc *sc)
2329{
2330 int err;
2331
2332 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2333 if (!err)
2334 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2335 sc->txsdma.dd_desc_paddr,
2336 ATH_TXSTATUS_RING_SIZE);
2337
2338 return err;
2339}
2340
2341static void ath_tx_edma_cleanup(struct ath_softc *sc)
2342{
2343 struct ath_descdma *dd = &sc->txsdma;
2344
2345 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2346 dd->dd_desc_paddr);
2347}
2348
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002349int ath_tx_init(struct ath_softc *sc, int nbufs)
2350{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002351 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002352 int error = 0;
2353
Sujith797fe5cb2009-03-30 15:28:45 +05302354 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002355
Sujith797fe5cb2009-03-30 15:28:45 +05302356 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002357 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302358 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002359 ath_print(common, ATH_DBG_FATAL,
2360 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302361 goto err;
2362 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002363
Sujith797fe5cb2009-03-30 15:28:45 +05302364 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002365 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302366 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002367 ath_print(common, ATH_DBG_FATAL,
2368 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302369 goto err;
2370 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002372 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2373
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002374 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2375 error = ath_tx_edma_init(sc);
2376 if (error)
2377 goto err;
2378 }
2379
Sujith797fe5cb2009-03-30 15:28:45 +05302380err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002381 if (error != 0)
2382 ath_tx_cleanup(sc);
2383
2384 return error;
2385}
2386
Sujith797fe5cb2009-03-30 15:28:45 +05302387void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002388{
Sujithb77f4832008-12-07 21:44:03 +05302389 if (sc->beacon.bdma.dd_desc_len != 0)
2390 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002391
Sujithb77f4832008-12-07 21:44:03 +05302392 if (sc->tx.txdma.dd_desc_len != 0)
2393 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002394
2395 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2396 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002397}
2398
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002399void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2400{
Sujithc5170162008-10-29 10:13:59 +05302401 struct ath_atx_tid *tid;
2402 struct ath_atx_ac *ac;
2403 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002404
Sujith8ee5afb2008-12-07 21:43:36 +05302405 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302406 tidno < WME_NUM_TID;
2407 tidno++, tid++) {
2408 tid->an = an;
2409 tid->tidno = tidno;
2410 tid->seq_start = tid->seq_next = 0;
2411 tid->baw_size = WME_MAX_BA;
2412 tid->baw_head = tid->baw_tail = 0;
2413 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302414 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302415 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302416 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302417 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302418 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302419 tid->state &= ~AGGR_ADDBA_COMPLETE;
2420 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302421 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002422
Sujith8ee5afb2008-12-07 21:43:36 +05302423 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302424 acno < WME_NUM_AC; acno++, ac++) {
2425 ac->sched = false;
2426 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002427
Sujithc5170162008-10-29 10:13:59 +05302428 switch (acno) {
2429 case WME_AC_BE:
2430 ac->qnum = ath_tx_get_qnum(sc,
2431 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
2432 break;
2433 case WME_AC_BK:
2434 ac->qnum = ath_tx_get_qnum(sc,
2435 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
2436 break;
2437 case WME_AC_VI:
2438 ac->qnum = ath_tx_get_qnum(sc,
2439 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
2440 break;
2441 case WME_AC_VO:
2442 ac->qnum = ath_tx_get_qnum(sc,
2443 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
2444 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002445 }
2446 }
2447}
2448
Sujithb5aa9bf2008-10-29 10:13:31 +05302449void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002450{
2451 int i;
2452 struct ath_atx_ac *ac, *ac_tmp;
2453 struct ath_atx_tid *tid, *tid_tmp;
2454 struct ath_txq *txq;
Sujithe8324352009-01-16 21:38:42 +05302455
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002456 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
2457 if (ATH_TXQ_SETUP(sc, i)) {
Sujithb77f4832008-12-07 21:44:03 +05302458 txq = &sc->tx.txq[i];
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002459
Ming Leia9f042c2010-02-28 00:56:24 +08002460 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002461
2462 list_for_each_entry_safe(ac,
2463 ac_tmp, &txq->axq_acq, list) {
2464 tid = list_first_entry(&ac->tid_q,
2465 struct ath_atx_tid, list);
2466 if (tid && tid->an != an)
2467 continue;
2468 list_del(&ac->list);
2469 ac->sched = false;
2470
2471 list_for_each_entry_safe(tid,
2472 tid_tmp, &ac->tid_q, list) {
2473 list_del(&tid->list);
2474 tid->sched = false;
Sujithb5aa9bf2008-10-29 10:13:31 +05302475 ath_tid_drain(sc, txq, tid);
Sujitha37c2c72008-10-29 10:15:40 +05302476 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujitha37c2c72008-10-29 10:15:40 +05302477 tid->state &= ~AGGR_CLEANUP;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002478 }
2479 }
2480
Ming Leia9f042c2010-02-28 00:56:24 +08002481 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002482 }
2483 }
2484}