blob: 85a7323a04ef16c5ba1ee0ce0bf792d0ced0c81f [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
Sujithe8324352009-01-16 21:38:42 +0530858/********************/
859/* Queue Management */
860/********************/
861
Sujithe8324352009-01-16 21:38:42 +0530862static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
863 struct ath_txq *txq)
864{
865 struct ath_atx_ac *ac, *ac_tmp;
866 struct ath_atx_tid *tid, *tid_tmp;
867
868 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
869 list_del(&ac->list);
870 ac->sched = false;
871 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
872 list_del(&tid->list);
873 tid->sched = false;
874 ath_tid_drain(sc, txq, tid);
875 }
876 }
877}
878
879struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
880{
Sujithcbe61d82009-02-09 13:27:12 +0530881 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700882 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530883 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400884 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530885
886 memset(&qi, 0, sizeof(qi));
887 qi.tqi_subtype = subtype;
888 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
889 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
890 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
891 qi.tqi_physCompBuf = 0;
892
893 /*
894 * Enable interrupts only for EOL and DESC conditions.
895 * We mark tx descriptors to receive a DESC interrupt
896 * when a tx queue gets deep; otherwise waiting for the
897 * EOL to reap descriptors. Note that this is done to
898 * reduce interrupt load and this only defers reaping
899 * descriptors, never transmitting frames. Aside from
900 * reducing interrupts this also permits more concurrency.
901 * The only potential downside is if the tx queue backs
902 * up in which case the top half of the kernel may backup
903 * due to a lack of tx descriptors.
904 *
905 * The UAPSD queue is an exception, since we take a desc-
906 * based intr on the EOSP frames.
907 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400908 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
909 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
910 TXQ_FLAG_TXERRINT_ENABLE;
911 } else {
912 if (qtype == ATH9K_TX_QUEUE_UAPSD)
913 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
914 else
915 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
916 TXQ_FLAG_TXDESCINT_ENABLE;
917 }
Sujithe8324352009-01-16 21:38:42 +0530918 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
919 if (qnum == -1) {
920 /*
921 * NB: don't print a message, this happens
922 * normally on parts with too few tx queues
923 */
924 return NULL;
925 }
926 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700927 ath_print(common, ATH_DBG_FATAL,
928 "qnum %u out of range, max %u!\n",
929 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530930 ath9k_hw_releasetxqueue(ah, qnum);
931 return NULL;
932 }
933 if (!ATH_TXQ_SETUP(sc, qnum)) {
934 struct ath_txq *txq = &sc->tx.txq[qnum];
935
Felix Fietkau293f2ba2010-06-12 00:33:49 -0400936 txq->axq_class = subtype;
Sujithe8324352009-01-16 21:38:42 +0530937 txq->axq_qnum = qnum;
938 txq->axq_link = NULL;
939 INIT_LIST_HEAD(&txq->axq_q);
940 INIT_LIST_HEAD(&txq->axq_acq);
941 spin_lock_init(&txq->axq_lock);
942 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400943 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530944 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400945
946 txq->txq_headidx = txq->txq_tailidx = 0;
947 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
948 INIT_LIST_HEAD(&txq->txq_fifo[i]);
949 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530950 }
951 return &sc->tx.txq[qnum];
952}
953
Sujithe8324352009-01-16 21:38:42 +0530954int ath_txq_update(struct ath_softc *sc, int qnum,
955 struct ath9k_tx_queue_info *qinfo)
956{
Sujithcbe61d82009-02-09 13:27:12 +0530957 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530958 int error = 0;
959 struct ath9k_tx_queue_info qi;
960
961 if (qnum == sc->beacon.beaconq) {
962 /*
963 * XXX: for beacon queue, we just save the parameter.
964 * It will be picked up by ath_beaconq_config when
965 * it's necessary.
966 */
967 sc->beacon.beacon_qi = *qinfo;
968 return 0;
969 }
970
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700971 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530972
973 ath9k_hw_get_txq_props(ah, qnum, &qi);
974 qi.tqi_aifs = qinfo->tqi_aifs;
975 qi.tqi_cwmin = qinfo->tqi_cwmin;
976 qi.tqi_cwmax = qinfo->tqi_cwmax;
977 qi.tqi_burstTime = qinfo->tqi_burstTime;
978 qi.tqi_readyTime = qinfo->tqi_readyTime;
979
980 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700981 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
982 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +0530983 error = -EIO;
984 } else {
985 ath9k_hw_resettxqueue(ah, qnum);
986 }
987
988 return error;
989}
990
991int ath_cabq_update(struct ath_softc *sc)
992{
993 struct ath9k_tx_queue_info qi;
994 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +0530995
996 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
997 /*
998 * Ensure the readytime % is within the bounds.
999 */
Sujith17d79042009-02-09 13:27:03 +05301000 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1001 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1002 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1003 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301004
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001005 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301006 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301007 ath_txq_update(sc, qnum, &qi);
1008
1009 return 0;
1010}
1011
Sujith043a0402009-01-16 21:38:47 +05301012/*
1013 * Drain a given TX queue (could be Beacon or Data)
1014 *
1015 * This assumes output has been stopped and
1016 * we do not need to block ath_tx_tasklet.
1017 */
1018void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301019{
1020 struct ath_buf *bf, *lastbf;
1021 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001022 struct ath_tx_status ts;
1023
1024 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301025 INIT_LIST_HEAD(&bf_head);
1026
Sujithe8324352009-01-16 21:38:42 +05301027 for (;;) {
1028 spin_lock_bh(&txq->axq_lock);
1029
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001030 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1031 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1032 txq->txq_headidx = txq->txq_tailidx = 0;
1033 spin_unlock_bh(&txq->axq_lock);
1034 break;
1035 } else {
1036 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1037 struct ath_buf, list);
1038 }
1039 } else {
1040 if (list_empty(&txq->axq_q)) {
1041 txq->axq_link = NULL;
1042 spin_unlock_bh(&txq->axq_lock);
1043 break;
1044 }
1045 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1046 list);
Sujithe8324352009-01-16 21:38:42 +05301047
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001048 if (bf->bf_stale) {
1049 list_del(&bf->list);
1050 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301051
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001052 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001053 continue;
1054 }
Sujithe8324352009-01-16 21:38:42 +05301055 }
1056
1057 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001058 if (!retry_tx)
1059 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301060
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001061 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1062 list_cut_position(&bf_head,
1063 &txq->txq_fifo[txq->txq_tailidx],
1064 &lastbf->list);
1065 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1066 } else {
1067 /* remove ath_buf's of the same mpdu from txq */
1068 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1069 }
1070
Sujithe8324352009-01-16 21:38:42 +05301071 txq->axq_depth--;
1072
1073 spin_unlock_bh(&txq->axq_lock);
1074
1075 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001076 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301077 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001078 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301079 }
1080
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001081 spin_lock_bh(&txq->axq_lock);
1082 txq->axq_tx_inprogress = false;
1083 spin_unlock_bh(&txq->axq_lock);
1084
Sujithe8324352009-01-16 21:38:42 +05301085 /* flush any pending frames if aggregation is enabled */
1086 if (sc->sc_flags & SC_OP_TXAGGR) {
1087 if (!retry_tx) {
1088 spin_lock_bh(&txq->axq_lock);
1089 ath_txq_drain_pending_buffers(sc, txq);
1090 spin_unlock_bh(&txq->axq_lock);
1091 }
1092 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001093
1094 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1095 spin_lock_bh(&txq->axq_lock);
1096 while (!list_empty(&txq->txq_fifo_pending)) {
1097 bf = list_first_entry(&txq->txq_fifo_pending,
1098 struct ath_buf, list);
1099 list_cut_position(&bf_head,
1100 &txq->txq_fifo_pending,
1101 &bf->bf_lastbf->list);
1102 spin_unlock_bh(&txq->axq_lock);
1103
1104 if (bf_isampdu(bf))
1105 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1106 &ts, 0);
1107 else
1108 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1109 &ts, 0, 0);
1110 spin_lock_bh(&txq->axq_lock);
1111 }
1112 spin_unlock_bh(&txq->axq_lock);
1113 }
Sujithe8324352009-01-16 21:38:42 +05301114}
1115
Sujith043a0402009-01-16 21:38:47 +05301116void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1117{
Sujithcbe61d82009-02-09 13:27:12 +05301118 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001119 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301120 struct ath_txq *txq;
1121 int i, npend = 0;
1122
1123 if (sc->sc_flags & SC_OP_INVALID)
1124 return;
1125
1126 /* Stop beacon queue */
1127 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1128
1129 /* Stop data queues */
1130 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1131 if (ATH_TXQ_SETUP(sc, i)) {
1132 txq = &sc->tx.txq[i];
1133 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1134 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1135 }
1136 }
1137
1138 if (npend) {
1139 int r;
1140
Sujithe8009e92009-12-14 14:57:08 +05301141 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001142 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301143
1144 spin_lock_bh(&sc->sc_resetlock);
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001145 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301146 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001147 ath_print(common, ATH_DBG_FATAL,
1148 "Unable to reset hardware; reset status %d\n",
1149 r);
Sujith043a0402009-01-16 21:38:47 +05301150 spin_unlock_bh(&sc->sc_resetlock);
1151 }
1152
1153 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1154 if (ATH_TXQ_SETUP(sc, i))
1155 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1156 }
1157}
1158
Sujithe8324352009-01-16 21:38:42 +05301159void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1160{
1161 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1162 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1163}
1164
Sujithe8324352009-01-16 21:38:42 +05301165void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1166{
1167 struct ath_atx_ac *ac;
1168 struct ath_atx_tid *tid;
1169
1170 if (list_empty(&txq->axq_acq))
1171 return;
1172
1173 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1174 list_del(&ac->list);
1175 ac->sched = false;
1176
1177 do {
1178 if (list_empty(&ac->tid_q))
1179 return;
1180
1181 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1182 list_del(&tid->list);
1183 tid->sched = false;
1184
1185 if (tid->paused)
1186 continue;
1187
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001188 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301189
1190 /*
1191 * add tid to round-robin queue if more frames
1192 * are pending for the tid
1193 */
1194 if (!list_empty(&tid->buf_q))
1195 ath_tx_queue_tid(txq, tid);
1196
1197 break;
1198 } while (!list_empty(&ac->tid_q));
1199
1200 if (!list_empty(&ac->tid_q)) {
1201 if (!ac->sched) {
1202 ac->sched = true;
1203 list_add_tail(&ac->list, &txq->axq_acq);
1204 }
1205 }
1206}
1207
1208int ath_tx_setup(struct ath_softc *sc, int haltype)
1209{
1210 struct ath_txq *txq;
1211
1212 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001213 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1214 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301215 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1216 return 0;
1217 }
1218 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1219 if (txq != NULL) {
1220 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1221 return 1;
1222 } else
1223 return 0;
1224}
1225
1226/***********/
1227/* TX, DMA */
1228/***********/
1229
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001230/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001231 * Insert a chain of ath_buf (descriptors) on a txq and
1232 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001233 */
Sujith102e0572008-10-29 10:15:16 +05301234static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1235 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001236{
Sujithcbe61d82009-02-09 13:27:12 +05301237 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001238 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001239 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301240
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001241 /*
1242 * Insert the frame on the outbound list and
1243 * pass it on to the hardware.
1244 */
1245
1246 if (list_empty(head))
1247 return;
1248
1249 bf = list_first_entry(head, struct ath_buf, list);
1250
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001251 ath_print(common, ATH_DBG_QUEUE,
1252 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001253
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001254 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1255 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1256 list_splice_tail_init(head, &txq->txq_fifo_pending);
1257 return;
1258 }
1259 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1260 ath_print(common, ATH_DBG_XMIT,
1261 "Initializing tx fifo %d which "
1262 "is non-empty\n",
1263 txq->txq_headidx);
1264 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1265 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1266 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001267 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001268 ath_print(common, ATH_DBG_XMIT,
1269 "TXDP[%u] = %llx (%p)\n",
1270 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001271 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001272 list_splice_tail_init(head, &txq->axq_q);
1273
1274 if (txq->axq_link == NULL) {
1275 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1276 ath_print(common, ATH_DBG_XMIT,
1277 "TXDP[%u] = %llx (%p)\n",
1278 txq->axq_qnum, ito64(bf->bf_daddr),
1279 bf->bf_desc);
1280 } else {
1281 *txq->axq_link = bf->bf_daddr;
1282 ath_print(common, ATH_DBG_XMIT,
1283 "link[%u] (%p)=%llx (%p)\n",
1284 txq->axq_qnum, txq->axq_link,
1285 ito64(bf->bf_daddr), bf->bf_desc);
1286 }
1287 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1288 &txq->axq_link);
1289 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001290 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001291 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001292}
1293
Sujithe8324352009-01-16 21:38:42 +05301294static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1295 struct list_head *bf_head,
1296 struct ath_tx_control *txctl)
1297{
1298 struct ath_buf *bf;
1299
Sujithe8324352009-01-16 21:38:42 +05301300 bf = list_first_entry(bf_head, struct ath_buf, list);
1301 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301302 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301303
1304 /*
1305 * Do not queue to h/w when any of the following conditions is true:
1306 * - there are pending frames in software queue
1307 * - the TID is currently paused for ADDBA/BAR request
1308 * - seqno is not within block-ack window
1309 * - h/w queue depth exceeds low water mark
1310 */
1311 if (!list_empty(&tid->buf_q) || tid->paused ||
1312 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1313 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001314 /*
Sujithe8324352009-01-16 21:38:42 +05301315 * Add this frame to software queue for scheduling later
1316 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001317 */
Sujithd43f30152009-01-16 21:38:53 +05301318 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301319 ath_tx_queue_tid(txctl->txq, tid);
1320 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001321 }
1322
Sujithe8324352009-01-16 21:38:42 +05301323 /* Add sub-frame to BAW */
1324 ath_tx_addto_baw(sc, tid, bf);
1325
1326 /* Queue to h/w without aggregation */
1327 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301328 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301329 ath_buf_set_rate(sc, bf);
1330 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301331}
1332
Sujithc37452b2009-03-09 09:31:57 +05301333static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1334 struct ath_atx_tid *tid,
1335 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001336{
Sujithe8324352009-01-16 21:38:42 +05301337 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001338
Sujithe8324352009-01-16 21:38:42 +05301339 bf = list_first_entry(bf_head, struct ath_buf, list);
1340 bf->bf_state.bf_type &= ~BUF_AMPDU;
1341
1342 /* update starting sequence number for subsequent ADDBA request */
1343 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1344
1345 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301346 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301347 ath_buf_set_rate(sc, bf);
1348 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301349 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001350}
1351
Sujithc37452b2009-03-09 09:31:57 +05301352static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1353 struct list_head *bf_head)
1354{
1355 struct ath_buf *bf;
1356
1357 bf = list_first_entry(bf_head, struct ath_buf, list);
1358
1359 bf->bf_lastbf = bf;
1360 bf->bf_nframes = 1;
1361 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);
Sujithc37452b2009-03-09 09:31:57 +05301364}
1365
Sujith528f0c62008-10-29 10:14:26 +05301366static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001367{
Sujith528f0c62008-10-29 10:14:26 +05301368 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001369 enum ath9k_pkt_type htype;
1370 __le16 fc;
1371
Sujith528f0c62008-10-29 10:14:26 +05301372 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001373 fc = hdr->frame_control;
1374
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001375 if (ieee80211_is_beacon(fc))
1376 htype = ATH9K_PKT_TYPE_BEACON;
1377 else if (ieee80211_is_probe_resp(fc))
1378 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1379 else if (ieee80211_is_atim(fc))
1380 htype = ATH9K_PKT_TYPE_ATIM;
1381 else if (ieee80211_is_pspoll(fc))
1382 htype = ATH9K_PKT_TYPE_PSPOLL;
1383 else
1384 htype = ATH9K_PKT_TYPE_NORMAL;
1385
1386 return htype;
1387}
1388
Sujith528f0c62008-10-29 10:14:26 +05301389static void assign_aggr_tid_seqno(struct sk_buff *skb,
1390 struct ath_buf *bf)
1391{
1392 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1393 struct ieee80211_hdr *hdr;
1394 struct ath_node *an;
1395 struct ath_atx_tid *tid;
1396 __le16 fc;
1397 u8 *qc;
1398
1399 if (!tx_info->control.sta)
1400 return;
1401
1402 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1403 hdr = (struct ieee80211_hdr *)skb->data;
1404 fc = hdr->frame_control;
1405
Sujith528f0c62008-10-29 10:14:26 +05301406 if (ieee80211_is_data_qos(fc)) {
1407 qc = ieee80211_get_qos_ctl(hdr);
1408 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301409 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001410
Sujithe8324352009-01-16 21:38:42 +05301411 /*
1412 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301413 * We also override seqno set by upper layer with the one
1414 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301415 */
1416 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301417 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301418 bf->bf_seqno = tid->seq_next;
1419 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301420}
1421
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001422static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301423{
1424 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1425 int flags = 0;
1426
1427 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1428 flags |= ATH9K_TXDESC_INTREQ;
1429
1430 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1431 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301432
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001433 if (use_ldpc)
1434 flags |= ATH9K_TXDESC_LDPC;
1435
Sujith528f0c62008-10-29 10:14:26 +05301436 return flags;
1437}
1438
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001440 * rix - rate index
1441 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1442 * width - 0 for 20 MHz, 1 for 40 MHz
1443 * half_gi - to use 4us v/s 3.6 us for symbol time
1444 */
Sujith102e0572008-10-29 10:15:16 +05301445static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1446 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001447{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001448 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001449 int streams, pktlen;
1450
Sujithcd3d39a2008-08-11 14:03:34 +05301451 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301452
1453 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001454 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001455 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001456 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001457 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1458
1459 if (!half_gi)
1460 duration = SYMBOL_TIME(nsymbols);
1461 else
1462 duration = SYMBOL_TIME_HALFGI(nsymbols);
1463
Sujithe63835b2008-11-18 09:07:53 +05301464 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001465 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301466
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001467 return duration;
1468}
1469
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001470static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1471{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001472 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001473 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301474 struct sk_buff *skb;
1475 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301476 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001477 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301478 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301479 int i, flags = 0;
1480 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301481 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301482
1483 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301484
Sujitha22be222009-03-30 15:28:36 +05301485 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301486 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301487 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301488 hdr = (struct ieee80211_hdr *)skb->data;
1489 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301490
Sujithc89424d2009-01-30 14:29:28 +05301491 /*
1492 * We check if Short Preamble is needed for the CTS rate by
1493 * checking the BSS's global flag.
1494 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1495 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001496 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1497 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301498 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001499 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001500
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001501 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001502 bool is_40, is_sgi, is_sp;
1503 int phy;
1504
Sujithe63835b2008-11-18 09:07:53 +05301505 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001506 continue;
1507
Sujitha8efee42008-11-18 09:07:30 +05301508 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301509 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001510 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001511
Felix Fietkau27032052010-01-17 21:08:50 +01001512 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1513 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301514 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001515 flags |= ATH9K_TXDESC_RTSENA;
1516 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1517 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1518 flags |= ATH9K_TXDESC_CTSENA;
1519 }
1520
Sujithc89424d2009-01-30 14:29:28 +05301521 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1522 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1523 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1524 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001525
Felix Fietkau545750d2009-11-23 22:21:01 +01001526 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1527 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1528 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1529
1530 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1531 /* MCS rates */
1532 series[i].Rate = rix | 0x80;
1533 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1534 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001535 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1536 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001537 continue;
1538 }
1539
1540 /* legcay rates */
1541 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1542 !(rate->flags & IEEE80211_RATE_ERP_G))
1543 phy = WLAN_RC_PHY_CCK;
1544 else
1545 phy = WLAN_RC_PHY_OFDM;
1546
1547 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1548 series[i].Rate = rate->hw_value;
1549 if (rate->hw_value_short) {
1550 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1551 series[i].Rate |= rate->hw_value_short;
1552 } else {
1553 is_sp = false;
1554 }
1555
1556 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1557 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001558 }
1559
Felix Fietkau27032052010-01-17 21:08:50 +01001560 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1561 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1562 flags &= ~ATH9K_TXDESC_RTSENA;
1563
1564 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1565 if (flags & ATH9K_TXDESC_RTSENA)
1566 flags &= ~ATH9K_TXDESC_CTSENA;
1567
Sujithe63835b2008-11-18 09:07:53 +05301568 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301569 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1570 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301571 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301572 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301573
Sujith17d79042009-02-09 13:27:03 +05301574 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301575 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001576}
1577
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001578static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301579 struct sk_buff *skb,
1580 struct ath_tx_control *txctl)
1581{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001582 struct ath_wiphy *aphy = hw->priv;
1583 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301584 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1585 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301586 int hdrlen;
1587 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001588 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001589 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301590
Felix Fietkau827e69b2009-11-15 23:09:25 +01001591 tx_info->pad[0] = 0;
1592 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001593 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001594 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001595 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001596 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1597 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001598 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001599 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1600 break;
1601 }
Sujithe8324352009-01-16 21:38:42 +05301602 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1603 fc = hdr->frame_control;
1604
1605 ATH_TXBUF_RESET(bf);
1606
Felix Fietkau827e69b2009-11-15 23:09:25 +01001607 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001608 bf->bf_frmlen = skb->len + FCS_LEN;
1609 /* Remove the padding size from bf_frmlen, if any */
1610 padpos = ath9k_cmn_padpos(hdr->frame_control);
1611 padsize = padpos & 3;
1612 if (padsize && skb->len>padpos+padsize) {
1613 bf->bf_frmlen -= padsize;
1614 }
Sujithe8324352009-01-16 21:38:42 +05301615
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001616 if (!txctl->paprd && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301617 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001618 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1619 use_ldpc = true;
1620 }
Sujithe8324352009-01-16 21:38:42 +05301621
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001622 bf->bf_state.bfs_paprd = txctl->paprd;
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001623 if (txctl->paprd)
1624 bf->bf_state.bfs_paprd_timestamp = jiffies;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001625 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301626
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001627 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301628 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1629 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1630 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1631 } else {
1632 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1633 }
1634
Sujith17b182e2009-12-14 14:56:56 +05301635 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1636 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301637 assign_aggr_tid_seqno(skb, bf);
1638
1639 bf->bf_mpdu = skb;
1640
1641 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1642 skb->len, DMA_TO_DEVICE);
1643 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1644 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001645 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1646 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301647 return -ENOMEM;
1648 }
1649
1650 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001651
1652 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1653 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1654 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301655 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001656 } else
1657 bf->bf_isnullfunc = false;
1658
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001659 bf->bf_tx_aborted = false;
1660
Sujithe8324352009-01-16 21:38:42 +05301661 return 0;
1662}
1663
1664/* FIXME: tx power */
1665static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1666 struct ath_tx_control *txctl)
1667{
Sujitha22be222009-03-30 15:28:36 +05301668 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301669 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301670 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301671 struct ath_node *an = NULL;
1672 struct list_head bf_head;
1673 struct ath_desc *ds;
1674 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301675 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301676 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301677 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301678
1679 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301680 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301681
1682 INIT_LIST_HEAD(&bf_head);
1683 list_add_tail(&bf->list, &bf_head);
1684
1685 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001686 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301687
1688 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1689 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1690
1691 ath9k_hw_filltxdesc(ah, ds,
1692 skb->len, /* segment length */
1693 true, /* first segment */
1694 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001695 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001696 bf->bf_buf_addr,
1697 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301698
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001699 if (bf->bf_state.bfs_paprd)
1700 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1701
Sujithe8324352009-01-16 21:38:42 +05301702 spin_lock_bh(&txctl->txq->axq_lock);
1703
1704 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1705 tx_info->control.sta) {
1706 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1707 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1708
Sujithc37452b2009-03-09 09:31:57 +05301709 if (!ieee80211_is_data_qos(fc)) {
1710 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1711 goto tx_done;
1712 }
1713
Felix Fietkau4fdec032010-03-12 04:02:43 +01001714 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301715 /*
1716 * Try aggregation if it's a unicast data frame
1717 * and the destination is HT capable.
1718 */
1719 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1720 } else {
1721 /*
1722 * Send this frame as regular when ADDBA
1723 * exchange is neither complete nor pending.
1724 */
Sujithc37452b2009-03-09 09:31:57 +05301725 ath_tx_send_ht_normal(sc, txctl->txq,
1726 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301727 }
1728 } else {
Sujithc37452b2009-03-09 09:31:57 +05301729 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301730 }
1731
Sujithc37452b2009-03-09 09:31:57 +05301732tx_done:
Sujithe8324352009-01-16 21:38:42 +05301733 spin_unlock_bh(&txctl->txq->axq_lock);
1734}
1735
1736/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001737int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301738 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001739{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001740 struct ath_wiphy *aphy = hw->priv;
1741 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001742 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001743 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744 struct ath_buf *bf;
Felix Fietkau97923b12010-06-12 00:33:55 -04001745 int q, r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001746
Sujithe8324352009-01-16 21:38:42 +05301747 bf = ath_tx_get_buffer(sc);
1748 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001749 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301750 return -1;
1751 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001752
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001753 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301754 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001755 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001756
Sujithe8324352009-01-16 21:38:42 +05301757 /* upon ath_tx_processq() this TX queue will be resumed, we
1758 * guarantee this will happen by knowing beforehand that
1759 * we will at least have to run TX completionon one buffer
1760 * on the queue */
1761 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001762 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001763 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301764 txq->stopped = 1;
1765 }
1766 spin_unlock_bh(&txq->axq_lock);
1767
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001768 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301769
1770 return r;
1771 }
1772
Felix Fietkau97923b12010-06-12 00:33:55 -04001773 q = skb_get_queue_mapping(skb);
1774 if (q >= 4)
1775 q = 0;
1776
1777 spin_lock_bh(&txq->axq_lock);
1778 if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
1779 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1780 txq->stopped = 1;
1781 }
1782 spin_unlock_bh(&txq->axq_lock);
1783
Sujithe8324352009-01-16 21:38:42 +05301784 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001785
1786 return 0;
1787}
1788
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001789void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001790{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001791 struct ath_wiphy *aphy = hw->priv;
1792 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001793 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001794 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1795 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301796 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1797 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001798
Sujithe8324352009-01-16 21:38:42 +05301799 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001800
Sujithe8324352009-01-16 21:38:42 +05301801 /*
1802 * As a temporary workaround, assign seq# here; this will likely need
1803 * to be cleaned up to work better with Beacon transmission and virtual
1804 * BSSes.
1805 */
1806 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301807 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1808 sc->tx.seq_no += 0x10;
1809 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1810 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001811 }
1812
Sujithe8324352009-01-16 21:38:42 +05301813 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001814 padpos = ath9k_cmn_padpos(hdr->frame_control);
1815 padsize = padpos & 3;
1816 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301817 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001818 ath_print(common, ATH_DBG_XMIT,
1819 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301820 dev_kfree_skb_any(skb);
1821 return;
1822 }
1823 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001824 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001825 }
1826
Sujithe8324352009-01-16 21:38:42 +05301827 txctl.txq = sc->beacon.cabq;
1828
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001829 ath_print(common, ATH_DBG_XMIT,
1830 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301831
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001832 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001833 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301834 goto exit;
1835 }
1836
1837 return;
1838exit:
1839 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001840}
1841
Sujithe8324352009-01-16 21:38:42 +05301842/*****************/
1843/* TX Completion */
1844/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001845
Sujithe8324352009-01-16 21:38:42 +05301846static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001847 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001848{
Sujithe8324352009-01-16 21:38:42 +05301849 struct ieee80211_hw *hw = sc->hw;
1850 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001851 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001852 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001853 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301854
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001855 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301856
Felix Fietkau827e69b2009-11-15 23:09:25 +01001857 if (aphy)
1858 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301859
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301860 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301861 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301862
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301863 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301864 /* Frame was ACKed */
1865 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1866 }
1867
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001868 padpos = ath9k_cmn_padpos(hdr->frame_control);
1869 padsize = padpos & 3;
1870 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301871 /*
1872 * Remove MAC header padding before giving the frame back to
1873 * mac80211.
1874 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001875 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301876 skb_pull(skb, padsize);
1877 }
1878
Sujith1b04b932010-01-08 10:36:05 +05301879 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1880 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001881 ath_print(common, ATH_DBG_PS,
1882 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001883 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301884 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1885 PS_WAIT_FOR_CAB |
1886 PS_WAIT_FOR_PSPOLL_DATA |
1887 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001888 }
1889
Felix Fietkau827e69b2009-11-15 23:09:25 +01001890 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c2009-03-03 19:23:31 +02001891 ath9k_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001892 else {
1893 q = skb_get_queue_mapping(skb);
1894 if (q >= 4)
1895 q = 0;
1896
1897 if (--sc->tx.pending_frames[q] < 0)
1898 sc->tx.pending_frames[q] = 0;
1899
Felix Fietkau827e69b2009-11-15 23:09:25 +01001900 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001901 }
Sujithe8324352009-01-16 21:38:42 +05301902}
1903
1904static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001905 struct ath_txq *txq, struct list_head *bf_q,
1906 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301907{
1908 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301909 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301910 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301911
Sujithe8324352009-01-16 21:38:42 +05301912 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301913 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301914
1915 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301916 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301917
1918 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301919 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301920 }
1921
1922 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001923
1924 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001925 if (time_after(jiffies,
1926 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001927 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001928 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001929 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001930 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001931 } else {
1932 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
1933 ath_debug_stat_tx(sc, txq, bf, ts);
1934 }
Sujithe8324352009-01-16 21:38:42 +05301935
1936 /*
1937 * Return the list of ath_buf of this mpdu to free queue
1938 */
1939 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1940 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1941 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1942}
1943
1944static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001945 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301946{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001947 u16 seq_st = 0;
1948 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301949 int ba_index;
1950 int nbad = 0;
1951 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001952
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001953 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301954 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301955
Sujithcd3d39a2008-08-11 14:03:34 +05301956 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001957 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001958 seq_st = ts->ts_seqnum;
1959 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001960 }
1961
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001962 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301963 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1964 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1965 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001966
Sujithe8324352009-01-16 21:38:42 +05301967 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001968 }
1969
Sujithe8324352009-01-16 21:38:42 +05301970 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001971}
1972
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001973static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301974 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301975{
Sujitha22be222009-03-30 15:28:36 +05301976 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301977 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301978 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001979 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301980 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301981
Sujith95e4acb2009-03-13 08:56:09 +05301982 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001983 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301984
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001985 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301986 WARN_ON(tx_rateindex >= hw->max_rates);
1987
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001988 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301989 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01001990 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
1991 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301992
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001993 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301994 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05301995 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001996 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01001997 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
1998 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001999 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
2000 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002001 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2002 tx_info->status.ampdu_len = bf->bf_nframes;
2003 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302004 }
2005 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302006
Felix Fietkau545750d2009-11-23 22:21:01 +01002007 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302008 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002009 tx_info->status.rates[i].idx = -1;
2010 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302011
Felix Fietkau78c46532010-06-25 01:26:16 +02002012 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302013}
2014
Sujith059d8062009-01-16 21:38:49 +05302015static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2016{
2017 int qnum;
2018
Felix Fietkau97923b12010-06-12 00:33:55 -04002019 qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
2020 if (qnum == -1)
2021 return;
2022
Sujith059d8062009-01-16 21:38:49 +05302023 spin_lock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04002024 if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07002025 if (ath_mac80211_start_queue(sc, qnum))
2026 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05302027 }
2028 spin_unlock_bh(&txq->axq_lock);
2029}
2030
Sujithc4288392008-11-18 09:09:30 +05302031static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002032{
Sujithcbe61d82009-02-09 13:27:12 +05302033 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002034 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002035 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2036 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302037 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002038 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302039 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002040 int status;
2041
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002042 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2043 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2044 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002046 for (;;) {
2047 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002048 if (list_empty(&txq->axq_q)) {
2049 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002050 spin_unlock_bh(&txq->axq_lock);
2051 break;
2052 }
2053 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2054
2055 /*
2056 * There is a race condition that a BH gets scheduled
2057 * after sw writes TxE and before hw re-load the last
2058 * descriptor to get the newly chained one.
2059 * Software must keep the last DONE descriptor as a
2060 * holding descriptor - software does so by marking
2061 * it with the STALE flag.
2062 */
2063 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302064 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002065 bf_held = bf;
2066 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302067 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002068 break;
2069 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002070 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302071 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002072 }
2073 }
2074
2075 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302076 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002077
Felix Fietkau29bffa92010-03-29 20:14:23 -07002078 memset(&ts, 0, sizeof(ts));
2079 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002080 if (status == -EINPROGRESS) {
2081 spin_unlock_bh(&txq->axq_lock);
2082 break;
2083 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084
2085 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002086 * We now know the nullfunc frame has been ACKed so we
2087 * can disable RX.
2088 */
2089 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002090 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302091 if ((sc->ps_flags & PS_ENABLED))
2092 ath9k_enable_ps(sc);
2093 else
Sujith1b04b932010-01-08 10:36:05 +05302094 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002095 }
2096
2097 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 * Remove ath_buf's of the same transmit unit from txq,
2099 * however leave the last descriptor back as the holding
2100 * descriptor for hw.
2101 */
Sujitha119cc42009-03-30 15:28:38 +05302102 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002103 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002104 if (!list_is_singular(&lastbf->list))
2105 list_cut_position(&bf_head,
2106 &txq->axq_q, lastbf->list.prev);
2107
2108 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002109 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002110 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002111 if (bf_held)
2112 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002113 spin_unlock_bh(&txq->axq_lock);
2114
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002115 if (bf_held)
2116 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002117
Sujithcd3d39a2008-08-11 14:03:34 +05302118 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002119 /*
2120 * This frame is sent out as a single frame.
2121 * Use hardware retry status for this frame.
2122 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002123 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302124 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002125 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002126 }
Johannes Berge6a98542008-10-21 12:40:02 +02002127
Sujithcd3d39a2008-08-11 14:03:34 +05302128 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002129 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002130 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002131 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002132
Sujith059d8062009-01-16 21:38:49 +05302133 ath_wake_mac80211_queue(sc, txq);
2134
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002135 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302136 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002137 ath_txq_schedule(sc, txq);
2138 spin_unlock_bh(&txq->axq_lock);
2139 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140}
2141
Sujith305fe472009-07-23 15:32:29 +05302142static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002143{
2144 struct ath_softc *sc = container_of(work, struct ath_softc,
2145 tx_complete_work.work);
2146 struct ath_txq *txq;
2147 int i;
2148 bool needreset = false;
2149
2150 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2151 if (ATH_TXQ_SETUP(sc, i)) {
2152 txq = &sc->tx.txq[i];
2153 spin_lock_bh(&txq->axq_lock);
2154 if (txq->axq_depth) {
2155 if (txq->axq_tx_inprogress) {
2156 needreset = true;
2157 spin_unlock_bh(&txq->axq_lock);
2158 break;
2159 } else {
2160 txq->axq_tx_inprogress = true;
2161 }
2162 }
2163 spin_unlock_bh(&txq->axq_lock);
2164 }
2165
2166 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002167 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2168 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302169 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002170 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302171 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002172 }
2173
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002174 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002175 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2176}
2177
2178
Sujithe8324352009-01-16 21:38:42 +05302179
2180void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002181{
Sujithe8324352009-01-16 21:38:42 +05302182 int i;
2183 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002184
Sujithe8324352009-01-16 21:38:42 +05302185 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002186
2187 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302188 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2189 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002190 }
2191}
2192
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002193void ath_tx_edma_tasklet(struct ath_softc *sc)
2194{
2195 struct ath_tx_status txs;
2196 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2197 struct ath_hw *ah = sc->sc_ah;
2198 struct ath_txq *txq;
2199 struct ath_buf *bf, *lastbf;
2200 struct list_head bf_head;
2201 int status;
2202 int txok;
2203
2204 for (;;) {
2205 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2206 if (status == -EINPROGRESS)
2207 break;
2208 if (status == -EIO) {
2209 ath_print(common, ATH_DBG_XMIT,
2210 "Error processing tx status\n");
2211 break;
2212 }
2213
2214 /* Skip beacon completions */
2215 if (txs.qid == sc->beacon.beaconq)
2216 continue;
2217
2218 txq = &sc->tx.txq[txs.qid];
2219
2220 spin_lock_bh(&txq->axq_lock);
2221 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2222 spin_unlock_bh(&txq->axq_lock);
2223 return;
2224 }
2225
2226 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2227 struct ath_buf, list);
2228 lastbf = bf->bf_lastbf;
2229
2230 INIT_LIST_HEAD(&bf_head);
2231 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2232 &lastbf->list);
2233 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2234 txq->axq_depth--;
2235 txq->axq_tx_inprogress = false;
2236 spin_unlock_bh(&txq->axq_lock);
2237
2238 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2239
Vasanthakumar Thiagarajande0f6482010-05-17 18:57:54 -07002240 /*
2241 * Make sure null func frame is acked before configuring
2242 * hw into ps mode.
2243 */
2244 if (bf->bf_isnullfunc && txok) {
2245 if ((sc->ps_flags & PS_ENABLED))
2246 ath9k_enable_ps(sc);
2247 else
2248 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
2249 }
2250
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002251 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002252 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2253 bf->bf_state.bf_type |= BUF_XRETRY;
2254 ath_tx_rc_status(bf, &txs, 0, txok, true);
2255 }
2256
2257 if (bf_isampdu(bf))
2258 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2259 else
2260 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2261 &txs, txok, 0);
2262
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002263 ath_wake_mac80211_queue(sc, txq);
2264
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002265 spin_lock_bh(&txq->axq_lock);
2266 if (!list_empty(&txq->txq_fifo_pending)) {
2267 INIT_LIST_HEAD(&bf_head);
2268 bf = list_first_entry(&txq->txq_fifo_pending,
2269 struct ath_buf, list);
2270 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2271 &bf->bf_lastbf->list);
2272 ath_tx_txqaddbuf(sc, txq, &bf_head);
2273 } else if (sc->sc_flags & SC_OP_TXAGGR)
2274 ath_txq_schedule(sc, txq);
2275 spin_unlock_bh(&txq->axq_lock);
2276 }
2277}
2278
Sujithe8324352009-01-16 21:38:42 +05302279/*****************/
2280/* Init, Cleanup */
2281/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002282
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002283static int ath_txstatus_setup(struct ath_softc *sc, int size)
2284{
2285 struct ath_descdma *dd = &sc->txsdma;
2286 u8 txs_len = sc->sc_ah->caps.txs_len;
2287
2288 dd->dd_desc_len = size * txs_len;
2289 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2290 &dd->dd_desc_paddr, GFP_KERNEL);
2291 if (!dd->dd_desc)
2292 return -ENOMEM;
2293
2294 return 0;
2295}
2296
2297static int ath_tx_edma_init(struct ath_softc *sc)
2298{
2299 int err;
2300
2301 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2302 if (!err)
2303 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2304 sc->txsdma.dd_desc_paddr,
2305 ATH_TXSTATUS_RING_SIZE);
2306
2307 return err;
2308}
2309
2310static void ath_tx_edma_cleanup(struct ath_softc *sc)
2311{
2312 struct ath_descdma *dd = &sc->txsdma;
2313
2314 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2315 dd->dd_desc_paddr);
2316}
2317
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002318int ath_tx_init(struct ath_softc *sc, int nbufs)
2319{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002320 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002321 int error = 0;
2322
Sujith797fe5cb2009-03-30 15:28:45 +05302323 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002324
Sujith797fe5cb2009-03-30 15:28:45 +05302325 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002326 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302327 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002328 ath_print(common, ATH_DBG_FATAL,
2329 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302330 goto err;
2331 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002332
Sujith797fe5cb2009-03-30 15:28:45 +05302333 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002334 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302335 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002336 ath_print(common, ATH_DBG_FATAL,
2337 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302338 goto err;
2339 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002340
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002341 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2342
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002343 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2344 error = ath_tx_edma_init(sc);
2345 if (error)
2346 goto err;
2347 }
2348
Sujith797fe5cb2009-03-30 15:28:45 +05302349err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002350 if (error != 0)
2351 ath_tx_cleanup(sc);
2352
2353 return error;
2354}
2355
Sujith797fe5cb2009-03-30 15:28:45 +05302356void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002357{
Sujithb77f4832008-12-07 21:44:03 +05302358 if (sc->beacon.bdma.dd_desc_len != 0)
2359 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002360
Sujithb77f4832008-12-07 21:44:03 +05302361 if (sc->tx.txdma.dd_desc_len != 0)
2362 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002363
2364 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2365 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366}
2367
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002368void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2369{
Sujithc5170162008-10-29 10:13:59 +05302370 struct ath_atx_tid *tid;
2371 struct ath_atx_ac *ac;
2372 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002373
Sujith8ee5afb2008-12-07 21:43:36 +05302374 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302375 tidno < WME_NUM_TID;
2376 tidno++, tid++) {
2377 tid->an = an;
2378 tid->tidno = tidno;
2379 tid->seq_start = tid->seq_next = 0;
2380 tid->baw_size = WME_MAX_BA;
2381 tid->baw_head = tid->baw_tail = 0;
2382 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302383 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302384 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302385 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302386 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302387 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302388 tid->state &= ~AGGR_ADDBA_COMPLETE;
2389 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302390 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002391
Sujith8ee5afb2008-12-07 21:43:36 +05302392 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302393 acno < WME_NUM_AC; acno++, ac++) {
2394 ac->sched = false;
Felix Fietkau1d2231e2010-06-12 00:33:51 -04002395 ac->qnum = sc->tx.hwq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302396 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002397 }
2398}
2399
Sujithb5aa9bf2008-10-29 10:13:31 +05302400void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002401{
Felix Fietkau2b409942010-07-07 19:42:08 +02002402 struct ath_atx_ac *ac;
2403 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002404 struct ath_txq *txq;
Felix Fietkau2b409942010-07-07 19:42:08 +02002405 int i, tidno;
Sujithe8324352009-01-16 21:38:42 +05302406
Felix Fietkau2b409942010-07-07 19:42:08 +02002407 for (tidno = 0, tid = &an->tid[tidno];
2408 tidno < WME_NUM_TID; tidno++, tid++) {
2409 i = tid->ac->qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002410
Felix Fietkau2b409942010-07-07 19:42:08 +02002411 if (!ATH_TXQ_SETUP(sc, i))
2412 continue;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002413
Felix Fietkau2b409942010-07-07 19:42:08 +02002414 txq = &sc->tx.txq[i];
2415 ac = tid->ac;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002416
Felix Fietkau2b409942010-07-07 19:42:08 +02002417 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002418
Felix Fietkau2b409942010-07-07 19:42:08 +02002419 if (tid->sched) {
2420 list_del(&tid->list);
2421 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002422 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002423
2424 if (ac->sched) {
2425 list_del(&ac->list);
2426 tid->ac->sched = false;
2427 }
2428
2429 ath_tid_drain(sc, txq, tid);
2430 tid->state &= ~AGGR_ADDBA_COMPLETE;
2431 tid->state &= ~AGGR_CLEANUP;
2432
2433 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002434 }
2435}