blob: f7da6b20a92574c9eec02ba6672df834f69319d7 [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
Ben Greear686b9cb2010-09-23 09:44:36 -0700331 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530332 if (!sta) {
333 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200334
Felix Fietkau31e79a52010-07-12 23:16:34 +0200335 INIT_LIST_HEAD(&bf_head);
336 while (bf) {
337 bf_next = bf->bf_next;
338
339 bf->bf_state.bf_type |= BUF_XRETRY;
340 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
341 !bf->bf_stale || bf_next != NULL)
342 list_move_tail(&bf->list, &bf_head);
343
344 ath_tx_rc_status(bf, ts, 0, 0, false);
345 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
346 0, 0);
347
348 bf = bf_next;
349 }
Sujith1286ec62009-01-27 13:30:37 +0530350 return;
Sujithe8324352009-01-16 21:38:42 +0530351 }
352
Sujith1286ec62009-01-27 13:30:37 +0530353 an = (struct ath_node *)sta->drv_priv;
354 tid = ATH_AN_2_TID(an, bf->bf_tidno);
355
Felix Fietkaub11b1602010-07-11 12:48:44 +0200356 /*
357 * The hardware occasionally sends a tx status for the wrong TID.
358 * In this case, the BA status cannot be considered valid and all
359 * subframes need to be retransmitted
360 */
361 if (bf->bf_tidno != ts->tid)
362 txok = false;
363
Sujithe8324352009-01-16 21:38:42 +0530364 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530365 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530366
Sujithd43f30152009-01-16 21:38:53 +0530367 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700368 if (ts->ts_flags & ATH9K_TX_BA) {
369 seq_st = ts->ts_seqnum;
370 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530371 } else {
Sujithd43f30152009-01-16 21:38:53 +0530372 /*
373 * AR5416 can become deaf/mute when BA
374 * issue happens. Chip needs to be reset.
375 * But AP code may have sychronization issues
376 * when perform internal reset in this routine.
377 * Only enable reset in STA mode for now.
378 */
Sujith2660b812009-02-09 13:27:26 +0530379 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530380 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530381 }
382 }
383
384 INIT_LIST_HEAD(&bf_pending);
385 INIT_LIST_HEAD(&bf_head);
386
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700387 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530388 while (bf) {
389 txfail = txpending = 0;
390 bf_next = bf->bf_next;
391
Felix Fietkau78c46532010-06-25 01:26:16 +0200392 skb = bf->bf_mpdu;
393 tx_info = IEEE80211_SKB_CB(skb);
394
Sujithe8324352009-01-16 21:38:42 +0530395 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
396 /* transmit completion, subframe is
397 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530398 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530399 } else if (!isaggr && txok) {
400 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530401 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530402 } else {
Sujithe8324352009-01-16 21:38:42 +0530403 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400404 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530405 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530406 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530407 txpending = 1;
408 } else {
409 bf->bf_state.bf_type |= BUF_XRETRY;
410 txfail = 1;
411 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530412 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530413 }
414 } else {
415 /*
416 * cleanup in progress, just fail
417 * the un-acked sub-frames
418 */
419 txfail = 1;
420 }
421 }
422
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400423 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
424 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530425 /*
426 * Make sure the last desc is reclaimed if it
427 * not a holding desc.
428 */
429 if (!bf_last->bf_stale)
430 list_move_tail(&bf->list, &bf_head);
431 else
432 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530433 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700434 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530435 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530436 }
437
Felix Fietkau90fa5392010-09-20 13:45:38 +0200438 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530439 /*
440 * complete the acked-ones/xretried ones; update
441 * block-ack window
442 */
443 spin_lock_bh(&txq->axq_lock);
444 ath_tx_update_baw(sc, tid, bf->bf_seqno);
445 spin_unlock_bh(&txq->axq_lock);
446
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530447 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200448 memcpy(tx_info->control.rates, rates, sizeof(rates));
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700449 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530450 rc_update = false;
451 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700452 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530453 }
454
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700455 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
456 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530457 } else {
Sujithd43f30152009-01-16 21:38:53 +0530458 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400459 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
460 if (bf->bf_next == NULL && bf_last->bf_stale) {
461 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530462
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400463 tbf = ath_clone_txbuf(sc, bf_last);
464 /*
465 * Update tx baw and complete the
466 * frame with failed status if we
467 * run out of tx buf.
468 */
469 if (!tbf) {
470 spin_lock_bh(&txq->axq_lock);
471 ath_tx_update_baw(sc, tid,
472 bf->bf_seqno);
473 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400474
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400475 bf->bf_state.bf_type |=
476 BUF_XRETRY;
477 ath_tx_rc_status(bf, ts, nbad,
478 0, false);
479 ath_tx_complete_buf(sc, bf, txq,
480 &bf_head,
481 ts, 0, 0);
482 break;
483 }
484
485 ath9k_hw_cleartxdesc(sc->sc_ah,
486 tbf->bf_desc);
487 list_add_tail(&tbf->list, &bf_head);
488 } else {
489 /*
490 * Clear descriptor status words for
491 * software retry
492 */
493 ath9k_hw_cleartxdesc(sc->sc_ah,
494 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400495 }
Sujithe8324352009-01-16 21:38:42 +0530496 }
497
498 /*
499 * Put this buffer to the temporary pending
500 * queue to retain ordering
501 */
502 list_splice_tail_init(&bf_head, &bf_pending);
503 }
504
505 bf = bf_next;
506 }
507
Felix Fietkau4cee7862010-07-23 03:53:16 +0200508 /* prepend un-acked frames to the beginning of the pending frame queue */
509 if (!list_empty(&bf_pending)) {
510 spin_lock_bh(&txq->axq_lock);
511 list_splice(&bf_pending, &tid->buf_q);
512 ath_tx_queue_tid(txq, tid);
513 spin_unlock_bh(&txq->axq_lock);
514 }
515
Sujithe8324352009-01-16 21:38:42 +0530516 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200517 ath_tx_flush_tid(sc, tid);
518
Sujithe8324352009-01-16 21:38:42 +0530519 if (tid->baw_head == tid->baw_tail) {
520 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530521 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530522 }
Sujithe8324352009-01-16 21:38:42 +0530523 }
524
Sujith1286ec62009-01-27 13:30:37 +0530525 rcu_read_unlock();
526
Sujithe8324352009-01-16 21:38:42 +0530527 if (needreset)
528 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530529}
530
531static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
532 struct ath_atx_tid *tid)
533{
Sujithe8324352009-01-16 21:38:42 +0530534 struct sk_buff *skb;
535 struct ieee80211_tx_info *tx_info;
536 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530537 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530538 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530539 int i;
540
Sujitha22be222009-03-30 15:28:36 +0530541 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530542 tx_info = IEEE80211_SKB_CB(skb);
543 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530544
545 /*
546 * Find the lowest frame length among the rate series that will have a
547 * 4ms transmit duration.
548 * TODO - TXOP limit needs to be considered.
549 */
550 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
551
552 for (i = 0; i < 4; i++) {
553 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100554 int modeidx;
555 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530556 legacy = 1;
557 break;
558 }
559
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200560 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100561 modeidx = MCS_HT40;
562 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200563 modeidx = MCS_HT20;
564
565 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
566 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100567
568 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530569 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530570 }
571 }
572
573 /*
574 * limit aggregate size by the minimum rate if rate selected is
575 * not a probe rate, if rate selected is a probe rate then
576 * avoid aggregation of this packet.
577 */
578 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
579 return 0;
580
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530581 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
582 aggr_limit = min((max_4ms_framelen * 3) / 8,
583 (u32)ATH_AMPDU_LIMIT_MAX);
584 else
585 aggr_limit = min(max_4ms_framelen,
586 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530587
588 /*
589 * h/w can accept aggregates upto 16 bit lengths (65535).
590 * The IE, however can hold upto 65536, which shows up here
591 * as zero. Ignore 65536 since we are constrained by hw.
592 */
Sujith4ef70842009-07-23 15:32:41 +0530593 if (tid->an->maxampdu)
594 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530595
596 return aggr_limit;
597}
598
599/*
Sujithd43f30152009-01-16 21:38:53 +0530600 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530601 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530602 */
603static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
604 struct ath_buf *bf, u16 frmlen)
605{
Sujithe8324352009-01-16 21:38:42 +0530606 struct sk_buff *skb = bf->bf_mpdu;
607 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530608 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530609 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100610 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200611 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530612
613 /* Select standard number of delimiters based on frame length alone */
614 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
615
616 /*
617 * If encryption enabled, hardware requires some more padding between
618 * subframes.
619 * TODO - this could be improved to be dependent on the rate.
620 * The hardware can keep up at lower rates, but not higher rates
621 */
622 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
623 ndelim += ATH_AGGR_ENCRYPTDELIM;
624
625 /*
626 * Convert desired mpdu density from microeconds to bytes based
627 * on highest rate in rate series (i.e. first rate) to determine
628 * required minimum length for subframe. Take into account
629 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530630 *
Sujithe8324352009-01-16 21:38:42 +0530631 * If there is no mpdu density restriction, no further calculation
632 * is needed.
633 */
Sujith4ef70842009-07-23 15:32:41 +0530634
635 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530636 return ndelim;
637
638 rix = tx_info->control.rates[0].idx;
639 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530640 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
641 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
642
643 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530644 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530645 else
Sujith4ef70842009-07-23 15:32:41 +0530646 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530647
648 if (nsymbols == 0)
649 nsymbols = 1;
650
Felix Fietkauc6663872010-04-19 19:57:33 +0200651 streams = HT_RC_2_STREAMS(rix);
652 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530653 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
654
Sujithe8324352009-01-16 21:38:42 +0530655 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530656 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
657 ndelim = max(mindelim, ndelim);
658 }
659
660 return ndelim;
661}
662
663static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530664 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530665 struct ath_atx_tid *tid,
666 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530667{
668#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530669 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
670 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530671 u16 aggr_limit = 0, al = 0, bpad = 0,
672 al_delta, h_baw = tid->baw_size / 2;
673 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Sujithe8324352009-01-16 21:38:42 +0530674
675 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
676
677 do {
678 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
679
Sujithd43f30152009-01-16 21:38:53 +0530680 /* do not step over block-ack window */
Sujithe8324352009-01-16 21:38:42 +0530681 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
682 status = ATH_AGGR_BAW_CLOSED;
683 break;
684 }
685
686 if (!rl) {
687 aggr_limit = ath_lookup_rate(sc, bf, tid);
688 rl = 1;
689 }
690
Sujithd43f30152009-01-16 21:38:53 +0530691 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530692 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
693
Sujithd43f30152009-01-16 21:38:53 +0530694 if (nframes &&
695 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530696 status = ATH_AGGR_LIMITED;
697 break;
698 }
699
Sujithd43f30152009-01-16 21:38:53 +0530700 /* do not exceed subframe limit */
701 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530702 status = ATH_AGGR_LIMITED;
703 break;
704 }
Sujithd43f30152009-01-16 21:38:53 +0530705 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530706
Sujithd43f30152009-01-16 21:38:53 +0530707 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530708 al += bpad + al_delta;
709
710 /*
711 * Get the delimiters needed to meet the MPDU
712 * density for this node.
713 */
714 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530715 bpad = PADBYTES(al_delta) + (ndelim << 2);
716
717 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400718 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530719
Sujithd43f30152009-01-16 21:38:53 +0530720 /* link buffers of this frame to the aggregate */
Sujithe8324352009-01-16 21:38:42 +0530721 ath_tx_addto_baw(sc, tid, bf);
Sujithd43f30152009-01-16 21:38:53 +0530722 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
723 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530724 if (bf_prev) {
725 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400726 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
727 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530728 }
729 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530730
Sujithe8324352009-01-16 21:38:42 +0530731 } while (!list_empty(&tid->buf_q));
732
733 bf_first->bf_al = al;
734 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530735
Sujithe8324352009-01-16 21:38:42 +0530736 return status;
737#undef PADBYTES
738}
739
740static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
741 struct ath_atx_tid *tid)
742{
Sujithd43f30152009-01-16 21:38:53 +0530743 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530744 enum ATH_AGGR_STATUS status;
745 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530746
747 do {
748 if (list_empty(&tid->buf_q))
749 return;
750
751 INIT_LIST_HEAD(&bf_q);
752
Sujithfec247c2009-07-27 12:08:16 +0530753 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530754
755 /*
Sujithd43f30152009-01-16 21:38:53 +0530756 * no frames picked up to be aggregated;
757 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530758 */
759 if (list_empty(&bf_q))
760 break;
761
762 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530763 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530764
Sujithd43f30152009-01-16 21:38:53 +0530765 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530766 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530767 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530768 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530769 ath_buf_set_rate(sc, bf);
770 ath_tx_txqaddbuf(sc, txq, &bf_q);
771 continue;
772 }
773
Sujithd43f30152009-01-16 21:38:53 +0530774 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530775 bf->bf_state.bf_type |= BUF_AGGR;
776 ath_buf_set_rate(sc, bf);
777 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
778
Sujithd43f30152009-01-16 21:38:53 +0530779 /* anchor last desc of aggregate */
780 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530781
Sujithe8324352009-01-16 21:38:42 +0530782 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530783 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530784
785 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
786 status != ATH_AGGR_BAW_CLOSED);
787}
788
Felix Fietkau231c3a12010-09-20 19:35:28 +0200789int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
790 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530791{
792 struct ath_atx_tid *txtid;
793 struct ath_node *an;
794
795 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530796 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200797
798 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
799 return -EAGAIN;
800
Sujithf83da962009-07-23 15:32:37 +0530801 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200802 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530803 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200804
805 return 0;
Sujithe8324352009-01-16 21:38:42 +0530806}
807
Sujithf83da962009-07-23 15:32:37 +0530808void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530809{
810 struct ath_node *an = (struct ath_node *)sta->drv_priv;
811 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
812 struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
Sujithe8324352009-01-16 21:38:42 +0530813
814 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530815 return;
Sujithe8324352009-01-16 21:38:42 +0530816
817 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530818 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530819 return;
Sujithe8324352009-01-16 21:38:42 +0530820 }
821
Sujithe8324352009-01-16 21:38:42 +0530822 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200823 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200824
825 /*
826 * If frames are still being transmitted for this TID, they will be
827 * cleaned up during tx completion. To prevent race conditions, this
828 * TID can only be reused after all in-progress subframes have been
829 * completed.
830 */
831 if (txtid->baw_head != txtid->baw_tail)
832 txtid->state |= AGGR_CLEANUP;
833 else
834 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530835 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530836
Felix Fietkau90fa5392010-09-20 13:45:38 +0200837 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530838}
839
840void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
841{
842 struct ath_atx_tid *txtid;
843 struct ath_node *an;
844
845 an = (struct ath_node *)sta->drv_priv;
846
847 if (sc->sc_flags & SC_OP_TXAGGR) {
848 txtid = ATH_AN_2_TID(an, tid);
849 txtid->baw_size =
850 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
851 txtid->state |= AGGR_ADDBA_COMPLETE;
852 txtid->state &= ~AGGR_ADDBA_PROGRESS;
853 ath_tx_resume_tid(sc, txtid);
854 }
855}
856
Sujithe8324352009-01-16 21:38:42 +0530857/********************/
858/* Queue Management */
859/********************/
860
Sujithe8324352009-01-16 21:38:42 +0530861static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
862 struct ath_txq *txq)
863{
864 struct ath_atx_ac *ac, *ac_tmp;
865 struct ath_atx_tid *tid, *tid_tmp;
866
867 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
868 list_del(&ac->list);
869 ac->sched = false;
870 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
871 list_del(&tid->list);
872 tid->sched = false;
873 ath_tid_drain(sc, txq, tid);
874 }
875 }
876}
877
878struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
879{
Sujithcbe61d82009-02-09 13:27:12 +0530880 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700881 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530882 struct ath9k_tx_queue_info qi;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400883 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530884
885 memset(&qi, 0, sizeof(qi));
886 qi.tqi_subtype = subtype;
887 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
888 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
889 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
890 qi.tqi_physCompBuf = 0;
891
892 /*
893 * Enable interrupts only for EOL and DESC conditions.
894 * We mark tx descriptors to receive a DESC interrupt
895 * when a tx queue gets deep; otherwise waiting for the
896 * EOL to reap descriptors. Note that this is done to
897 * reduce interrupt load and this only defers reaping
898 * descriptors, never transmitting frames. Aside from
899 * reducing interrupts this also permits more concurrency.
900 * The only potential downside is if the tx queue backs
901 * up in which case the top half of the kernel may backup
902 * due to a lack of tx descriptors.
903 *
904 * The UAPSD queue is an exception, since we take a desc-
905 * based intr on the EOSP frames.
906 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400907 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
908 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
909 TXQ_FLAG_TXERRINT_ENABLE;
910 } else {
911 if (qtype == ATH9K_TX_QUEUE_UAPSD)
912 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
913 else
914 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
915 TXQ_FLAG_TXDESCINT_ENABLE;
916 }
Sujithe8324352009-01-16 21:38:42 +0530917 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
918 if (qnum == -1) {
919 /*
920 * NB: don't print a message, this happens
921 * normally on parts with too few tx queues
922 */
923 return NULL;
924 }
925 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700926 ath_print(common, ATH_DBG_FATAL,
927 "qnum %u out of range, max %u!\n",
928 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530929 ath9k_hw_releasetxqueue(ah, qnum);
930 return NULL;
931 }
932 if (!ATH_TXQ_SETUP(sc, qnum)) {
933 struct ath_txq *txq = &sc->tx.txq[qnum];
934
Felix Fietkau293f2ba2010-06-12 00:33:49 -0400935 txq->axq_class = subtype;
Sujithe8324352009-01-16 21:38:42 +0530936 txq->axq_qnum = qnum;
937 txq->axq_link = NULL;
938 INIT_LIST_HEAD(&txq->axq_q);
939 INIT_LIST_HEAD(&txq->axq_acq);
940 spin_lock_init(&txq->axq_lock);
941 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400942 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530943 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400944
945 txq->txq_headidx = txq->txq_tailidx = 0;
946 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
947 INIT_LIST_HEAD(&txq->txq_fifo[i]);
948 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530949 }
950 return &sc->tx.txq[qnum];
951}
952
Sujithe8324352009-01-16 21:38:42 +0530953int ath_txq_update(struct ath_softc *sc, int qnum,
954 struct ath9k_tx_queue_info *qinfo)
955{
Sujithcbe61d82009-02-09 13:27:12 +0530956 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530957 int error = 0;
958 struct ath9k_tx_queue_info qi;
959
960 if (qnum == sc->beacon.beaconq) {
961 /*
962 * XXX: for beacon queue, we just save the parameter.
963 * It will be picked up by ath_beaconq_config when
964 * it's necessary.
965 */
966 sc->beacon.beacon_qi = *qinfo;
967 return 0;
968 }
969
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700970 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530971
972 ath9k_hw_get_txq_props(ah, qnum, &qi);
973 qi.tqi_aifs = qinfo->tqi_aifs;
974 qi.tqi_cwmin = qinfo->tqi_cwmin;
975 qi.tqi_cwmax = qinfo->tqi_cwmax;
976 qi.tqi_burstTime = qinfo->tqi_burstTime;
977 qi.tqi_readyTime = qinfo->tqi_readyTime;
978
979 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700980 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
981 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +0530982 error = -EIO;
983 } else {
984 ath9k_hw_resettxqueue(ah, qnum);
985 }
986
987 return error;
988}
989
990int ath_cabq_update(struct ath_softc *sc)
991{
992 struct ath9k_tx_queue_info qi;
993 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +0530994
995 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
996 /*
997 * Ensure the readytime % is within the bounds.
998 */
Sujith17d79042009-02-09 13:27:03 +0530999 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1000 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1001 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1002 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301003
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001004 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301005 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301006 ath_txq_update(sc, qnum, &qi);
1007
1008 return 0;
1009}
1010
Sujith043a0402009-01-16 21:38:47 +05301011/*
1012 * Drain a given TX queue (could be Beacon or Data)
1013 *
1014 * This assumes output has been stopped and
1015 * we do not need to block ath_tx_tasklet.
1016 */
1017void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301018{
1019 struct ath_buf *bf, *lastbf;
1020 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001021 struct ath_tx_status ts;
1022
1023 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301024 INIT_LIST_HEAD(&bf_head);
1025
Sujithe8324352009-01-16 21:38:42 +05301026 for (;;) {
1027 spin_lock_bh(&txq->axq_lock);
1028
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001029 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1030 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1031 txq->txq_headidx = txq->txq_tailidx = 0;
1032 spin_unlock_bh(&txq->axq_lock);
1033 break;
1034 } else {
1035 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1036 struct ath_buf, list);
1037 }
1038 } else {
1039 if (list_empty(&txq->axq_q)) {
1040 txq->axq_link = NULL;
1041 spin_unlock_bh(&txq->axq_lock);
1042 break;
1043 }
1044 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1045 list);
Sujithe8324352009-01-16 21:38:42 +05301046
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001047 if (bf->bf_stale) {
1048 list_del(&bf->list);
1049 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301050
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001051 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001052 continue;
1053 }
Sujithe8324352009-01-16 21:38:42 +05301054 }
1055
1056 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001057 if (!retry_tx)
1058 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301059
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001060 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1061 list_cut_position(&bf_head,
1062 &txq->txq_fifo[txq->txq_tailidx],
1063 &lastbf->list);
1064 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1065 } else {
1066 /* remove ath_buf's of the same mpdu from txq */
1067 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1068 }
1069
Sujithe8324352009-01-16 21:38:42 +05301070 txq->axq_depth--;
1071
1072 spin_unlock_bh(&txq->axq_lock);
1073
1074 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001075 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301076 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001077 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301078 }
1079
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001080 spin_lock_bh(&txq->axq_lock);
1081 txq->axq_tx_inprogress = false;
1082 spin_unlock_bh(&txq->axq_lock);
1083
Sujithe8324352009-01-16 21:38:42 +05301084 /* flush any pending frames if aggregation is enabled */
1085 if (sc->sc_flags & SC_OP_TXAGGR) {
1086 if (!retry_tx) {
1087 spin_lock_bh(&txq->axq_lock);
1088 ath_txq_drain_pending_buffers(sc, txq);
1089 spin_unlock_bh(&txq->axq_lock);
1090 }
1091 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001092
1093 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1094 spin_lock_bh(&txq->axq_lock);
1095 while (!list_empty(&txq->txq_fifo_pending)) {
1096 bf = list_first_entry(&txq->txq_fifo_pending,
1097 struct ath_buf, list);
1098 list_cut_position(&bf_head,
1099 &txq->txq_fifo_pending,
1100 &bf->bf_lastbf->list);
1101 spin_unlock_bh(&txq->axq_lock);
1102
1103 if (bf_isampdu(bf))
1104 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1105 &ts, 0);
1106 else
1107 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1108 &ts, 0, 0);
1109 spin_lock_bh(&txq->axq_lock);
1110 }
1111 spin_unlock_bh(&txq->axq_lock);
1112 }
Sujithe8324352009-01-16 21:38:42 +05301113}
1114
Sujith043a0402009-01-16 21:38:47 +05301115void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1116{
Sujithcbe61d82009-02-09 13:27:12 +05301117 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001118 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301119 struct ath_txq *txq;
1120 int i, npend = 0;
1121
1122 if (sc->sc_flags & SC_OP_INVALID)
1123 return;
1124
1125 /* Stop beacon queue */
1126 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1127
1128 /* Stop data queues */
1129 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1130 if (ATH_TXQ_SETUP(sc, i)) {
1131 txq = &sc->tx.txq[i];
1132 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1133 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1134 }
1135 }
1136
1137 if (npend) {
1138 int r;
1139
Sujithe8009e92009-12-14 14:57:08 +05301140 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001141 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301142
1143 spin_lock_bh(&sc->sc_resetlock);
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001144 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301145 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001146 ath_print(common, ATH_DBG_FATAL,
1147 "Unable to reset hardware; reset status %d\n",
1148 r);
Sujith043a0402009-01-16 21:38:47 +05301149 spin_unlock_bh(&sc->sc_resetlock);
1150 }
1151
1152 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1153 if (ATH_TXQ_SETUP(sc, i))
1154 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1155 }
1156}
1157
Sujithe8324352009-01-16 21:38:42 +05301158void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1159{
1160 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1161 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1162}
1163
Sujithe8324352009-01-16 21:38:42 +05301164void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1165{
1166 struct ath_atx_ac *ac;
1167 struct ath_atx_tid *tid;
1168
1169 if (list_empty(&txq->axq_acq))
1170 return;
1171
1172 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1173 list_del(&ac->list);
1174 ac->sched = false;
1175
1176 do {
1177 if (list_empty(&ac->tid_q))
1178 return;
1179
1180 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1181 list_del(&tid->list);
1182 tid->sched = false;
1183
1184 if (tid->paused)
1185 continue;
1186
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001187 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301188
1189 /*
1190 * add tid to round-robin queue if more frames
1191 * are pending for the tid
1192 */
1193 if (!list_empty(&tid->buf_q))
1194 ath_tx_queue_tid(txq, tid);
1195
1196 break;
1197 } while (!list_empty(&ac->tid_q));
1198
1199 if (!list_empty(&ac->tid_q)) {
1200 if (!ac->sched) {
1201 ac->sched = true;
1202 list_add_tail(&ac->list, &txq->axq_acq);
1203 }
1204 }
1205}
1206
1207int ath_tx_setup(struct ath_softc *sc, int haltype)
1208{
1209 struct ath_txq *txq;
1210
1211 if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001212 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1213 "HAL AC %u out of range, max %zu!\n",
Sujithe8324352009-01-16 21:38:42 +05301214 haltype, ARRAY_SIZE(sc->tx.hwq_map));
1215 return 0;
1216 }
1217 txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
1218 if (txq != NULL) {
1219 sc->tx.hwq_map[haltype] = txq->axq_qnum;
1220 return 1;
1221 } else
1222 return 0;
1223}
1224
1225/***********/
1226/* TX, DMA */
1227/***********/
1228
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001229/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001230 * Insert a chain of ath_buf (descriptors) on a txq and
1231 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001232 */
Sujith102e0572008-10-29 10:15:16 +05301233static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1234 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001235{
Sujithcbe61d82009-02-09 13:27:12 +05301236 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001237 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001238 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301239
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001240 /*
1241 * Insert the frame on the outbound list and
1242 * pass it on to the hardware.
1243 */
1244
1245 if (list_empty(head))
1246 return;
1247
1248 bf = list_first_entry(head, struct ath_buf, list);
1249
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001250 ath_print(common, ATH_DBG_QUEUE,
1251 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001252
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001253 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1254 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1255 list_splice_tail_init(head, &txq->txq_fifo_pending);
1256 return;
1257 }
1258 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1259 ath_print(common, ATH_DBG_XMIT,
1260 "Initializing tx fifo %d which "
1261 "is non-empty\n",
1262 txq->txq_headidx);
1263 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1264 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1265 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001266 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001267 ath_print(common, ATH_DBG_XMIT,
1268 "TXDP[%u] = %llx (%p)\n",
1269 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001270 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001271 list_splice_tail_init(head, &txq->axq_q);
1272
1273 if (txq->axq_link == NULL) {
1274 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1275 ath_print(common, ATH_DBG_XMIT,
1276 "TXDP[%u] = %llx (%p)\n",
1277 txq->axq_qnum, ito64(bf->bf_daddr),
1278 bf->bf_desc);
1279 } else {
1280 *txq->axq_link = bf->bf_daddr;
1281 ath_print(common, ATH_DBG_XMIT,
1282 "link[%u] (%p)=%llx (%p)\n",
1283 txq->axq_qnum, txq->axq_link,
1284 ito64(bf->bf_daddr), bf->bf_desc);
1285 }
1286 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1287 &txq->axq_link);
1288 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001289 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001290 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001291}
1292
Sujithe8324352009-01-16 21:38:42 +05301293static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1294 struct list_head *bf_head,
1295 struct ath_tx_control *txctl)
1296{
1297 struct ath_buf *bf;
1298
Sujithe8324352009-01-16 21:38:42 +05301299 bf = list_first_entry(bf_head, struct ath_buf, list);
1300 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301301 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Sujithe8324352009-01-16 21:38:42 +05301302
1303 /*
1304 * Do not queue to h/w when any of the following conditions is true:
1305 * - there are pending frames in software queue
1306 * - the TID is currently paused for ADDBA/BAR request
1307 * - seqno is not within block-ack window
1308 * - h/w queue depth exceeds low water mark
1309 */
1310 if (!list_empty(&tid->buf_q) || tid->paused ||
1311 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
1312 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001313 /*
Sujithe8324352009-01-16 21:38:42 +05301314 * Add this frame to software queue for scheduling later
1315 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001316 */
Sujithd43f30152009-01-16 21:38:53 +05301317 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301318 ath_tx_queue_tid(txctl->txq, tid);
1319 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001320 }
1321
Sujithe8324352009-01-16 21:38:42 +05301322 /* Add sub-frame to BAW */
1323 ath_tx_addto_baw(sc, tid, bf);
1324
1325 /* Queue to h/w without aggregation */
1326 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301327 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301328 ath_buf_set_rate(sc, bf);
1329 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301330}
1331
Sujithc37452b2009-03-09 09:31:57 +05301332static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
1333 struct ath_atx_tid *tid,
1334 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001335{
Sujithe8324352009-01-16 21:38:42 +05301336 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001337
Sujithe8324352009-01-16 21:38:42 +05301338 bf = list_first_entry(bf_head, struct ath_buf, list);
1339 bf->bf_state.bf_type &= ~BUF_AMPDU;
1340
1341 /* update starting sequence number for subsequent ADDBA request */
1342 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
1343
1344 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301345 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301346 ath_buf_set_rate(sc, bf);
1347 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301348 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001349}
1350
Sujithc37452b2009-03-09 09:31:57 +05301351static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1352 struct list_head *bf_head)
1353{
1354 struct ath_buf *bf;
1355
1356 bf = list_first_entry(bf_head, struct ath_buf, list);
1357
1358 bf->bf_lastbf = bf;
1359 bf->bf_nframes = 1;
1360 ath_buf_set_rate(sc, bf);
1361 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301362 TX_STAT_INC(txq->axq_qnum, queued);
Sujithc37452b2009-03-09 09:31:57 +05301363}
1364
Sujith528f0c62008-10-29 10:14:26 +05301365static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001366{
Sujith528f0c62008-10-29 10:14:26 +05301367 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001368 enum ath9k_pkt_type htype;
1369 __le16 fc;
1370
Sujith528f0c62008-10-29 10:14:26 +05301371 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001372 fc = hdr->frame_control;
1373
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001374 if (ieee80211_is_beacon(fc))
1375 htype = ATH9K_PKT_TYPE_BEACON;
1376 else if (ieee80211_is_probe_resp(fc))
1377 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1378 else if (ieee80211_is_atim(fc))
1379 htype = ATH9K_PKT_TYPE_ATIM;
1380 else if (ieee80211_is_pspoll(fc))
1381 htype = ATH9K_PKT_TYPE_PSPOLL;
1382 else
1383 htype = ATH9K_PKT_TYPE_NORMAL;
1384
1385 return htype;
1386}
1387
Sujith528f0c62008-10-29 10:14:26 +05301388static void assign_aggr_tid_seqno(struct sk_buff *skb,
1389 struct ath_buf *bf)
1390{
1391 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1392 struct ieee80211_hdr *hdr;
1393 struct ath_node *an;
1394 struct ath_atx_tid *tid;
1395 __le16 fc;
1396 u8 *qc;
1397
1398 if (!tx_info->control.sta)
1399 return;
1400
1401 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1402 hdr = (struct ieee80211_hdr *)skb->data;
1403 fc = hdr->frame_control;
1404
Sujith528f0c62008-10-29 10:14:26 +05301405 if (ieee80211_is_data_qos(fc)) {
1406 qc = ieee80211_get_qos_ctl(hdr);
1407 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301408 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409
Sujithe8324352009-01-16 21:38:42 +05301410 /*
1411 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301412 * We also override seqno set by upper layer with the one
1413 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301414 */
1415 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301416 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301417 bf->bf_seqno = tid->seq_next;
1418 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301419}
1420
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001421static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
Sujith528f0c62008-10-29 10:14:26 +05301422{
1423 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1424 int flags = 0;
1425
1426 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1427 flags |= ATH9K_TXDESC_INTREQ;
1428
1429 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1430 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301431
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001432 if (use_ldpc)
1433 flags |= ATH9K_TXDESC_LDPC;
1434
Sujith528f0c62008-10-29 10:14:26 +05301435 return flags;
1436}
1437
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001438/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439 * rix - rate index
1440 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1441 * width - 0 for 20 MHz, 1 for 40 MHz
1442 * half_gi - to use 4us v/s 3.6 us for symbol time
1443 */
Sujith102e0572008-10-29 10:15:16 +05301444static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1445 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001446{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001447 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001448 int streams, pktlen;
1449
Sujithcd3d39a2008-08-11 14:03:34 +05301450 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301451
1452 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001453 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001454 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001455 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1457
1458 if (!half_gi)
1459 duration = SYMBOL_TIME(nsymbols);
1460 else
1461 duration = SYMBOL_TIME_HALFGI(nsymbols);
1462
Sujithe63835b2008-11-18 09:07:53 +05301463 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301465
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001466 return duration;
1467}
1468
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001469static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1470{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001471 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001472 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301473 struct sk_buff *skb;
1474 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301475 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001476 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301477 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301478 int i, flags = 0;
1479 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301480 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301481
1482 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301483
Sujitha22be222009-03-30 15:28:36 +05301484 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301485 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301486 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301487 hdr = (struct ieee80211_hdr *)skb->data;
1488 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301489
Sujithc89424d2009-01-30 14:29:28 +05301490 /*
1491 * We check if Short Preamble is needed for the CTS rate by
1492 * checking the BSS's global flag.
1493 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1494 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001495 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1496 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301497 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001498 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001499
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001500 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001501 bool is_40, is_sgi, is_sp;
1502 int phy;
1503
Sujithe63835b2008-11-18 09:07:53 +05301504 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505 continue;
1506
Sujitha8efee42008-11-18 09:07:30 +05301507 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301508 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001509 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001510
Felix Fietkau27032052010-01-17 21:08:50 +01001511 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1512 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301513 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001514 flags |= ATH9K_TXDESC_RTSENA;
1515 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1516 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1517 flags |= ATH9K_TXDESC_CTSENA;
1518 }
1519
Sujithc89424d2009-01-30 14:29:28 +05301520 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1521 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1522 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1523 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001524
Felix Fietkau545750d2009-11-23 22:21:01 +01001525 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1526 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1527 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1528
1529 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1530 /* MCS rates */
1531 series[i].Rate = rix | 0x80;
1532 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1533 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001534 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1535 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001536 continue;
1537 }
1538
1539 /* legcay rates */
1540 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1541 !(rate->flags & IEEE80211_RATE_ERP_G))
1542 phy = WLAN_RC_PHY_CCK;
1543 else
1544 phy = WLAN_RC_PHY_OFDM;
1545
1546 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1547 series[i].Rate = rate->hw_value;
1548 if (rate->hw_value_short) {
1549 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1550 series[i].Rate |= rate->hw_value_short;
1551 } else {
1552 is_sp = false;
1553 }
1554
1555 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1556 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001557 }
1558
Felix Fietkau27032052010-01-17 21:08:50 +01001559 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1560 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1561 flags &= ~ATH9K_TXDESC_RTSENA;
1562
1563 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1564 if (flags & ATH9K_TXDESC_RTSENA)
1565 flags &= ~ATH9K_TXDESC_CTSENA;
1566
Sujithe63835b2008-11-18 09:07:53 +05301567 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301568 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1569 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301570 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301571 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301572
Sujith17d79042009-02-09 13:27:03 +05301573 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301574 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001575}
1576
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001577static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
Sujithe8324352009-01-16 21:38:42 +05301578 struct sk_buff *skb,
1579 struct ath_tx_control *txctl)
1580{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001581 struct ath_wiphy *aphy = hw->priv;
1582 struct ath_softc *sc = aphy->sc;
Sujithe8324352009-01-16 21:38:42 +05301583 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1584 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301585 int hdrlen;
1586 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001587 int padpos, padsize;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001588 bool use_ldpc = false;
Sujithe8324352009-01-16 21:38:42 +05301589
Felix Fietkau827e69b2009-11-15 23:09:25 +01001590 tx_info->pad[0] = 0;
1591 switch (txctl->frame_type) {
Pavel Roskinc81494d2010-03-31 18:05:25 -04001592 case ATH9K_IFT_NOT_INTERNAL:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001593 break;
Pavel Roskinc81494d2010-03-31 18:05:25 -04001594 case ATH9K_IFT_PAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001595 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
1596 /* fall through */
Pavel Roskinc81494d2010-03-31 18:05:25 -04001597 case ATH9K_IFT_UNPAUSE:
Felix Fietkau827e69b2009-11-15 23:09:25 +01001598 tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
1599 break;
1600 }
Sujithe8324352009-01-16 21:38:42 +05301601 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1602 fc = hdr->frame_control;
1603
1604 ATH_TXBUF_RESET(bf);
1605
Felix Fietkau827e69b2009-11-15 23:09:25 +01001606 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001607 bf->bf_frmlen = skb->len + FCS_LEN;
1608 /* Remove the padding size from bf_frmlen, if any */
1609 padpos = ath9k_cmn_padpos(hdr->frame_control);
1610 padsize = padpos & 3;
1611 if (padsize && skb->len>padpos+padsize) {
1612 bf->bf_frmlen -= padsize;
1613 }
Sujithe8324352009-01-16 21:38:42 +05301614
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001615 if (!txctl->paprd && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301616 bf->bf_state.bf_type |= BUF_HT;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001617 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
1618 use_ldpc = true;
1619 }
Sujithe8324352009-01-16 21:38:42 +05301620
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001621 bf->bf_state.bfs_paprd = txctl->paprd;
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001622 if (txctl->paprd)
1623 bf->bf_state.bfs_paprd_timestamp = jiffies;
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001624 bf->bf_flags = setup_tx_flags(skb, use_ldpc);
Sujithe8324352009-01-16 21:38:42 +05301625
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001626 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301627 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1628 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1629 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1630 } else {
1631 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1632 }
1633
Sujith17b182e2009-12-14 14:56:56 +05301634 if (ieee80211_is_data_qos(fc) && bf_isht(bf) &&
1635 (sc->sc_flags & SC_OP_TXAGGR))
Sujithe8324352009-01-16 21:38:42 +05301636 assign_aggr_tid_seqno(skb, bf);
1637
1638 bf->bf_mpdu = skb;
1639
1640 bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
1641 skb->len, DMA_TO_DEVICE);
1642 if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
1643 bf->bf_mpdu = NULL;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001644 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1645 "dma_mapping_error() on TX\n");
Sujithe8324352009-01-16 21:38:42 +05301646 return -ENOMEM;
1647 }
1648
1649 bf->bf_buf_addr = bf->bf_dmacontext;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001650
1651 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1652 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1653 bf->bf_isnullfunc = true;
Sujith1b04b932010-01-08 10:36:05 +05301654 sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001655 } else
1656 bf->bf_isnullfunc = false;
1657
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001658 bf->bf_tx_aborted = false;
1659
Sujithe8324352009-01-16 21:38:42 +05301660 return 0;
1661}
1662
1663/* FIXME: tx power */
1664static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1665 struct ath_tx_control *txctl)
1666{
Sujitha22be222009-03-30 15:28:36 +05301667 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301668 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301669 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301670 struct ath_node *an = NULL;
1671 struct list_head bf_head;
1672 struct ath_desc *ds;
1673 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301674 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301675 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301676 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301677
1678 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301679 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301680
1681 INIT_LIST_HEAD(&bf_head);
1682 list_add_tail(&bf->list, &bf_head);
1683
1684 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001685 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301686
1687 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1688 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1689
1690 ath9k_hw_filltxdesc(ah, ds,
1691 skb->len, /* segment length */
1692 true, /* first segment */
1693 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001694 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001695 bf->bf_buf_addr,
1696 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301697
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001698 if (bf->bf_state.bfs_paprd)
1699 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1700
Sujithe8324352009-01-16 21:38:42 +05301701 spin_lock_bh(&txctl->txq->axq_lock);
1702
1703 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1704 tx_info->control.sta) {
1705 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1706 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1707
Sujithc37452b2009-03-09 09:31:57 +05301708 if (!ieee80211_is_data_qos(fc)) {
1709 ath_tx_send_normal(sc, txctl->txq, &bf_head);
1710 goto tx_done;
1711 }
1712
Felix Fietkau4fdec032010-03-12 04:02:43 +01001713 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301714 /*
1715 * Try aggregation if it's a unicast data frame
1716 * and the destination is HT capable.
1717 */
1718 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1719 } else {
1720 /*
1721 * Send this frame as regular when ADDBA
1722 * exchange is neither complete nor pending.
1723 */
Sujithc37452b2009-03-09 09:31:57 +05301724 ath_tx_send_ht_normal(sc, txctl->txq,
1725 tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301726 }
1727 } else {
Sujithc37452b2009-03-09 09:31:57 +05301728 ath_tx_send_normal(sc, txctl->txq, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301729 }
1730
Sujithc37452b2009-03-09 09:31:57 +05301731tx_done:
Sujithe8324352009-01-16 21:38:42 +05301732 spin_unlock_bh(&txctl->txq->axq_lock);
1733}
1734
1735/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001736int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301737 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001738{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001739 struct ath_wiphy *aphy = hw->priv;
1740 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001741 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau84642d62010-06-01 21:33:13 +02001742 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001743 struct ath_buf *bf;
Felix Fietkau97923b12010-06-12 00:33:55 -04001744 int q, r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001745
Sujithe8324352009-01-16 21:38:42 +05301746 bf = ath_tx_get_buffer(sc);
1747 if (!bf) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001748 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
Sujithe8324352009-01-16 21:38:42 +05301749 return -1;
1750 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001751
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001752 r = ath_tx_setup_buffer(hw, bf, skb, txctl);
Sujithe8324352009-01-16 21:38:42 +05301753 if (unlikely(r)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001754 ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001755
Sujithe8324352009-01-16 21:38:42 +05301756 /* upon ath_tx_processq() this TX queue will be resumed, we
1757 * guarantee this will happen by knowing beforehand that
1758 * we will at least have to run TX completionon one buffer
1759 * on the queue */
1760 spin_lock_bh(&txq->axq_lock);
Felix Fietkau84642d62010-06-01 21:33:13 +02001761 if (!txq->stopped && txq->axq_depth > 1) {
Luis R. Rodriguezf52de032009-11-02 17:09:12 -08001762 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
Sujithe8324352009-01-16 21:38:42 +05301763 txq->stopped = 1;
1764 }
1765 spin_unlock_bh(&txq->axq_lock);
1766
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001767 ath_tx_return_buffer(sc, bf);
Sujithe8324352009-01-16 21:38:42 +05301768
1769 return r;
1770 }
1771
Felix Fietkau97923b12010-06-12 00:33:55 -04001772 q = skb_get_queue_mapping(skb);
1773 if (q >= 4)
1774 q = 0;
1775
1776 spin_lock_bh(&txq->axq_lock);
1777 if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
1778 ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
1779 txq->stopped = 1;
1780 }
1781 spin_unlock_bh(&txq->axq_lock);
1782
Sujithe8324352009-01-16 21:38:42 +05301783 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001784
1785 return 0;
1786}
1787
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001788void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001789{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001790 struct ath_wiphy *aphy = hw->priv;
1791 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001792 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001793 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1794 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301795 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1796 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001797
Sujithe8324352009-01-16 21:38:42 +05301798 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001799
Sujithe8324352009-01-16 21:38:42 +05301800 /*
1801 * As a temporary workaround, assign seq# here; this will likely need
1802 * to be cleaned up to work better with Beacon transmission and virtual
1803 * BSSes.
1804 */
1805 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301806 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1807 sc->tx.seq_no += 0x10;
1808 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1809 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001810 }
1811
Sujithe8324352009-01-16 21:38:42 +05301812 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001813 padpos = ath9k_cmn_padpos(hdr->frame_control);
1814 padsize = padpos & 3;
1815 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301816 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001817 ath_print(common, ATH_DBG_XMIT,
1818 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301819 dev_kfree_skb_any(skb);
1820 return;
1821 }
1822 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001823 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001824 }
1825
Sujithe8324352009-01-16 21:38:42 +05301826 txctl.txq = sc->beacon.cabq;
1827
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001828 ath_print(common, ATH_DBG_XMIT,
1829 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301830
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001831 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001832 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301833 goto exit;
1834 }
1835
1836 return;
1837exit:
1838 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001839}
1840
Sujithe8324352009-01-16 21:38:42 +05301841/*****************/
1842/* TX Completion */
1843/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001844
Sujithe8324352009-01-16 21:38:42 +05301845static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau827e69b2009-11-15 23:09:25 +01001846 struct ath_wiphy *aphy, int tx_flags)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001847{
Sujithe8324352009-01-16 21:38:42 +05301848 struct ieee80211_hw *hw = sc->hw;
1849 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001850 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001851 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001852 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301853
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001854 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301855
Felix Fietkau827e69b2009-11-15 23:09:25 +01001856 if (aphy)
1857 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301858
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301859 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301860 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301861
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301862 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301863 /* Frame was ACKed */
1864 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1865 }
1866
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001867 padpos = ath9k_cmn_padpos(hdr->frame_control);
1868 padsize = padpos & 3;
1869 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301870 /*
1871 * Remove MAC header padding before giving the frame back to
1872 * mac80211.
1873 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001874 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301875 skb_pull(skb, padsize);
1876 }
1877
Sujith1b04b932010-01-08 10:36:05 +05301878 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1879 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001880 ath_print(common, ATH_DBG_PS,
1881 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001882 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301883 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1884 PS_WAIT_FOR_CAB |
1885 PS_WAIT_FOR_PSPOLL_DATA |
1886 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001887 }
1888
Felix Fietkau827e69b2009-11-15 23:09:25 +01001889 if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
Jouni Malinenf0ed85c62009-03-03 19:23:31 +02001890 ath9k_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001891 else {
1892 q = skb_get_queue_mapping(skb);
1893 if (q >= 4)
1894 q = 0;
1895
1896 if (--sc->tx.pending_frames[q] < 0)
1897 sc->tx.pending_frames[q] = 0;
1898
Felix Fietkau827e69b2009-11-15 23:09:25 +01001899 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001900 }
Sujithe8324352009-01-16 21:38:42 +05301901}
1902
1903static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001904 struct ath_txq *txq, struct list_head *bf_q,
1905 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301906{
1907 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301908 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301909 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301910
Sujithe8324352009-01-16 21:38:42 +05301911 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301912 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301913
1914 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301915 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301916
1917 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301918 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301919 }
1920
1921 dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001922
1923 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001924 if (time_after(jiffies,
1925 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001926 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001927 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001928 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001929 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001930 } else {
1931 ath_tx_complete(sc, skb, bf->aphy, tx_flags);
1932 ath_debug_stat_tx(sc, txq, bf, ts);
1933 }
Sujithe8324352009-01-16 21:38:42 +05301934
1935 /*
1936 * Return the list of ath_buf of this mpdu to free queue
1937 */
1938 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1939 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1940 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1941}
1942
1943static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001944 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301945{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001946 u16 seq_st = 0;
1947 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301948 int ba_index;
1949 int nbad = 0;
1950 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001951
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001952 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301953 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301954
Sujithcd3d39a2008-08-11 14:03:34 +05301955 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001956 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001957 seq_st = ts->ts_seqnum;
1958 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001959 }
1960
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001961 while (bf) {
Sujithe8324352009-01-16 21:38:42 +05301962 ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
1963 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1964 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001965
Sujithe8324352009-01-16 21:38:42 +05301966 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001967 }
1968
Sujithe8324352009-01-16 21:38:42 +05301969 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001970}
1971
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001972static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301973 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301974{
Sujitha22be222009-03-30 15:28:36 +05301975 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301976 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301977 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001978 struct ieee80211_hw *hw = bf->aphy->hw;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301979 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301980
Sujith95e4acb2009-03-13 08:56:09 +05301981 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001982 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301983
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001984 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301985 WARN_ON(tx_rateindex >= hw->max_rates);
1986
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001987 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301988 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Felix Fietkaud9698472010-03-01 13:32:11 +01001989 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
1990 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301991
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001992 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301993 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Sujith254ad0f2009-02-04 08:10:19 +05301994 if (ieee80211_is_data(hdr->frame_control)) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001995 if (ts->ts_flags &
Felix Fietkau827e69b2009-11-15 23:09:25 +01001996 (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
1997 tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001998 if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
1999 (ts->ts_status & ATH9K_TXERR_FIFO))
Felix Fietkau827e69b2009-11-15 23:09:25 +01002000 tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
2001 tx_info->status.ampdu_len = bf->bf_nframes;
2002 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
Sujithc4288392008-11-18 09:09:30 +05302003 }
2004 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302005
Felix Fietkau545750d2009-11-23 22:21:01 +01002006 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302007 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01002008 tx_info->status.rates[i].idx = -1;
2009 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05302010
Felix Fietkau78c46532010-06-25 01:26:16 +02002011 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05302012}
2013
Sujith059d8062009-01-16 21:38:49 +05302014static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
2015{
2016 int qnum;
2017
Felix Fietkau97923b12010-06-12 00:33:55 -04002018 qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
2019 if (qnum == -1)
2020 return;
2021
Sujith059d8062009-01-16 21:38:49 +05302022 spin_lock_bh(&txq->axq_lock);
Felix Fietkau97923b12010-06-12 00:33:55 -04002023 if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07002024 if (ath_mac80211_start_queue(sc, qnum))
2025 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05302026 }
2027 spin_unlock_bh(&txq->axq_lock);
2028}
2029
Sujithc4288392008-11-18 09:09:30 +05302030static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002031{
Sujithcbe61d82009-02-09 13:27:12 +05302032 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002033 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002034 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2035 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302036 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002037 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302038 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002039 int status;
2040
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002041 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2042 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2043 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002044
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045 for (;;) {
2046 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002047 if (list_empty(&txq->axq_q)) {
2048 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049 spin_unlock_bh(&txq->axq_lock);
2050 break;
2051 }
2052 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2053
2054 /*
2055 * There is a race condition that a BH gets scheduled
2056 * after sw writes TxE and before hw re-load the last
2057 * descriptor to get the newly chained one.
2058 * Software must keep the last DONE descriptor as a
2059 * holding descriptor - software does so by marking
2060 * it with the STALE flag.
2061 */
2062 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302063 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002064 bf_held = bf;
2065 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302066 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002067 break;
2068 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302070 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002071 }
2072 }
2073
2074 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302075 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076
Felix Fietkau29bffa92010-03-29 20:14:23 -07002077 memset(&ts, 0, sizeof(ts));
2078 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002079 if (status == -EINPROGRESS) {
2080 spin_unlock_bh(&txq->axq_lock);
2081 break;
2082 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002083
2084 /*
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002085 * We now know the nullfunc frame has been ACKed so we
2086 * can disable RX.
2087 */
2088 if (bf->bf_isnullfunc &&
Felix Fietkau29bffa92010-03-29 20:14:23 -07002089 (ts.ts_status & ATH9K_TX_ACKED)) {
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05302090 if ((sc->ps_flags & PS_ENABLED))
2091 ath9k_enable_ps(sc);
2092 else
Sujith1b04b932010-01-08 10:36:05 +05302093 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05002094 }
2095
2096 /*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002097 * Remove ath_buf's of the same transmit unit from txq,
2098 * however leave the last descriptor back as the holding
2099 * descriptor for hw.
2100 */
Sujitha119cc42009-03-30 15:28:38 +05302101 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002102 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002103 if (!list_is_singular(&lastbf->list))
2104 list_cut_position(&bf_head,
2105 &txq->axq_q, lastbf->list.prev);
2106
2107 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002108 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002109 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002110 if (bf_held)
2111 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002112 spin_unlock_bh(&txq->axq_lock);
2113
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002114 if (bf_held)
2115 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002116
Sujithcd3d39a2008-08-11 14:03:34 +05302117 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002118 /*
2119 * This frame is sent out as a single frame.
2120 * Use hardware retry status for this frame.
2121 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002122 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302123 bf->bf_state.bf_type |= BUF_XRETRY;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002124 ath_tx_rc_status(bf, &ts, 0, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002125 }
Johannes Berge6a98542008-10-21 12:40:02 +02002126
Sujithcd3d39a2008-08-11 14:03:34 +05302127 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002128 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002129 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002130 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002131
Sujith059d8062009-01-16 21:38:49 +05302132 ath_wake_mac80211_queue(sc, txq);
2133
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002134 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302135 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002136 ath_txq_schedule(sc, txq);
2137 spin_unlock_bh(&txq->axq_lock);
2138 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002139}
2140
Sujith305fe472009-07-23 15:32:29 +05302141static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002142{
2143 struct ath_softc *sc = container_of(work, struct ath_softc,
2144 tx_complete_work.work);
2145 struct ath_txq *txq;
2146 int i;
2147 bool needreset = false;
2148
2149 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2150 if (ATH_TXQ_SETUP(sc, i)) {
2151 txq = &sc->tx.txq[i];
2152 spin_lock_bh(&txq->axq_lock);
2153 if (txq->axq_depth) {
2154 if (txq->axq_tx_inprogress) {
2155 needreset = true;
2156 spin_unlock_bh(&txq->axq_lock);
2157 break;
2158 } else {
2159 txq->axq_tx_inprogress = true;
2160 }
2161 }
2162 spin_unlock_bh(&txq->axq_lock);
2163 }
2164
2165 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002166 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2167 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302168 ath9k_ps_wakeup(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002169 ath_reset(sc, false);
Sujith332c5562009-10-09 09:51:28 +05302170 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002171 }
2172
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002173 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002174 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2175}
2176
2177
Sujithe8324352009-01-16 21:38:42 +05302178
2179void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002180{
Sujithe8324352009-01-16 21:38:42 +05302181 int i;
2182 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002183
Sujithe8324352009-01-16 21:38:42 +05302184 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002185
2186 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302187 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2188 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002189 }
2190}
2191
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002192void ath_tx_edma_tasklet(struct ath_softc *sc)
2193{
2194 struct ath_tx_status txs;
2195 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2196 struct ath_hw *ah = sc->sc_ah;
2197 struct ath_txq *txq;
2198 struct ath_buf *bf, *lastbf;
2199 struct list_head bf_head;
2200 int status;
2201 int txok;
2202
2203 for (;;) {
2204 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2205 if (status == -EINPROGRESS)
2206 break;
2207 if (status == -EIO) {
2208 ath_print(common, ATH_DBG_XMIT,
2209 "Error processing tx status\n");
2210 break;
2211 }
2212
2213 /* Skip beacon completions */
2214 if (txs.qid == sc->beacon.beaconq)
2215 continue;
2216
2217 txq = &sc->tx.txq[txs.qid];
2218
2219 spin_lock_bh(&txq->axq_lock);
2220 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2221 spin_unlock_bh(&txq->axq_lock);
2222 return;
2223 }
2224
2225 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2226 struct ath_buf, list);
2227 lastbf = bf->bf_lastbf;
2228
2229 INIT_LIST_HEAD(&bf_head);
2230 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2231 &lastbf->list);
2232 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2233 txq->axq_depth--;
2234 txq->axq_tx_inprogress = false;
2235 spin_unlock_bh(&txq->axq_lock);
2236
2237 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2238
Vasanthakumar Thiagarajande0f6482010-05-17 18:57:54 -07002239 /*
2240 * Make sure null func frame is acked before configuring
2241 * hw into ps mode.
2242 */
2243 if (bf->bf_isnullfunc && txok) {
2244 if ((sc->ps_flags & PS_ENABLED))
2245 ath9k_enable_ps(sc);
2246 else
2247 sc->ps_flags |= PS_NULLFUNC_COMPLETED;
2248 }
2249
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002250 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002251 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2252 bf->bf_state.bf_type |= BUF_XRETRY;
2253 ath_tx_rc_status(bf, &txs, 0, txok, true);
2254 }
2255
2256 if (bf_isampdu(bf))
2257 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2258 else
2259 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2260 &txs, txok, 0);
2261
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002262 ath_wake_mac80211_queue(sc, txq);
2263
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002264 spin_lock_bh(&txq->axq_lock);
2265 if (!list_empty(&txq->txq_fifo_pending)) {
2266 INIT_LIST_HEAD(&bf_head);
2267 bf = list_first_entry(&txq->txq_fifo_pending,
2268 struct ath_buf, list);
2269 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2270 &bf->bf_lastbf->list);
2271 ath_tx_txqaddbuf(sc, txq, &bf_head);
2272 } else if (sc->sc_flags & SC_OP_TXAGGR)
2273 ath_txq_schedule(sc, txq);
2274 spin_unlock_bh(&txq->axq_lock);
2275 }
2276}
2277
Sujithe8324352009-01-16 21:38:42 +05302278/*****************/
2279/* Init, Cleanup */
2280/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002281
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002282static int ath_txstatus_setup(struct ath_softc *sc, int size)
2283{
2284 struct ath_descdma *dd = &sc->txsdma;
2285 u8 txs_len = sc->sc_ah->caps.txs_len;
2286
2287 dd->dd_desc_len = size * txs_len;
2288 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2289 &dd->dd_desc_paddr, GFP_KERNEL);
2290 if (!dd->dd_desc)
2291 return -ENOMEM;
2292
2293 return 0;
2294}
2295
2296static int ath_tx_edma_init(struct ath_softc *sc)
2297{
2298 int err;
2299
2300 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2301 if (!err)
2302 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2303 sc->txsdma.dd_desc_paddr,
2304 ATH_TXSTATUS_RING_SIZE);
2305
2306 return err;
2307}
2308
2309static void ath_tx_edma_cleanup(struct ath_softc *sc)
2310{
2311 struct ath_descdma *dd = &sc->txsdma;
2312
2313 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2314 dd->dd_desc_paddr);
2315}
2316
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002317int ath_tx_init(struct ath_softc *sc, int nbufs)
2318{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002319 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002320 int error = 0;
2321
Sujith797fe5cb2009-03-30 15:28:45 +05302322 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002323
Sujith797fe5cb2009-03-30 15:28:45 +05302324 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002325 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302326 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002327 ath_print(common, ATH_DBG_FATAL,
2328 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302329 goto err;
2330 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002331
Sujith797fe5cb2009-03-30 15:28:45 +05302332 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002333 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302334 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002335 ath_print(common, ATH_DBG_FATAL,
2336 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302337 goto err;
2338 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002339
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002340 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2341
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002342 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2343 error = ath_tx_edma_init(sc);
2344 if (error)
2345 goto err;
2346 }
2347
Sujith797fe5cb2009-03-30 15:28:45 +05302348err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002349 if (error != 0)
2350 ath_tx_cleanup(sc);
2351
2352 return error;
2353}
2354
Sujith797fe5cb2009-03-30 15:28:45 +05302355void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002356{
Sujithb77f4832008-12-07 21:44:03 +05302357 if (sc->beacon.bdma.dd_desc_len != 0)
2358 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002359
Sujithb77f4832008-12-07 21:44:03 +05302360 if (sc->tx.txdma.dd_desc_len != 0)
2361 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002362
2363 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2364 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002365}
2366
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002367void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2368{
Sujithc5170162008-10-29 10:13:59 +05302369 struct ath_atx_tid *tid;
2370 struct ath_atx_ac *ac;
2371 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002372
Sujith8ee5afb2008-12-07 21:43:36 +05302373 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302374 tidno < WME_NUM_TID;
2375 tidno++, tid++) {
2376 tid->an = an;
2377 tid->tidno = tidno;
2378 tid->seq_start = tid->seq_next = 0;
2379 tid->baw_size = WME_MAX_BA;
2380 tid->baw_head = tid->baw_tail = 0;
2381 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302382 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302383 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302384 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302385 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302386 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302387 tid->state &= ~AGGR_ADDBA_COMPLETE;
2388 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302389 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002390
Sujith8ee5afb2008-12-07 21:43:36 +05302391 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302392 acno < WME_NUM_AC; acno++, ac++) {
2393 ac->sched = false;
Felix Fietkau1d2231e2010-06-12 00:33:51 -04002394 ac->qnum = sc->tx.hwq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302395 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002396 }
2397}
2398
Sujithb5aa9bf2008-10-29 10:13:31 +05302399void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002400{
Felix Fietkau2b409942010-07-07 19:42:08 +02002401 struct ath_atx_ac *ac;
2402 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002403 struct ath_txq *txq;
Felix Fietkau2b409942010-07-07 19:42:08 +02002404 int i, tidno;
Sujithe8324352009-01-16 21:38:42 +05302405
Felix Fietkau2b409942010-07-07 19:42:08 +02002406 for (tidno = 0, tid = &an->tid[tidno];
2407 tidno < WME_NUM_TID; tidno++, tid++) {
2408 i = tid->ac->qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002409
Felix Fietkau2b409942010-07-07 19:42:08 +02002410 if (!ATH_TXQ_SETUP(sc, i))
2411 continue;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002412
Felix Fietkau2b409942010-07-07 19:42:08 +02002413 txq = &sc->tx.txq[i];
2414 ac = tid->ac;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002415
Felix Fietkau2b409942010-07-07 19:42:08 +02002416 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002417
Felix Fietkau2b409942010-07-07 19:42:08 +02002418 if (tid->sched) {
2419 list_del(&tid->list);
2420 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002421 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002422
2423 if (ac->sched) {
2424 list_del(&ac->list);
2425 tid->ac->sched = false;
2426 }
2427
2428 ath_tid_drain(sc, txq, tid);
2429 tid->state &= ~AGGR_ADDBA_COMPLETE;
2430 tid->state &= ~AGGR_CLEANUP;
2431
2432 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002433 }
2434}