blob: 4078982fb9e97ade9aca78de3ab330ba39cb16a8 [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
37static u32 bits_per_symbol[][2] = {
38 /* 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 */
47 { 52, 108 }, /* 8: BPSK */
48 { 104, 216 }, /* 9: QPSK 1/2 */
49 { 156, 324 }, /* 10: QPSK 3/4 */
50 { 208, 432 }, /* 11: 16-QAM 1/2 */
51 { 312, 648 }, /* 12: 16-QAM 3/4 */
52 { 416, 864 }, /* 13: 64-QAM 2/3 */
53 { 468, 972 }, /* 14: 64-QAM 3/4 */
54 { 520, 1080 }, /* 15: 64-QAM 5/6 */
55};
56
57#define IS_HT_RATE(_rate) ((_rate) & 0x80)
58
Sujithc37452b2009-03-09 09:31:57 +053059static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
60 struct ath_atx_tid *tid,
61 struct list_head *bf_head);
Sujithe8324352009-01-16 21:38:42 +053062static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070063 struct ath_txq *txq, struct list_head *bf_q,
64 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053065static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
66 struct list_head *head);
67static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +053068static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070069 struct ath_tx_status *ts, int txok);
70static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +053071 int nbad, int txok, bool update_rc);
Sujithe8324352009-01-16 21:38:42 +053072
Felix Fietkau545750d2009-11-23 22:21:01 +010073enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020074 MCS_HT20,
75 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010076 MCS_HT40,
77 MCS_HT40_SGI,
78};
79
Felix Fietkau0e668cd2010-04-19 19:57:32 +020080static int ath_max_4ms_framelen[4][32] = {
81 [MCS_HT20] = {
82 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
83 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
84 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
85 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
86 },
87 [MCS_HT20_SGI] = {
88 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
89 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
90 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
91 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010092 },
93 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020094 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
95 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
96 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
97 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010098 },
99 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200100 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
101 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
102 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
103 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +0100104 }
105};
106
Sujithe8324352009-01-16 21:38:42 +0530107/*********************/
108/* Aggregation logic */
109/*********************/
110
Sujithe8324352009-01-16 21:38:42 +0530111static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
112{
113 struct ath_atx_ac *ac = tid->ac;
114
115 if (tid->paused)
116 return;
117
118 if (tid->sched)
119 return;
120
121 tid->sched = true;
122 list_add_tail(&tid->list, &ac->tid_q);
123
124 if (ac->sched)
125 return;
126
127 ac->sched = true;
128 list_add_tail(&ac->list, &txq->axq_acq);
129}
130
131static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
132{
133 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
134
135 spin_lock_bh(&txq->axq_lock);
136 tid->paused++;
137 spin_unlock_bh(&txq->axq_lock);
138}
139
140static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
141{
142 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
143
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700144 BUG_ON(tid->paused <= 0);
Sujithe8324352009-01-16 21:38:42 +0530145 spin_lock_bh(&txq->axq_lock);
146
147 tid->paused--;
148
149 if (tid->paused > 0)
150 goto unlock;
151
152 if (list_empty(&tid->buf_q))
153 goto unlock;
154
155 ath_tx_queue_tid(txq, tid);
156 ath_txq_schedule(sc, txq);
157unlock:
158 spin_unlock_bh(&txq->axq_lock);
159}
160
161static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
162{
163 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
164 struct ath_buf *bf;
165 struct list_head bf_head;
166 INIT_LIST_HEAD(&bf_head);
167
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700168 BUG_ON(tid->paused <= 0);
Sujithe8324352009-01-16 21:38:42 +0530169 spin_lock_bh(&txq->axq_lock);
170
171 tid->paused--;
172
173 if (tid->paused > 0) {
174 spin_unlock_bh(&txq->axq_lock);
175 return;
176 }
177
178 while (!list_empty(&tid->buf_q)) {
179 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700180 BUG_ON(bf_isretried(bf));
Sujithd43f30152009-01-16 21:38:53 +0530181 list_move_tail(&bf->list, &bf_head);
Sujithc37452b2009-03-09 09:31:57 +0530182 ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530183 }
184
185 spin_unlock_bh(&txq->axq_lock);
186}
187
188static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
189 int seqno)
190{
191 int index, cindex;
192
193 index = ATH_BA_INDEX(tid->seq_start, seqno);
194 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
195
196 tid->tx_buf[cindex] = NULL;
197
198 while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
199 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
200 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
201 }
202}
203
204static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
205 struct ath_buf *bf)
206{
207 int index, cindex;
208
209 if (bf_isretried(bf))
210 return;
211
212 index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
213 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
214
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700215 BUG_ON(tid->tx_buf[cindex] != NULL);
Sujithe8324352009-01-16 21:38:42 +0530216 tid->tx_buf[cindex] = bf;
217
218 if (index >= ((tid->baw_tail - tid->baw_head) &
219 (ATH_TID_MAX_BUFS - 1))) {
220 tid->baw_tail = cindex;
221 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
222 }
223}
224
225/*
226 * TODO: For frame(s) that are in the retry state, we will reuse the
227 * sequence number(s) without setting the retry bit. The
228 * alternative is to give up on these and BAR the receiver's window
229 * forward.
230 */
231static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
232 struct ath_atx_tid *tid)
233
234{
235 struct ath_buf *bf;
236 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700237 struct ath_tx_status ts;
238
239 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530240 INIT_LIST_HEAD(&bf_head);
241
242 for (;;) {
243 if (list_empty(&tid->buf_q))
244 break;
Sujithe8324352009-01-16 21:38:42 +0530245
Sujithd43f30152009-01-16 21:38:53 +0530246 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
247 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530248
249 if (bf_isretried(bf))
250 ath_tx_update_baw(sc, tid, bf->bf_seqno);
251
252 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700253 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530254 spin_lock(&txq->axq_lock);
255 }
256
257 tid->seq_next = tid->seq_start;
258 tid->baw_tail = tid->baw_head;
259}
260
Sujithfec247c2009-07-27 12:08:16 +0530261static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
262 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530263{
264 struct sk_buff *skb;
265 struct ieee80211_hdr *hdr;
266
267 bf->bf_state.bf_type |= BUF_RETRY;
268 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530269 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530270
271 skb = bf->bf_mpdu;
272 hdr = (struct ieee80211_hdr *)skb->data;
273 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
274}
275
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200276static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
277{
278 struct ath_buf *bf = NULL;
279
280 spin_lock_bh(&sc->tx.txbuflock);
281
282 if (unlikely(list_empty(&sc->tx.txbuf))) {
283 spin_unlock_bh(&sc->tx.txbuflock);
284 return NULL;
285 }
286
287 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
288 list_del(&bf->list);
289
290 spin_unlock_bh(&sc->tx.txbuflock);
291
292 return bf;
293}
294
295static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
296{
297 spin_lock_bh(&sc->tx.txbuflock);
298 list_add_tail(&bf->list, &sc->tx.txbuf);
299 spin_unlock_bh(&sc->tx.txbuflock);
300}
301
Sujithd43f30152009-01-16 21:38:53 +0530302static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
303{
304 struct ath_buf *tbf;
305
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200306 tbf = ath_tx_get_buffer(sc);
307 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530308 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530309
310 ATH_TXBUF_RESET(tbf);
311
Felix Fietkau827e69b2009-11-15 23:09:25 +0100312 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530313 tbf->bf_mpdu = bf->bf_mpdu;
314 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400315 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530316 tbf->bf_state = bf->bf_state;
317 tbf->bf_dmacontext = bf->bf_dmacontext;
318
319 return tbf;
320}
321
322static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
323 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700324 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530325{
326 struct ath_node *an = NULL;
327 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530328 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800329 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530330 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800331 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530332 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530333 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530334 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530335 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530336 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530337 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
338 bool rc_update = true;
Sujithe8324352009-01-16 21:38:42 +0530339
Sujitha22be222009-03-30 15:28:36 +0530340 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530341 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530342
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800343 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100344 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800345
Sujith1286ec62009-01-27 13:30:37 +0530346 rcu_read_lock();
347
Johannes Berg5ed176e2009-11-04 14:42:28 +0100348 /* XXX: use ieee80211_find_sta! */
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800349 sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
Sujith1286ec62009-01-27 13:30:37 +0530350 if (!sta) {
351 rcu_read_unlock();
352 return;
Sujithe8324352009-01-16 21:38:42 +0530353 }
354
Sujith1286ec62009-01-27 13:30:37 +0530355 an = (struct ath_node *)sta->drv_priv;
356 tid = ATH_AN_2_TID(an, bf->bf_tidno);
357
Sujithe8324352009-01-16 21:38:42 +0530358 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530359 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530360
Sujithd43f30152009-01-16 21:38:53 +0530361 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700362 if (ts->ts_flags & ATH9K_TX_BA) {
363 seq_st = ts->ts_seqnum;
364 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530365 } else {
Sujithd43f30152009-01-16 21:38:53 +0530366 /*
367 * AR5416 can become deaf/mute when BA
368 * issue happens. Chip needs to be reset.
369 * But AP code may have sychronization issues
370 * when perform internal reset in this routine.
371 * Only enable reset in STA mode for now.
372 */
Sujith2660b812009-02-09 13:27:26 +0530373 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530374 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530375 }
376 }
377
378 INIT_LIST_HEAD(&bf_pending);
379 INIT_LIST_HEAD(&bf_head);
380
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700381 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530382 while (bf) {
383 txfail = txpending = 0;
384 bf_next = bf->bf_next;
385
386 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
387 /* transmit completion, subframe is
388 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530389 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530390 } else if (!isaggr && txok) {
391 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530392 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530393 } else {
Sujithe8324352009-01-16 21:38:42 +0530394 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400395 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530396 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530397 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530398 txpending = 1;
399 } else {
400 bf->bf_state.bf_type |= BUF_XRETRY;
401 txfail = 1;
402 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530403 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530404 }
405 } else {
406 /*
407 * cleanup in progress, just fail
408 * the un-acked sub-frames
409 */
410 txfail = 1;
411 }
412 }
413
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400414 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
415 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530416 /*
417 * Make sure the last desc is reclaimed if it
418 * not a holding desc.
419 */
420 if (!bf_last->bf_stale)
421 list_move_tail(&bf->list, &bf_head);
422 else
423 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530424 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700425 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530426 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530427 }
428
429 if (!txpending) {
430 /*
431 * complete the acked-ones/xretried ones; update
432 * block-ack window
433 */
434 spin_lock_bh(&txq->axq_lock);
435 ath_tx_update_baw(sc, tid, bf->bf_seqno);
436 spin_unlock_bh(&txq->axq_lock);
437
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530438 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700439 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530440 rc_update = false;
441 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700442 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530443 }
444
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700445 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
446 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530447 } else {
Sujithd43f30152009-01-16 21:38:53 +0530448 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400449 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
450 if (bf->bf_next == NULL && bf_last->bf_stale) {
451 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530452
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400453 tbf = ath_clone_txbuf(sc, bf_last);
454 /*
455 * Update tx baw and complete the
456 * frame with failed status if we
457 * run out of tx buf.
458 */
459 if (!tbf) {
460 spin_lock_bh(&txq->axq_lock);
461 ath_tx_update_baw(sc, tid,
462 bf->bf_seqno);
463 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400464
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400465 bf->bf_state.bf_type |=
466 BUF_XRETRY;
467 ath_tx_rc_status(bf, ts, nbad,
468 0, false);
469 ath_tx_complete_buf(sc, bf, txq,
470 &bf_head,
471 ts, 0, 0);
472 break;
473 }
474
475 ath9k_hw_cleartxdesc(sc->sc_ah,
476 tbf->bf_desc);
477 list_add_tail(&tbf->list, &bf_head);
478 } else {
479 /*
480 * Clear descriptor status words for
481 * software retry
482 */
483 ath9k_hw_cleartxdesc(sc->sc_ah,
484 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400485 }
Sujithe8324352009-01-16 21:38:42 +0530486 }
487
488 /*
489 * Put this buffer to the temporary pending
490 * queue to retain ordering
491 */
492 list_splice_tail_init(&bf_head, &bf_pending);
493 }
494
495 bf = bf_next;
496 }
497
498 if (tid->state & AGGR_CLEANUP) {
Sujithe8324352009-01-16 21:38:42 +0530499 if (tid->baw_head == tid->baw_tail) {
500 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530501 tid->state &= ~AGGR_CLEANUP;
502
503 /* send buffered frames as singles */
504 ath_tx_flush_tid(sc, tid);
Sujithd43f30152009-01-16 21:38:53 +0530505 }
Sujith1286ec62009-01-27 13:30:37 +0530506 rcu_read_unlock();
Sujithe8324352009-01-16 21:38:42 +0530507 return;
508 }
509
Sujithd43f30152009-01-16 21:38:53 +0530510 /* prepend un-acked frames to the beginning of the pending frame queue */
Sujithe8324352009-01-16 21:38:42 +0530511 if (!list_empty(&bf_pending)) {
512 spin_lock_bh(&txq->axq_lock);
513 list_splice(&bf_pending, &tid->buf_q);
514 ath_tx_queue_tid(txq, tid);
515 spin_unlock_bh(&txq->axq_lock);
516 }
517
Sujith1286ec62009-01-27 13:30:37 +0530518 rcu_read_unlock();
519
Sujithe8324352009-01-16 21:38:42 +0530520 if (needreset)
521 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530522}
523
524static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
525 struct ath_atx_tid *tid)
526{
Sujithe8324352009-01-16 21:38:42 +0530527 struct sk_buff *skb;
528 struct ieee80211_tx_info *tx_info;
529 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530530 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530531 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530532 int i;
533
Sujitha22be222009-03-30 15:28:36 +0530534 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530535 tx_info = IEEE80211_SKB_CB(skb);
536 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530537
538 /*
539 * Find the lowest frame length among the rate series that will have a
540 * 4ms transmit duration.
541 * TODO - TXOP limit needs to be considered.
542 */
543 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
544
545 for (i = 0; i < 4; i++) {
546 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100547 int modeidx;
548 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530549 legacy = 1;
550 break;
551 }
552
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200553 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100554 modeidx = MCS_HT40;
555 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200556 modeidx = MCS_HT20;
557
558 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
559 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100560
561 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530562 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530563 }
564 }
565
566 /*
567 * limit aggregate size by the minimum rate if rate selected is
568 * not a probe rate, if rate selected is a probe rate then
569 * avoid aggregation of this packet.
570 */
571 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
572 return 0;
573
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530574 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
575 aggr_limit = min((max_4ms_framelen * 3) / 8,
576 (u32)ATH_AMPDU_LIMIT_MAX);
577 else
578 aggr_limit = min(max_4ms_framelen,
579 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530580
581 /*
582 * h/w can accept aggregates upto 16 bit lengths (65535).
583 * The IE, however can hold upto 65536, which shows up here
584 * as zero. Ignore 65536 since we are constrained by hw.
585 */
Sujith4ef70842009-07-23 15:32:41 +0530586 if (tid->an->maxampdu)
587 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530588
589 return aggr_limit;
590}
591
592/*
Sujithd43f30152009-01-16 21:38:53 +0530593 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530594 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530595 */
596static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
597 struct ath_buf *bf, u16 frmlen)
598{
Sujithe8324352009-01-16 21:38:42 +0530599 struct sk_buff *skb = bf->bf_mpdu;
600 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530601 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530602 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100603 u8 flags, rix;
Sujithe8324352009-01-16 21:38:42 +0530604 int width, half_gi, ndelim, mindelim;
605
606 /* Select standard number of delimiters based on frame length alone */
607 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
608
609 /*
610 * If encryption enabled, hardware requires some more padding between
611 * subframes.
612 * TODO - this could be improved to be dependent on the rate.
613 * The hardware can keep up at lower rates, but not higher rates
614 */
615 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
616 ndelim += ATH_AGGR_ENCRYPTDELIM;
617
618 /*
619 * Convert desired mpdu density from microeconds to bytes based
620 * on highest rate in rate series (i.e. first rate) to determine
621 * required minimum length for subframe. Take into account
622 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530623 *
Sujithe8324352009-01-16 21:38:42 +0530624 * If there is no mpdu density restriction, no further calculation
625 * is needed.
626 */
Sujith4ef70842009-07-23 15:32:41 +0530627
628 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530629 return ndelim;
630
631 rix = tx_info->control.rates[0].idx;
632 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530633 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
634 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
635
636 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530637 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530638 else
Sujith4ef70842009-07-23 15:32:41 +0530639 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530640
641 if (nsymbols == 0)
642 nsymbols = 1;
643
Felix Fietkau545750d2009-11-23 22:21:01 +0100644 nsymbits = bits_per_symbol[rix][width];
Sujithe8324352009-01-16 21:38:42 +0530645 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
646
Sujithe8324352009-01-16 21:38:42 +0530647 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530648 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
649 ndelim = max(mindelim, ndelim);
650 }
651
652 return ndelim;
653}
654
655static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530656 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530657 struct ath_atx_tid *tid,
658 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530659{
660#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530661 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
662 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530663 u16 aggr_limit = 0, al = 0, bpad = 0,
664 al_delta, h_baw = tid->baw_size / 2;
665 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Sujithe8324352009-01-16 21:38:42 +0530666
667 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
668
669 do {
670 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
671
Sujithd43f30152009-01-16 21:38:53 +0530672 /* do not step over block-ack window */
Sujithe8324352009-01-16 21:38:42 +0530673 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
674 status = ATH_AGGR_BAW_CLOSED;
675 break;
676 }
677
678 if (!rl) {
679 aggr_limit = ath_lookup_rate(sc, bf, tid);
680 rl = 1;
681 }
682
Sujithd43f30152009-01-16 21:38:53 +0530683 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530684 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
685
Sujithd43f30152009-01-16 21:38:53 +0530686 if (nframes &&
687 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530688 status = ATH_AGGR_LIMITED;
689 break;
690 }
691
Sujithd43f30152009-01-16 21:38:53 +0530692 /* do not exceed subframe limit */
693 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530694 status = ATH_AGGR_LIMITED;
695 break;
696 }
Sujithd43f30152009-01-16 21:38:53 +0530697 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530698
Sujithd43f30152009-01-16 21:38:53 +0530699 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530700 al += bpad + al_delta;
701
702 /*
703 * Get the delimiters needed to meet the MPDU
704 * density for this node.
705 */
706 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530707 bpad = PADBYTES(al_delta) + (ndelim << 2);
708
709 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400710 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530711
Sujithd43f30152009-01-16 21:38:53 +0530712 /* link buffers of this frame to the aggregate */
Sujithe8324352009-01-16 21:38:42 +0530713 ath_tx_addto_baw(sc, tid, bf);
Sujithd43f30152009-01-16 21:38:53 +0530714 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
715 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530716 if (bf_prev) {
717 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400718 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
719 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530720 }
721 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530722
Sujithe8324352009-01-16 21:38:42 +0530723 } while (!list_empty(&tid->buf_q));
724
725 bf_first->bf_al = al;
726 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530727
Sujithe8324352009-01-16 21:38:42 +0530728 return status;
729#undef PADBYTES
730}
731
732static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
733 struct ath_atx_tid *tid)
734{
Sujithd43f30152009-01-16 21:38:53 +0530735 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530736 enum ATH_AGGR_STATUS status;
737 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530738
739 do {
740 if (list_empty(&tid->buf_q))
741 return;
742
743 INIT_LIST_HEAD(&bf_q);
744
Sujithfec247c2009-07-27 12:08:16 +0530745 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530746
747 /*
Sujithd43f30152009-01-16 21:38:53 +0530748 * no frames picked up to be aggregated;
749 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530750 */
751 if (list_empty(&bf_q))
752 break;
753
754 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530755 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530756
Sujithd43f30152009-01-16 21:38:53 +0530757 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530758 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530759 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530760 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530761 ath_buf_set_rate(sc, bf);
762 ath_tx_txqaddbuf(sc, txq, &bf_q);
763 continue;
764 }
765
Sujithd43f30152009-01-16 21:38:53 +0530766 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530767 bf->bf_state.bf_type |= BUF_AGGR;
768 ath_buf_set_rate(sc, bf);
769 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
770
Sujithd43f30152009-01-16 21:38:53 +0530771 /* anchor last desc of aggregate */
772 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530773
Sujithe8324352009-01-16 21:38:42 +0530774 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530775 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530776
777 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
778 status != ATH_AGGR_BAW_CLOSED);
779}
780
Sujithf83da962009-07-23 15:32:37 +0530781void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
782 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530783{
784 struct ath_atx_tid *txtid;
785 struct ath_node *an;
786
787 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530788 txtid = ATH_AN_2_TID(an, tid);
789 txtid->state |= AGGR_ADDBA_PROGRESS;
790 ath_tx_pause_tid(sc, txtid);
791 *ssn = txtid->seq_start;
Sujithe8324352009-01-16 21:38:42 +0530792}
793
Sujithf83da962009-07-23 15:32:37 +0530794void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530795{
796 struct ath_node *an = (struct ath_node *)sta->drv_priv;
797 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
798 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700799 struct ath_tx_status ts;
Sujithe8324352009-01-16 21:38:42 +0530800 struct ath_buf *bf;
801 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700802
803 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530804 INIT_LIST_HEAD(&bf_head);
805
806 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530807 return;
Sujithe8324352009-01-16 21:38:42 +0530808
809 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530810 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530811 return;
Sujithe8324352009-01-16 21:38:42 +0530812 }
813
814 ath_tx_pause_tid(sc, txtid);
815
816 /* drop all software retried frames and mark this TID */
817 spin_lock_bh(&txq->axq_lock);
818 while (!list_empty(&txtid->buf_q)) {
819 bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
820 if (!bf_isretried(bf)) {
821 /*
822 * NB: it's based on the assumption that
823 * software retried frame will always stay
824 * at the head of software queue.
825 */
826 break;
827 }
Sujithd43f30152009-01-16 21:38:53 +0530828 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530829 ath_tx_update_baw(sc, txtid, bf->bf_seqno);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700830 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530831 }
Sujithd43f30152009-01-16 21:38:53 +0530832 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530833
834 if (txtid->baw_head != txtid->baw_tail) {
Sujithe8324352009-01-16 21:38:42 +0530835 txtid->state |= AGGR_CLEANUP;
836 } else {
837 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530838 ath_tx_flush_tid(sc, txtid);
839 }
Sujithe8324352009-01-16 21:38:42 +0530840}
841
842void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
843{
844 struct ath_atx_tid *txtid;
845 struct ath_node *an;
846
847 an = (struct ath_node *)sta->drv_priv;
848
849 if (sc->sc_flags & SC_OP_TXAGGR) {
850 txtid = ATH_AN_2_TID(an, tid);
851 txtid->baw_size =
852 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
853 txtid->state |= AGGR_ADDBA_COMPLETE;
854 txtid->state &= ~AGGR_ADDBA_PROGRESS;
855 ath_tx_resume_tid(sc, txtid);
856 }
857}
858
859bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
860{
861 struct ath_atx_tid *txtid;
862
863 if (!(sc->sc_flags & SC_OP_TXAGGR))
864 return false;
865
866 txtid = ATH_AN_2_TID(an, tidno);
867
Vasanthakumar Thiagarajanc3d8f022009-06-10 17:50:08 +0530868 if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
Sujithe8324352009-01-16 21:38:42 +0530869 return true;
Sujithe8324352009-01-16 21:38:42 +0530870 return false;
871}
872
873/********************/
874/* Queue Management */
875/********************/
876
Sujithe8324352009-01-16 21:38:42 +0530877static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
878 struct ath_txq *txq)
879{
880 struct ath_atx_ac *ac, *ac_tmp;
881 struct ath_atx_tid *tid, *tid_tmp;
882
883 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
884 list_del(&ac->list);
885 ac->sched = false;
886 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
887 list_del(&tid->list);
888 tid->sched = false;
889 ath_tid_drain(sc, txq, tid);
890 }
891 }
892}
893
894struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
895{
Sujithcbe61d82009-02-09 13:27:12 +0530896 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700897 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530898 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400899 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530900
901 memset(&qi, 0, sizeof(qi));
902 qi.tqi_subtype = subtype;
903 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
904 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
905 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
906 qi.tqi_physCompBuf = 0;
907
908 /*
909 * Enable interrupts only for EOL and DESC conditions.
910 * We mark tx descriptors to receive a DESC interrupt
911 * when a tx queue gets deep; otherwise waiting for the
912 * EOL to reap descriptors. Note that this is done to
913 * reduce interrupt load and this only defers reaping
914 * descriptors, never transmitting frames. Aside from
915 * reducing interrupts this also permits more concurrency.
916 * The only potential downside is if the tx queue backs
917 * up in which case the top half of the kernel may backup
918 * due to a lack of tx descriptors.
919 *
920 * The UAPSD queue is an exception, since we take a desc-
921 * based intr on the EOSP frames.
922 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400923 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
924 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
925 TXQ_FLAG_TXERRINT_ENABLE;
926 } else {
927 if (qtype == ATH9K_TX_QUEUE_UAPSD)
928 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
929 else
930 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
931 TXQ_FLAG_TXDESCINT_ENABLE;
932 }
Sujithe8324352009-01-16 21:38:42 +0530933 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
934 if (qnum == -1) {
935 /*
936 * NB: don't print a message, this happens
937 * normally on parts with too few tx queues
938 */
939 return NULL;
940 }
941 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700942 ath_print(common, ATH_DBG_FATAL,
943 "qnum %u out of range, max %u!\n",
944 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530945 ath9k_hw_releasetxqueue(ah, qnum);
946 return NULL;
947 }
948 if (!ATH_TXQ_SETUP(sc, qnum)) {
949 struct ath_txq *txq = &sc->tx.txq[qnum];
950
951 txq->axq_qnum = qnum;
952 txq->axq_link = NULL;
953 INIT_LIST_HEAD(&txq->axq_q);
954 INIT_LIST_HEAD(&txq->axq_acq);
955 spin_lock_init(&txq->axq_lock);
956 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400957 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530958 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400959
960 txq->txq_headidx = txq->txq_tailidx = 0;
961 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
962 INIT_LIST_HEAD(&txq->txq_fifo[i]);
963 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530964 }
965 return &sc->tx.txq[qnum];
966}
967
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530968int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
Sujithe8324352009-01-16 21:38:42 +0530969{
970 int qnum;
971
972 switch (qtype) {
973 case ATH9K_TX_QUEUE_DATA:
974 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700975 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
976 "HAL AC %u out of range, max %zu!\n",
977 haltype, ARRAY_SIZE(sc->tx.hwq_map));
Sujithe8324352009-01-16 21:38:42 +0530978 return -1;
979 }
980 qnum = sc->tx.hwq_map[haltype];
981 break;
982 case ATH9K_TX_QUEUE_BEACON:
983 qnum = sc->beacon.beaconq;
984 break;
985 case ATH9K_TX_QUEUE_CAB:
986 qnum = sc->beacon.cabq->axq_qnum;
987 break;
988 default:
989 qnum = -1;
990 }
991 return qnum;
992}
993
994struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
995{
996 struct ath_txq *txq = NULL;
Luis R. Rodriguezf52de032009-11-02 17:09:12 -0800997 u16 skb_queue = skb_get_queue_mapping(skb);
Sujithe8324352009-01-16 21:38:42 +0530998 int qnum;
999
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001000 qnum = ath_get_hal_qnum(skb_queue, sc);
Sujithe8324352009-01-16 21:38:42 +05301001 txq = &sc->tx.txq[qnum];
1002
1003 spin_lock_bh(&txq->axq_lock);
1004
1005 if (txq->axq_depth >= (ATH_TXBUF - 20)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001006 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
1007 "TX queue: %d is full, depth: %d\n",
1008 qnum, txq->axq_depth);
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001009 ath_mac80211_stop_queue(sc, skb_queue);
Sujithe8324352009-01-16 21:38:42 +05301010 txq->stopped = 1;
1011 spin_unlock_bh(&txq->axq_lock);
1012 return NULL;
1013 }
1014
1015 spin_unlock_bh(&txq->axq_lock);
1016
1017 return txq;
1018}
1019
1020int ath_txq_update(struct ath_softc *sc, int qnum,
1021 struct ath9k_tx_queue_info *qinfo)
1022{
Sujithcbe61d82009-02-09 13:27:12 +05301023 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301024 int error = 0;
1025 struct ath9k_tx_queue_info qi;
1026
1027 if (qnum == sc->beacon.beaconq) {
1028 /*
1029 * XXX: for beacon queue, we just save the parameter.
1030 * It will be picked up by ath_beaconq_config when
1031 * it's necessary.
1032 */
1033 sc->beacon.beacon_qi = *qinfo;
1034 return 0;
1035 }
1036
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -07001037 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +05301038
1039 ath9k_hw_get_txq_props(ah, qnum, &qi);
1040 qi.tqi_aifs = qinfo->tqi_aifs;
1041 qi.tqi_cwmin = qinfo->tqi_cwmin;
1042 qi.tqi_cwmax = qinfo->tqi_cwmax;
1043 qi.tqi_burstTime = qinfo->tqi_burstTime;
1044 qi.tqi_readyTime = qinfo->tqi_readyTime;
1045
1046 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001047 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1048 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301049 error = -EIO;
1050 } else {
1051 ath9k_hw_resettxqueue(ah, qnum);
1052 }
1053
1054 return error;
1055}
1056
1057int ath_cabq_update(struct ath_softc *sc)
1058{
1059 struct ath9k_tx_queue_info qi;
1060 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301061
1062 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1063 /*
1064 * Ensure the readytime % is within the bounds.
1065 */
Sujith17d79042009-02-09 13:27:03 +05301066 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1067 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1068 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1069 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301070
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001071 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301072 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301073 ath_txq_update(sc, qnum, &qi);
1074
1075 return 0;
1076}
1077
Sujith043a0402009-01-16 21:38:47 +05301078/*
1079 * Drain a given TX queue (could be Beacon or Data)
1080 *
1081 * This assumes output has been stopped and
1082 * we do not need to block ath_tx_tasklet.
1083 */
1084void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301085{
1086 struct ath_buf *bf, *lastbf;
1087 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001088 struct ath_tx_status ts;
1089
1090 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301091 INIT_LIST_HEAD(&bf_head);
1092
Sujithe8324352009-01-16 21:38:42 +05301093 for (;;) {
1094 spin_lock_bh(&txq->axq_lock);
1095
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001096 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1097 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1098 txq->txq_headidx = txq->txq_tailidx = 0;
1099 spin_unlock_bh(&txq->axq_lock);
1100 break;
1101 } else {
1102 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1103 struct ath_buf, list);
1104 }
1105 } else {
1106 if (list_empty(&txq->axq_q)) {
1107 txq->axq_link = NULL;
1108 spin_unlock_bh(&txq->axq_lock);
1109 break;
1110 }
1111 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1112 list);
Sujithe8324352009-01-16 21:38:42 +05301113
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001114 if (bf->bf_stale) {
1115 list_del(&bf->list);
1116 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301117
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001118 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001119 continue;
1120 }
Sujithe8324352009-01-16 21:38:42 +05301121 }
1122
1123 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001124 if (!retry_tx)
1125 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301126
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001127 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1128 list_cut_position(&bf_head,
1129 &txq->txq_fifo[txq->txq_tailidx],
1130 &lastbf->list);
1131 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1132 } else {
1133 /* remove ath_buf's of the same mpdu from txq */
1134 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1135 }
1136
Sujithe8324352009-01-16 21:38:42 +05301137 txq->axq_depth--;
1138
1139 spin_unlock_bh(&txq->axq_lock);
1140
1141 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001142 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301143 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001144 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301145 }
1146
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001147 spin_lock_bh(&txq->axq_lock);
1148 txq->axq_tx_inprogress = false;
1149 spin_unlock_bh(&txq->axq_lock);
1150
Sujithe8324352009-01-16 21:38:42 +05301151 /* flush any pending frames if aggregation is enabled */
1152 if (sc->sc_flags & SC_OP_TXAGGR) {
1153 if (!retry_tx) {
1154 spin_lock_bh(&txq->axq_lock);
1155 ath_txq_drain_pending_buffers(sc, txq);
1156 spin_unlock_bh(&txq->axq_lock);
1157 }
1158 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001159
1160 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1161 spin_lock_bh(&txq->axq_lock);
1162 while (!list_empty(&txq->txq_fifo_pending)) {
1163 bf = list_first_entry(&txq->txq_fifo_pending,
1164 struct ath_buf, list);
1165 list_cut_position(&bf_head,
1166 &txq->txq_fifo_pending,
1167 &bf->bf_lastbf->list);
1168 spin_unlock_bh(&txq->axq_lock);
1169
1170 if (bf_isampdu(bf))
1171 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1172 &ts, 0);
1173 else
1174 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1175 &ts, 0, 0);
1176 spin_lock_bh(&txq->axq_lock);
1177 }
1178 spin_unlock_bh(&txq->axq_lock);
1179 }
Sujithe8324352009-01-16 21:38:42 +05301180}
1181
Sujith043a0402009-01-16 21:38:47 +05301182void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1183{
Sujithcbe61d82009-02-09 13:27:12 +05301184 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001185 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301186 struct ath_txq *txq;
1187 int i, npend = 0;
1188
1189 if (sc->sc_flags & SC_OP_INVALID)
1190 return;
1191
1192 /* Stop beacon queue */
1193 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1194
1195 /* Stop data queues */
1196 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1197 if (ATH_TXQ_SETUP(sc, i)) {
1198 txq = &sc->tx.txq[i];
1199 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1200 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1201 }
1202 }
1203
1204 if (npend) {
1205 int r;
1206
Sujithe8009e92009-12-14 14:57:08 +05301207 ath_print(common, ATH_DBG_FATAL,
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001208 "Unable to stop TxDMA. Reset HAL!\n");
Sujith043a0402009-01-16 21:38:47 +05301209
1210 spin_lock_bh(&sc->sc_resetlock);
Sujithe8009e92009-12-14 14:57:08 +05301211 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
Sujith043a0402009-01-16 21:38:47 +05301212 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001213 ath_print(common, ATH_DBG_FATAL,
1214 "Unable to reset hardware; reset status %d\n",
1215 r);
Sujith043a0402009-01-16 21:38:47 +05301216 spin_unlock_bh(&sc->sc_resetlock);
1217 }
1218
1219 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1220 if (ATH_TXQ_SETUP(sc, i))
1221 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1222 }
1223}
1224
Sujithe8324352009-01-16 21:38:42 +05301225void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1226{
1227 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1228 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1229}
1230
Sujithe8324352009-01-16 21:38:42 +05301231void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1232{
1233 struct ath_atx_ac *ac;
1234 struct ath_atx_tid *tid;
1235
1236 if (list_empty(&txq->axq_acq))
1237 return;
1238
1239 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1240 list_del(&ac->list);
1241 ac->sched = false;
1242
1243 do {
1244 if (list_empty(&ac->tid_q))
1245 return;
1246
1247 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1248 list_del(&tid->list);
1249 tid->sched = false;
1250
1251 if (tid->paused)
1252 continue;
1253
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001254 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301255
1256 /*
1257 * add tid to round-robin queue if more frames
1258 * are pending for the tid
1259 */
1260 if (!list_empty(&tid->buf_q))
1261 ath_tx_queue_tid(txq, tid);
1262
1263 break;
1264 } while (!list_empty(&ac->tid_q));
1265
1266 if (!list_empty(&ac->tid_q)) {
1267 if (!ac->sched) {
1268 ac->sched = true;
1269 list_add_tail(&ac->list, &txq->axq_acq);
1270 }
1271 }
1272}
1273
1274int ath_tx_setup(struct ath_softc *sc, int haltype)
1275{
1276 struct ath_txq *txq;
1277
1278 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001279 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1280 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301281 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1282 return 0;
1283 }
1284 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1285 if (txq != NULL) {
1286 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1287 return 1;
1288 } else
1289 return 0;
1290}
1291
1292/***********/
1293/* TX, DMA */
1294/***********/
1295
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001296/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001297 * Insert a chain of ath_buf (descriptors) on a txq and
1298 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001299 */
Sujith102e0572008-10-29 10:15:16 +05301300static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1301 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001302{
Sujithcbe61d82009-02-09 13:27:12 +05301303 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001304 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001305 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301306
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001307 /*
1308 * Insert the frame on the outbound list and
1309 * pass it on to the hardware.
1310 */
1311
1312 if (list_empty(head))
1313 return;
1314
1315 bf = list_first_entry(head, struct ath_buf, list);
1316
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001317 ath_print(common, ATH_DBG_QUEUE,
1318 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001319
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001320 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1321 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1322 list_splice_tail_init(head, &txq->txq_fifo_pending);
1323 return;
1324 }
1325 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1326 ath_print(common, ATH_DBG_XMIT,
1327 "Initializing tx fifo %d which "
1328 "is non-empty\n",
1329 txq->txq_headidx);
1330 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1331 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1332 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001333 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001334 ath_print(common, ATH_DBG_XMIT,
1335 "TXDP[%u] = %llx (%p)\n",
1336 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001337 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001338 list_splice_tail_init(head, &txq->axq_q);
1339
1340 if (txq->axq_link == NULL) {
1341 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1342 ath_print(common, ATH_DBG_XMIT,
1343 "TXDP[%u] = %llx (%p)\n",
1344 txq->axq_qnum, ito64(bf->bf_daddr),
1345 bf->bf_desc);
1346 } else {
1347 *txq->axq_link = bf->bf_daddr;
1348 ath_print(common, ATH_DBG_XMIT,
1349 "link[%u] (%p)=%llx (%p)\n",
1350 txq->axq_qnum, txq->axq_link,
1351 ito64(bf->bf_daddr), bf->bf_desc);
1352 }
1353 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1354 &txq->axq_link);
1355 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001356 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001357 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001358}
1359
Sujithe8324352009-01-16 21:38:42 +05301360static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1361 struct list_head *bf_head,
1362 struct ath_tx_control *txctl)
1363{
1364 struct ath_buf *bf;
1365
Sujithe8324352009-01-16 21:38:42 +05301366 bf = list_first_entry(bf_head, struct ath_buf, list);
1367 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301368 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301369
1370 /*
1371 * Do not queue to h/w when any of the following conditions is true:
1372 * - there are pending frames in software queue
1373 * - the TID is currently paused for ADDBA/BAR request
1374 * - seqno is not within block-ack window
1375 * - h/w queue depth exceeds low water mark
1376 */
1377 if (!list_empty(&tid->buf_q) || tid->paused ||
1378 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1379 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001380 /*
Sujithe8324352009-01-16 21:38:42 +05301381 * Add this frame to software queue for scheduling later
1382 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001383 */
Sujithd43f30152009-01-16 21:38:53 +05301384 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301385 ath_tx_queue_tid(txctl->txq, tid);
1386 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001387 }
1388
Sujithe8324352009-01-16 21:38:42 +05301389 /* Add sub-frame to BAW */
1390 ath_tx_addto_baw(sc, tid, bf);
1391
1392 /* Queue to h/w without aggregation */
1393 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301394 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301395 ath_buf_set_rate(sc, bf);
1396 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301397}
1398
Sujithc37452b2009-03-09 09:31:57 +05301399static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1400 struct ath_atx_tid *tid,
1401 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001402{
Sujithe8324352009-01-16 21:38:42 +05301403 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001404
Sujithe8324352009-01-16 21:38:42 +05301405 bf = list_first_entry(bf_head, struct ath_buf, list);
1406 bf->bf_state.bf_type &= ~BUF_AMPDU;
1407
1408 /* update starting sequence number for subsequent ADDBA request */
1409 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1410
1411 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301412 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301413 ath_buf_set_rate(sc, bf);
1414 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301415 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001416}
1417
Sujithc37452b2009-03-09 09:31:57 +05301418static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1419 struct list_head *bf_head)
1420{
1421 struct ath_buf *bf;
1422
1423 bf = list_first_entry(bf_head, struct ath_buf, list);
1424
1425 bf->bf_lastbf = bf;
1426 bf->bf_nframes = 1;
1427 ath_buf_set_rate(sc, bf);
1428 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301429 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301430}
1431
Sujith528f0c62008-10-29 10:14:26 +05301432static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001433{
Sujith528f0c62008-10-29 10:14:26 +05301434 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001435 enum ath9k_pkt_type htype;
1436 __le16 fc;
1437
Sujith528f0c62008-10-29 10:14:26 +05301438 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439 fc = hdr->frame_control;
1440
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001441 if (ieee80211_is_beacon(fc))
1442 htype = ATH9K_PKT_TYPE_BEACON;
1443 else if (ieee80211_is_probe_resp(fc))
1444 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1445 else if (ieee80211_is_atim(fc))
1446 htype = ATH9K_PKT_TYPE_ATIM;
1447 else if (ieee80211_is_pspoll(fc))
1448 htype = ATH9K_PKT_TYPE_PSPOLL;
1449 else
1450 htype = ATH9K_PKT_TYPE_NORMAL;
1451
1452 return htype;
1453}
1454
Sujith528f0c62008-10-29 10:14:26 +05301455static int get_hw_crypto_keytype(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456{
Sujith528f0c62008-10-29 10:14:26 +05301457 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1458
1459 if (tx_info->control.hw_key) {
1460 if (tx_info->control.hw_key->alg == ALG_WEP)
1461 return ATH9K_KEY_TYPE_WEP;
1462 else if (tx_info->control.hw_key->alg == ALG_TKIP)
1463 return ATH9K_KEY_TYPE_TKIP;
1464 else if (tx_info->control.hw_key->alg == ALG_CCMP)
1465 return ATH9K_KEY_TYPE_AES;
1466 }
1467
1468 return ATH9K_KEY_TYPE_CLEAR;
1469}
1470
Sujith528f0c62008-10-29 10:14:26 +05301471static void assign_aggr_tid_seqno(struct sk_buff *skb,
1472 struct ath_buf *bf)
1473{
1474 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1475 struct ieee80211_hdr *hdr;
1476 struct ath_node *an;
1477 struct ath_atx_tid *tid;
1478 __le16 fc;
1479 u8 *qc;
1480
1481 if (!tx_info->control.sta)
1482 return;
1483
1484 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1485 hdr = (struct ieee80211_hdr *)skb->data;
1486 fc = hdr->frame_control;
1487
Sujith528f0c62008-10-29 10:14:26 +05301488 if (ieee80211_is_data_qos(fc)) {
1489 qc = ieee80211_get_qos_ctl(hdr);
1490 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301491 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001492
Sujithe8324352009-01-16 21:38:42 +05301493 /*
1494 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301495 * We also override seqno set by upper layer with the one
1496 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301497 */
1498 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301499 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301500 bf->bf_seqno = tid->seq_next;
1501 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301502}
1503
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001504static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301505{
1506 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1507 int flags = 0;
1508
1509 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1510 flags |= ATH9K_TXDESC_INTREQ;
1511
1512 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1513 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301514
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001515 if (use_ldpc)
1516 flags |= ATH9K_TXDESC_LDPC;
1517
Sujith528f0c62008-10-29 10:14:26 +05301518 return flags;
1519}
1520
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001521/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001522 * rix - rate index
1523 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1524 * width - 0 for 20 MHz, 1 for 40 MHz
1525 * half_gi - to use 4us v/s 3.6 us for symbol time
1526 */
Sujith102e0572008-10-29 10:15:16 +05301527static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1528 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001529{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001530 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001531 int streams, pktlen;
1532
Sujithcd3d39a2008-08-11 14:03:34 +05301533 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301534
1535 /* find number of symbols: PLCP + data */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001536 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkau545750d2009-11-23 22:21:01 +01001537 nsymbits = bits_per_symbol[rix][width];
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001538 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1539
1540 if (!half_gi)
1541 duration = SYMBOL_TIME(nsymbols);
1542 else
1543 duration = SYMBOL_TIME_HALFGI(nsymbols);
1544
Sujithe63835b2008-11-18 09:07:53 +05301545 /* addup duration for legacy/ht training and signal fields */
Felix Fietkau545750d2009-11-23 22:21:01 +01001546 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001547 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301548
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001549 return duration;
1550}
1551
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001552static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1553{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001554 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001555 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301556 struct sk_buff *skb;
1557 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301558 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001559 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301560 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301561 int i, flags = 0;
1562 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301563 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301564
1565 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301566
Sujitha22be222009-03-30 15:28:36 +05301567 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301568 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301569 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301570 hdr = (struct ieee80211_hdr *)skb->data;
1571 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301572
Sujithc89424d2009-01-30 14:29:28 +05301573 /*
1574 * We check if Short Preamble is needed for the CTS rate by
1575 * checking the BSS's global flag.
1576 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1577 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001578 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1579 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301580 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001581 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001582
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001583 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001584 bool is_40, is_sgi, is_sp;
1585 int phy;
1586
Sujithe63835b2008-11-18 09:07:53 +05301587 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001588 continue;
1589
Sujitha8efee42008-11-18 09:07:30 +05301590 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301591 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001592 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001593
Felix Fietkau27032052010-01-17 21:08:50 +01001594 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1595 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301596 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001597 flags |= ATH9K_TXDESC_RTSENA;
1598 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1599 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1600 flags |= ATH9K_TXDESC_CTSENA;
1601 }
1602
Sujithc89424d2009-01-30 14:29:28 +05301603 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1604 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1605 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1606 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001607
Felix Fietkau545750d2009-11-23 22:21:01 +01001608 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1609 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1610 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1611
1612 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1613 /* MCS rates */
1614 series[i].Rate = rix | 0x80;
1615 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1616 is_40, is_sgi, is_sp);
1617 continue;
1618 }
1619
1620 /* legcay rates */
1621 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1622 !(rate->flags & IEEE80211_RATE_ERP_G))
1623 phy = WLAN_RC_PHY_CCK;
1624 else
1625 phy = WLAN_RC_PHY_OFDM;
1626
1627 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1628 series[i].Rate = rate->hw_value;
1629 if (rate->hw_value_short) {
1630 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1631 series[i].Rate |= rate->hw_value_short;
1632 } else {
1633 is_sp = false;
1634 }
1635
1636 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1637 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001638 }
1639
Felix Fietkau27032052010-01-17 21:08:50 +01001640 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1641 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1642 flags &= ~ATH9K_TXDESC_RTSENA;
1643
1644 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1645 if (flags & ATH9K_TXDESC_RTSENA)
1646 flags &= ~ATH9K_TXDESC_CTSENA;
1647
Sujithe63835b2008-11-18 09:07:53 +05301648 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301649 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1650 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301651 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301652 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301653
Sujith17d79042009-02-09 13:27:03 +05301654 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301655 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001656}
1657
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001658static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301659 struct sk_buff *skb,
1660 struct ath_tx_control *txctl)
1661{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001662 struct ath_wiphy *aphy = hw->priv;
1663 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301664 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1665 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301666 int hdrlen;
1667 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001668 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001669 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301670
Felix Fietkau827e69b2009-11-15 23:09:25 +01001671 tx_info->pad[0] = 0;
1672 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001673 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001674 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001675 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001676 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1677 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001678 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001679 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1680 break;
1681 }
Sujithe8324352009-01-16 21:38:42 +05301682 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1683 fc = hdr->frame_control;
1684
1685 ATH_TXBUF_RESET(bf);
1686
Felix Fietkau827e69b2009-11-15 23:09:25 +01001687 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001688 bf->bf_frmlen = skb->len + FCS_LEN;
1689 /* Remove the padding size from bf_frmlen, if any */
1690 padpos = ath9k_cmn_padpos(hdr->frame_control);
1691 padsize = padpos & 3;
1692 if (padsize && skb->len>padpos+padsize) {
1693 bf->bf_frmlen -= padsize;
1694 }
Sujithe8324352009-01-16 21:38:42 +05301695
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001696 if (conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301697 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001698 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1699 use_ldpc = true;
1700 }
Sujithe8324352009-01-16 21:38:42 +05301701
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001702 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301703
1704 bf->bf_keytype = get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301705 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1706 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1707 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1708 } else {
1709 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1710 }
1711
Sujith17b182e2009-12-14 14:56:56 +05301712 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1713 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301714 assign_aggr_tid_seqno(skb, bf);
1715
1716 bf->bf_mpdu = skb;
1717
1718 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1719 skb->len, DMA_TO_DEVICE);
1720 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1721 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001722 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1723 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301724 return -ENOMEM;
1725 }
1726
1727 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001728
1729 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1730 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1731 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301732 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001733 } else
1734 bf->bf_isnullfunc = false;
1735
Sujithe8324352009-01-16 21:38:42 +05301736 return 0;
1737}
1738
1739/* FIXME: tx power */
1740static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1741 struct ath_tx_control *txctl)
1742{
Sujitha22be222009-03-30 15:28:36 +05301743 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301744 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301745 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301746 struct ath_node *an = NULL;
1747 struct list_head bf_head;
1748 struct ath_desc *ds;
1749 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301750 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301751 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301752 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301753
1754 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301755 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301756
1757 INIT_LIST_HEAD(&bf_head);
1758 list_add_tail(&bf->list, &bf_head);
1759
1760 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001761 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301762
1763 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1764 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1765
1766 ath9k_hw_filltxdesc(ah, ds,
1767 skb->len, /* segment length */
1768 true, /* first segment */
1769 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001770 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001771 bf->bf_buf_addr,
1772 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301773
Sujithe8324352009-01-16 21:38:42 +05301774 spin_lock_bh(&txctl->txq->axq_lock);
1775
1776 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1777 tx_info->control.sta) {
1778 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1779 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1780
Sujithc37452b2009-03-09 09:31:57 +05301781 if (!ieee80211_is_data_qos(fc)) {
1782 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1783 goto tx_done;
1784 }
1785
Felix Fietkau4fdec032010-03-12 04:02:43 +01001786 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301787 /*
1788 * Try aggregation if it's a unicast data frame
1789 * and the destination is HT capable.
1790 */
1791 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1792 } else {
1793 /*
1794 * Send this frame as regular when ADDBA
1795 * exchange is neither complete nor pending.
1796 */
Sujithc37452b2009-03-09 09:31:57 +05301797 ath_tx_send_ht_normal(sc, txctl->txq,
1798 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301799 }
1800 } else {
Sujithc37452b2009-03-09 09:31:57 +05301801 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301802 }
1803
Sujithc37452b2009-03-09 09:31:57 +05301804tx_done:
Sujithe8324352009-01-16 21:38:42 +05301805 spin_unlock_bh(&txctl->txq->axq_lock);
1806}
1807
1808/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001809int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301810 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001811{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001812 struct ath_wiphy *aphy = hw->priv;
1813 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001814 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001815 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301816 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001817
Sujithe8324352009-01-16 21:38:42 +05301818 bf = ath_tx_get_buffer(sc);
1819 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001820 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301821 return -1;
1822 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001823
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001824 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301825 if (unlikely(r)) {
1826 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001827
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001828 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001829
Sujithe8324352009-01-16 21:38:42 +05301830 /* upon ath_tx_processq() this TX queue will be resumed, we
1831 * guarantee this will happen by knowing beforehand that
1832 * we will at least have to run TX completionon one buffer
1833 * on the queue */
1834 spin_lock_bh(&txq->axq_lock);
Sujithf7a99e42009-02-17 15:36:33 +05301835 if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001836 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301837 txq->stopped = 1;
1838 }
1839 spin_unlock_bh(&txq->axq_lock);
1840
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001841 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301842
1843 return r;
1844 }
1845
1846 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001847
1848 return 0;
1849}
1850
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001851void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001852{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001853 struct ath_wiphy *aphy = hw->priv;
1854 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001855 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001856 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1857 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301858 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1859 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001860
Sujithe8324352009-01-16 21:38:42 +05301861 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001862
Sujithe8324352009-01-16 21:38:42 +05301863 /*
1864 * As a temporary workaround, assign seq# here; this will likely need
1865 * to be cleaned up to work better with Beacon transmission and virtual
1866 * BSSes.
1867 */
1868 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301869 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1870 sc->tx.seq_no += 0x10;
1871 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1872 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001873 }
1874
Sujithe8324352009-01-16 21:38:42 +05301875 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001876 padpos = ath9k_cmn_padpos(hdr->frame_control);
1877 padsize = padpos & 3;
1878 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301879 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001880 ath_print(common, ATH_DBG_XMIT,
1881 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301882 dev_kfree_skb_any(skb);
1883 return;
1884 }
1885 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001886 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001887 }
1888
Sujithe8324352009-01-16 21:38:42 +05301889 txctl.txq = sc->beacon.cabq;
1890
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001891 ath_print(common, ATH_DBG_XMIT,
1892 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301893
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001894 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001895 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301896 goto exit;
1897 }
1898
1899 return;
1900exit:
1901 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001902}
1903
Sujithe8324352009-01-16 21:38:42 +05301904/*****************/
1905/* TX Completion */
1906/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001907
Sujithe8324352009-01-16 21:38:42 +05301908static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001909 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001910{
Sujithe8324352009-01-16 21:38:42 +05301911 struct ieee80211_hw *hw = sc->hw;
1912 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001913 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001914 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
1915 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301916
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001917 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301918
Felix Fietkau827e69b2009-11-15 23:09:25 +01001919 if (aphy)
1920 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301921
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301922 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301923 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301924
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301925 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301926 /* Frame was ACKed */
1927 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1928 }
1929
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001930 padpos = ath9k_cmn_padpos(hdr->frame_control);
1931 padsize = padpos & 3;
1932 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301933 /*
1934 * Remove MAC header padding before giving the frame back to
1935 * mac80211.
1936 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001937 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301938 skb_pull(skb, padsize);
1939 }
1940
Sujith1b04b932010-01-08 10:36:05 +05301941 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1942 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001943 ath_print(common, ATH_DBG_PS,
1944 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001945 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301946 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1947 PS_WAIT_FOR_CAB |
1948 PS_WAIT_FOR_PSPOLL_DATA |
1949 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001950 }
1951
Felix Fietkau827e69b2009-11-15 23:09:25 +01001952 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001953 ath9k_tx_status(hw, skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001954 else
1955 ieee80211_tx_status(hw, skb);
Sujithe8324352009-01-16 21:38:42 +05301956}
1957
1958static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001959 struct ath_txq *txq, struct list_head *bf_q,
1960 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301961{
1962 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301963 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301964 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301965
Sujithe8324352009-01-16 21:38:42 +05301966 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301967 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301968
1969 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301970 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301971
1972 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301973 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301974 }
1975
1976 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001977 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001978 ath_debug_stat_tx(sc, txq, bf, ts);
Sujithe8324352009-01-16 21:38:42 +05301979
1980 /*
1981 * Return the list of ath_buf of this mpdu to free queue
1982 */
1983 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1984 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1985 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1986}
1987
1988static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001989 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301990{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001991 u16 seq_st = 0;
1992 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301993 int ba_index;
1994 int nbad = 0;
1995 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001996
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001997 if (bf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301998 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301999
Sujithcd3d39a2008-08-11 14:03:34 +05302000 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002001 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002002 seq_st = ts->ts_seqnum;
2003 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002004 }
2005
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002006 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05302007 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
2008 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
2009 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002010
Sujithe8324352009-01-16 21:38:42 +05302011 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012 }
2013
Sujithe8324352009-01-16 21:38:42 +05302014 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002015}
2016
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002017static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302018 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05302019{
Sujitha22be222009-03-30 15:28:36 +05302020 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05302021 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05302022 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01002023 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302024 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05302025
Sujith95e4acb2009-03-13 08:56:09 +05302026 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002027 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05302028
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002029 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302030 WARN_ON(tx_rateindex >= hw->max_rates);
2031
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002032 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302033 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01002034 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
2035 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302036
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002037 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302038 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05302039 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002040 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01002041 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
2042 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002043 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2044 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002045 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2046 tx_info->status.ampdu_len = bf->bf_nframes;
2047 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302048 }
2049 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302050
Felix Fietkau545750d2009-11-23 22:21:01 +01002051 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302052 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002053 tx_info->status.rates[i].idx = -1;
2054 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302055
2056 tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
Sujithc4288392008-11-18 09:09:30 +05302057}
2058
Sujith059d8062009-01-16 21:38:49 +05302059static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2060{
2061 int qnum;
2062
2063 spin_lock_bh(&txq->axq_lock);
2064 if (txq->stopped &&
Sujithf7a99e42009-02-17 15:36:33 +05302065 sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
Sujith059d8062009-01-16 21:38:49 +05302066 qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
2067 if (qnum != -1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08002068 ath_mac80211_start_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302069 txq->stopped = 0;
2070 }
2071 }
2072 spin_unlock_bh(&txq->axq_lock);
2073}
2074
Sujithc4288392008-11-18 09:09:30 +05302075static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076{
Sujithcbe61d82009-02-09 13:27:12 +05302077 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002078 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2080 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302081 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002082 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302083 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084 int status;
2085
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002086 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2087 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2088 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002089
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002090 for (;;) {
2091 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002092 if (list_empty(&txq->axq_q)) {
2093 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094 spin_unlock_bh(&txq->axq_lock);
2095 break;
2096 }
2097 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2098
2099 /*
2100 * There is a race condition that a BH gets scheduled
2101 * after sw writes TxE and before hw re-load the last
2102 * descriptor to get the newly chained one.
2103 * Software must keep the last DONE descriptor as a
2104 * holding descriptor - software does so by marking
2105 * it with the STALE flag.
2106 */
2107 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302108 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002109 bf_held = bf;
2110 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302111 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002112 break;
2113 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002114 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302115 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002116 }
2117 }
2118
2119 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302120 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002121
Felix Fietkau29bffa92010-03-29 20:14:23 -07002122 memset(&ts, 0, sizeof(ts));
2123 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002124 if (status == -EINPROGRESS) {
2125 spin_unlock_bh(&txq->axq_lock);
2126 break;
2127 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002128
2129 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002130 * We now know the nullfunc frame has been ACKed so we
2131 * can disable RX.
2132 */
2133 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002134 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302135 if ((sc->ps_flags & PS_ENABLED))
2136 ath9k_enable_ps(sc);
2137 else
Sujith1b04b932010-01-08 10:36:05 +05302138 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002139 }
2140
2141 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002142 * Remove ath_buf's of the same transmit unit from txq,
2143 * however leave the last descriptor back as the holding
2144 * descriptor for hw.
2145 */
Sujitha119cc42009-03-30 15:28:38 +05302146 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002147 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002148 if (!list_is_singular(&lastbf->list))
2149 list_cut_position(&bf_head,
2150 &txq->axq_q, lastbf->list.prev);
2151
2152 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002153 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002154 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002155 if (bf_held)
2156 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002157 spin_unlock_bh(&txq->axq_lock);
2158
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002159 if (bf_held)
2160 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002161
Sujithcd3d39a2008-08-11 14:03:34 +05302162 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002163 /*
2164 * This frame is sent out as a single frame.
2165 * Use hardware retry status for this frame.
2166 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002167 bf->bf_retries = ts.ts_longretry;
2168 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302169 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002170 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002171 }
Johannes Berge6a98542008-10-21 12:40:02 +02002172
Sujithcd3d39a2008-08-11 14:03:34 +05302173 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002174 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002175 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002176 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002177
Sujith059d8062009-01-16 21:38:49 +05302178 ath_wake_mac80211_queue(sc, txq);
2179
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002180 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302181 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002182 ath_txq_schedule(sc, txq);
2183 spin_unlock_bh(&txq->axq_lock);
2184 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002185}
2186
Sujith305fe472009-07-23 15:32:29 +05302187static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002188{
2189 struct ath_softc *sc = container_of(work, struct ath_softc,
2190 tx_complete_work.work);
2191 struct ath_txq *txq;
2192 int i;
2193 bool needreset = false;
2194
2195 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2196 if (ATH_TXQ_SETUP(sc, i)) {
2197 txq = &sc->tx.txq[i];
2198 spin_lock_bh(&txq->axq_lock);
2199 if (txq->axq_depth) {
2200 if (txq->axq_tx_inprogress) {
2201 needreset = true;
2202 spin_unlock_bh(&txq->axq_lock);
2203 break;
2204 } else {
2205 txq->axq_tx_inprogress = true;
2206 }
2207 }
2208 spin_unlock_bh(&txq->axq_lock);
2209 }
2210
2211 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002212 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2213 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302214 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002215 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302216 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002217 }
2218
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002219 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002220 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2221}
2222
2223
Sujithe8324352009-01-16 21:38:42 +05302224
2225void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002226{
Sujithe8324352009-01-16 21:38:42 +05302227 int i;
2228 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002229
Sujithe8324352009-01-16 21:38:42 +05302230 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002231
2232 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302233 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2234 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002235 }
2236}
2237
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002238void ath_tx_edma_tasklet(struct ath_softc *sc)
2239{
2240 struct ath_tx_status txs;
2241 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2242 struct ath_hw *ah = sc->sc_ah;
2243 struct ath_txq *txq;
2244 struct ath_buf *bf, *lastbf;
2245 struct list_head bf_head;
2246 int status;
2247 int txok;
2248
2249 for (;;) {
2250 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2251 if (status == -EINPROGRESS)
2252 break;
2253 if (status == -EIO) {
2254 ath_print(common, ATH_DBG_XMIT,
2255 "Error processing tx status\n");
2256 break;
2257 }
2258
2259 /* Skip beacon completions */
2260 if (txs.qid == sc->beacon.beaconq)
2261 continue;
2262
2263 txq = &sc->tx.txq[txs.qid];
2264
2265 spin_lock_bh(&txq->axq_lock);
2266 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2267 spin_unlock_bh(&txq->axq_lock);
2268 return;
2269 }
2270
2271 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2272 struct ath_buf, list);
2273 lastbf = bf->bf_lastbf;
2274
2275 INIT_LIST_HEAD(&bf_head);
2276 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2277 &lastbf->list);
2278 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2279 txq->axq_depth--;
2280 txq->axq_tx_inprogress = false;
2281 spin_unlock_bh(&txq->axq_lock);
2282
2283 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2284
2285 if (!bf_isampdu(bf)) {
2286 bf->bf_retries = txs.ts_longretry;
2287 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2288 bf->bf_state.bf_type |= BUF_XRETRY;
2289 ath_tx_rc_status(bf, &txs, 0, txok, true);
2290 }
2291
2292 if (bf_isampdu(bf))
2293 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2294 else
2295 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2296 &txs, txok, 0);
2297
2298 spin_lock_bh(&txq->axq_lock);
2299 if (!list_empty(&txq->txq_fifo_pending)) {
2300 INIT_LIST_HEAD(&bf_head);
2301 bf = list_first_entry(&txq->txq_fifo_pending,
2302 struct ath_buf, list);
2303 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2304 &bf->bf_lastbf->list);
2305 ath_tx_txqaddbuf(sc, txq, &bf_head);
2306 } else if (sc->sc_flags & SC_OP_TXAGGR)
2307 ath_txq_schedule(sc, txq);
2308 spin_unlock_bh(&txq->axq_lock);
2309 }
2310}
2311
Sujithe8324352009-01-16 21:38:42 +05302312/*****************/
2313/* Init, Cleanup */
2314/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002315
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002316static int ath_txstatus_setup(struct ath_softc *sc, int size)
2317{
2318 struct ath_descdma *dd = &sc->txsdma;
2319 u8 txs_len = sc->sc_ah->caps.txs_len;
2320
2321 dd->dd_desc_len = size * txs_len;
2322 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2323 &dd->dd_desc_paddr, GFP_KERNEL);
2324 if (!dd->dd_desc)
2325 return -ENOMEM;
2326
2327 return 0;
2328}
2329
2330static int ath_tx_edma_init(struct ath_softc *sc)
2331{
2332 int err;
2333
2334 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2335 if (!err)
2336 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2337 sc->txsdma.dd_desc_paddr,
2338 ATH_TXSTATUS_RING_SIZE);
2339
2340 return err;
2341}
2342
2343static void ath_tx_edma_cleanup(struct ath_softc *sc)
2344{
2345 struct ath_descdma *dd = &sc->txsdma;
2346
2347 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2348 dd->dd_desc_paddr);
2349}
2350
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002351int ath_tx_init(struct ath_softc *sc, int nbufs)
2352{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002353 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354 int error = 0;
2355
Sujith797fe5cb2009-03-30 15:28:45 +05302356 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002357
Sujith797fe5cb2009-03-30 15:28:45 +05302358 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002359 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302360 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002361 ath_print(common, ATH_DBG_FATAL,
2362 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302363 goto err;
2364 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002365
Sujith797fe5cb2009-03-30 15:28:45 +05302366 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002367 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302368 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002369 ath_print(common, ATH_DBG_FATAL,
2370 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302371 goto err;
2372 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002373
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002374 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2375
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002376 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2377 error = ath_tx_edma_init(sc);
2378 if (error)
2379 goto err;
2380 }
2381
Sujith797fe5cb2009-03-30 15:28:45 +05302382err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002383 if (error != 0)
2384 ath_tx_cleanup(sc);
2385
2386 return error;
2387}
2388
Sujith797fe5cb2009-03-30 15:28:45 +05302389void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002390{
Sujithb77f4832008-12-07 21:44:03 +05302391 if (sc->beacon.bdma.dd_desc_len != 0)
2392 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002393
Sujithb77f4832008-12-07 21:44:03 +05302394 if (sc->tx.txdma.dd_desc_len != 0)
2395 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002396
2397 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2398 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002399}
2400
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002401void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2402{
Sujithc5170162008-10-29 10:13:59 +05302403 struct ath_atx_tid *tid;
2404 struct ath_atx_ac *ac;
2405 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002406
Sujith8ee5afb2008-12-07 21:43:36 +05302407 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302408 tidno < WME_NUM_TID;
2409 tidno++, tid++) {
2410 tid->an = an;
2411 tid->tidno = tidno;
2412 tid->seq_start = tid->seq_next = 0;
2413 tid->baw_size = WME_MAX_BA;
2414 tid->baw_head = tid->baw_tail = 0;
2415 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302416 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302417 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302418 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302419 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302420 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302421 tid->state &= ~AGGR_ADDBA_COMPLETE;
2422 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302423 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002424
Sujith8ee5afb2008-12-07 21:43:36 +05302425 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302426 acno < WME_NUM_AC; acno++, ac++) {
2427 ac->sched = false;
2428 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002429
Sujithc5170162008-10-29 10:13:59 +05302430 switch (acno) {
2431 case WME_AC_BE:
2432 ac->qnum = ath_tx_get_qnum(sc,
2433 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
2434 break;
2435 case WME_AC_BK:
2436 ac->qnum = ath_tx_get_qnum(sc,
2437 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
2438 break;
2439 case WME_AC_VI:
2440 ac->qnum = ath_tx_get_qnum(sc,
2441 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
2442 break;
2443 case WME_AC_VO:
2444 ac->qnum = ath_tx_get_qnum(sc,
2445 ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
2446 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002447 }
2448 }
2449}
2450
Sujithb5aa9bf2008-10-29 10:13:31 +05302451void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002452{
2453 int i;
2454 struct ath_atx_ac *ac, *ac_tmp;
2455 struct ath_atx_tid *tid, *tid_tmp;
2456 struct ath_txq *txq;
Sujithe8324352009-01-16 21:38:42 +05302457
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002458 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
2459 if (ATH_TXQ_SETUP(sc, i)) {
Sujithb77f4832008-12-07 21:44:03 +05302460 txq = &sc->tx.txq[i];
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002461
Ming Leia9f042c2010-02-28 00:56:24 +08002462 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002463
2464 list_for_each_entry_safe(ac,
2465 ac_tmp, &txq->axq_acq, list) {
2466 tid = list_first_entry(&ac->tid_q,
2467 struct ath_atx_tid, list);
2468 if (tid && tid->an != an)
2469 continue;
2470 list_del(&ac->list);
2471 ac->sched = false;
2472
2473 list_for_each_entry_safe(tid,
2474 tid_tmp, &ac->tid_q, list) {
2475 list_del(&tid->list);
2476 tid->sched = false;
Sujithb5aa9bf2008-10-29 10:13:31 +05302477 ath_tid_drain(sc, txq, tid);
Sujitha37c2c72008-10-29 10:15:40 +05302478 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujitha37c2c72008-10-29 10:15:40 +05302479 tid->state &= ~AGGR_CLEANUP;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002480 }
2481 }
2482
Ming Leia9f042c2010-02-28 00:56:24 +08002483 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002484 }
2485 }
2486}