blob: e53433e3e4cccd0b090c130ca2cf819a93e8b5ef [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Sujith394cf0a2009-02-09 13:26:54 +053017#include "ath9k.h"
Luis R. Rodriguezb622a722010-04-15 17:39:28 -040018#include "ar9003_mac.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070019
20#define BITS_PER_BYTE 8
21#define OFDM_PLCP_BITS 22
Felix Fietkau7817e4c2010-04-19 19:57:31 +020022#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070023#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
24#define L_STF 8
25#define L_LTF 8
26#define L_SIG 4
27#define HT_SIG 8
28#define HT_STF 4
29#define HT_LTF(_ns) (4 * (_ns))
30#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
31#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
32#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
33#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
34
35#define OFDM_SIFS_TIME 16
36
Felix Fietkauc6663872010-04-19 19:57:33 +020037static u16 bits_per_symbol[][2] = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070038 /* 20MHz 40MHz */
39 { 26, 54 }, /* 0: BPSK */
40 { 52, 108 }, /* 1: QPSK 1/2 */
41 { 78, 162 }, /* 2: QPSK 3/4 */
42 { 104, 216 }, /* 3: 16-QAM 1/2 */
43 { 156, 324 }, /* 4: 16-QAM 3/4 */
44 { 208, 432 }, /* 5: 64-QAM 2/3 */
45 { 234, 486 }, /* 6: 64-QAM 3/4 */
46 { 260, 540 }, /* 7: 64-QAM 5/6 */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070047};
48
49#define IS_HT_RATE(_rate) ((_rate) & 0x80)
50
Sujithc37452b2009-03-09 09:31:57 +053051static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
52 struct ath_atx_tid *tid,
53 struct list_head *bf_head);
Sujithe8324352009-01-16 21:38:42 +053054static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070055 struct ath_txq *txq, struct list_head *bf_q,
56 struct ath_tx_status *ts, int txok, int sendbar);
Sujithe8324352009-01-16 21:38:42 +053057static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
58 struct list_head *head);
59static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +053060static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070061 struct ath_tx_status *ts, int txok);
62static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +053063 int nbad, int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020064static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
65 int seqno);
Sujithe8324352009-01-16 21:38:42 +053066
Felix Fietkau545750d2009-11-23 22:21:01 +010067enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020068 MCS_HT20,
69 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010070 MCS_HT40,
71 MCS_HT40_SGI,
72};
73
Felix Fietkau0e668cd2010-04-19 19:57:32 +020074static int ath_max_4ms_framelen[4][32] = {
75 [MCS_HT20] = {
76 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
77 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
78 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
79 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
80 },
81 [MCS_HT20_SGI] = {
82 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
83 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
84 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
85 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010086 },
87 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020088 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
89 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
90 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
91 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010092 },
93 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020094 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
95 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
96 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
97 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010098 }
99};
100
Sujithe8324352009-01-16 21:38:42 +0530101/*********************/
102/* Aggregation logic */
103/*********************/
104
Sujithe8324352009-01-16 21:38:42 +0530105static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
106{
107 struct ath_atx_ac *ac = tid->ac;
108
109 if (tid->paused)
110 return;
111
112 if (tid->sched)
113 return;
114
115 tid->sched = true;
116 list_add_tail(&tid->list, &ac->tid_q);
117
118 if (ac->sched)
119 return;
120
121 ac->sched = true;
122 list_add_tail(&ac->list, &txq->axq_acq);
123}
124
Sujithe8324352009-01-16 21:38:42 +0530125static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
126{
127 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
128
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200129 WARN_ON(!tid->paused);
130
Sujithe8324352009-01-16 21:38:42 +0530131 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200132 tid->paused = false;
Sujithe8324352009-01-16 21:38:42 +0530133
134 if (list_empty(&tid->buf_q))
135 goto unlock;
136
137 ath_tx_queue_tid(txq, tid);
138 ath_txq_schedule(sc, txq);
139unlock:
140 spin_unlock_bh(&txq->axq_lock);
141}
142
143static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
144{
145 struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
146 struct ath_buf *bf;
147 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200148 struct ath_tx_status ts;
149
Sujithe8324352009-01-16 21:38:42 +0530150 INIT_LIST_HEAD(&bf_head);
151
Felix Fietkau90fa5392010-09-20 13:45:38 +0200152 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530153 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530154
155 while (!list_empty(&tid->buf_q)) {
156 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530157 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200158
159 if (bf_isretried(bf)) {
160 ath_tx_update_baw(sc, tid, bf->bf_seqno);
161 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
162 } else {
163 ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
164 }
Sujithe8324352009-01-16 21:38:42 +0530165 }
166
167 spin_unlock_bh(&txq->axq_lock);
168}
169
170static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
171 int seqno)
172{
173 int index, cindex;
174
175 index = ATH_BA_INDEX(tid->seq_start, seqno);
176 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
177
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200178 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530179
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200180 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530181 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
182 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
183 }
184}
185
186static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
187 struct ath_buf *bf)
188{
189 int index, cindex;
190
191 if (bf_isretried(bf))
192 return;
193
194 index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
195 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200196 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530197
198 if (index >= ((tid->baw_tail - tid->baw_head) &
199 (ATH_TID_MAX_BUFS - 1))) {
200 tid->baw_tail = cindex;
201 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
202 }
203}
204
205/*
206 * TODO: For frame(s) that are in the retry state, we will reuse the
207 * sequence number(s) without setting the retry bit. The
208 * alternative is to give up on these and BAR the receiver's window
209 * forward.
210 */
211static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
212 struct ath_atx_tid *tid)
213
214{
215 struct ath_buf *bf;
216 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700217 struct ath_tx_status ts;
218
219 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530220 INIT_LIST_HEAD(&bf_head);
221
222 for (;;) {
223 if (list_empty(&tid->buf_q))
224 break;
Sujithe8324352009-01-16 21:38:42 +0530225
Sujithd43f30152009-01-16 21:38:53 +0530226 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
227 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530228
229 if (bf_isretried(bf))
230 ath_tx_update_baw(sc, tid, bf->bf_seqno);
231
232 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700233 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530234 spin_lock(&txq->axq_lock);
235 }
236
237 tid->seq_next = tid->seq_start;
238 tid->baw_tail = tid->baw_head;
239}
240
Sujithfec247c2009-07-27 12:08:16 +0530241static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
242 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530243{
244 struct sk_buff *skb;
245 struct ieee80211_hdr *hdr;
246
247 bf->bf_state.bf_type |= BUF_RETRY;
248 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530249 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530250
251 skb = bf->bf_mpdu;
252 hdr = (struct ieee80211_hdr *)skb->data;
253 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
254}
255
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200256static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
257{
258 struct ath_buf *bf = NULL;
259
260 spin_lock_bh(&sc->tx.txbuflock);
261
262 if (unlikely(list_empty(&sc->tx.txbuf))) {
263 spin_unlock_bh(&sc->tx.txbuflock);
264 return NULL;
265 }
266
267 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
268 list_del(&bf->list);
269
270 spin_unlock_bh(&sc->tx.txbuflock);
271
272 return bf;
273}
274
275static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
276{
277 spin_lock_bh(&sc->tx.txbuflock);
278 list_add_tail(&bf->list, &sc->tx.txbuf);
279 spin_unlock_bh(&sc->tx.txbuflock);
280}
281
Sujithd43f30152009-01-16 21:38:53 +0530282static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
283{
284 struct ath_buf *tbf;
285
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200286 tbf = ath_tx_get_buffer(sc);
287 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530288 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530289
290 ATH_TXBUF_RESET(tbf);
291
Felix Fietkau827e69b2009-11-15 23:09:25 +0100292 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530293 tbf->bf_mpdu = bf->bf_mpdu;
294 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400295 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530296 tbf->bf_state = bf->bf_state;
297 tbf->bf_dmacontext = bf->bf_dmacontext;
298
299 return tbf;
300}
301
302static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
303 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700304 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530305{
306 struct ath_node *an = NULL;
307 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530308 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800309 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530310 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800311 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530312 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530313 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530314 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530315 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530316 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530317 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
318 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200319 struct ieee80211_tx_rate rates[4];
Sujithe8324352009-01-16 21:38:42 +0530320
Sujitha22be222009-03-30 15:28:36 +0530321 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530322 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530323
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800324 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100325 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800326
Felix Fietkau78c46532010-06-25 01:26:16 +0200327 memcpy(rates, tx_info->control.rates, sizeof(rates));
328
Sujith1286ec62009-01-27 13:30:37 +0530329 rcu_read_lock();
330
Johannes Berg5ed176e2009-11-04 14:42:28 +0100331 /* XXX: use ieee80211_find_sta! */
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800332 sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
Sujith1286ec62009-01-27 13:30:37 +0530333 if (!sta) {
334 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200335
Felix Fietkau31e79a52010-07-12 23:16:34 +0200336 INIT_LIST_HEAD(&bf_head);
337 while (bf) {
338 bf_next = bf->bf_next;
339
340 bf->bf_state.bf_type |= BUF_XRETRY;
341 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
342 !bf->bf_stale || bf_next != NULL)
343 list_move_tail(&bf->list, &bf_head);
344
345 ath_tx_rc_status(bf, ts, 0, 0, false);
346 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
347 0, 0);
348
349 bf = bf_next;
350 }
Sujith1286ec62009-01-27 13:30:37 +0530351 return;
Sujithe8324352009-01-16 21:38:42 +0530352 }
353
Sujith1286ec62009-01-27 13:30:37 +0530354 an = (struct ath_node *)sta->drv_priv;
355 tid = ATH_AN_2_TID(an, bf->bf_tidno);
356
Felix Fietkaub11b1602010-07-11 12:48:44 +0200357 /*
358 * The hardware occasionally sends a tx status for the wrong TID.
359 * In this case, the BA status cannot be considered valid and all
360 * subframes need to be retransmitted
361 */
362 if (bf->bf_tidno != ts->tid)
363 txok = false;
364
Sujithe8324352009-01-16 21:38:42 +0530365 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530366 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530367
Sujithd43f30152009-01-16 21:38:53 +0530368 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700369 if (ts->ts_flags & ATH9K_TX_BA) {
370 seq_st = ts->ts_seqnum;
371 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530372 } else {
Sujithd43f30152009-01-16 21:38:53 +0530373 /*
374 * AR5416 can become deaf/mute when BA
375 * issue happens. Chip needs to be reset.
376 * But AP code may have sychronization issues
377 * when perform internal reset in this routine.
378 * Only enable reset in STA mode for now.
379 */
Sujith2660b812009-02-09 13:27:26 +0530380 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530381 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530382 }
383 }
384
385 INIT_LIST_HEAD(&bf_pending);
386 INIT_LIST_HEAD(&bf_head);
387
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700388 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530389 while (bf) {
390 txfail = txpending = 0;
391 bf_next = bf->bf_next;
392
Felix Fietkau78c46532010-06-25 01:26:16 +0200393 skb = bf->bf_mpdu;
394 tx_info = IEEE80211_SKB_CB(skb);
395
Sujithe8324352009-01-16 21:38:42 +0530396 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
397 /* transmit completion, subframe is
398 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530399 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530400 } else if (!isaggr && txok) {
401 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530402 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530403 } else {
Sujithe8324352009-01-16 21:38:42 +0530404 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400405 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530406 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530407 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530408 txpending = 1;
409 } else {
410 bf->bf_state.bf_type |= BUF_XRETRY;
411 txfail = 1;
412 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530413 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530414 }
415 } else {
416 /*
417 * cleanup in progress, just fail
418 * the un-acked sub-frames
419 */
420 txfail = 1;
421 }
422 }
423
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400424 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
425 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530426 /*
427 * Make sure the last desc is reclaimed if it
428 * not a holding desc.
429 */
430 if (!bf_last->bf_stale)
431 list_move_tail(&bf->list, &bf_head);
432 else
433 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530434 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700435 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530436 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530437 }
438
Felix Fietkau90fa5392010-09-20 13:45:38 +0200439 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530440 /*
441 * complete the acked-ones/xretried ones; update
442 * block-ack window
443 */
444 spin_lock_bh(&txq->axq_lock);
445 ath_tx_update_baw(sc, tid, bf->bf_seqno);
446 spin_unlock_bh(&txq->axq_lock);
447
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530448 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200449 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700450 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530451 rc_update = false;
452 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700453 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530454 }
455
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700456 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
457 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530458 } else {
Sujithd43f30152009-01-16 21:38:53 +0530459 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400460 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
461 if (bf->bf_next == NULL && bf_last->bf_stale) {
462 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530463
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400464 tbf = ath_clone_txbuf(sc, bf_last);
465 /*
466 * Update tx baw and complete the
467 * frame with failed status if we
468 * run out of tx buf.
469 */
470 if (!tbf) {
471 spin_lock_bh(&txq->axq_lock);
472 ath_tx_update_baw(sc, tid,
473 bf->bf_seqno);
474 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400475
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400476 bf->bf_state.bf_type |=
477 BUF_XRETRY;
478 ath_tx_rc_status(bf, ts, nbad,
479 0, false);
480 ath_tx_complete_buf(sc, bf, txq,
481 &bf_head,
482 ts, 0, 0);
483 break;
484 }
485
486 ath9k_hw_cleartxdesc(sc->sc_ah,
487 tbf->bf_desc);
488 list_add_tail(&tbf->list, &bf_head);
489 } else {
490 /*
491 * Clear descriptor status words for
492 * software retry
493 */
494 ath9k_hw_cleartxdesc(sc->sc_ah,
495 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400496 }
Sujithe8324352009-01-16 21:38:42 +0530497 }
498
499 /*
500 * Put this buffer to the temporary pending
501 * queue to retain ordering
502 */
503 list_splice_tail_init(&bf_head, &bf_pending);
504 }
505
506 bf = bf_next;
507 }
508
Felix Fietkau4cee7862010-07-23 03:53:16 +0200509 /* prepend un-acked frames to the beginning of the pending frame queue */
510 if (!list_empty(&bf_pending)) {
511 spin_lock_bh(&txq->axq_lock);
512 list_splice(&bf_pending, &tid->buf_q);
513 ath_tx_queue_tid(txq, tid);
514 spin_unlock_bh(&txq->axq_lock);
515 }
516
Sujithe8324352009-01-16 21:38:42 +0530517 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200518 ath_tx_flush_tid(sc, tid);
519
Sujithe8324352009-01-16 21:38:42 +0530520 if (tid->baw_head == tid->baw_tail) {
521 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530522 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530523 }
Sujithe8324352009-01-16 21:38:42 +0530524 }
525
Sujith1286ec62009-01-27 13:30:37 +0530526 rcu_read_unlock();
527
Sujithe8324352009-01-16 21:38:42 +0530528 if (needreset)
529 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530530}
531
532static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
533 struct ath_atx_tid *tid)
534{
Sujithe8324352009-01-16 21:38:42 +0530535 struct sk_buff *skb;
536 struct ieee80211_tx_info *tx_info;
537 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530538 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530539 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530540 int i;
541
Sujitha22be222009-03-30 15:28:36 +0530542 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530543 tx_info = IEEE80211_SKB_CB(skb);
544 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530545
546 /*
547 * Find the lowest frame length among the rate series that will have a
548 * 4ms transmit duration.
549 * TODO - TXOP limit needs to be considered.
550 */
551 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
552
553 for (i = 0; i < 4; i++) {
554 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100555 int modeidx;
556 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530557 legacy = 1;
558 break;
559 }
560
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200561 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100562 modeidx = MCS_HT40;
563 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200564 modeidx = MCS_HT20;
565
566 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
567 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100568
569 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530570 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530571 }
572 }
573
574 /*
575 * limit aggregate size by the minimum rate if rate selected is
576 * not a probe rate, if rate selected is a probe rate then
577 * avoid aggregation of this packet.
578 */
579 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
580 return 0;
581
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530582 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
583 aggr_limit = min((max_4ms_framelen * 3) / 8,
584 (u32)ATH_AMPDU_LIMIT_MAX);
585 else
586 aggr_limit = min(max_4ms_framelen,
587 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530588
589 /*
590 * h/w can accept aggregates upto 16 bit lengths (65535).
591 * The IE, however can hold upto 65536, which shows up here
592 * as zero. Ignore 65536 since we are constrained by hw.
593 */
Sujith4ef70842009-07-23 15:32:41 +0530594 if (tid->an->maxampdu)
595 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530596
597 return aggr_limit;
598}
599
600/*
Sujithd43f30152009-01-16 21:38:53 +0530601 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530602 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530603 */
604static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
605 struct ath_buf *bf, u16 frmlen)
606{
Sujithe8324352009-01-16 21:38:42 +0530607 struct sk_buff *skb = bf->bf_mpdu;
608 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530609 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530610 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100611 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200612 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530613
614 /* Select standard number of delimiters based on frame length alone */
615 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
616
617 /*
618 * If encryption enabled, hardware requires some more padding between
619 * subframes.
620 * TODO - this could be improved to be dependent on the rate.
621 * The hardware can keep up at lower rates, but not higher rates
622 */
623 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
624 ndelim += ATH_AGGR_ENCRYPTDELIM;
625
626 /*
627 * Convert desired mpdu density from microeconds to bytes based
628 * on highest rate in rate series (i.e. first rate) to determine
629 * required minimum length for subframe. Take into account
630 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530631 *
Sujithe8324352009-01-16 21:38:42 +0530632 * If there is no mpdu density restriction, no further calculation
633 * is needed.
634 */
Sujith4ef70842009-07-23 15:32:41 +0530635
636 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530637 return ndelim;
638
639 rix = tx_info->control.rates[0].idx;
640 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530641 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
642 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
643
644 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530645 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530646 else
Sujith4ef70842009-07-23 15:32:41 +0530647 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530648
649 if (nsymbols == 0)
650 nsymbols = 1;
651
Felix Fietkauc6663872010-04-19 19:57:33 +0200652 streams = HT_RC_2_STREAMS(rix);
653 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530654 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
655
Sujithe8324352009-01-16 21:38:42 +0530656 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530657 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
658 ndelim = max(mindelim, ndelim);
659 }
660
661 return ndelim;
662}
663
664static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530665 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530666 struct ath_atx_tid *tid,
667 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530668{
669#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530670 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
671 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530672 u16 aggr_limit = 0, al = 0, bpad = 0,
673 al_delta, h_baw = tid->baw_size / 2;
674 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Sujithe8324352009-01-16 21:38:42 +0530675
676 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
677
678 do {
679 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
680
Sujithd43f30152009-01-16 21:38:53 +0530681 /* do not step over block-ack window */
Sujithe8324352009-01-16 21:38:42 +0530682 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
683 status = ATH_AGGR_BAW_CLOSED;
684 break;
685 }
686
687 if (!rl) {
688 aggr_limit = ath_lookup_rate(sc, bf, tid);
689 rl = 1;
690 }
691
Sujithd43f30152009-01-16 21:38:53 +0530692 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530693 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
694
Sujithd43f30152009-01-16 21:38:53 +0530695 if (nframes &&
696 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530697 status = ATH_AGGR_LIMITED;
698 break;
699 }
700
Sujithd43f30152009-01-16 21:38:53 +0530701 /* do not exceed subframe limit */
702 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530703 status = ATH_AGGR_LIMITED;
704 break;
705 }
Sujithd43f30152009-01-16 21:38:53 +0530706 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530707
Sujithd43f30152009-01-16 21:38:53 +0530708 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530709 al += bpad + al_delta;
710
711 /*
712 * Get the delimiters needed to meet the MPDU
713 * density for this node.
714 */
715 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530716 bpad = PADBYTES(al_delta) + (ndelim << 2);
717
718 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400719 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530720
Sujithd43f30152009-01-16 21:38:53 +0530721 /* link buffers of this frame to the aggregate */
Sujithe8324352009-01-16 21:38:42 +0530722 ath_tx_addto_baw(sc, tid, bf);
Sujithd43f30152009-01-16 21:38:53 +0530723 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
724 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530725 if (bf_prev) {
726 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400727 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
728 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530729 }
730 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530731
Sujithe8324352009-01-16 21:38:42 +0530732 } while (!list_empty(&tid->buf_q));
733
734 bf_first->bf_al = al;
735 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530736
Sujithe8324352009-01-16 21:38:42 +0530737 return status;
738#undef PADBYTES
739}
740
741static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
742 struct ath_atx_tid *tid)
743{
Sujithd43f30152009-01-16 21:38:53 +0530744 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530745 enum ATH_AGGR_STATUS status;
746 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530747
748 do {
749 if (list_empty(&tid->buf_q))
750 return;
751
752 INIT_LIST_HEAD(&bf_q);
753
Sujithfec247c2009-07-27 12:08:16 +0530754 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530755
756 /*
Sujithd43f30152009-01-16 21:38:53 +0530757 * no frames picked up to be aggregated;
758 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530759 */
760 if (list_empty(&bf_q))
761 break;
762
763 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530764 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530765
Sujithd43f30152009-01-16 21:38:53 +0530766 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530767 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530768 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530769 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530770 ath_buf_set_rate(sc, bf);
771 ath_tx_txqaddbuf(sc, txq, &bf_q);
772 continue;
773 }
774
Sujithd43f30152009-01-16 21:38:53 +0530775 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530776 bf->bf_state.bf_type |= BUF_AGGR;
777 ath_buf_set_rate(sc, bf);
778 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
779
Sujithd43f30152009-01-16 21:38:53 +0530780 /* anchor last desc of aggregate */
781 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530782
Sujithe8324352009-01-16 21:38:42 +0530783 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530784 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530785
786 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
787 status != ATH_AGGR_BAW_CLOSED);
788}
789
Felix Fietkau231c3a12010-09-20 19:35:28 +0200790int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
791 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530792{
793 struct ath_atx_tid *txtid;
794 struct ath_node *an;
795
796 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530797 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200798
799 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
800 return -EAGAIN;
801
Sujithf83da962009-07-23 15:32:37 +0530802 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200803 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530804 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200805
806 return 0;
Sujithe8324352009-01-16 21:38:42 +0530807}
808
Sujithf83da962009-07-23 15:32:37 +0530809void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530810{
811 struct ath_node *an = (struct ath_node *)sta->drv_priv;
812 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
813 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
Sujithe8324352009-01-16 21:38:42 +0530814
815 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530816 return;
Sujithe8324352009-01-16 21:38:42 +0530817
818 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530819 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530820 return;
Sujithe8324352009-01-16 21:38:42 +0530821 }
822
Sujithe8324352009-01-16 21:38:42 +0530823 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200824 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200825
826 /*
827 * If frames are still being transmitted for this TID, they will be
828 * cleaned up during tx completion. To prevent race conditions, this
829 * TID can only be reused after all in-progress subframes have been
830 * completed.
831 */
832 if (txtid->baw_head != txtid->baw_tail)
833 txtid->state |= AGGR_CLEANUP;
834 else
835 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530836 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530837
Felix Fietkau90fa5392010-09-20 13:45:38 +0200838 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530839}
840
841void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
842{
843 struct ath_atx_tid *txtid;
844 struct ath_node *an;
845
846 an = (struct ath_node *)sta->drv_priv;
847
848 if (sc->sc_flags & SC_OP_TXAGGR) {
849 txtid = ATH_AN_2_TID(an, tid);
850 txtid->baw_size =
851 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
852 txtid->state |= AGGR_ADDBA_COMPLETE;
853 txtid->state &= ~AGGR_ADDBA_PROGRESS;
854 ath_tx_resume_tid(sc, txtid);
855 }
856}
857
858bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
859{
860 struct ath_atx_tid *txtid;
861
862 if (!(sc->sc_flags & SC_OP_TXAGGR))
863 return false;
864
865 txtid = ATH_AN_2_TID(an, tidno);
866
Vasanthakumar Thiagarajanc3d8f022009-06-10 17:50:08 +0530867 if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
Sujithe8324352009-01-16 21:38:42 +0530868 return true;
Sujithe8324352009-01-16 21:38:42 +0530869 return false;
870}
871
872/********************/
873/* Queue Management */
874/********************/
875
Sujithe8324352009-01-16 21:38:42 +0530876static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
877 struct ath_txq *txq)
878{
879 struct ath_atx_ac *ac, *ac_tmp;
880 struct ath_atx_tid *tid, *tid_tmp;
881
882 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
883 list_del(&ac->list);
884 ac->sched = false;
885 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
886 list_del(&tid->list);
887 tid->sched = false;
888 ath_tid_drain(sc, txq, tid);
889 }
890 }
891}
892
893struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
894{
Sujithcbe61d8a2009-02-09 13:27:12 +0530895 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700896 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530897 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400898 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530899
900 memset(&qi, 0, sizeof(qi));
901 qi.tqi_subtype = subtype;
902 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
903 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
904 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
905 qi.tqi_physCompBuf = 0;
906
907 /*
908 * Enable interrupts only for EOL and DESC conditions.
909 * We mark tx descriptors to receive a DESC interrupt
910 * when a tx queue gets deep; otherwise waiting for the
911 * EOL to reap descriptors. Note that this is done to
912 * reduce interrupt load and this only defers reaping
913 * descriptors, never transmitting frames. Aside from
914 * reducing interrupts this also permits more concurrency.
915 * The only potential downside is if the tx queue backs
916 * up in which case the top half of the kernel may backup
917 * due to a lack of tx descriptors.
918 *
919 * The UAPSD queue is an exception, since we take a desc-
920 * based intr on the EOSP frames.
921 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400922 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
923 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
924 TXQ_FLAG_TXERRINT_ENABLE;
925 } else {
926 if (qtype == ATH9K_TX_QUEUE_UAPSD)
927 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
928 else
929 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
930 TXQ_FLAG_TXDESCINT_ENABLE;
931 }
Sujithe8324352009-01-16 21:38:42 +0530932 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
933 if (qnum == -1) {
934 /*
935 * NB: don't print a message, this happens
936 * normally on parts with too few tx queues
937 */
938 return NULL;
939 }
940 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700941 ath_print(common, ATH_DBG_FATAL,
942 "qnum %u out of range, max %u!\n",
943 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530944 ath9k_hw_releasetxqueue(ah, qnum);
945 return NULL;
946 }
947 if (!ATH_TXQ_SETUP(sc, qnum)) {
948 struct ath_txq *txq = &sc->tx.txq[qnum];
949
Felix Fietkau293f2ba2010-06-12 00:33:49 -0400950 txq->axq_class = subtype;
Sujithe8324352009-01-16 21:38:42 +0530951 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
Sujithe8324352009-01-16 21:38:42 +0530968int ath_txq_update(struct ath_softc *sc, int qnum,
969 struct ath9k_tx_queue_info *qinfo)
970{
Sujithcbe61d8a2009-02-09 13:27:12 +0530971 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530972 int error = 0;
973 struct ath9k_tx_queue_info qi;
974
975 if (qnum == sc->beacon.beaconq) {
976 /*
977 * XXX: for beacon queue, we just save the parameter.
978 * It will be picked up by ath_beaconq_config when
979 * it's necessary.
980 */
981 sc->beacon.beacon_qi = *qinfo;
982 return 0;
983 }
984
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700985 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530986
987 ath9k_hw_get_txq_props(ah, qnum, &qi);
988 qi.tqi_aifs = qinfo->tqi_aifs;
989 qi.tqi_cwmin = qinfo->tqi_cwmin;
990 qi.tqi_cwmax = qinfo->tqi_cwmax;
991 qi.tqi_burstTime = qinfo->tqi_burstTime;
992 qi.tqi_readyTime = qinfo->tqi_readyTime;
993
994 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700995 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
996 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +0530997 error = -EIO;
998 } else {
999 ath9k_hw_resettxqueue(ah, qnum);
1000 }
1001
1002 return error;
1003}
1004
1005int ath_cabq_update(struct ath_softc *sc)
1006{
1007 struct ath9k_tx_queue_info qi;
1008 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301009
1010 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1011 /*
1012 * Ensure the readytime % is within the bounds.
1013 */
Sujith17d79042009-02-09 13:27:03 +05301014 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1015 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1016 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1017 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301018
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001019 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301020 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301021 ath_txq_update(sc, qnum, &qi);
1022
1023 return 0;
1024}
1025
Sujith043a0402009-01-16 21:38:47 +05301026/*
1027 * Drain a given TX queue (could be Beacon or Data)
1028 *
1029 * This assumes output has been stopped and
1030 * we do not need to block ath_tx_tasklet.
1031 */
1032void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301033{
1034 struct ath_buf *bf, *lastbf;
1035 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001036 struct ath_tx_status ts;
1037
1038 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301039 INIT_LIST_HEAD(&bf_head);
1040
Sujithe8324352009-01-16 21:38:42 +05301041 for (;;) {
1042 spin_lock_bh(&txq->axq_lock);
1043
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001044 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1045 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1046 txq->txq_headidx = txq->txq_tailidx = 0;
1047 spin_unlock_bh(&txq->axq_lock);
1048 break;
1049 } else {
1050 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1051 struct ath_buf, list);
1052 }
1053 } else {
1054 if (list_empty(&txq->axq_q)) {
1055 txq->axq_link = NULL;
1056 spin_unlock_bh(&txq->axq_lock);
1057 break;
1058 }
1059 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1060 list);
Sujithe8324352009-01-16 21:38:42 +05301061
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001062 if (bf->bf_stale) {
1063 list_del(&bf->list);
1064 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301065
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001066 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001067 continue;
1068 }
Sujithe8324352009-01-16 21:38:42 +05301069 }
1070
1071 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001072 if (!retry_tx)
1073 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301074
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001075 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1076 list_cut_position(&bf_head,
1077 &txq->txq_fifo[txq->txq_tailidx],
1078 &lastbf->list);
1079 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1080 } else {
1081 /* remove ath_buf's of the same mpdu from txq */
1082 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1083 }
1084
Sujithe8324352009-01-16 21:38:42 +05301085 txq->axq_depth--;
1086
1087 spin_unlock_bh(&txq->axq_lock);
1088
1089 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001090 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301091 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001092 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301093 }
1094
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001095 spin_lock_bh(&txq->axq_lock);
1096 txq->axq_tx_inprogress = false;
1097 spin_unlock_bh(&txq->axq_lock);
1098
Sujithe8324352009-01-16 21:38:42 +05301099 /* flush any pending frames if aggregation is enabled */
1100 if (sc->sc_flags & SC_OP_TXAGGR) {
1101 if (!retry_tx) {
1102 spin_lock_bh(&txq->axq_lock);
1103 ath_txq_drain_pending_buffers(sc, txq);
1104 spin_unlock_bh(&txq->axq_lock);
1105 }
1106 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001107
1108 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1109 spin_lock_bh(&txq->axq_lock);
1110 while (!list_empty(&txq->txq_fifo_pending)) {
1111 bf = list_first_entry(&txq->txq_fifo_pending,
1112 struct ath_buf, list);
1113 list_cut_position(&bf_head,
1114 &txq->txq_fifo_pending,
1115 &bf->bf_lastbf->list);
1116 spin_unlock_bh(&txq->axq_lock);
1117
1118 if (bf_isampdu(bf))
1119 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1120 &ts, 0);
1121 else
1122 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1123 &ts, 0, 0);
1124 spin_lock_bh(&txq->axq_lock);
1125 }
1126 spin_unlock_bh(&txq->axq_lock);
1127 }
Sujithe8324352009-01-16 21:38:42 +05301128}
1129
Sujith043a0402009-01-16 21:38:47 +05301130void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1131{
Sujithcbe61d8a2009-02-09 13:27:12 +05301132 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001133 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301134 struct ath_txq *txq;
1135 int i, npend = 0;
1136
1137 if (sc->sc_flags & SC_OP_INVALID)
1138 return;
1139
1140 /* Stop beacon queue */
1141 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1142
1143 /* Stop data queues */
1144 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1145 if (ATH_TXQ_SETUP(sc, i)) {
1146 txq = &sc->tx.txq[i];
1147 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1148 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1149 }
1150 }
1151
1152 if (npend) {
1153 int r;
1154
Sujithe8009e92009-12-14 14:57:08 +05301155 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001156 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301157
1158 spin_lock_bh(&sc->sc_resetlock);
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001159 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301160 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001161 ath_print(common, ATH_DBG_FATAL,
1162 "Unable to reset hardware; reset status %d\n",
1163 r);
Sujith043a0402009-01-16 21:38:47 +05301164 spin_unlock_bh(&sc->sc_resetlock);
1165 }
1166
1167 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1168 if (ATH_TXQ_SETUP(sc, i))
1169 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1170 }
1171}
1172
Sujithe8324352009-01-16 21:38:42 +05301173void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1174{
1175 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1176 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1177}
1178
Sujithe8324352009-01-16 21:38:42 +05301179void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1180{
1181 struct ath_atx_ac *ac;
1182 struct ath_atx_tid *tid;
1183
1184 if (list_empty(&txq->axq_acq))
1185 return;
1186
1187 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1188 list_del(&ac->list);
1189 ac->sched = false;
1190
1191 do {
1192 if (list_empty(&ac->tid_q))
1193 return;
1194
1195 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1196 list_del(&tid->list);
1197 tid->sched = false;
1198
1199 if (tid->paused)
1200 continue;
1201
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001202 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301203
1204 /*
1205 * add tid to round-robin queue if more frames
1206 * are pending for the tid
1207 */
1208 if (!list_empty(&tid->buf_q))
1209 ath_tx_queue_tid(txq, tid);
1210
1211 break;
1212 } while (!list_empty(&ac->tid_q));
1213
1214 if (!list_empty(&ac->tid_q)) {
1215 if (!ac->sched) {
1216 ac->sched = true;
1217 list_add_tail(&ac->list, &txq->axq_acq);
1218 }
1219 }
1220}
1221
1222int ath_tx_setup(struct ath_softc *sc, int haltype)
1223{
1224 struct ath_txq *txq;
1225
1226 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001227 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1228 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301229 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1230 return 0;
1231 }
1232 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1233 if (txq != NULL) {
1234 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1235 return 1;
1236 } else
1237 return 0;
1238}
1239
1240/***********/
1241/* TX, DMA */
1242/***********/
1243
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001244/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001245 * Insert a chain of ath_buf (descriptors) on a txq and
1246 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001247 */
Sujith102e0572008-10-29 10:15:16 +05301248static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1249 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001250{
Sujithcbe61d8a2009-02-09 13:27:12 +05301251 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001252 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001253 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301254
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001255 /*
1256 * Insert the frame on the outbound list and
1257 * pass it on to the hardware.
1258 */
1259
1260 if (list_empty(head))
1261 return;
1262
1263 bf = list_first_entry(head, struct ath_buf, list);
1264
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001265 ath_print(common, ATH_DBG_QUEUE,
1266 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001267
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001268 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1269 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1270 list_splice_tail_init(head, &txq->txq_fifo_pending);
1271 return;
1272 }
1273 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1274 ath_print(common, ATH_DBG_XMIT,
1275 "Initializing tx fifo %d which "
1276 "is non-empty\n",
1277 txq->txq_headidx);
1278 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1279 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1280 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001281 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001282 ath_print(common, ATH_DBG_XMIT,
1283 "TXDP[%u] = %llx (%p)\n",
1284 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001285 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001286 list_splice_tail_init(head, &txq->axq_q);
1287
1288 if (txq->axq_link == NULL) {
1289 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1290 ath_print(common, ATH_DBG_XMIT,
1291 "TXDP[%u] = %llx (%p)\n",
1292 txq->axq_qnum, ito64(bf->bf_daddr),
1293 bf->bf_desc);
1294 } else {
1295 *txq->axq_link = bf->bf_daddr;
1296 ath_print(common, ATH_DBG_XMIT,
1297 "link[%u] (%p)=%llx (%p)\n",
1298 txq->axq_qnum, txq->axq_link,
1299 ito64(bf->bf_daddr), bf->bf_desc);
1300 }
1301 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1302 &txq->axq_link);
1303 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001304 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001305 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001306}
1307
Sujithe8324352009-01-16 21:38:42 +05301308static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1309 struct list_head *bf_head,
1310 struct ath_tx_control *txctl)
1311{
1312 struct ath_buf *bf;
1313
Sujithe8324352009-01-16 21:38:42 +05301314 bf = list_first_entry(bf_head, struct ath_buf, list);
1315 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301316 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301317
1318 /*
1319 * Do not queue to h/w when any of the following conditions is true:
1320 * - there are pending frames in software queue
1321 * - the TID is currently paused for ADDBA/BAR request
1322 * - seqno is not within block-ack window
1323 * - h/w queue depth exceeds low water mark
1324 */
1325 if (!list_empty(&tid->buf_q) || tid->paused ||
1326 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1327 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001328 /*
Sujithe8324352009-01-16 21:38:42 +05301329 * Add this frame to software queue for scheduling later
1330 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001331 */
Sujithd43f30152009-01-16 21:38:53 +05301332 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301333 ath_tx_queue_tid(txctl->txq, tid);
1334 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001335 }
1336
Sujithe8324352009-01-16 21:38:42 +05301337 /* Add sub-frame to BAW */
1338 ath_tx_addto_baw(sc, tid, bf);
1339
1340 /* Queue to h/w without aggregation */
1341 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301342 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301343 ath_buf_set_rate(sc, bf);
1344 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301345}
1346
Sujithc37452b2009-03-09 09:31:57 +05301347static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1348 struct ath_atx_tid *tid,
1349 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001350{
Sujithe8324352009-01-16 21:38:42 +05301351 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001352
Sujithe8324352009-01-16 21:38:42 +05301353 bf = list_first_entry(bf_head, struct ath_buf, list);
1354 bf->bf_state.bf_type &= ~BUF_AMPDU;
1355
1356 /* update starting sequence number for subsequent ADDBA request */
1357 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1358
1359 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301360 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301361 ath_buf_set_rate(sc, bf);
1362 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301363 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001364}
1365
Sujithc37452b2009-03-09 09:31:57 +05301366static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1367 struct list_head *bf_head)
1368{
1369 struct ath_buf *bf;
1370
1371 bf = list_first_entry(bf_head, struct ath_buf, list);
1372
1373 bf->bf_lastbf = bf;
1374 bf->bf_nframes = 1;
1375 ath_buf_set_rate(sc, bf);
1376 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301377 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301378}
1379
Sujith528f0c62008-10-29 10:14:26 +05301380static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001381{
Sujith528f0c62008-10-29 10:14:26 +05301382 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001383 enum ath9k_pkt_type htype;
1384 __le16 fc;
1385
Sujith528f0c62008-10-29 10:14:26 +05301386 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001387 fc = hdr->frame_control;
1388
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001389 if (ieee80211_is_beacon(fc))
1390 htype = ATH9K_PKT_TYPE_BEACON;
1391 else if (ieee80211_is_probe_resp(fc))
1392 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1393 else if (ieee80211_is_atim(fc))
1394 htype = ATH9K_PKT_TYPE_ATIM;
1395 else if (ieee80211_is_pspoll(fc))
1396 htype = ATH9K_PKT_TYPE_PSPOLL;
1397 else
1398 htype = ATH9K_PKT_TYPE_NORMAL;
1399
1400 return htype;
1401}
1402
Sujith528f0c62008-10-29 10:14:26 +05301403static void assign_aggr_tid_seqno(struct sk_buff *skb,
1404 struct ath_buf *bf)
1405{
1406 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1407 struct ieee80211_hdr *hdr;
1408 struct ath_node *an;
1409 struct ath_atx_tid *tid;
1410 __le16 fc;
1411 u8 *qc;
1412
1413 if (!tx_info->control.sta)
1414 return;
1415
1416 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1417 hdr = (struct ieee80211_hdr *)skb->data;
1418 fc = hdr->frame_control;
1419
Sujith528f0c62008-10-29 10:14:26 +05301420 if (ieee80211_is_data_qos(fc)) {
1421 qc = ieee80211_get_qos_ctl(hdr);
1422 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301423 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001424
Sujithe8324352009-01-16 21:38:42 +05301425 /*
1426 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301427 * We also override seqno set by upper layer with the one
1428 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301429 */
1430 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301431 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301432 bf->bf_seqno = tid->seq_next;
1433 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301434}
1435
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001436static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301437{
1438 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1439 int flags = 0;
1440
1441 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1442 flags |= ATH9K_TXDESC_INTREQ;
1443
1444 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1445 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301446
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001447 if (use_ldpc)
1448 flags |= ATH9K_TXDESC_LDPC;
1449
Sujith528f0c62008-10-29 10:14:26 +05301450 return flags;
1451}
1452
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001453/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001454 * rix - rate index
1455 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1456 * width - 0 for 20 MHz, 1 for 40 MHz
1457 * half_gi - to use 4us v/s 3.6 us for symbol time
1458 */
Sujith102e0572008-10-29 10:15:16 +05301459static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1460 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001461{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001462 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001463 int streams, pktlen;
1464
Sujithcd3d39a2008-08-11 14:03:34 +05301465 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301466
1467 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001468 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001469 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001470 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001471 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1472
1473 if (!half_gi)
1474 duration = SYMBOL_TIME(nsymbols);
1475 else
1476 duration = SYMBOL_TIME_HALFGI(nsymbols);
1477
Sujithe63835b2008-11-18 09:07:53 +05301478 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001479 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301480
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001481 return duration;
1482}
1483
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001484static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1485{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001486 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001487 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301488 struct sk_buff *skb;
1489 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301490 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001491 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301492 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301493 int i, flags = 0;
1494 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301495 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301496
1497 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301498
Sujitha22be222009-03-30 15:28:36 +05301499 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301500 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301501 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301502 hdr = (struct ieee80211_hdr *)skb->data;
1503 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301504
Sujithc89424d2009-01-30 14:29:28 +05301505 /*
1506 * We check if Short Preamble is needed for the CTS rate by
1507 * checking the BSS's global flag.
1508 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1509 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001510 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1511 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301512 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001513 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001514
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001515 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001516 bool is_40, is_sgi, is_sp;
1517 int phy;
1518
Sujithe63835b2008-11-18 09:07:53 +05301519 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001520 continue;
1521
Sujitha8efee42008-11-18 09:07:30 +05301522 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301523 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001524 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001525
Felix Fietkau27032052010-01-17 21:08:50 +01001526 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1527 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301528 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001529 flags |= ATH9K_TXDESC_RTSENA;
1530 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1531 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1532 flags |= ATH9K_TXDESC_CTSENA;
1533 }
1534
Sujithc89424d2009-01-30 14:29:28 +05301535 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1536 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1537 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1538 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001539
Felix Fietkau545750d2009-11-23 22:21:01 +01001540 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1541 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1542 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1543
1544 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1545 /* MCS rates */
1546 series[i].Rate = rix | 0x80;
1547 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1548 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001549 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1550 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001551 continue;
1552 }
1553
1554 /* legcay rates */
1555 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1556 !(rate->flags & IEEE80211_RATE_ERP_G))
1557 phy = WLAN_RC_PHY_CCK;
1558 else
1559 phy = WLAN_RC_PHY_OFDM;
1560
1561 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1562 series[i].Rate = rate->hw_value;
1563 if (rate->hw_value_short) {
1564 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1565 series[i].Rate |= rate->hw_value_short;
1566 } else {
1567 is_sp = false;
1568 }
1569
1570 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1571 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001572 }
1573
Felix Fietkau27032052010-01-17 21:08:50 +01001574 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1575 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1576 flags &= ~ATH9K_TXDESC_RTSENA;
1577
1578 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1579 if (flags & ATH9K_TXDESC_RTSENA)
1580 flags &= ~ATH9K_TXDESC_CTSENA;
1581
Sujithe63835b2008-11-18 09:07:53 +05301582 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301583 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1584 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301585 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301586 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301587
Sujith17d79042009-02-09 13:27:03 +05301588 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301589 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001590}
1591
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001592static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301593 struct sk_buff *skb,
1594 struct ath_tx_control *txctl)
1595{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001596 struct ath_wiphy *aphy = hw->priv;
1597 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301598 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1599 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301600 int hdrlen;
1601 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001602 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001603 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301604
Felix Fietkau827e69b2009-11-15 23:09:25 +01001605 tx_info->pad[0] = 0;
1606 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001607 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001608 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001609 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001610 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1611 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001612 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001613 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1614 break;
1615 }
Sujithe8324352009-01-16 21:38:42 +05301616 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1617 fc = hdr->frame_control;
1618
1619 ATH_TXBUF_RESET(bf);
1620
Felix Fietkau827e69b2009-11-15 23:09:25 +01001621 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001622 bf->bf_frmlen = skb->len + FCS_LEN;
1623 /* Remove the padding size from bf_frmlen, if any */
1624 padpos = ath9k_cmn_padpos(hdr->frame_control);
1625 padsize = padpos & 3;
1626 if (padsize && skb->len>padpos+padsize) {
1627 bf->bf_frmlen -= padsize;
1628 }
Sujithe8324352009-01-16 21:38:42 +05301629
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001630 if (!txctl->paprd && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301631 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001632 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1633 use_ldpc = true;
1634 }
Sujithe8324352009-01-16 21:38:42 +05301635
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001636 bf->bf_state.bfs_paprd = txctl->paprd;
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001637 if (txctl->paprd)
1638 bf->bf_state.bfs_paprd_timestamp = jiffies;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001639 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301640
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001641 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301642 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1643 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1644 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1645 } else {
1646 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1647 }
1648
Sujith17b182e2009-12-14 14:56:56 +05301649 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1650 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301651 assign_aggr_tid_seqno(skb, bf);
1652
1653 bf->bf_mpdu = skb;
1654
1655 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1656 skb->len, DMA_TO_DEVICE);
1657 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1658 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001659 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1660 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301661 return -ENOMEM;
1662 }
1663
1664 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001665
1666 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1667 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1668 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301669 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001670 } else
1671 bf->bf_isnullfunc = false;
1672
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001673 bf->bf_tx_aborted = false;
1674
Sujithe8324352009-01-16 21:38:42 +05301675 return 0;
1676}
1677
1678/* FIXME: tx power */
1679static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1680 struct ath_tx_control *txctl)
1681{
Sujitha22be222009-03-30 15:28:36 +05301682 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301683 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301684 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301685 struct ath_node *an = NULL;
1686 struct list_head bf_head;
1687 struct ath_desc *ds;
1688 struct ath_atx_tid *tid;
Sujithcbe61d8a2009-02-09 13:27:12 +05301689 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301690 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301691 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301692
1693 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301694 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301695
1696 INIT_LIST_HEAD(&bf_head);
1697 list_add_tail(&bf->list, &bf_head);
1698
1699 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001700 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301701
1702 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1703 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1704
1705 ath9k_hw_filltxdesc(ah, ds,
1706 skb->len, /* segment length */
1707 true, /* first segment */
1708 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001709 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001710 bf->bf_buf_addr,
1711 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301712
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001713 if (bf->bf_state.bfs_paprd)
1714 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1715
Sujithe8324352009-01-16 21:38:42 +05301716 spin_lock_bh(&txctl->txq->axq_lock);
1717
1718 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1719 tx_info->control.sta) {
1720 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1721 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1722
Sujithc37452b2009-03-09 09:31:57 +05301723 if (!ieee80211_is_data_qos(fc)) {
1724 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1725 goto tx_done;
1726 }
1727
Felix Fietkau4fdec032010-03-12 04:02:43 +01001728 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301729 /*
1730 * Try aggregation if it's a unicast data frame
1731 * and the destination is HT capable.
1732 */
1733 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1734 } else {
1735 /*
1736 * Send this frame as regular when ADDBA
1737 * exchange is neither complete nor pending.
1738 */
Sujithc37452b2009-03-09 09:31:57 +05301739 ath_tx_send_ht_normal(sc, txctl->txq,
1740 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301741 }
1742 } else {
Sujithc37452b2009-03-09 09:31:57 +05301743 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301744 }
1745
Sujithc37452b2009-03-09 09:31:57 +05301746tx_done:
Sujithe8324352009-01-16 21:38:42 +05301747 spin_unlock_bh(&txctl->txq->axq_lock);
1748}
1749
1750/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001751int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301752 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001753{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001754 struct ath_wiphy *aphy = hw->priv;
1755 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001756 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001757 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001758 struct ath_buf *bf;
Felix Fietkau97923b12010-06-12 00:33:55 -04001759 int q, r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001760
Sujithe8324352009-01-16 21:38:42 +05301761 bf = ath_tx_get_buffer(sc);
1762 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001763 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301764 return -1;
1765 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001766
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001767 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301768 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001769 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001770
Sujithe8324352009-01-16 21:38:42 +05301771 /* upon ath_tx_processq() this TX queue will be resumed, we
1772 * guarantee this will happen by knowing beforehand that
1773 * we will at least have to run TX completionon one buffer
1774 * on the queue */
1775 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001776 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001777 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301778 txq->stopped = 1;
1779 }
1780 spin_unlock_bh(&txq->axq_lock);
1781
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001782 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301783
1784 return r;
1785 }
1786
Felix Fietkau97923b12010-06-12 00:33:55 -04001787 q = skb_get_queue_mapping(skb);
1788 if (q >= 4)
1789 q = 0;
1790
1791 spin_lock_bh(&txq->axq_lock);
1792 if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
1793 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1794 txq->stopped = 1;
1795 }
1796 spin_unlock_bh(&txq->axq_lock);
1797
Sujithe8324352009-01-16 21:38:42 +05301798 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001799
1800 return 0;
1801}
1802
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001803void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001804{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001805 struct ath_wiphy *aphy = hw->priv;
1806 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001807 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001808 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1809 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301810 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1811 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001812
Sujithe8324352009-01-16 21:38:42 +05301813 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001814
Sujithe8324352009-01-16 21:38:42 +05301815 /*
1816 * As a temporary workaround, assign seq# here; this will likely need
1817 * to be cleaned up to work better with Beacon transmission and virtual
1818 * BSSes.
1819 */
1820 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301821 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1822 sc->tx.seq_no += 0x10;
1823 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1824 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001825 }
1826
Sujithe8324352009-01-16 21:38:42 +05301827 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001828 padpos = ath9k_cmn_padpos(hdr->frame_control);
1829 padsize = padpos & 3;
1830 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301831 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001832 ath_print(common, ATH_DBG_XMIT,
1833 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301834 dev_kfree_skb_any(skb);
1835 return;
1836 }
1837 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001838 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001839 }
1840
Sujithe8324352009-01-16 21:38:42 +05301841 txctl.txq = sc->beacon.cabq;
1842
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001843 ath_print(common, ATH_DBG_XMIT,
1844 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301845
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001846 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001847 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301848 goto exit;
1849 }
1850
1851 return;
1852exit:
1853 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001854}
1855
Sujithe8324352009-01-16 21:38:42 +05301856/*****************/
1857/* TX Completion */
1858/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001859
Sujithe8324352009-01-16 21:38:42 +05301860static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001861 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001862{
Sujithe8324352009-01-16 21:38:42 +05301863 struct ieee80211_hw *hw = sc->hw;
1864 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001865 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001866 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001867 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301868
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001869 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301870
Felix Fietkau827e69b2009-11-15 23:09:25 +01001871 if (aphy)
1872 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301873
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301874 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301875 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301876
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301877 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301878 /* Frame was ACKed */
1879 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1880 }
1881
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001882 padpos = ath9k_cmn_padpos(hdr->frame_control);
1883 padsize = padpos & 3;
1884 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301885 /*
1886 * Remove MAC header padding before giving the frame back to
1887 * mac80211.
1888 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001889 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301890 skb_pull(skb, padsize);
1891 }
1892
Sujith1b04b932010-01-08 10:36:05 +05301893 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1894 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001895 ath_print(common, ATH_DBG_PS,
1896 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001897 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301898 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1899 PS_WAIT_FOR_CAB |
1900 PS_WAIT_FOR_PSPOLL_DATA |
1901 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001902 }
1903
Felix Fietkau827e69b2009-11-15 23:09:25 +01001904 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001905 ath9k_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001906 else {
1907 q = skb_get_queue_mapping(skb);
1908 if (q >= 4)
1909 q = 0;
1910
1911 if (--sc->tx.pending_frames[q] < 0)
1912 sc->tx.pending_frames[q] = 0;
1913
Felix Fietkau827e69b2009-11-15 23:09:25 +01001914 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001915 }
Sujithe8324352009-01-16 21:38:42 +05301916}
1917
1918static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001919 struct ath_txq *txq, struct list_head *bf_q,
1920 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301921{
1922 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301923 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301924 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301925
Sujithe8324352009-01-16 21:38:42 +05301926 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301927 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301928
1929 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301930 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301931
1932 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301933 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301934 }
1935
1936 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001937
1938 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001939 if (time_after(jiffies,
1940 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001941 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001942 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001943 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001944 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001945 } else {
1946 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
1947 ath_debug_stat_tx(sc, txq, bf, ts);
1948 }
Sujithe8324352009-01-16 21:38:42 +05301949
1950 /*
1951 * Return the list of ath_buf of this mpdu to free queue
1952 */
1953 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1954 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1955 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1956}
1957
1958static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001959 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301960{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001961 u16 seq_st = 0;
1962 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301963 int ba_index;
1964 int nbad = 0;
1965 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001966
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001967 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301968 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301969
Sujithcd3d39a2008-08-11 14:03:34 +05301970 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001971 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001972 seq_st = ts->ts_seqnum;
1973 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001974 }
1975
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001976 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301977 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1978 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1979 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001980
Sujithe8324352009-01-16 21:38:42 +05301981 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001982 }
1983
Sujithe8324352009-01-16 21:38:42 +05301984 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001985}
1986
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001987static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301988 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301989{
Sujitha22be222009-03-30 15:28:36 +05301990 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301991 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301992 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001993 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301994 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301995
Sujith95e4acb2009-03-13 08:56:09 +05301996 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001997 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301998
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001999 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302000 WARN_ON(tx_rateindex >= hw->max_rates);
2001
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002002 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05302003 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01002004 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
2005 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05302006
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002007 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302008 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05302009 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002010 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01002011 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
2012 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07002013 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2014 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002015 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2016 tx_info->status.ampdu_len = bf->bf_nframes;
2017 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302018 }
2019 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302020
Felix Fietkau545750d2009-11-23 22:21:01 +01002021 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302022 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002023 tx_info->status.rates[i].idx = -1;
2024 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302025
Felix Fietkau78c46532010-06-25 01:26:16 +02002026 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302027}
2028
Sujith059d8062009-01-16 21:38:49 +05302029static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2030{
2031 int qnum;
2032
Felix Fietkau97923b12010-06-12 00:33:55 -04002033 qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
2034 if (qnum == -1)
2035 return;
2036
Sujith059d8062009-01-16 21:38:49 +05302037 spin_lock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04002038 if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07002039 if (ath_mac80211_start_queue(sc, qnum))
2040 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05302041 }
2042 spin_unlock_bh(&txq->axq_lock);
2043}
2044
Sujithc4288392008-11-18 09:09:30 +05302045static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002046{
Sujithcbe61d8a2009-02-09 13:27:12 +05302047 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002048 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2050 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302051 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002052 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302053 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002054 int status;
2055
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002056 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2057 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2058 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002059
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060 for (;;) {
2061 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002062 if (list_empty(&txq->axq_q)) {
2063 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002064 spin_unlock_bh(&txq->axq_lock);
2065 break;
2066 }
2067 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2068
2069 /*
2070 * There is a race condition that a BH gets scheduled
2071 * after sw writes TxE and before hw re-load the last
2072 * descriptor to get the newly chained one.
2073 * Software must keep the last DONE descriptor as a
2074 * holding descriptor - software does so by marking
2075 * it with the STALE flag.
2076 */
2077 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302078 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 bf_held = bf;
2080 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302081 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002082 break;
2083 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302085 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002086 }
2087 }
2088
2089 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302090 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002091
Felix Fietkau29bffa92010-03-29 20:14:23 -07002092 memset(&ts, 0, sizeof(ts));
2093 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094 if (status == -EINPROGRESS) {
2095 spin_unlock_bh(&txq->axq_lock);
2096 break;
2097 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098
2099 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002100 * We now know the nullfunc frame has been ACKed so we
2101 * can disable RX.
2102 */
2103 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002104 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302105 if ((sc->ps_flags & PS_ENABLED))
2106 ath9k_enable_ps(sc);
2107 else
Sujith1b04b932010-01-08 10:36:05 +05302108 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002109 }
2110
2111 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002112 * Remove ath_buf's of the same transmit unit from txq,
2113 * however leave the last descriptor back as the holding
2114 * descriptor for hw.
2115 */
Sujitha119cc42009-03-30 15:28:38 +05302116 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002118 if (!list_is_singular(&lastbf->list))
2119 list_cut_position(&bf_head,
2120 &txq->axq_q, lastbf->list.prev);
2121
2122 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002123 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002124 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002125 if (bf_held)
2126 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002127 spin_unlock_bh(&txq->axq_lock);
2128
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002129 if (bf_held)
2130 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002131
Sujithcd3d39a2008-08-11 14:03:34 +05302132 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002133 /*
2134 * This frame is sent out as a single frame.
2135 * Use hardware retry status for this frame.
2136 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002137 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302138 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002139 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140 }
Johannes Berge6a98542008-10-21 12:40:02 +02002141
Sujithcd3d39a2008-08-11 14:03:34 +05302142 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002143 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002144 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002145 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002146
Sujith059d8062009-01-16 21:38:49 +05302147 ath_wake_mac80211_queue(sc, txq);
2148
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002149 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302150 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002151 ath_txq_schedule(sc, txq);
2152 spin_unlock_bh(&txq->axq_lock);
2153 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002154}
2155
Sujith305fe472009-07-23 15:32:29 +05302156static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002157{
2158 struct ath_softc *sc = container_of(work, struct ath_softc,
2159 tx_complete_work.work);
2160 struct ath_txq *txq;
2161 int i;
2162 bool needreset = false;
2163
2164 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2165 if (ATH_TXQ_SETUP(sc, i)) {
2166 txq = &sc->tx.txq[i];
2167 spin_lock_bh(&txq->axq_lock);
2168 if (txq->axq_depth) {
2169 if (txq->axq_tx_inprogress) {
2170 needreset = true;
2171 spin_unlock_bh(&txq->axq_lock);
2172 break;
2173 } else {
2174 txq->axq_tx_inprogress = true;
2175 }
2176 }
2177 spin_unlock_bh(&txq->axq_lock);
2178 }
2179
2180 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002181 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2182 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302183 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002184 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302185 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002186 }
2187
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002188 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002189 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2190}
2191
2192
Sujithe8324352009-01-16 21:38:42 +05302193
2194void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002195{
Sujithe8324352009-01-16 21:38:42 +05302196 int i;
2197 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002198
Sujithe8324352009-01-16 21:38:42 +05302199 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002200
2201 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302202 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2203 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002204 }
2205}
2206
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002207void ath_tx_edma_tasklet(struct ath_softc *sc)
2208{
2209 struct ath_tx_status txs;
2210 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2211 struct ath_hw *ah = sc->sc_ah;
2212 struct ath_txq *txq;
2213 struct ath_buf *bf, *lastbf;
2214 struct list_head bf_head;
2215 int status;
2216 int txok;
2217
2218 for (;;) {
2219 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2220 if (status == -EINPROGRESS)
2221 break;
2222 if (status == -EIO) {
2223 ath_print(common, ATH_DBG_XMIT,
2224 "Error processing tx status\n");
2225 break;
2226 }
2227
2228 /* Skip beacon completions */
2229 if (txs.qid == sc->beacon.beaconq)
2230 continue;
2231
2232 txq = &sc->tx.txq[txs.qid];
2233
2234 spin_lock_bh(&txq->axq_lock);
2235 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2236 spin_unlock_bh(&txq->axq_lock);
2237 return;
2238 }
2239
2240 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2241 struct ath_buf, list);
2242 lastbf = bf->bf_lastbf;
2243
2244 INIT_LIST_HEAD(&bf_head);
2245 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2246 &lastbf->list);
2247 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2248 txq->axq_depth--;
2249 txq->axq_tx_inprogress = false;
2250 spin_unlock_bh(&txq->axq_lock);
2251
2252 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2253
Vasanthakumar Thiagarajande0f6482010-05-17 18:57:54 -07002254 /*
2255 * Make sure null func frame is acked before configuring
2256 * hw into ps mode.
2257 */
2258 if (bf->bf_isnullfunc && txok) {
2259 if ((sc->ps_flags & PS_ENABLED))
2260 ath9k_enable_ps(sc);
2261 else
2262 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
2263 }
2264
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002265 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002266 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2267 bf->bf_state.bf_type |= BUF_XRETRY;
2268 ath_tx_rc_status(bf, &txs, 0, txok, true);
2269 }
2270
2271 if (bf_isampdu(bf))
2272 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2273 else
2274 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2275 &txs, txok, 0);
2276
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002277 ath_wake_mac80211_queue(sc, txq);
2278
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002279 spin_lock_bh(&txq->axq_lock);
2280 if (!list_empty(&txq->txq_fifo_pending)) {
2281 INIT_LIST_HEAD(&bf_head);
2282 bf = list_first_entry(&txq->txq_fifo_pending,
2283 struct ath_buf, list);
2284 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2285 &bf->bf_lastbf->list);
2286 ath_tx_txqaddbuf(sc, txq, &bf_head);
2287 } else if (sc->sc_flags & SC_OP_TXAGGR)
2288 ath_txq_schedule(sc, txq);
2289 spin_unlock_bh(&txq->axq_lock);
2290 }
2291}
2292
Sujithe8324352009-01-16 21:38:42 +05302293/*****************/
2294/* Init, Cleanup */
2295/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002296
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002297static int ath_txstatus_setup(struct ath_softc *sc, int size)
2298{
2299 struct ath_descdma *dd = &sc->txsdma;
2300 u8 txs_len = sc->sc_ah->caps.txs_len;
2301
2302 dd->dd_desc_len = size * txs_len;
2303 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2304 &dd->dd_desc_paddr, GFP_KERNEL);
2305 if (!dd->dd_desc)
2306 return -ENOMEM;
2307
2308 return 0;
2309}
2310
2311static int ath_tx_edma_init(struct ath_softc *sc)
2312{
2313 int err;
2314
2315 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2316 if (!err)
2317 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2318 sc->txsdma.dd_desc_paddr,
2319 ATH_TXSTATUS_RING_SIZE);
2320
2321 return err;
2322}
2323
2324static void ath_tx_edma_cleanup(struct ath_softc *sc)
2325{
2326 struct ath_descdma *dd = &sc->txsdma;
2327
2328 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2329 dd->dd_desc_paddr);
2330}
2331
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002332int ath_tx_init(struct ath_softc *sc, int nbufs)
2333{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002334 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002335 int error = 0;
2336
Sujith797fe5cb2009-03-30 15:28:45 +05302337 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002338
Sujith797fe5cb2009-03-30 15:28:45 +05302339 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002340 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302341 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002342 ath_print(common, ATH_DBG_FATAL,
2343 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302344 goto err;
2345 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002346
Sujith797fe5cb2009-03-30 15:28:45 +05302347 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002348 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302349 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002350 ath_print(common, ATH_DBG_FATAL,
2351 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302352 goto err;
2353 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002355 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2356
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002357 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2358 error = ath_tx_edma_init(sc);
2359 if (error)
2360 goto err;
2361 }
2362
Sujith797fe5cb2009-03-30 15:28:45 +05302363err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002364 if (error != 0)
2365 ath_tx_cleanup(sc);
2366
2367 return error;
2368}
2369
Sujith797fe5cb2009-03-30 15:28:45 +05302370void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371{
Sujithb77f4832008-12-07 21:44:03 +05302372 if (sc->beacon.bdma.dd_desc_len != 0)
2373 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002374
Sujithb77f4832008-12-07 21:44:03 +05302375 if (sc->tx.txdma.dd_desc_len != 0)
2376 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002377
2378 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2379 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002380}
2381
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002382void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2383{
Sujithc5170162008-10-29 10:13:59 +05302384 struct ath_atx_tid *tid;
2385 struct ath_atx_ac *ac;
2386 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002387
Sujith8ee5afb2008-12-07 21:43:36 +05302388 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302389 tidno < WME_NUM_TID;
2390 tidno++, tid++) {
2391 tid->an = an;
2392 tid->tidno = tidno;
2393 tid->seq_start = tid->seq_next = 0;
2394 tid->baw_size = WME_MAX_BA;
2395 tid->baw_head = tid->baw_tail = 0;
2396 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302397 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302398 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302399 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302400 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302401 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302402 tid->state &= ~AGGR_ADDBA_COMPLETE;
2403 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302404 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002405
Sujith8ee5afb2008-12-07 21:43:36 +05302406 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302407 acno < WME_NUM_AC; acno++, ac++) {
2408 ac->sched = false;
Felix Fietkau1d2231e2010-06-12 00:33:51 -04002409 ac->qnum = sc->tx.hwq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302410 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002411 }
2412}
2413
Sujithb5aa9bf2008-10-29 10:13:31 +05302414void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002415{
Felix Fietkau2b409942010-07-07 19:42:08 +02002416 struct ath_atx_ac *ac;
2417 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002418 struct ath_txq *txq;
Felix Fietkau2b409942010-07-07 19:42:08 +02002419 int i, tidno;
Sujithe8324352009-01-16 21:38:42 +05302420
Felix Fietkau2b409942010-07-07 19:42:08 +02002421 for (tidno = 0, tid = &an->tid[tidno];
2422 tidno < WME_NUM_TID; tidno++, tid++) {
2423 i = tid->ac->qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002424
Felix Fietkau2b409942010-07-07 19:42:08 +02002425 if (!ATH_TXQ_SETUP(sc, i))
2426 continue;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002427
Felix Fietkau2b409942010-07-07 19:42:08 +02002428 txq = &sc->tx.txq[i];
2429 ac = tid->ac;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002430
Felix Fietkau2b409942010-07-07 19:42:08 +02002431 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002432
Felix Fietkau2b409942010-07-07 19:42:08 +02002433 if (tid->sched) {
2434 list_del(&tid->list);
2435 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002436 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002437
2438 if (ac->sched) {
2439 list_del(&ac->list);
2440 tid->ac->sched = false;
2441 }
2442
2443 ath_tid_drain(sc, txq, tid);
2444 tid->state &= ~AGGR_ADDBA_COMPLETE;
2445 tid->state &= ~AGGR_CLEANUP;
2446
2447 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002448 }
2449}