blob: 7547c8f9a584e780adb5007d346728be8a14f8ad [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
Sujithe8324352009-01-16 21:38:42 +0530987int ath_txq_update(struct ath_softc *sc, int qnum,
988 struct ath9k_tx_queue_info *qinfo)
989{
Sujithcbe61d82009-02-09 13:27:12 +0530990 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530991 int error = 0;
992 struct ath9k_tx_queue_info qi;
993
994 if (qnum == sc->beacon.beaconq) {
995 /*
996 * XXX: for beacon queue, we just save the parameter.
997 * It will be picked up by ath_beaconq_config when
998 * it's necessary.
999 */
1000 sc->beacon.beacon_qi = *qinfo;
1001 return 0;
1002 }
1003
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001004 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301005
1006 ath9k_hw_get_txq_props(ah, qnum, &qi);
1007 qi.tqi_aifs = qinfo->tqi_aifs;
1008 qi.tqi_cwmin = qinfo->tqi_cwmin;
1009 qi.tqi_cwmax = qinfo->tqi_cwmax;
1010 qi.tqi_burstTime = qinfo->tqi_burstTime;
1011 qi.tqi_readyTime = qinfo->tqi_readyTime;
1012
1013 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001014 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1015 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301016 error = -EIO;
1017 } else {
1018 ath9k_hw_resettxqueue(ah, qnum);
1019 }
1020
1021 return error;
1022}
1023
1024int ath_cabq_update(struct ath_softc *sc)
1025{
1026 struct ath9k_tx_queue_info qi;
1027 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301028
1029 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1030 /*
1031 * Ensure the readytime % is within the bounds.
1032 */
Sujith17d79042009-02-09 13:27:03 +05301033 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1034 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1035 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1036 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301037
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001038 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301039 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301040 ath_txq_update(sc, qnum, &qi);
1041
1042 return 0;
1043}
1044
Sujith043a0402009-01-16 21:38:47 +05301045/*
1046 * Drain a given TX queue (could be Beacon or Data)
1047 *
1048 * This assumes output has been stopped and
1049 * we do not need to block ath_tx_tasklet.
1050 */
1051void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301052{
1053 struct ath_buf *bf, *lastbf;
1054 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001055 struct ath_tx_status ts;
1056
1057 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301058 INIT_LIST_HEAD(&bf_head);
1059
Sujithe8324352009-01-16 21:38:42 +05301060 for (;;) {
1061 spin_lock_bh(&txq->axq_lock);
1062
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001063 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1064 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1065 txq->txq_headidx = txq->txq_tailidx = 0;
1066 spin_unlock_bh(&txq->axq_lock);
1067 break;
1068 } else {
1069 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1070 struct ath_buf, list);
1071 }
1072 } else {
1073 if (list_empty(&txq->axq_q)) {
1074 txq->axq_link = NULL;
1075 spin_unlock_bh(&txq->axq_lock);
1076 break;
1077 }
1078 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1079 list);
Sujithe8324352009-01-16 21:38:42 +05301080
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001081 if (bf->bf_stale) {
1082 list_del(&bf->list);
1083 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301084
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001085 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001086 continue;
1087 }
Sujithe8324352009-01-16 21:38:42 +05301088 }
1089
1090 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001091 if (!retry_tx)
1092 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301093
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001094 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1095 list_cut_position(&bf_head,
1096 &txq->txq_fifo[txq->txq_tailidx],
1097 &lastbf->list);
1098 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1099 } else {
1100 /* remove ath_buf's of the same mpdu from txq */
1101 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1102 }
1103
Sujithe8324352009-01-16 21:38:42 +05301104 txq->axq_depth--;
1105
1106 spin_unlock_bh(&txq->axq_lock);
1107
1108 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001109 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301110 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001111 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301112 }
1113
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001114 spin_lock_bh(&txq->axq_lock);
1115 txq->axq_tx_inprogress = false;
1116 spin_unlock_bh(&txq->axq_lock);
1117
Sujithe8324352009-01-16 21:38:42 +05301118 /* flush any pending frames if aggregation is enabled */
1119 if (sc->sc_flags & SC_OP_TXAGGR) {
1120 if (!retry_tx) {
1121 spin_lock_bh(&txq->axq_lock);
1122 ath_txq_drain_pending_buffers(sc, txq);
1123 spin_unlock_bh(&txq->axq_lock);
1124 }
1125 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001126
1127 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1128 spin_lock_bh(&txq->axq_lock);
1129 while (!list_empty(&txq->txq_fifo_pending)) {
1130 bf = list_first_entry(&txq->txq_fifo_pending,
1131 struct ath_buf, list);
1132 list_cut_position(&bf_head,
1133 &txq->txq_fifo_pending,
1134 &bf->bf_lastbf->list);
1135 spin_unlock_bh(&txq->axq_lock);
1136
1137 if (bf_isampdu(bf))
1138 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1139 &ts, 0);
1140 else
1141 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1142 &ts, 0, 0);
1143 spin_lock_bh(&txq->axq_lock);
1144 }
1145 spin_unlock_bh(&txq->axq_lock);
1146 }
Sujithe8324352009-01-16 21:38:42 +05301147}
1148
Sujith043a0402009-01-16 21:38:47 +05301149void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1150{
Sujithcbe61d82009-02-09 13:27:12 +05301151 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001152 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301153 struct ath_txq *txq;
1154 int i, npend = 0;
1155
1156 if (sc->sc_flags & SC_OP_INVALID)
1157 return;
1158
1159 /* Stop beacon queue */
1160 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1161
1162 /* Stop data queues */
1163 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1164 if (ATH_TXQ_SETUP(sc, i)) {
1165 txq = &sc->tx.txq[i];
1166 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1167 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1168 }
1169 }
1170
1171 if (npend) {
1172 int r;
1173
Sujithe8009e92009-12-14 14:57:08 +05301174 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001175 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301176
1177 spin_lock_bh(&sc->sc_resetlock);
Sujithe8009e92009-12-14 14:57:08 +05301178 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
Sujith043a0402009-01-16 21:38:47 +05301179 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001180 ath_print(common, ATH_DBG_FATAL,
1181 "Unable to reset hardware; reset status %d\n",
1182 r);
Sujith043a0402009-01-16 21:38:47 +05301183 spin_unlock_bh(&sc->sc_resetlock);
1184 }
1185
1186 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1187 if (ATH_TXQ_SETUP(sc, i))
1188 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1189 }
1190}
1191
Sujithe8324352009-01-16 21:38:42 +05301192void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1193{
1194 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1195 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1196}
1197
Sujithe8324352009-01-16 21:38:42 +05301198void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1199{
1200 struct ath_atx_ac *ac;
1201 struct ath_atx_tid *tid;
1202
1203 if (list_empty(&txq->axq_acq))
1204 return;
1205
1206 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1207 list_del(&ac->list);
1208 ac->sched = false;
1209
1210 do {
1211 if (list_empty(&ac->tid_q))
1212 return;
1213
1214 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1215 list_del(&tid->list);
1216 tid->sched = false;
1217
1218 if (tid->paused)
1219 continue;
1220
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001221 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301222
1223 /*
1224 * add tid to round-robin queue if more frames
1225 * are pending for the tid
1226 */
1227 if (!list_empty(&tid->buf_q))
1228 ath_tx_queue_tid(txq, tid);
1229
1230 break;
1231 } while (!list_empty(&ac->tid_q));
1232
1233 if (!list_empty(&ac->tid_q)) {
1234 if (!ac->sched) {
1235 ac->sched = true;
1236 list_add_tail(&ac->list, &txq->axq_acq);
1237 }
1238 }
1239}
1240
1241int ath_tx_setup(struct ath_softc *sc, int haltype)
1242{
1243 struct ath_txq *txq;
1244
1245 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001246 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1247 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301248 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1249 return 0;
1250 }
1251 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1252 if (txq != NULL) {
1253 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1254 return 1;
1255 } else
1256 return 0;
1257}
1258
1259/***********/
1260/* TX, DMA */
1261/***********/
1262
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001263/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001264 * Insert a chain of ath_buf (descriptors) on a txq and
1265 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001266 */
Sujith102e0572008-10-29 10:15:16 +05301267static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1268 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001269{
Sujithcbe61d82009-02-09 13:27:12 +05301270 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001271 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001272 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301273
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001274 /*
1275 * Insert the frame on the outbound list and
1276 * pass it on to the hardware.
1277 */
1278
1279 if (list_empty(head))
1280 return;
1281
1282 bf = list_first_entry(head, struct ath_buf, list);
1283
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001284 ath_print(common, ATH_DBG_QUEUE,
1285 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001286
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001287 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1288 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1289 list_splice_tail_init(head, &txq->txq_fifo_pending);
1290 return;
1291 }
1292 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1293 ath_print(common, ATH_DBG_XMIT,
1294 "Initializing tx fifo %d which "
1295 "is non-empty\n",
1296 txq->txq_headidx);
1297 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1298 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1299 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001300 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001301 ath_print(common, ATH_DBG_XMIT,
1302 "TXDP[%u] = %llx (%p)\n",
1303 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001304 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001305 list_splice_tail_init(head, &txq->axq_q);
1306
1307 if (txq->axq_link == NULL) {
1308 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1309 ath_print(common, ATH_DBG_XMIT,
1310 "TXDP[%u] = %llx (%p)\n",
1311 txq->axq_qnum, ito64(bf->bf_daddr),
1312 bf->bf_desc);
1313 } else {
1314 *txq->axq_link = bf->bf_daddr;
1315 ath_print(common, ATH_DBG_XMIT,
1316 "link[%u] (%p)=%llx (%p)\n",
1317 txq->axq_qnum, txq->axq_link,
1318 ito64(bf->bf_daddr), bf->bf_desc);
1319 }
1320 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1321 &txq->axq_link);
1322 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001323 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001324 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001325}
1326
Sujithe8324352009-01-16 21:38:42 +05301327static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1328 struct list_head *bf_head,
1329 struct ath_tx_control *txctl)
1330{
1331 struct ath_buf *bf;
1332
Sujithe8324352009-01-16 21:38:42 +05301333 bf = list_first_entry(bf_head, struct ath_buf, list);
1334 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301335 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301336
1337 /*
1338 * Do not queue to h/w when any of the following conditions is true:
1339 * - there are pending frames in software queue
1340 * - the TID is currently paused for ADDBA/BAR request
1341 * - seqno is not within block-ack window
1342 * - h/w queue depth exceeds low water mark
1343 */
1344 if (!list_empty(&tid->buf_q) || tid->paused ||
1345 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1346 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001347 /*
Sujithe8324352009-01-16 21:38:42 +05301348 * Add this frame to software queue for scheduling later
1349 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001350 */
Sujithd43f30152009-01-16 21:38:53 +05301351 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301352 ath_tx_queue_tid(txctl->txq, tid);
1353 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001354 }
1355
Sujithe8324352009-01-16 21:38:42 +05301356 /* Add sub-frame to BAW */
1357 ath_tx_addto_baw(sc, tid, bf);
1358
1359 /* Queue to h/w without aggregation */
1360 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301361 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301362 ath_buf_set_rate(sc, bf);
1363 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301364}
1365
Sujithc37452b2009-03-09 09:31:57 +05301366static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1367 struct ath_atx_tid *tid,
1368 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001369{
Sujithe8324352009-01-16 21:38:42 +05301370 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001371
Sujithe8324352009-01-16 21:38:42 +05301372 bf = list_first_entry(bf_head, struct ath_buf, list);
1373 bf->bf_state.bf_type &= ~BUF_AMPDU;
1374
1375 /* update starting sequence number for subsequent ADDBA request */
1376 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1377
1378 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301379 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301380 ath_buf_set_rate(sc, bf);
1381 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301382 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001383}
1384
Sujithc37452b2009-03-09 09:31:57 +05301385static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1386 struct list_head *bf_head)
1387{
1388 struct ath_buf *bf;
1389
1390 bf = list_first_entry(bf_head, struct ath_buf, list);
1391
1392 bf->bf_lastbf = bf;
1393 bf->bf_nframes = 1;
1394 ath_buf_set_rate(sc, bf);
1395 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301396 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301397}
1398
Sujith528f0c62008-10-29 10:14:26 +05301399static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001400{
Sujith528f0c62008-10-29 10:14:26 +05301401 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001402 enum ath9k_pkt_type htype;
1403 __le16 fc;
1404
Sujith528f0c62008-10-29 10:14:26 +05301405 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001406 fc = hdr->frame_control;
1407
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001408 if (ieee80211_is_beacon(fc))
1409 htype = ATH9K_PKT_TYPE_BEACON;
1410 else if (ieee80211_is_probe_resp(fc))
1411 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1412 else if (ieee80211_is_atim(fc))
1413 htype = ATH9K_PKT_TYPE_ATIM;
1414 else if (ieee80211_is_pspoll(fc))
1415 htype = ATH9K_PKT_TYPE_PSPOLL;
1416 else
1417 htype = ATH9K_PKT_TYPE_NORMAL;
1418
1419 return htype;
1420}
1421
Sujith528f0c62008-10-29 10:14:26 +05301422static int get_hw_crypto_keytype(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001423{
Sujith528f0c62008-10-29 10:14:26 +05301424 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1425
1426 if (tx_info->control.hw_key) {
1427 if (tx_info->control.hw_key->alg == ALG_WEP)
1428 return ATH9K_KEY_TYPE_WEP;
1429 else if (tx_info->control.hw_key->alg == ALG_TKIP)
1430 return ATH9K_KEY_TYPE_TKIP;
1431 else if (tx_info->control.hw_key->alg == ALG_CCMP)
1432 return ATH9K_KEY_TYPE_AES;
1433 }
1434
1435 return ATH9K_KEY_TYPE_CLEAR;
1436}
1437
Sujith528f0c62008-10-29 10:14:26 +05301438static void assign_aggr_tid_seqno(struct sk_buff *skb,
1439 struct ath_buf *bf)
1440{
1441 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1442 struct ieee80211_hdr *hdr;
1443 struct ath_node *an;
1444 struct ath_atx_tid *tid;
1445 __le16 fc;
1446 u8 *qc;
1447
1448 if (!tx_info->control.sta)
1449 return;
1450
1451 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1452 hdr = (struct ieee80211_hdr *)skb->data;
1453 fc = hdr->frame_control;
1454
Sujith528f0c62008-10-29 10:14:26 +05301455 if (ieee80211_is_data_qos(fc)) {
1456 qc = ieee80211_get_qos_ctl(hdr);
1457 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301458 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001459
Sujithe8324352009-01-16 21:38:42 +05301460 /*
1461 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301462 * We also override seqno set by upper layer with the one
1463 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301464 */
1465 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301466 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301467 bf->bf_seqno = tid->seq_next;
1468 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301469}
1470
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001471static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301472{
1473 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1474 int flags = 0;
1475
1476 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1477 flags |= ATH9K_TXDESC_INTREQ;
1478
1479 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1480 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301481
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001482 if (use_ldpc)
1483 flags |= ATH9K_TXDESC_LDPC;
1484
Sujith528f0c62008-10-29 10:14:26 +05301485 return flags;
1486}
1487
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001488/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001489 * rix - rate index
1490 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1491 * width - 0 for 20 MHz, 1 for 40 MHz
1492 * half_gi - to use 4us v/s 3.6 us for symbol time
1493 */
Sujith102e0572008-10-29 10:15:16 +05301494static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1495 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001496{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001498 int streams, pktlen;
1499
Sujithcd3d39a2008-08-11 14:03:34 +05301500 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301501
1502 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001503 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001504 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001505 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001506 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1507
1508 if (!half_gi)
1509 duration = SYMBOL_TIME(nsymbols);
1510 else
1511 duration = SYMBOL_TIME_HALFGI(nsymbols);
1512
Sujithe63835b2008-11-18 09:07:53 +05301513 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001514 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301515
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001516 return duration;
1517}
1518
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001519static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1520{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001521 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001522 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301523 struct sk_buff *skb;
1524 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301525 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001526 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301527 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301528 int i, flags = 0;
1529 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301530 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301531
1532 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301533
Sujitha22be222009-03-30 15:28:36 +05301534 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301535 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301536 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301537 hdr = (struct ieee80211_hdr *)skb->data;
1538 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301539
Sujithc89424d2009-01-30 14:29:28 +05301540 /*
1541 * We check if Short Preamble is needed for the CTS rate by
1542 * checking the BSS's global flag.
1543 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1544 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001545 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1546 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301547 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001548 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001549
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001550 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001551 bool is_40, is_sgi, is_sp;
1552 int phy;
1553
Sujithe63835b2008-11-18 09:07:53 +05301554 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001555 continue;
1556
Sujitha8efee42008-11-18 09:07:30 +05301557 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301558 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001559 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001560
Felix Fietkau27032052010-01-17 21:08:50 +01001561 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1562 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301563 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001564 flags |= ATH9K_TXDESC_RTSENA;
1565 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1566 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1567 flags |= ATH9K_TXDESC_CTSENA;
1568 }
1569
Sujithc89424d2009-01-30 14:29:28 +05301570 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1571 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1572 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1573 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001574
Felix Fietkau545750d2009-11-23 22:21:01 +01001575 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1576 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1577 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1578
1579 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1580 /* MCS rates */
1581 series[i].Rate = rix | 0x80;
1582 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1583 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001584 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1585 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001586 continue;
1587 }
1588
1589 /* legcay rates */
1590 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1591 !(rate->flags & IEEE80211_RATE_ERP_G))
1592 phy = WLAN_RC_PHY_CCK;
1593 else
1594 phy = WLAN_RC_PHY_OFDM;
1595
1596 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1597 series[i].Rate = rate->hw_value;
1598 if (rate->hw_value_short) {
1599 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1600 series[i].Rate |= rate->hw_value_short;
1601 } else {
1602 is_sp = false;
1603 }
1604
1605 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1606 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001607 }
1608
Felix Fietkau27032052010-01-17 21:08:50 +01001609 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1610 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1611 flags &= ~ATH9K_TXDESC_RTSENA;
1612
1613 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1614 if (flags & ATH9K_TXDESC_RTSENA)
1615 flags &= ~ATH9K_TXDESC_CTSENA;
1616
Sujithe63835b2008-11-18 09:07:53 +05301617 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301618 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1619 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301620 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301621 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301622
Sujith17d79042009-02-09 13:27:03 +05301623 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301624 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001625}
1626
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001627static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301628 struct sk_buff *skb,
1629 struct ath_tx_control *txctl)
1630{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001631 struct ath_wiphy *aphy = hw->priv;
1632 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301633 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1634 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301635 int hdrlen;
1636 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001637 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001638 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301639
Felix Fietkau827e69b2009-11-15 23:09:25 +01001640 tx_info->pad[0] = 0;
1641 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001642 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001643 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001644 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001645 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1646 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001647 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001648 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1649 break;
1650 }
Sujithe8324352009-01-16 21:38:42 +05301651 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1652 fc = hdr->frame_control;
1653
1654 ATH_TXBUF_RESET(bf);
1655
Felix Fietkau827e69b2009-11-15 23:09:25 +01001656 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001657 bf->bf_frmlen = skb->len + FCS_LEN;
1658 /* Remove the padding size from bf_frmlen, if any */
1659 padpos = ath9k_cmn_padpos(hdr->frame_control);
1660 padsize = padpos & 3;
1661 if (padsize && skb->len>padpos+padsize) {
1662 bf->bf_frmlen -= padsize;
1663 }
Sujithe8324352009-01-16 21:38:42 +05301664
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001665 if (conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301666 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001667 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1668 use_ldpc = true;
1669 }
Sujithe8324352009-01-16 21:38:42 +05301670
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001671 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301672
1673 bf->bf_keytype = get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301674 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1675 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1676 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1677 } else {
1678 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1679 }
1680
Sujith17b182e2009-12-14 14:56:56 +05301681 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1682 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301683 assign_aggr_tid_seqno(skb, bf);
1684
1685 bf->bf_mpdu = skb;
1686
1687 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1688 skb->len, DMA_TO_DEVICE);
1689 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1690 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001691 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1692 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301693 return -ENOMEM;
1694 }
1695
1696 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001697
1698 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1699 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1700 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301701 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001702 } else
1703 bf->bf_isnullfunc = false;
1704
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001705 bf->bf_tx_aborted = false;
1706
Sujithe8324352009-01-16 21:38:42 +05301707 return 0;
1708}
1709
1710/* FIXME: tx power */
1711static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1712 struct ath_tx_control *txctl)
1713{
Sujitha22be222009-03-30 15:28:36 +05301714 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301715 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301716 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301717 struct ath_node *an = NULL;
1718 struct list_head bf_head;
1719 struct ath_desc *ds;
1720 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301721 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301722 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301723 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301724
1725 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301726 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301727
1728 INIT_LIST_HEAD(&bf_head);
1729 list_add_tail(&bf->list, &bf_head);
1730
1731 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001732 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301733
1734 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1735 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1736
1737 ath9k_hw_filltxdesc(ah, ds,
1738 skb->len, /* segment length */
1739 true, /* first segment */
1740 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001741 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001742 bf->bf_buf_addr,
1743 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301744
Sujithe8324352009-01-16 21:38:42 +05301745 spin_lock_bh(&txctl->txq->axq_lock);
1746
1747 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1748 tx_info->control.sta) {
1749 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1750 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1751
Sujithc37452b2009-03-09 09:31:57 +05301752 if (!ieee80211_is_data_qos(fc)) {
1753 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1754 goto tx_done;
1755 }
1756
Felix Fietkau4fdec032010-03-12 04:02:43 +01001757 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301758 /*
1759 * Try aggregation if it's a unicast data frame
1760 * and the destination is HT capable.
1761 */
1762 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1763 } else {
1764 /*
1765 * Send this frame as regular when ADDBA
1766 * exchange is neither complete nor pending.
1767 */
Sujithc37452b2009-03-09 09:31:57 +05301768 ath_tx_send_ht_normal(sc, txctl->txq,
1769 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301770 }
1771 } else {
Sujithc37452b2009-03-09 09:31:57 +05301772 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301773 }
1774
Sujithc37452b2009-03-09 09:31:57 +05301775tx_done:
Sujithe8324352009-01-16 21:38:42 +05301776 spin_unlock_bh(&txctl->txq->axq_lock);
1777}
1778
1779/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001780int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301781 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001782{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001783 struct ath_wiphy *aphy = hw->priv;
1784 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001785 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001786 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001787 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301788 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001789
Sujithe8324352009-01-16 21:38:42 +05301790 bf = ath_tx_get_buffer(sc);
1791 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001792 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301793 return -1;
1794 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001795
Felix Fietkau84642d62010-06-01 21:33:13 +02001796 bf->txq = txctl->txq;
1797 spin_lock_bh(&bf->txq->axq_lock);
1798 if (++bf->txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1799 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1800 txq->stopped = 1;
1801 }
1802 spin_unlock_bh(&bf->txq->axq_lock);
1803
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001804 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301805 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001806 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001807
Sujithe8324352009-01-16 21:38:42 +05301808 /* upon ath_tx_processq() this TX queue will be resumed, we
1809 * guarantee this will happen by knowing beforehand that
1810 * we will at least have to run TX completionon one buffer
1811 * on the queue */
1812 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001813 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001814 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301815 txq->stopped = 1;
1816 }
1817 spin_unlock_bh(&txq->axq_lock);
1818
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001819 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301820
1821 return r;
1822 }
1823
1824 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001825
1826 return 0;
1827}
1828
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001829void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001830{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001831 struct ath_wiphy *aphy = hw->priv;
1832 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001833 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001834 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1835 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301836 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1837 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001838
Sujithe8324352009-01-16 21:38:42 +05301839 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001840
Sujithe8324352009-01-16 21:38:42 +05301841 /*
1842 * As a temporary workaround, assign seq# here; this will likely need
1843 * to be cleaned up to work better with Beacon transmission and virtual
1844 * BSSes.
1845 */
1846 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301847 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1848 sc->tx.seq_no += 0x10;
1849 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1850 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001851 }
1852
Sujithe8324352009-01-16 21:38:42 +05301853 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001854 padpos = ath9k_cmn_padpos(hdr->frame_control);
1855 padsize = padpos & 3;
1856 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301857 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001858 ath_print(common, ATH_DBG_XMIT,
1859 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301860 dev_kfree_skb_any(skb);
1861 return;
1862 }
1863 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001864 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001865 }
1866
Sujithe8324352009-01-16 21:38:42 +05301867 txctl.txq = sc->beacon.cabq;
1868
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001869 ath_print(common, ATH_DBG_XMIT,
1870 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301871
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001872 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001873 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301874 goto exit;
1875 }
1876
1877 return;
1878exit:
1879 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001880}
1881
Sujithe8324352009-01-16 21:38:42 +05301882/*****************/
1883/* TX Completion */
1884/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001885
Sujithe8324352009-01-16 21:38:42 +05301886static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001887 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001888{
Sujithe8324352009-01-16 21:38:42 +05301889 struct ieee80211_hw *hw = sc->hw;
1890 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001891 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001892 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
1893 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301894
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001895 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301896
Felix Fietkau827e69b2009-11-15 23:09:25 +01001897 if (aphy)
1898 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301899
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301900 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301901 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301902
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301903 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301904 /* Frame was ACKed */
1905 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1906 }
1907
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001908 padpos = ath9k_cmn_padpos(hdr->frame_control);
1909 padsize = padpos & 3;
1910 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301911 /*
1912 * Remove MAC header padding before giving the frame back to
1913 * mac80211.
1914 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001915 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301916 skb_pull(skb, padsize);
1917 }
1918
Sujith1b04b932010-01-08 10:36:05 +05301919 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1920 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001921 ath_print(common, ATH_DBG_PS,
1922 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001923 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301924 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1925 PS_WAIT_FOR_CAB |
1926 PS_WAIT_FOR_PSPOLL_DATA |
1927 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001928 }
1929
Felix Fietkau827e69b2009-11-15 23:09:25 +01001930 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001931 ath9k_tx_status(hw, skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001932 else
1933 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301934}
1935
1936static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001937 struct ath_txq *txq, struct list_head *bf_q,
1938 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301939{
1940 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301941 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301942 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301943
Sujithe8324352009-01-16 21:38:42 +05301944 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301945 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301946
1947 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301948 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301949
1950 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301951 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301952 }
1953
Felix Fietkau84642d62010-06-01 21:33:13 +02001954 if (bf->txq) {
1955 spin_lock_bh(&bf->txq->axq_lock);
1956 bf->txq->pending_frames--;
1957 spin_unlock_bh(&bf->txq->axq_lock);
1958 bf->txq = NULL;
1959 }
1960
Sujithe8324352009-01-16 21:38:42 +05301961 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001962 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001963 ath_debug_stat_tx(sc, txq, bf, ts);
Sujithe8324352009-01-16 21:38:42 +05301964
1965 /*
1966 * Return the list of ath_buf of this mpdu to free queue
1967 */
1968 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1969 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1970 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1971}
1972
1973static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001974 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301975{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001976 u16 seq_st = 0;
1977 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301978 int ba_index;
1979 int nbad = 0;
1980 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001981
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001982 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301983 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301984
Sujithcd3d39a2008-08-11 14:03:34 +05301985 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001986 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001987 seq_st = ts->ts_seqnum;
1988 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001989 }
1990
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001991 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301992 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1993 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1994 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001995
Sujithe8324352009-01-16 21:38:42 +05301996 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001997 }
1998
Sujithe8324352009-01-16 21:38:42 +05301999 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002000}
2001
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002002static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302003 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302004{
Sujitha22be222009-03-30 15:28:36 +05302005 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302006 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302007 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01002008 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302009 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302010
Sujith95e4acb2009-03-13 08:56:09 +05302011 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002012 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302013
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002014 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302015 WARN_ON(tx_rateindex >= hw->max_rates);
2016
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002017 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302018 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01002019 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
2020 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302021
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002022 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302023 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05302024 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002025 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01002026 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
2027 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002028 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2029 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002030 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2031 tx_info->status.ampdu_len = bf->bf_nframes;
2032 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302033 }
2034 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302035
Felix Fietkau545750d2009-11-23 22:21:01 +01002036 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302037 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002038 tx_info->status.rates[i].idx = -1;
2039 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302040
2041 tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
Sujithc4288392008-11-18 09:09:30 +05302042}
2043
Sujith059d8062009-01-16 21:38:49 +05302044static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2045{
2046 int qnum;
2047
2048 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02002049 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Sujith059d8062009-01-16 21:38:49 +05302050 qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
2051 if (qnum != -1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08002052 ath_mac80211_start_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302053 txq->stopped = 0;
2054 }
2055 }
2056 spin_unlock_bh(&txq->axq_lock);
2057}
2058
Sujithc4288392008-11-18 09:09:30 +05302059static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060{
Sujithcbe61d82009-02-09 13:27:12 +05302061 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002062 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002063 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2064 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302065 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002066 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302067 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002068 int status;
2069
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002070 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2071 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2072 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002073
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002074 for (;;) {
2075 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076 if (list_empty(&txq->axq_q)) {
2077 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002078 spin_unlock_bh(&txq->axq_lock);
2079 break;
2080 }
2081 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2082
2083 /*
2084 * There is a race condition that a BH gets scheduled
2085 * after sw writes TxE and before hw re-load the last
2086 * descriptor to get the newly chained one.
2087 * Software must keep the last DONE descriptor as a
2088 * holding descriptor - software does so by marking
2089 * it with the STALE flag.
2090 */
2091 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302092 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002093 bf_held = bf;
2094 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302095 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002096 break;
2097 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302099 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002100 }
2101 }
2102
2103 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302104 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002105
Felix Fietkau29bffa92010-03-29 20:14:23 -07002106 memset(&ts, 0, sizeof(ts));
2107 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002108 if (status == -EINPROGRESS) {
2109 spin_unlock_bh(&txq->axq_lock);
2110 break;
2111 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002112
2113 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002114 * We now know the nullfunc frame has been ACKed so we
2115 * can disable RX.
2116 */
2117 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002118 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302119 if ((sc->ps_flags & PS_ENABLED))
2120 ath9k_enable_ps(sc);
2121 else
Sujith1b04b932010-01-08 10:36:05 +05302122 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002123 }
2124
2125 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002126 * Remove ath_buf's of the same transmit unit from txq,
2127 * however leave the last descriptor back as the holding
2128 * descriptor for hw.
2129 */
Sujitha119cc42009-03-30 15:28:38 +05302130 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002131 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002132 if (!list_is_singular(&lastbf->list))
2133 list_cut_position(&bf_head,
2134 &txq->axq_q, lastbf->list.prev);
2135
2136 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002137 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002138 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002139 if (bf_held)
2140 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002141 spin_unlock_bh(&txq->axq_lock);
2142
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002143 if (bf_held)
2144 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002145
Sujithcd3d39a2008-08-11 14:03:34 +05302146 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002147 /*
2148 * This frame is sent out as a single frame.
2149 * Use hardware retry status for this frame.
2150 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002151 bf->bf_retries = ts.ts_longretry;
2152 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302153 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002154 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002155 }
Johannes Berge6a98542008-10-21 12:40:02 +02002156
Sujithcd3d39a2008-08-11 14:03:34 +05302157 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002158 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002159 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002160 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002161
Sujith059d8062009-01-16 21:38:49 +05302162 ath_wake_mac80211_queue(sc, txq);
2163
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002164 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302165 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002166 ath_txq_schedule(sc, txq);
2167 spin_unlock_bh(&txq->axq_lock);
2168 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002169}
2170
Sujith305fe472009-07-23 15:32:29 +05302171static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002172{
2173 struct ath_softc *sc = container_of(work, struct ath_softc,
2174 tx_complete_work.work);
2175 struct ath_txq *txq;
2176 int i;
2177 bool needreset = false;
2178
2179 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2180 if (ATH_TXQ_SETUP(sc, i)) {
2181 txq = &sc->tx.txq[i];
2182 spin_lock_bh(&txq->axq_lock);
2183 if (txq->axq_depth) {
2184 if (txq->axq_tx_inprogress) {
2185 needreset = true;
2186 spin_unlock_bh(&txq->axq_lock);
2187 break;
2188 } else {
2189 txq->axq_tx_inprogress = true;
2190 }
2191 }
2192 spin_unlock_bh(&txq->axq_lock);
2193 }
2194
2195 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002196 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2197 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302198 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002199 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302200 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002201 }
2202
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002203 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002204 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2205}
2206
2207
Sujithe8324352009-01-16 21:38:42 +05302208
2209void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002210{
Sujithe8324352009-01-16 21:38:42 +05302211 int i;
2212 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002213
Sujithe8324352009-01-16 21:38:42 +05302214 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002215
2216 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302217 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2218 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002219 }
2220}
2221
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002222void ath_tx_edma_tasklet(struct ath_softc *sc)
2223{
2224 struct ath_tx_status txs;
2225 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2226 struct ath_hw *ah = sc->sc_ah;
2227 struct ath_txq *txq;
2228 struct ath_buf *bf, *lastbf;
2229 struct list_head bf_head;
2230 int status;
2231 int txok;
2232
2233 for (;;) {
2234 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2235 if (status == -EINPROGRESS)
2236 break;
2237 if (status == -EIO) {
2238 ath_print(common, ATH_DBG_XMIT,
2239 "Error processing tx status\n");
2240 break;
2241 }
2242
2243 /* Skip beacon completions */
2244 if (txs.qid == sc->beacon.beaconq)
2245 continue;
2246
2247 txq = &sc->tx.txq[txs.qid];
2248
2249 spin_lock_bh(&txq->axq_lock);
2250 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2251 spin_unlock_bh(&txq->axq_lock);
2252 return;
2253 }
2254
2255 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2256 struct ath_buf, list);
2257 lastbf = bf->bf_lastbf;
2258
2259 INIT_LIST_HEAD(&bf_head);
2260 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2261 &lastbf->list);
2262 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2263 txq->axq_depth--;
2264 txq->axq_tx_inprogress = false;
2265 spin_unlock_bh(&txq->axq_lock);
2266
2267 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2268
Vasanthakumar Thiagarajande0f6482010-05-17 18:57:54 -07002269 /*
2270 * Make sure null func frame is acked before configuring
2271 * hw into ps mode.
2272 */
2273 if (bf->bf_isnullfunc && txok) {
2274 if ((sc->ps_flags & PS_ENABLED))
2275 ath9k_enable_ps(sc);
2276 else
2277 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
2278 }
2279
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002280 if (!bf_isampdu(bf)) {
2281 bf->bf_retries = txs.ts_longretry;
2282 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2283 bf->bf_state.bf_type |= BUF_XRETRY;
2284 ath_tx_rc_status(bf, &txs, 0, txok, true);
2285 }
2286
2287 if (bf_isampdu(bf))
2288 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2289 else
2290 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2291 &txs, txok, 0);
2292
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002293 ath_wake_mac80211_queue(sc, txq);
2294
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002295 spin_lock_bh(&txq->axq_lock);
2296 if (!list_empty(&txq->txq_fifo_pending)) {
2297 INIT_LIST_HEAD(&bf_head);
2298 bf = list_first_entry(&txq->txq_fifo_pending,
2299 struct ath_buf, list);
2300 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2301 &bf->bf_lastbf->list);
2302 ath_tx_txqaddbuf(sc, txq, &bf_head);
2303 } else if (sc->sc_flags & SC_OP_TXAGGR)
2304 ath_txq_schedule(sc, txq);
2305 spin_unlock_bh(&txq->axq_lock);
2306 }
2307}
2308
Sujithe8324352009-01-16 21:38:42 +05302309/*****************/
2310/* Init, Cleanup */
2311/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002312
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002313static int ath_txstatus_setup(struct ath_softc *sc, int size)
2314{
2315 struct ath_descdma *dd = &sc->txsdma;
2316 u8 txs_len = sc->sc_ah->caps.txs_len;
2317
2318 dd->dd_desc_len = size * txs_len;
2319 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2320 &dd->dd_desc_paddr, GFP_KERNEL);
2321 if (!dd->dd_desc)
2322 return -ENOMEM;
2323
2324 return 0;
2325}
2326
2327static int ath_tx_edma_init(struct ath_softc *sc)
2328{
2329 int err;
2330
2331 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2332 if (!err)
2333 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2334 sc->txsdma.dd_desc_paddr,
2335 ATH_TXSTATUS_RING_SIZE);
2336
2337 return err;
2338}
2339
2340static void ath_tx_edma_cleanup(struct ath_softc *sc)
2341{
2342 struct ath_descdma *dd = &sc->txsdma;
2343
2344 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2345 dd->dd_desc_paddr);
2346}
2347
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002348int ath_tx_init(struct ath_softc *sc, int nbufs)
2349{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002350 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002351 int error = 0;
2352
Sujith797fe5cb2009-03-30 15:28:45 +05302353 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354
Sujith797fe5cb2009-03-30 15:28:45 +05302355 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002356 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302357 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002358 ath_print(common, ATH_DBG_FATAL,
2359 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302360 goto err;
2361 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002362
Sujith797fe5cb2009-03-30 15:28:45 +05302363 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002364 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302365 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002366 ath_print(common, ATH_DBG_FATAL,
2367 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302368 goto err;
2369 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002370
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002371 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2372
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002373 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2374 error = ath_tx_edma_init(sc);
2375 if (error)
2376 goto err;
2377 }
2378
Sujith797fe5cb2009-03-30 15:28:45 +05302379err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002380 if (error != 0)
2381 ath_tx_cleanup(sc);
2382
2383 return error;
2384}
2385
Sujith797fe5cb2009-03-30 15:28:45 +05302386void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002387{
Sujithb77f4832008-12-07 21:44:03 +05302388 if (sc->beacon.bdma.dd_desc_len != 0)
2389 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002390
Sujithb77f4832008-12-07 21:44:03 +05302391 if (sc->tx.txdma.dd_desc_len != 0)
2392 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002393
2394 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2395 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002396}
2397
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002398void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2399{
Sujithc5170162008-10-29 10:13:59 +05302400 struct ath_atx_tid *tid;
2401 struct ath_atx_ac *ac;
2402 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002403
Sujith8ee5afb2008-12-07 21:43:36 +05302404 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302405 tidno < WME_NUM_TID;
2406 tidno++, tid++) {
2407 tid->an = an;
2408 tid->tidno = tidno;
2409 tid->seq_start = tid->seq_next = 0;
2410 tid->baw_size = WME_MAX_BA;
2411 tid->baw_head = tid->baw_tail = 0;
2412 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302413 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302414 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302415 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302416 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302417 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302418 tid->state &= ~AGGR_ADDBA_COMPLETE;
2419 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302420 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002421
Sujith8ee5afb2008-12-07 21:43:36 +05302422 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302423 acno < WME_NUM_AC; acno++, ac++) {
2424 ac->sched = false;
2425 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002426
Sujithc5170162008-10-29 10:13:59 +05302427 switch (acno) {
2428 case WME_AC_BE:
2429 ac->qnum = ath_tx_get_qnum(sc,
2430 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
2431 break;
2432 case WME_AC_BK:
2433 ac->qnum = ath_tx_get_qnum(sc,
2434 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
2435 break;
2436 case WME_AC_VI:
2437 ac->qnum = ath_tx_get_qnum(sc,
2438 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
2439 break;
2440 case WME_AC_VO:
2441 ac->qnum = ath_tx_get_qnum(sc,
2442 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
2443 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002444 }
2445 }
2446}
2447
Sujithb5aa9bf2008-10-29 10:13:31 +05302448void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002449{
2450 int i;
2451 struct ath_atx_ac *ac, *ac_tmp;
2452 struct ath_atx_tid *tid, *tid_tmp;
2453 struct ath_txq *txq;
Sujithe8324352009-01-16 21:38:42 +05302454
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002455 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
2456 if (ATH_TXQ_SETUP(sc, i)) {
Sujithb77f4832008-12-07 21:44:03 +05302457 txq = &sc->tx.txq[i];
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002458
Ming Leia9f042c2010-02-28 00:56:24 +08002459 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002460
2461 list_for_each_entry_safe(ac,
2462 ac_tmp, &txq->axq_acq, list) {
2463 tid = list_first_entry(&ac->tid_q,
2464 struct ath_atx_tid, list);
2465 if (tid && tid->an != an)
2466 continue;
2467 list_del(&ac->list);
2468 ac->sched = false;
2469
2470 list_for_each_entry_safe(tid,
2471 tid_tmp, &ac->tid_q, list) {
2472 list_del(&tid->list);
2473 tid->sched = false;
Sujithb5aa9bf2008-10-29 10:13:31 +05302474 ath_tid_drain(sc, txq, tid);
Sujitha37c2c72008-10-29 10:15:40 +05302475 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujitha37c2c72008-10-29 10:15:40 +05302476 tid->state &= ~AGGR_CLEANUP;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002477 }
2478 }
2479
Ming Leia9f042c2010-02-28 00:56:24 +08002480 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002481 }
2482 }
2483}