blob: 2237658144e666fa59e040c184d6a4391811112b [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
944 txq->axq_qnum = qnum;
945 txq->axq_link = NULL;
946 INIT_LIST_HEAD(&txq->axq_q);
947 INIT_LIST_HEAD(&txq->axq_acq);
948 spin_lock_init(&txq->axq_lock);
949 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400950 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530951 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400952
953 txq->txq_headidx = txq->txq_tailidx = 0;
954 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
955 INIT_LIST_HEAD(&txq->txq_fifo[i]);
956 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530957 }
958 return &sc->tx.txq[qnum];
959}
960
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530961int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
Sujithe8324352009-01-16 21:38:42 +0530962{
963 int qnum;
964
965 switch (qtype) {
966 case ATH9K_TX_QUEUE_DATA:
967 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700968 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
969 "HAL AC %u out of range, max %zu!\n",
970 haltype, ARRAY_SIZE(sc->tx.hwq_map));
Sujithe8324352009-01-16 21:38:42 +0530971 return -1;
972 }
973 qnum = sc->tx.hwq_map[haltype];
974 break;
975 case ATH9K_TX_QUEUE_BEACON:
976 qnum = sc->beacon.beaconq;
977 break;
978 case ATH9K_TX_QUEUE_CAB:
979 qnum = sc->beacon.cabq->axq_qnum;
980 break;
981 default:
982 qnum = -1;
983 }
984 return qnum;
985}
986
987struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
988{
989 struct ath_txq *txq = NULL;
Luis R. Rodriguezf52de032009-11-02 17:09:12 -0800990 u16 skb_queue = skb_get_queue_mapping(skb);
Sujithe8324352009-01-16 21:38:42 +0530991 int qnum;
992
Luis R. Rodriguezf52de032009-11-02 17:09:12 -0800993 qnum = ath_get_hal_qnum(skb_queue, sc);
Sujithe8324352009-01-16 21:38:42 +0530994 txq = &sc->tx.txq[qnum];
995
996 spin_lock_bh(&txq->axq_lock);
997
998 if (txq->axq_depth >= (ATH_TXBUF - 20)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700999 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
1000 "TX queue: %d is full, depth: %d\n",
1001 qnum, txq->axq_depth);
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001002 ath_mac80211_stop_queue(sc, skb_queue);
Sujithe8324352009-01-16 21:38:42 +05301003 txq->stopped = 1;
1004 spin_unlock_bh(&txq->axq_lock);
1005 return NULL;
1006 }
1007
1008 spin_unlock_bh(&txq->axq_lock);
1009
1010 return txq;
1011}
1012
1013int ath_txq_update(struct ath_softc *sc, int qnum,
1014 struct ath9k_tx_queue_info *qinfo)
1015{
Sujithcbe61d82009-02-09 13:27:12 +05301016 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301017 int error = 0;
1018 struct ath9k_tx_queue_info qi;
1019
1020 if (qnum == sc->beacon.beaconq) {
1021 /*
1022 * XXX: for beacon queue, we just save the parameter.
1023 * It will be picked up by ath_beaconq_config when
1024 * it's necessary.
1025 */
1026 sc->beacon.beacon_qi = *qinfo;
1027 return 0;
1028 }
1029
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001030 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301031
1032 ath9k_hw_get_txq_props(ah, qnum, &qi);
1033 qi.tqi_aifs = qinfo->tqi_aifs;
1034 qi.tqi_cwmin = qinfo->tqi_cwmin;
1035 qi.tqi_cwmax = qinfo->tqi_cwmax;
1036 qi.tqi_burstTime = qinfo->tqi_burstTime;
1037 qi.tqi_readyTime = qinfo->tqi_readyTime;
1038
1039 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001040 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1041 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301042 error = -EIO;
1043 } else {
1044 ath9k_hw_resettxqueue(ah, qnum);
1045 }
1046
1047 return error;
1048}
1049
1050int ath_cabq_update(struct ath_softc *sc)
1051{
1052 struct ath9k_tx_queue_info qi;
1053 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301054
1055 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1056 /*
1057 * Ensure the readytime % is within the bounds.
1058 */
Sujith17d79042009-02-09 13:27:03 +05301059 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1060 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1061 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1062 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301063
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001064 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301065 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301066 ath_txq_update(sc, qnum, &qi);
1067
1068 return 0;
1069}
1070
Sujith043a0402009-01-16 21:38:47 +05301071/*
1072 * Drain a given TX queue (could be Beacon or Data)
1073 *
1074 * This assumes output has been stopped and
1075 * we do not need to block ath_tx_tasklet.
1076 */
1077void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301078{
1079 struct ath_buf *bf, *lastbf;
1080 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001081 struct ath_tx_status ts;
1082
1083 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301084 INIT_LIST_HEAD(&bf_head);
1085
Sujithe8324352009-01-16 21:38:42 +05301086 for (;;) {
1087 spin_lock_bh(&txq->axq_lock);
1088
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001089 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1090 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1091 txq->txq_headidx = txq->txq_tailidx = 0;
1092 spin_unlock_bh(&txq->axq_lock);
1093 break;
1094 } else {
1095 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1096 struct ath_buf, list);
1097 }
1098 } else {
1099 if (list_empty(&txq->axq_q)) {
1100 txq->axq_link = NULL;
1101 spin_unlock_bh(&txq->axq_lock);
1102 break;
1103 }
1104 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1105 list);
Sujithe8324352009-01-16 21:38:42 +05301106
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001107 if (bf->bf_stale) {
1108 list_del(&bf->list);
1109 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301110
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001111 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001112 continue;
1113 }
Sujithe8324352009-01-16 21:38:42 +05301114 }
1115
1116 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001117 if (!retry_tx)
1118 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301119
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001120 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1121 list_cut_position(&bf_head,
1122 &txq->txq_fifo[txq->txq_tailidx],
1123 &lastbf->list);
1124 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1125 } else {
1126 /* remove ath_buf's of the same mpdu from txq */
1127 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1128 }
1129
Sujithe8324352009-01-16 21:38:42 +05301130 txq->axq_depth--;
1131
1132 spin_unlock_bh(&txq->axq_lock);
1133
1134 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001135 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301136 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001137 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301138 }
1139
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001140 spin_lock_bh(&txq->axq_lock);
1141 txq->axq_tx_inprogress = false;
1142 spin_unlock_bh(&txq->axq_lock);
1143
Sujithe8324352009-01-16 21:38:42 +05301144 /* flush any pending frames if aggregation is enabled */
1145 if (sc->sc_flags & SC_OP_TXAGGR) {
1146 if (!retry_tx) {
1147 spin_lock_bh(&txq->axq_lock);
1148 ath_txq_drain_pending_buffers(sc, txq);
1149 spin_unlock_bh(&txq->axq_lock);
1150 }
1151 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001152
1153 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1154 spin_lock_bh(&txq->axq_lock);
1155 while (!list_empty(&txq->txq_fifo_pending)) {
1156 bf = list_first_entry(&txq->txq_fifo_pending,
1157 struct ath_buf, list);
1158 list_cut_position(&bf_head,
1159 &txq->txq_fifo_pending,
1160 &bf->bf_lastbf->list);
1161 spin_unlock_bh(&txq->axq_lock);
1162
1163 if (bf_isampdu(bf))
1164 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1165 &ts, 0);
1166 else
1167 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1168 &ts, 0, 0);
1169 spin_lock_bh(&txq->axq_lock);
1170 }
1171 spin_unlock_bh(&txq->axq_lock);
1172 }
Sujithe8324352009-01-16 21:38:42 +05301173}
1174
Sujith043a0402009-01-16 21:38:47 +05301175void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1176{
Sujithcbe61d82009-02-09 13:27:12 +05301177 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001178 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301179 struct ath_txq *txq;
1180 int i, npend = 0;
1181
1182 if (sc->sc_flags & SC_OP_INVALID)
1183 return;
1184
1185 /* Stop beacon queue */
1186 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1187
1188 /* Stop data queues */
1189 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1190 if (ATH_TXQ_SETUP(sc, i)) {
1191 txq = &sc->tx.txq[i];
1192 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1193 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1194 }
1195 }
1196
1197 if (npend) {
1198 int r;
1199
Sujithe8009e92009-12-14 14:57:08 +05301200 ath_print(common, ATH_DBG_FATAL,
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001201 "Unable to stop TxDMA. Reset HAL!\n");
Sujith043a0402009-01-16 21:38:47 +05301202
1203 spin_lock_bh(&sc->sc_resetlock);
Sujithe8009e92009-12-14 14:57:08 +05301204 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
Sujith043a0402009-01-16 21:38:47 +05301205 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001206 ath_print(common, ATH_DBG_FATAL,
1207 "Unable to reset hardware; reset status %d\n",
1208 r);
Sujith043a0402009-01-16 21:38:47 +05301209 spin_unlock_bh(&sc->sc_resetlock);
1210 }
1211
1212 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1213 if (ATH_TXQ_SETUP(sc, i))
1214 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1215 }
1216}
1217
Sujithe8324352009-01-16 21:38:42 +05301218void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1219{
1220 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1221 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1222}
1223
Sujithe8324352009-01-16 21:38:42 +05301224void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1225{
1226 struct ath_atx_ac *ac;
1227 struct ath_atx_tid *tid;
1228
1229 if (list_empty(&txq->axq_acq))
1230 return;
1231
1232 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1233 list_del(&ac->list);
1234 ac->sched = false;
1235
1236 do {
1237 if (list_empty(&ac->tid_q))
1238 return;
1239
1240 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1241 list_del(&tid->list);
1242 tid->sched = false;
1243
1244 if (tid->paused)
1245 continue;
1246
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001247 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301248
1249 /*
1250 * add tid to round-robin queue if more frames
1251 * are pending for the tid
1252 */
1253 if (!list_empty(&tid->buf_q))
1254 ath_tx_queue_tid(txq, tid);
1255
1256 break;
1257 } while (!list_empty(&ac->tid_q));
1258
1259 if (!list_empty(&ac->tid_q)) {
1260 if (!ac->sched) {
1261 ac->sched = true;
1262 list_add_tail(&ac->list, &txq->axq_acq);
1263 }
1264 }
1265}
1266
1267int ath_tx_setup(struct ath_softc *sc, int haltype)
1268{
1269 struct ath_txq *txq;
1270
1271 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001272 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1273 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301274 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1275 return 0;
1276 }
1277 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1278 if (txq != NULL) {
1279 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1280 return 1;
1281 } else
1282 return 0;
1283}
1284
1285/***********/
1286/* TX, DMA */
1287/***********/
1288
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001289/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001290 * Insert a chain of ath_buf (descriptors) on a txq and
1291 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001292 */
Sujith102e0572008-10-29 10:15:16 +05301293static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1294 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001295{
Sujithcbe61d82009-02-09 13:27:12 +05301296 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001297 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001298 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301299
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001300 /*
1301 * Insert the frame on the outbound list and
1302 * pass it on to the hardware.
1303 */
1304
1305 if (list_empty(head))
1306 return;
1307
1308 bf = list_first_entry(head, struct ath_buf, list);
1309
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001310 ath_print(common, ATH_DBG_QUEUE,
1311 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001312
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001313 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1314 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1315 list_splice_tail_init(head, &txq->txq_fifo_pending);
1316 return;
1317 }
1318 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1319 ath_print(common, ATH_DBG_XMIT,
1320 "Initializing tx fifo %d which "
1321 "is non-empty\n",
1322 txq->txq_headidx);
1323 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1324 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1325 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001326 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001327 ath_print(common, ATH_DBG_XMIT,
1328 "TXDP[%u] = %llx (%p)\n",
1329 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001330 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001331 list_splice_tail_init(head, &txq->axq_q);
1332
1333 if (txq->axq_link == NULL) {
1334 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1335 ath_print(common, ATH_DBG_XMIT,
1336 "TXDP[%u] = %llx (%p)\n",
1337 txq->axq_qnum, ito64(bf->bf_daddr),
1338 bf->bf_desc);
1339 } else {
1340 *txq->axq_link = bf->bf_daddr;
1341 ath_print(common, ATH_DBG_XMIT,
1342 "link[%u] (%p)=%llx (%p)\n",
1343 txq->axq_qnum, txq->axq_link,
1344 ito64(bf->bf_daddr), bf->bf_desc);
1345 }
1346 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1347 &txq->axq_link);
1348 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001349 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001350 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001351}
1352
Sujithe8324352009-01-16 21:38:42 +05301353static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1354 struct list_head *bf_head,
1355 struct ath_tx_control *txctl)
1356{
1357 struct ath_buf *bf;
1358
Sujithe8324352009-01-16 21:38:42 +05301359 bf = list_first_entry(bf_head, struct ath_buf, list);
1360 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301361 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301362
1363 /*
1364 * Do not queue to h/w when any of the following conditions is true:
1365 * - there are pending frames in software queue
1366 * - the TID is currently paused for ADDBA/BAR request
1367 * - seqno is not within block-ack window
1368 * - h/w queue depth exceeds low water mark
1369 */
1370 if (!list_empty(&tid->buf_q) || tid->paused ||
1371 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1372 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001373 /*
Sujithe8324352009-01-16 21:38:42 +05301374 * Add this frame to software queue for scheduling later
1375 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001376 */
Sujithd43f30152009-01-16 21:38:53 +05301377 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301378 ath_tx_queue_tid(txctl->txq, tid);
1379 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001380 }
1381
Sujithe8324352009-01-16 21:38:42 +05301382 /* Add sub-frame to BAW */
1383 ath_tx_addto_baw(sc, tid, bf);
1384
1385 /* Queue to h/w without aggregation */
1386 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301387 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301388 ath_buf_set_rate(sc, bf);
1389 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301390}
1391
Sujithc37452b2009-03-09 09:31:57 +05301392static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1393 struct ath_atx_tid *tid,
1394 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001395{
Sujithe8324352009-01-16 21:38:42 +05301396 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001397
Sujithe8324352009-01-16 21:38:42 +05301398 bf = list_first_entry(bf_head, struct ath_buf, list);
1399 bf->bf_state.bf_type &= ~BUF_AMPDU;
1400
1401 /* update starting sequence number for subsequent ADDBA request */
1402 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1403
1404 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301405 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301406 ath_buf_set_rate(sc, bf);
1407 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301408 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409}
1410
Sujithc37452b2009-03-09 09:31:57 +05301411static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1412 struct list_head *bf_head)
1413{
1414 struct ath_buf *bf;
1415
1416 bf = list_first_entry(bf_head, struct ath_buf, list);
1417
1418 bf->bf_lastbf = bf;
1419 bf->bf_nframes = 1;
1420 ath_buf_set_rate(sc, bf);
1421 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301422 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301423}
1424
Sujith528f0c62008-10-29 10:14:26 +05301425static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001426{
Sujith528f0c62008-10-29 10:14:26 +05301427 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001428 enum ath9k_pkt_type htype;
1429 __le16 fc;
1430
Sujith528f0c62008-10-29 10:14:26 +05301431 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001432 fc = hdr->frame_control;
1433
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001434 if (ieee80211_is_beacon(fc))
1435 htype = ATH9K_PKT_TYPE_BEACON;
1436 else if (ieee80211_is_probe_resp(fc))
1437 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1438 else if (ieee80211_is_atim(fc))
1439 htype = ATH9K_PKT_TYPE_ATIM;
1440 else if (ieee80211_is_pspoll(fc))
1441 htype = ATH9K_PKT_TYPE_PSPOLL;
1442 else
1443 htype = ATH9K_PKT_TYPE_NORMAL;
1444
1445 return htype;
1446}
1447
Sujith528f0c62008-10-29 10:14:26 +05301448static int get_hw_crypto_keytype(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001449{
Sujith528f0c62008-10-29 10:14:26 +05301450 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1451
1452 if (tx_info->control.hw_key) {
1453 if (tx_info->control.hw_key->alg == ALG_WEP)
1454 return ATH9K_KEY_TYPE_WEP;
1455 else if (tx_info->control.hw_key->alg == ALG_TKIP)
1456 return ATH9K_KEY_TYPE_TKIP;
1457 else if (tx_info->control.hw_key->alg == ALG_CCMP)
1458 return ATH9K_KEY_TYPE_AES;
1459 }
1460
1461 return ATH9K_KEY_TYPE_CLEAR;
1462}
1463
Sujith528f0c62008-10-29 10:14:26 +05301464static void assign_aggr_tid_seqno(struct sk_buff *skb,
1465 struct ath_buf *bf)
1466{
1467 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1468 struct ieee80211_hdr *hdr;
1469 struct ath_node *an;
1470 struct ath_atx_tid *tid;
1471 __le16 fc;
1472 u8 *qc;
1473
1474 if (!tx_info->control.sta)
1475 return;
1476
1477 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1478 hdr = (struct ieee80211_hdr *)skb->data;
1479 fc = hdr->frame_control;
1480
Sujith528f0c62008-10-29 10:14:26 +05301481 if (ieee80211_is_data_qos(fc)) {
1482 qc = ieee80211_get_qos_ctl(hdr);
1483 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301484 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001485
Sujithe8324352009-01-16 21:38:42 +05301486 /*
1487 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301488 * We also override seqno set by upper layer with the one
1489 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301490 */
1491 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301492 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301493 bf->bf_seqno = tid->seq_next;
1494 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301495}
1496
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001497static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301498{
1499 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1500 int flags = 0;
1501
1502 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1503 flags |= ATH9K_TXDESC_INTREQ;
1504
1505 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1506 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301507
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001508 if (use_ldpc)
1509 flags |= ATH9K_TXDESC_LDPC;
1510
Sujith528f0c62008-10-29 10:14:26 +05301511 return flags;
1512}
1513
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001514/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001515 * rix - rate index
1516 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1517 * width - 0 for 20 MHz, 1 for 40 MHz
1518 * half_gi - to use 4us v/s 3.6 us for symbol time
1519 */
Sujith102e0572008-10-29 10:15:16 +05301520static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1521 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001522{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001523 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001524 int streams, pktlen;
1525
Sujithcd3d39a2008-08-11 14:03:34 +05301526 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301527
1528 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001529 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001530 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001531 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001532 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1533
1534 if (!half_gi)
1535 duration = SYMBOL_TIME(nsymbols);
1536 else
1537 duration = SYMBOL_TIME_HALFGI(nsymbols);
1538
Sujithe63835b2008-11-18 09:07:53 +05301539 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001540 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301541
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001542 return duration;
1543}
1544
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001545static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1546{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001547 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001548 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301549 struct sk_buff *skb;
1550 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301551 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001552 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301553 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301554 int i, flags = 0;
1555 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301556 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301557
1558 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301559
Sujitha22be222009-03-30 15:28:36 +05301560 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301561 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301562 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301563 hdr = (struct ieee80211_hdr *)skb->data;
1564 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301565
Sujithc89424d2009-01-30 14:29:28 +05301566 /*
1567 * We check if Short Preamble is needed for the CTS rate by
1568 * checking the BSS's global flag.
1569 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1570 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001571 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1572 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301573 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001574 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001575
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001576 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001577 bool is_40, is_sgi, is_sp;
1578 int phy;
1579
Sujithe63835b2008-11-18 09:07:53 +05301580 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001581 continue;
1582
Sujitha8efee42008-11-18 09:07:30 +05301583 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301584 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001585 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001586
Felix Fietkau27032052010-01-17 21:08:50 +01001587 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1588 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301589 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001590 flags |= ATH9K_TXDESC_RTSENA;
1591 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1592 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1593 flags |= ATH9K_TXDESC_CTSENA;
1594 }
1595
Sujithc89424d2009-01-30 14:29:28 +05301596 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1597 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1598 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1599 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001600
Felix Fietkau545750d2009-11-23 22:21:01 +01001601 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1602 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1603 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1604
1605 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1606 /* MCS rates */
1607 series[i].Rate = rix | 0x80;
1608 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1609 is_40, is_sgi, is_sp);
1610 continue;
1611 }
1612
1613 /* legcay rates */
1614 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1615 !(rate->flags & IEEE80211_RATE_ERP_G))
1616 phy = WLAN_RC_PHY_CCK;
1617 else
1618 phy = WLAN_RC_PHY_OFDM;
1619
1620 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1621 series[i].Rate = rate->hw_value;
1622 if (rate->hw_value_short) {
1623 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1624 series[i].Rate |= rate->hw_value_short;
1625 } else {
1626 is_sp = false;
1627 }
1628
1629 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1630 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001631 }
1632
Felix Fietkau27032052010-01-17 21:08:50 +01001633 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1634 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1635 flags &= ~ATH9K_TXDESC_RTSENA;
1636
1637 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1638 if (flags & ATH9K_TXDESC_RTSENA)
1639 flags &= ~ATH9K_TXDESC_CTSENA;
1640
Sujithe63835b2008-11-18 09:07:53 +05301641 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301642 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1643 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301644 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301645 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301646
Sujith17d79042009-02-09 13:27:03 +05301647 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301648 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001649}
1650
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001651static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301652 struct sk_buff *skb,
1653 struct ath_tx_control *txctl)
1654{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001655 struct ath_wiphy *aphy = hw->priv;
1656 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301657 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1658 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301659 int hdrlen;
1660 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001661 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001662 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301663
Felix Fietkau827e69b2009-11-15 23:09:25 +01001664 tx_info->pad[0] = 0;
1665 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001666 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001667 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001668 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001669 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1670 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001671 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001672 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1673 break;
1674 }
Sujithe8324352009-01-16 21:38:42 +05301675 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1676 fc = hdr->frame_control;
1677
1678 ATH_TXBUF_RESET(bf);
1679
Felix Fietkau827e69b2009-11-15 23:09:25 +01001680 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001681 bf->bf_frmlen = skb->len + FCS_LEN;
1682 /* Remove the padding size from bf_frmlen, if any */
1683 padpos = ath9k_cmn_padpos(hdr->frame_control);
1684 padsize = padpos & 3;
1685 if (padsize && skb->len>padpos+padsize) {
1686 bf->bf_frmlen -= padsize;
1687 }
Sujithe8324352009-01-16 21:38:42 +05301688
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001689 if (conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301690 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001691 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1692 use_ldpc = true;
1693 }
Sujithe8324352009-01-16 21:38:42 +05301694
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001695 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301696
1697 bf->bf_keytype = get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301698 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1699 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1700 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1701 } else {
1702 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1703 }
1704
Sujith17b182e2009-12-14 14:56:56 +05301705 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1706 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301707 assign_aggr_tid_seqno(skb, bf);
1708
1709 bf->bf_mpdu = skb;
1710
1711 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1712 skb->len, DMA_TO_DEVICE);
1713 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1714 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001715 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1716 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301717 return -ENOMEM;
1718 }
1719
1720 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001721
1722 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1723 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1724 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301725 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001726 } else
1727 bf->bf_isnullfunc = false;
1728
Sujithe8324352009-01-16 21:38:42 +05301729 return 0;
1730}
1731
1732/* FIXME: tx power */
1733static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1734 struct ath_tx_control *txctl)
1735{
Sujitha22be222009-03-30 15:28:36 +05301736 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301737 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301738 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301739 struct ath_node *an = NULL;
1740 struct list_head bf_head;
1741 struct ath_desc *ds;
1742 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301743 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301744 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301745 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301746
1747 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301748 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301749
1750 INIT_LIST_HEAD(&bf_head);
1751 list_add_tail(&bf->list, &bf_head);
1752
1753 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001754 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301755
1756 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1757 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1758
1759 ath9k_hw_filltxdesc(ah, ds,
1760 skb->len, /* segment length */
1761 true, /* first segment */
1762 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001763 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001764 bf->bf_buf_addr,
1765 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301766
Sujithe8324352009-01-16 21:38:42 +05301767 spin_lock_bh(&txctl->txq->axq_lock);
1768
1769 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1770 tx_info->control.sta) {
1771 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1772 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1773
Sujithc37452b2009-03-09 09:31:57 +05301774 if (!ieee80211_is_data_qos(fc)) {
1775 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1776 goto tx_done;
1777 }
1778
Felix Fietkau4fdec032010-03-12 04:02:43 +01001779 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301780 /*
1781 * Try aggregation if it's a unicast data frame
1782 * and the destination is HT capable.
1783 */
1784 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1785 } else {
1786 /*
1787 * Send this frame as regular when ADDBA
1788 * exchange is neither complete nor pending.
1789 */
Sujithc37452b2009-03-09 09:31:57 +05301790 ath_tx_send_ht_normal(sc, txctl->txq,
1791 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301792 }
1793 } else {
Sujithc37452b2009-03-09 09:31:57 +05301794 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301795 }
1796
Sujithc37452b2009-03-09 09:31:57 +05301797tx_done:
Sujithe8324352009-01-16 21:38:42 +05301798 spin_unlock_bh(&txctl->txq->axq_lock);
1799}
1800
1801/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001802int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301803 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001804{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001805 struct ath_wiphy *aphy = hw->priv;
1806 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001807 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001808 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301809 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001810
Sujithe8324352009-01-16 21:38:42 +05301811 bf = ath_tx_get_buffer(sc);
1812 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001813 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301814 return -1;
1815 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001816
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001817 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301818 if (unlikely(r)) {
1819 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001820
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001821 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001822
Sujithe8324352009-01-16 21:38:42 +05301823 /* upon ath_tx_processq() this TX queue will be resumed, we
1824 * guarantee this will happen by knowing beforehand that
1825 * we will at least have to run TX completionon one buffer
1826 * on the queue */
1827 spin_lock_bh(&txq->axq_lock);
Sujithf7a99e42009-02-17 15:36:33 +05301828 if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001829 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301830 txq->stopped = 1;
1831 }
1832 spin_unlock_bh(&txq->axq_lock);
1833
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001834 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301835
1836 return r;
1837 }
1838
1839 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001840
1841 return 0;
1842}
1843
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001844void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001845{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001846 struct ath_wiphy *aphy = hw->priv;
1847 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001848 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001849 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1850 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301851 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1852 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001853
Sujithe8324352009-01-16 21:38:42 +05301854 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001855
Sujithe8324352009-01-16 21:38:42 +05301856 /*
1857 * As a temporary workaround, assign seq# here; this will likely need
1858 * to be cleaned up to work better with Beacon transmission and virtual
1859 * BSSes.
1860 */
1861 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301862 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1863 sc->tx.seq_no += 0x10;
1864 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1865 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001866 }
1867
Sujithe8324352009-01-16 21:38:42 +05301868 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001869 padpos = ath9k_cmn_padpos(hdr->frame_control);
1870 padsize = padpos & 3;
1871 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301872 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001873 ath_print(common, ATH_DBG_XMIT,
1874 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301875 dev_kfree_skb_any(skb);
1876 return;
1877 }
1878 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001879 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001880 }
1881
Sujithe8324352009-01-16 21:38:42 +05301882 txctl.txq = sc->beacon.cabq;
1883
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001884 ath_print(common, ATH_DBG_XMIT,
1885 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301886
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001887 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001888 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301889 goto exit;
1890 }
1891
1892 return;
1893exit:
1894 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001895}
1896
Sujithe8324352009-01-16 21:38:42 +05301897/*****************/
1898/* TX Completion */
1899/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001900
Sujithe8324352009-01-16 21:38:42 +05301901static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001902 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001903{
Sujithe8324352009-01-16 21:38:42 +05301904 struct ieee80211_hw *hw = sc->hw;
1905 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001906 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001907 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
1908 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301909
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001910 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301911
Felix Fietkau827e69b2009-11-15 23:09:25 +01001912 if (aphy)
1913 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301914
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301915 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301916 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301917
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301918 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301919 /* Frame was ACKed */
1920 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1921 }
1922
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001923 padpos = ath9k_cmn_padpos(hdr->frame_control);
1924 padsize = padpos & 3;
1925 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301926 /*
1927 * Remove MAC header padding before giving the frame back to
1928 * mac80211.
1929 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001930 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301931 skb_pull(skb, padsize);
1932 }
1933
Sujith1b04b932010-01-08 10:36:05 +05301934 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1935 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001936 ath_print(common, ATH_DBG_PS,
1937 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001938 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301939 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1940 PS_WAIT_FOR_CAB |
1941 PS_WAIT_FOR_PSPOLL_DATA |
1942 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001943 }
1944
Felix Fietkau827e69b2009-11-15 23:09:25 +01001945 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001946 ath9k_tx_status(hw, skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001947 else
1948 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301949}
1950
1951static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001952 struct ath_txq *txq, struct list_head *bf_q,
1953 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301954{
1955 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301956 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301957 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301958
Sujithe8324352009-01-16 21:38:42 +05301959 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301960 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301961
1962 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301963 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301964
1965 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301966 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301967 }
1968
1969 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001970 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001971 ath_debug_stat_tx(sc, txq, bf, ts);
Sujithe8324352009-01-16 21:38:42 +05301972
1973 /*
1974 * Return the list of ath_buf of this mpdu to free queue
1975 */
1976 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1977 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1978 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1979}
1980
1981static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001982 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301983{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001984 u16 seq_st = 0;
1985 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301986 int ba_index;
1987 int nbad = 0;
1988 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001989
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001990 if (bf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301991 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301992
Sujithcd3d39a2008-08-11 14:03:34 +05301993 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001994 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001995 seq_st = ts->ts_seqnum;
1996 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001997 }
1998
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001999 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05302000 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
2001 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
2002 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002003
Sujithe8324352009-01-16 21:38:42 +05302004 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002005 }
2006
Sujithe8324352009-01-16 21:38:42 +05302007 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002008}
2009
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002010static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302011 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302012{
Sujitha22be222009-03-30 15:28:36 +05302013 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302014 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302015 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01002016 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302017 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302018
Sujith95e4acb2009-03-13 08:56:09 +05302019 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002020 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302021
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002022 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302023 WARN_ON(tx_rateindex >= hw->max_rates);
2024
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002025 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302026 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01002027 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
2028 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302029
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002030 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302031 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05302032 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002033 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01002034 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
2035 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002036 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2037 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002038 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2039 tx_info->status.ampdu_len = bf->bf_nframes;
2040 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302041 }
2042 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302043
Felix Fietkau545750d2009-11-23 22:21:01 +01002044 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302045 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002046 tx_info->status.rates[i].idx = -1;
2047 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302048
2049 tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
Sujithc4288392008-11-18 09:09:30 +05302050}
2051
Sujith059d8062009-01-16 21:38:49 +05302052static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2053{
2054 int qnum;
2055
2056 spin_lock_bh(&txq->axq_lock);
2057 if (txq->stopped &&
Sujithf7a99e42009-02-17 15:36:33 +05302058 sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
Sujith059d8062009-01-16 21:38:49 +05302059 qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
2060 if (qnum != -1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08002061 ath_mac80211_start_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302062 txq->stopped = 0;
2063 }
2064 }
2065 spin_unlock_bh(&txq->axq_lock);
2066}
2067
Sujithc4288392008-11-18 09:09:30 +05302068static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069{
Sujithcbe61d82009-02-09 13:27:12 +05302070 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002071 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002072 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2073 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302074 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002075 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302076 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002077 int status;
2078
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002079 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2080 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2081 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002082
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002083 for (;;) {
2084 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002085 if (list_empty(&txq->axq_q)) {
2086 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002087 spin_unlock_bh(&txq->axq_lock);
2088 break;
2089 }
2090 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2091
2092 /*
2093 * There is a race condition that a BH gets scheduled
2094 * after sw writes TxE and before hw re-load the last
2095 * descriptor to get the newly chained one.
2096 * Software must keep the last DONE descriptor as a
2097 * holding descriptor - software does so by marking
2098 * it with the STALE flag.
2099 */
2100 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302101 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002102 bf_held = bf;
2103 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302104 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002105 break;
2106 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002107 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302108 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109 }
2110 }
2111
2112 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302113 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002114
Felix Fietkau29bffa92010-03-29 20:14:23 -07002115 memset(&ts, 0, sizeof(ts));
2116 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117 if (status == -EINPROGRESS) {
2118 spin_unlock_bh(&txq->axq_lock);
2119 break;
2120 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002121
2122 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002123 * We now know the nullfunc frame has been ACKed so we
2124 * can disable RX.
2125 */
2126 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002127 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302128 if ((sc->ps_flags & PS_ENABLED))
2129 ath9k_enable_ps(sc);
2130 else
Sujith1b04b932010-01-08 10:36:05 +05302131 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002132 }
2133
2134 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002135 * Remove ath_buf's of the same transmit unit from txq,
2136 * however leave the last descriptor back as the holding
2137 * descriptor for hw.
2138 */
Sujitha119cc42009-03-30 15:28:38 +05302139 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002141 if (!list_is_singular(&lastbf->list))
2142 list_cut_position(&bf_head,
2143 &txq->axq_q, lastbf->list.prev);
2144
2145 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002146 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002147 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002148 if (bf_held)
2149 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002150 spin_unlock_bh(&txq->axq_lock);
2151
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002152 if (bf_held)
2153 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002154
Sujithcd3d39a2008-08-11 14:03:34 +05302155 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002156 /*
2157 * This frame is sent out as a single frame.
2158 * Use hardware retry status for this frame.
2159 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002160 bf->bf_retries = ts.ts_longretry;
2161 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302162 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002163 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164 }
Johannes Berge6a98542008-10-21 12:40:02 +02002165
Sujithcd3d39a2008-08-11 14:03:34 +05302166 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002167 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002168 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002169 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002170
Sujith059d8062009-01-16 21:38:49 +05302171 ath_wake_mac80211_queue(sc, txq);
2172
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002173 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302174 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002175 ath_txq_schedule(sc, txq);
2176 spin_unlock_bh(&txq->axq_lock);
2177 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002178}
2179
Sujith305fe472009-07-23 15:32:29 +05302180static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002181{
2182 struct ath_softc *sc = container_of(work, struct ath_softc,
2183 tx_complete_work.work);
2184 struct ath_txq *txq;
2185 int i;
2186 bool needreset = false;
2187
2188 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2189 if (ATH_TXQ_SETUP(sc, i)) {
2190 txq = &sc->tx.txq[i];
2191 spin_lock_bh(&txq->axq_lock);
2192 if (txq->axq_depth) {
2193 if (txq->axq_tx_inprogress) {
2194 needreset = true;
2195 spin_unlock_bh(&txq->axq_lock);
2196 break;
2197 } else {
2198 txq->axq_tx_inprogress = true;
2199 }
2200 }
2201 spin_unlock_bh(&txq->axq_lock);
2202 }
2203
2204 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002205 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2206 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302207 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002208 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302209 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002210 }
2211
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002212 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002213 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2214}
2215
2216
Sujithe8324352009-01-16 21:38:42 +05302217
2218void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002219{
Sujithe8324352009-01-16 21:38:42 +05302220 int i;
2221 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002222
Sujithe8324352009-01-16 21:38:42 +05302223 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002224
2225 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302226 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2227 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002228 }
2229}
2230
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002231void ath_tx_edma_tasklet(struct ath_softc *sc)
2232{
2233 struct ath_tx_status txs;
2234 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2235 struct ath_hw *ah = sc->sc_ah;
2236 struct ath_txq *txq;
2237 struct ath_buf *bf, *lastbf;
2238 struct list_head bf_head;
2239 int status;
2240 int txok;
2241
2242 for (;;) {
2243 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2244 if (status == -EINPROGRESS)
2245 break;
2246 if (status == -EIO) {
2247 ath_print(common, ATH_DBG_XMIT,
2248 "Error processing tx status\n");
2249 break;
2250 }
2251
2252 /* Skip beacon completions */
2253 if (txs.qid == sc->beacon.beaconq)
2254 continue;
2255
2256 txq = &sc->tx.txq[txs.qid];
2257
2258 spin_lock_bh(&txq->axq_lock);
2259 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2260 spin_unlock_bh(&txq->axq_lock);
2261 return;
2262 }
2263
2264 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2265 struct ath_buf, list);
2266 lastbf = bf->bf_lastbf;
2267
2268 INIT_LIST_HEAD(&bf_head);
2269 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2270 &lastbf->list);
2271 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2272 txq->axq_depth--;
2273 txq->axq_tx_inprogress = false;
2274 spin_unlock_bh(&txq->axq_lock);
2275
2276 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2277
2278 if (!bf_isampdu(bf)) {
2279 bf->bf_retries = txs.ts_longretry;
2280 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2281 bf->bf_state.bf_type |= BUF_XRETRY;
2282 ath_tx_rc_status(bf, &txs, 0, txok, true);
2283 }
2284
2285 if (bf_isampdu(bf))
2286 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2287 else
2288 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2289 &txs, txok, 0);
2290
2291 spin_lock_bh(&txq->axq_lock);
2292 if (!list_empty(&txq->txq_fifo_pending)) {
2293 INIT_LIST_HEAD(&bf_head);
2294 bf = list_first_entry(&txq->txq_fifo_pending,
2295 struct ath_buf, list);
2296 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2297 &bf->bf_lastbf->list);
2298 ath_tx_txqaddbuf(sc, txq, &bf_head);
2299 } else if (sc->sc_flags & SC_OP_TXAGGR)
2300 ath_txq_schedule(sc, txq);
2301 spin_unlock_bh(&txq->axq_lock);
2302 }
2303}
2304
Sujithe8324352009-01-16 21:38:42 +05302305/*****************/
2306/* Init, Cleanup */
2307/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002308
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002309static int ath_txstatus_setup(struct ath_softc *sc, int size)
2310{
2311 struct ath_descdma *dd = &sc->txsdma;
2312 u8 txs_len = sc->sc_ah->caps.txs_len;
2313
2314 dd->dd_desc_len = size * txs_len;
2315 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2316 &dd->dd_desc_paddr, GFP_KERNEL);
2317 if (!dd->dd_desc)
2318 return -ENOMEM;
2319
2320 return 0;
2321}
2322
2323static int ath_tx_edma_init(struct ath_softc *sc)
2324{
2325 int err;
2326
2327 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2328 if (!err)
2329 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2330 sc->txsdma.dd_desc_paddr,
2331 ATH_TXSTATUS_RING_SIZE);
2332
2333 return err;
2334}
2335
2336static void ath_tx_edma_cleanup(struct ath_softc *sc)
2337{
2338 struct ath_descdma *dd = &sc->txsdma;
2339
2340 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2341 dd->dd_desc_paddr);
2342}
2343
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002344int ath_tx_init(struct ath_softc *sc, int nbufs)
2345{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002346 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002347 int error = 0;
2348
Sujith797fe5cb2009-03-30 15:28:45 +05302349 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002350
Sujith797fe5cb2009-03-30 15:28:45 +05302351 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002352 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302353 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002354 ath_print(common, ATH_DBG_FATAL,
2355 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302356 goto err;
2357 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002358
Sujith797fe5cb2009-03-30 15:28:45 +05302359 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002360 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302361 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002362 ath_print(common, ATH_DBG_FATAL,
2363 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302364 goto err;
2365 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002367 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2368
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002369 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2370 error = ath_tx_edma_init(sc);
2371 if (error)
2372 goto err;
2373 }
2374
Sujith797fe5cb2009-03-30 15:28:45 +05302375err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002376 if (error != 0)
2377 ath_tx_cleanup(sc);
2378
2379 return error;
2380}
2381
Sujith797fe5cb2009-03-30 15:28:45 +05302382void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002383{
Sujithb77f4832008-12-07 21:44:03 +05302384 if (sc->beacon.bdma.dd_desc_len != 0)
2385 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002386
Sujithb77f4832008-12-07 21:44:03 +05302387 if (sc->tx.txdma.dd_desc_len != 0)
2388 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002389
2390 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2391 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002392}
2393
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002394void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2395{
Sujithc5170162008-10-29 10:13:59 +05302396 struct ath_atx_tid *tid;
2397 struct ath_atx_ac *ac;
2398 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002399
Sujith8ee5afb2008-12-07 21:43:36 +05302400 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302401 tidno < WME_NUM_TID;
2402 tidno++, tid++) {
2403 tid->an = an;
2404 tid->tidno = tidno;
2405 tid->seq_start = tid->seq_next = 0;
2406 tid->baw_size = WME_MAX_BA;
2407 tid->baw_head = tid->baw_tail = 0;
2408 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302409 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302410 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302411 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302412 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302413 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302414 tid->state &= ~AGGR_ADDBA_COMPLETE;
2415 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302416 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002417
Sujith8ee5afb2008-12-07 21:43:36 +05302418 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302419 acno < WME_NUM_AC; acno++, ac++) {
2420 ac->sched = false;
2421 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002422
Sujithc5170162008-10-29 10:13:59 +05302423 switch (acno) {
2424 case WME_AC_BE:
2425 ac->qnum = ath_tx_get_qnum(sc,
2426 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
2427 break;
2428 case WME_AC_BK:
2429 ac->qnum = ath_tx_get_qnum(sc,
2430 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
2431 break;
2432 case WME_AC_VI:
2433 ac->qnum = ath_tx_get_qnum(sc,
2434 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
2435 break;
2436 case WME_AC_VO:
2437 ac->qnum = ath_tx_get_qnum(sc,
2438 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
2439 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002440 }
2441 }
2442}
2443
Sujithb5aa9bf2008-10-29 10:13:31 +05302444void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002445{
2446 int i;
2447 struct ath_atx_ac *ac, *ac_tmp;
2448 struct ath_atx_tid *tid, *tid_tmp;
2449 struct ath_txq *txq;
Sujithe8324352009-01-16 21:38:42 +05302450
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002451 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
2452 if (ATH_TXQ_SETUP(sc, i)) {
Sujithb77f4832008-12-07 21:44:03 +05302453 txq = &sc->tx.txq[i];
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002454
Ming Leia9f042c2010-02-28 00:56:24 +08002455 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002456
2457 list_for_each_entry_safe(ac,
2458 ac_tmp, &txq->axq_acq, list) {
2459 tid = list_first_entry(&ac->tid_q,
2460 struct ath_atx_tid, list);
2461 if (tid && tid->an != an)
2462 continue;
2463 list_del(&ac->list);
2464 ac->sched = false;
2465
2466 list_for_each_entry_safe(tid,
2467 tid_tmp, &ac->tid_q, list) {
2468 list_del(&tid->list);
2469 tid->sched = false;
Sujithb5aa9bf2008-10-29 10:13:31 +05302470 ath_tid_drain(sc, txq, tid);
Sujitha37c2c72008-10-29 10:15:40 +05302471 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujitha37c2c72008-10-29 10:15:40 +05302472 tid->state &= ~AGGR_CLEANUP;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002473 }
2474 }
2475
Ming Leia9f042c2010-02-28 00:56:24 +08002476 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002477 }
2478 }
2479}