blob: 88efcc1671b1a75b39e36a20deb37ec9ebc6bbb6 [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
Felix Fietkau82b873a2010-11-11 03:18:37 +010051static void ath_tx_send_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);
Felix Fietkau269c44b2010-11-14 15:20:06 +010059static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
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{
Felix Fietkau066dae92010-11-07 14:59:39 +0100127 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530128
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
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100143static u16 ath_frame_seqno(struct sk_buff *skb)
144{
145 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
146 return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
147}
148
Sujithe8324352009-01-16 21:38:42 +0530149static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
150{
Felix Fietkau066dae92010-11-07 14:59:39 +0100151 struct ath_txq *txq = tid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530152 struct ath_buf *bf;
153 struct list_head bf_head;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200154 struct ath_tx_status ts;
155
Sujithe8324352009-01-16 21:38:42 +0530156 INIT_LIST_HEAD(&bf_head);
157
Felix Fietkau90fa5392010-09-20 13:45:38 +0200158 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530159 spin_lock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530160
161 while (!list_empty(&tid->buf_q)) {
162 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530163 list_move_tail(&bf->list, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200164
165 if (bf_isretried(bf)) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100166 ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu));
Felix Fietkau90fa5392010-09-20 13:45:38 +0200167 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
168 } else {
Felix Fietkau82b873a2010-11-11 03:18:37 +0100169 ath_tx_send_normal(sc, txq, tid, &bf_head);
Felix Fietkau90fa5392010-09-20 13:45:38 +0200170 }
Sujithe8324352009-01-16 21:38:42 +0530171 }
172
173 spin_unlock_bh(&txq->axq_lock);
174}
175
176static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
177 int seqno)
178{
179 int index, cindex;
180
181 index = ATH_BA_INDEX(tid->seq_start, seqno);
182 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
183
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200184 __clear_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530185
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200186 while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
Sujithe8324352009-01-16 21:38:42 +0530187 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
188 INCR(tid->baw_head, ATH_TID_MAX_BUFS);
189 }
190}
191
192static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100193 u16 seqno)
Sujithe8324352009-01-16 21:38:42 +0530194{
195 int index, cindex;
196
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100197 index = ATH_BA_INDEX(tid->seq_start, seqno);
Sujithe8324352009-01-16 21:38:42 +0530198 cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
Felix Fietkau81ee13b2010-09-20 13:45:36 +0200199 __set_bit(cindex, tid->tx_buf);
Sujithe8324352009-01-16 21:38:42 +0530200
201 if (index >= ((tid->baw_tail - tid->baw_head) &
202 (ATH_TID_MAX_BUFS - 1))) {
203 tid->baw_tail = cindex;
204 INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
205 }
206}
207
208/*
209 * TODO: For frame(s) that are in the retry state, we will reuse the
210 * sequence number(s) without setting the retry bit. The
211 * alternative is to give up on these and BAR the receiver's window
212 * forward.
213 */
214static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
215 struct ath_atx_tid *tid)
216
217{
218 struct ath_buf *bf;
219 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700220 struct ath_tx_status ts;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100221 u16 bf_seqno;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700222
223 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +0530224 INIT_LIST_HEAD(&bf_head);
225
226 for (;;) {
227 if (list_empty(&tid->buf_q))
228 break;
Sujithe8324352009-01-16 21:38:42 +0530229
Sujithd43f30152009-01-16 21:38:53 +0530230 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
231 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530232
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100233 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530234 if (bf_isretried(bf))
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100235 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530236
237 spin_unlock(&txq->axq_lock);
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700238 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +0530239 spin_lock(&txq->axq_lock);
240 }
241
242 tid->seq_next = tid->seq_start;
243 tid->baw_tail = tid->baw_head;
244}
245
Sujithfec247c2009-07-27 12:08:16 +0530246static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
247 struct ath_buf *bf)
Sujithe8324352009-01-16 21:38:42 +0530248{
249 struct sk_buff *skb;
250 struct ieee80211_hdr *hdr;
251
252 bf->bf_state.bf_type |= BUF_RETRY;
253 bf->bf_retries++;
Sujithfec247c2009-07-27 12:08:16 +0530254 TX_STAT_INC(txq->axq_qnum, a_retries);
Sujithe8324352009-01-16 21:38:42 +0530255
256 skb = bf->bf_mpdu;
257 hdr = (struct ieee80211_hdr *)skb->data;
258 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
259}
260
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200261static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
262{
263 struct ath_buf *bf = NULL;
264
265 spin_lock_bh(&sc->tx.txbuflock);
266
267 if (unlikely(list_empty(&sc->tx.txbuf))) {
268 spin_unlock_bh(&sc->tx.txbuflock);
269 return NULL;
270 }
271
272 bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
273 list_del(&bf->list);
274
275 spin_unlock_bh(&sc->tx.txbuflock);
276
277 return bf;
278}
279
280static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
281{
282 spin_lock_bh(&sc->tx.txbuflock);
283 list_add_tail(&bf->list, &sc->tx.txbuf);
284 spin_unlock_bh(&sc->tx.txbuflock);
285}
286
Sujithd43f30152009-01-16 21:38:53 +0530287static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
288{
289 struct ath_buf *tbf;
290
Felix Fietkau0a8cea82010-04-19 19:57:30 +0200291 tbf = ath_tx_get_buffer(sc);
292 if (WARN_ON(!tbf))
Vasanthakumar Thiagarajan8a460972009-06-10 17:50:09 +0530293 return NULL;
Sujithd43f30152009-01-16 21:38:53 +0530294
295 ATH_TXBUF_RESET(tbf);
296
Felix Fietkau827e69b2009-11-15 23:09:25 +0100297 tbf->aphy = bf->aphy;
Sujithd43f30152009-01-16 21:38:53 +0530298 tbf->bf_mpdu = bf->bf_mpdu;
299 tbf->bf_buf_addr = bf->bf_buf_addr;
Vasanthakumar Thiagarajand826c832010-04-15 17:38:45 -0400300 memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
Sujithd43f30152009-01-16 21:38:53 +0530301 tbf->bf_state = bf->bf_state;
Sujithd43f30152009-01-16 21:38:53 +0530302
303 return tbf;
304}
305
306static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
307 struct ath_buf *bf, struct list_head *bf_q,
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700308 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +0530309{
310 struct ath_node *an = NULL;
311 struct sk_buff *skb;
Sujith1286ec62009-01-27 13:30:37 +0530312 struct ieee80211_sta *sta;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800313 struct ieee80211_hw *hw;
Sujith1286ec62009-01-27 13:30:37 +0530314 struct ieee80211_hdr *hdr;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800315 struct ieee80211_tx_info *tx_info;
Sujithe8324352009-01-16 21:38:42 +0530316 struct ath_atx_tid *tid = NULL;
Sujithd43f30152009-01-16 21:38:53 +0530317 struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +0530318 struct list_head bf_head, bf_pending;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530319 u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
Sujithe8324352009-01-16 21:38:42 +0530320 u32 ba[WME_BA_BMP_SIZE >> 5];
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530321 int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
322 bool rc_update = true;
Felix Fietkau78c46532010-06-25 01:26:16 +0200323 struct ieee80211_tx_rate rates[4];
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100324 u16 bf_seqno;
Björn Smedmanebd02282010-10-10 22:44:39 +0200325 int nframes;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100326 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +0530327
Sujitha22be222009-03-30 15:28:36 +0530328 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530329 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530330
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800331 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100332 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800333
Felix Fietkau78c46532010-06-25 01:26:16 +0200334 memcpy(rates, tx_info->control.rates, sizeof(rates));
Björn Smedmanebd02282010-10-10 22:44:39 +0200335 nframes = bf->bf_nframes;
Felix Fietkau78c46532010-06-25 01:26:16 +0200336
Sujith1286ec62009-01-27 13:30:37 +0530337 rcu_read_lock();
338
Ben Greear686b9cb2010-09-23 09:44:36 -0700339 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530340 if (!sta) {
341 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200342
Felix Fietkau31e79a52010-07-12 23:16:34 +0200343 INIT_LIST_HEAD(&bf_head);
344 while (bf) {
345 bf_next = bf->bf_next;
346
347 bf->bf_state.bf_type |= BUF_XRETRY;
348 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
349 !bf->bf_stale || bf_next != NULL)
350 list_move_tail(&bf->list, &bf_head);
351
Björn Smedmanebd02282010-10-10 22:44:39 +0200352 ath_tx_rc_status(bf, ts, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200353 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
354 0, 0);
355
356 bf = bf_next;
357 }
Sujith1286ec62009-01-27 13:30:37 +0530358 return;
Sujithe8324352009-01-16 21:38:42 +0530359 }
360
Sujith1286ec62009-01-27 13:30:37 +0530361 an = (struct ath_node *)sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100362 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
363 tid = ATH_AN_2_TID(an, tidno);
Sujith1286ec62009-01-27 13:30:37 +0530364
Felix Fietkaub11b1602010-07-11 12:48:44 +0200365 /*
366 * The hardware occasionally sends a tx status for the wrong TID.
367 * In this case, the BA status cannot be considered valid and all
368 * subframes need to be retransmitted
369 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +0100370 if (tidno != ts->tid)
Felix Fietkaub11b1602010-07-11 12:48:44 +0200371 txok = false;
372
Sujithe8324352009-01-16 21:38:42 +0530373 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530374 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530375
Sujithd43f30152009-01-16 21:38:53 +0530376 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700377 if (ts->ts_flags & ATH9K_TX_BA) {
378 seq_st = ts->ts_seqnum;
379 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530380 } else {
Sujithd43f30152009-01-16 21:38:53 +0530381 /*
382 * AR5416 can become deaf/mute when BA
383 * issue happens. Chip needs to be reset.
384 * But AP code may have sychronization issues
385 * when perform internal reset in this routine.
386 * Only enable reset in STA mode for now.
387 */
Sujith2660b812009-02-09 13:27:26 +0530388 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530389 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530390 }
391 }
392
393 INIT_LIST_HEAD(&bf_pending);
394 INIT_LIST_HEAD(&bf_head);
395
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700396 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530397 while (bf) {
398 txfail = txpending = 0;
399 bf_next = bf->bf_next;
400
Felix Fietkau78c46532010-06-25 01:26:16 +0200401 skb = bf->bf_mpdu;
402 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100403 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200404
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100405 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530406 /* transmit completion, subframe is
407 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530408 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530409 } else if (!isaggr && txok) {
410 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530411 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530412 } else {
Sujithe8324352009-01-16 21:38:42 +0530413 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400414 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530415 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530416 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530417 txpending = 1;
418 } else {
419 bf->bf_state.bf_type |= BUF_XRETRY;
420 txfail = 1;
421 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530422 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530423 }
424 } else {
425 /*
426 * cleanup in progress, just fail
427 * the un-acked sub-frames
428 */
429 txfail = 1;
430 }
431 }
432
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400433 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
434 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530435 /*
436 * Make sure the last desc is reclaimed if it
437 * not a holding desc.
438 */
439 if (!bf_last->bf_stale)
440 list_move_tail(&bf->list, &bf_head);
441 else
442 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530443 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700444 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530445 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530446 }
447
Felix Fietkau90fa5392010-09-20 13:45:38 +0200448 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530449 /*
450 * complete the acked-ones/xretried ones; update
451 * block-ack window
452 */
453 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100454 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530455 spin_unlock_bh(&txq->axq_lock);
456
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530457 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200458 memcpy(tx_info->control.rates, rates, sizeof(rates));
Björn Smedmanebd02282010-10-10 22:44:39 +0200459 bf->bf_nframes = nframes;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700460 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530461 rc_update = false;
462 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700463 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530464 }
465
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700466 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
467 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530468 } else {
Sujithd43f30152009-01-16 21:38:53 +0530469 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400470 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
471 if (bf->bf_next == NULL && bf_last->bf_stale) {
472 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530473
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400474 tbf = ath_clone_txbuf(sc, bf_last);
475 /*
476 * Update tx baw and complete the
477 * frame with failed status if we
478 * run out of tx buf.
479 */
480 if (!tbf) {
481 spin_lock_bh(&txq->axq_lock);
482 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100483 bf_seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400484 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400485
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400486 bf->bf_state.bf_type |=
487 BUF_XRETRY;
488 ath_tx_rc_status(bf, ts, nbad,
489 0, false);
490 ath_tx_complete_buf(sc, bf, txq,
491 &bf_head,
492 ts, 0, 0);
493 break;
494 }
495
496 ath9k_hw_cleartxdesc(sc->sc_ah,
497 tbf->bf_desc);
498 list_add_tail(&tbf->list, &bf_head);
499 } else {
500 /*
501 * Clear descriptor status words for
502 * software retry
503 */
504 ath9k_hw_cleartxdesc(sc->sc_ah,
505 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400506 }
Sujithe8324352009-01-16 21:38:42 +0530507 }
508
509 /*
510 * Put this buffer to the temporary pending
511 * queue to retain ordering
512 */
513 list_splice_tail_init(&bf_head, &bf_pending);
514 }
515
516 bf = bf_next;
517 }
518
Felix Fietkau4cee7862010-07-23 03:53:16 +0200519 /* prepend un-acked frames to the beginning of the pending frame queue */
520 if (!list_empty(&bf_pending)) {
521 spin_lock_bh(&txq->axq_lock);
522 list_splice(&bf_pending, &tid->buf_q);
523 ath_tx_queue_tid(txq, tid);
524 spin_unlock_bh(&txq->axq_lock);
525 }
526
Sujithe8324352009-01-16 21:38:42 +0530527 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200528 ath_tx_flush_tid(sc, tid);
529
Sujithe8324352009-01-16 21:38:42 +0530530 if (tid->baw_head == tid->baw_tail) {
531 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530532 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530533 }
Sujithe8324352009-01-16 21:38:42 +0530534 }
535
Sujith1286ec62009-01-27 13:30:37 +0530536 rcu_read_unlock();
537
Sujithe8324352009-01-16 21:38:42 +0530538 if (needreset)
539 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530540}
541
542static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
543 struct ath_atx_tid *tid)
544{
Sujithe8324352009-01-16 21:38:42 +0530545 struct sk_buff *skb;
546 struct ieee80211_tx_info *tx_info;
547 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530548 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530549 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530550 int i;
551
Sujitha22be222009-03-30 15:28:36 +0530552 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530553 tx_info = IEEE80211_SKB_CB(skb);
554 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530555
556 /*
557 * Find the lowest frame length among the rate series that will have a
558 * 4ms transmit duration.
559 * TODO - TXOP limit needs to be considered.
560 */
561 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
562
563 for (i = 0; i < 4; i++) {
564 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100565 int modeidx;
566 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530567 legacy = 1;
568 break;
569 }
570
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200571 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100572 modeidx = MCS_HT40;
573 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200574 modeidx = MCS_HT20;
575
576 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
577 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100578
579 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530580 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530581 }
582 }
583
584 /*
585 * limit aggregate size by the minimum rate if rate selected is
586 * not a probe rate, if rate selected is a probe rate then
587 * avoid aggregation of this packet.
588 */
589 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
590 return 0;
591
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530592 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
593 aggr_limit = min((max_4ms_framelen * 3) / 8,
594 (u32)ATH_AMPDU_LIMIT_MAX);
595 else
596 aggr_limit = min(max_4ms_framelen,
597 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530598
599 /*
600 * h/w can accept aggregates upto 16 bit lengths (65535).
601 * The IE, however can hold upto 65536, which shows up here
602 * as zero. Ignore 65536 since we are constrained by hw.
603 */
Sujith4ef70842009-07-23 15:32:41 +0530604 if (tid->an->maxampdu)
605 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530606
607 return aggr_limit;
608}
609
610/*
Sujithd43f30152009-01-16 21:38:53 +0530611 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530612 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530613 */
614static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
615 struct ath_buf *bf, u16 frmlen)
616{
Sujithe8324352009-01-16 21:38:42 +0530617 struct sk_buff *skb = bf->bf_mpdu;
618 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530619 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530620 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100621 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200622 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530623
624 /* Select standard number of delimiters based on frame length alone */
625 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
626
627 /*
628 * If encryption enabled, hardware requires some more padding between
629 * subframes.
630 * TODO - this could be improved to be dependent on the rate.
631 * The hardware can keep up at lower rates, but not higher rates
632 */
Felix Fietkau952cd692010-11-14 15:20:03 +0100633 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +0530634 ndelim += ATH_AGGR_ENCRYPTDELIM;
635
636 /*
637 * Convert desired mpdu density from microeconds to bytes based
638 * on highest rate in rate series (i.e. first rate) to determine
639 * required minimum length for subframe. Take into account
640 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530641 *
Sujithe8324352009-01-16 21:38:42 +0530642 * If there is no mpdu density restriction, no further calculation
643 * is needed.
644 */
Sujith4ef70842009-07-23 15:32:41 +0530645
646 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530647 return ndelim;
648
649 rix = tx_info->control.rates[0].idx;
650 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530651 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
652 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
653
654 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530655 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530656 else
Sujith4ef70842009-07-23 15:32:41 +0530657 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530658
659 if (nsymbols == 0)
660 nsymbols = 1;
661
Felix Fietkauc6663872010-04-19 19:57:33 +0200662 streams = HT_RC_2_STREAMS(rix);
663 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530664 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
665
Sujithe8324352009-01-16 21:38:42 +0530666 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530667 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
668 ndelim = max(mindelim, ndelim);
669 }
670
671 return ndelim;
672}
673
674static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530675 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530676 struct ath_atx_tid *tid,
Felix Fietkau269c44b2010-11-14 15:20:06 +0100677 struct list_head *bf_q,
678 int *aggr_len)
Sujithe8324352009-01-16 21:38:42 +0530679{
680#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530681 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
682 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530683 u16 aggr_limit = 0, al = 0, bpad = 0,
684 al_delta, h_baw = tid->baw_size / 2;
685 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200686 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100687 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530688
689 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
690
691 do {
692 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100693 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530694
Sujithd43f30152009-01-16 21:38:53 +0530695 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100696 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530697 status = ATH_AGGR_BAW_CLOSED;
698 break;
699 }
700
701 if (!rl) {
702 aggr_limit = ath_lookup_rate(sc, bf, tid);
703 rl = 1;
704 }
705
Sujithd43f30152009-01-16 21:38:53 +0530706 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530707 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
708
Sujithd43f30152009-01-16 21:38:53 +0530709 if (nframes &&
710 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530711 status = ATH_AGGR_LIMITED;
712 break;
713 }
714
Felix Fietkau0299a502010-10-21 02:47:24 +0200715 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
716 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
717 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
718 break;
719
Sujithd43f30152009-01-16 21:38:53 +0530720 /* do not exceed subframe limit */
721 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530722 status = ATH_AGGR_LIMITED;
723 break;
724 }
Sujithd43f30152009-01-16 21:38:53 +0530725 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530726
Sujithd43f30152009-01-16 21:38:53 +0530727 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530728 al += bpad + al_delta;
729
730 /*
731 * Get the delimiters needed to meet the MPDU
732 * density for this node.
733 */
734 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530735 bpad = PADBYTES(al_delta) + (ndelim << 2);
736
737 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400738 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530739
Sujithd43f30152009-01-16 21:38:53 +0530740 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100741 if (!bf_isretried(bf))
742 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530743 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
744 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530745 if (bf_prev) {
746 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400747 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
748 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530749 }
750 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530751
Sujithe8324352009-01-16 21:38:42 +0530752 } while (!list_empty(&tid->buf_q));
753
Felix Fietkau269c44b2010-11-14 15:20:06 +0100754 *aggr_len = al;
Sujithe8324352009-01-16 21:38:42 +0530755 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530756
Sujithe8324352009-01-16 21:38:42 +0530757 return status;
758#undef PADBYTES
759}
760
761static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
762 struct ath_atx_tid *tid)
763{
Sujithd43f30152009-01-16 21:38:53 +0530764 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530765 enum ATH_AGGR_STATUS status;
766 struct list_head bf_q;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100767 int aggr_len;
Sujithe8324352009-01-16 21:38:42 +0530768
769 do {
770 if (list_empty(&tid->buf_q))
771 return;
772
773 INIT_LIST_HEAD(&bf_q);
774
Felix Fietkau269c44b2010-11-14 15:20:06 +0100775 status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530776
777 /*
Sujithd43f30152009-01-16 21:38:53 +0530778 * no frames picked up to be aggregated;
779 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530780 */
781 if (list_empty(&bf_q))
782 break;
783
784 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530785 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530786
Sujithd43f30152009-01-16 21:38:53 +0530787 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530788 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530789 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530790 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Felix Fietkau269c44b2010-11-14 15:20:06 +0100791 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530792 ath_tx_txqaddbuf(sc, txq, &bf_q);
793 continue;
794 }
795
Sujithd43f30152009-01-16 21:38:53 +0530796 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530797 bf->bf_state.bf_type |= BUF_AGGR;
Felix Fietkau269c44b2010-11-14 15:20:06 +0100798 ath_buf_set_rate(sc, bf, aggr_len);
799 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len);
Sujithe8324352009-01-16 21:38:42 +0530800
Sujithd43f30152009-01-16 21:38:53 +0530801 /* anchor last desc of aggregate */
802 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530803
Sujithe8324352009-01-16 21:38:42 +0530804 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530805 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530806
807 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
808 status != ATH_AGGR_BAW_CLOSED);
809}
810
Felix Fietkau231c3a12010-09-20 19:35:28 +0200811int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
812 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530813{
814 struct ath_atx_tid *txtid;
815 struct ath_node *an;
816
817 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530818 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200819
820 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
821 return -EAGAIN;
822
Sujithf83da962009-07-23 15:32:37 +0530823 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200824 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530825 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200826
827 return 0;
Sujithe8324352009-01-16 21:38:42 +0530828}
829
Sujithf83da962009-07-23 15:32:37 +0530830void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530831{
832 struct ath_node *an = (struct ath_node *)sta->drv_priv;
833 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100834 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530835
836 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530837 return;
Sujithe8324352009-01-16 21:38:42 +0530838
839 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530840 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530841 return;
Sujithe8324352009-01-16 21:38:42 +0530842 }
843
Sujithe8324352009-01-16 21:38:42 +0530844 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200845 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200846
847 /*
848 * If frames are still being transmitted for this TID, they will be
849 * cleaned up during tx completion. To prevent race conditions, this
850 * TID can only be reused after all in-progress subframes have been
851 * completed.
852 */
853 if (txtid->baw_head != txtid->baw_tail)
854 txtid->state |= AGGR_CLEANUP;
855 else
856 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530857 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530858
Felix Fietkau90fa5392010-09-20 13:45:38 +0200859 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530860}
861
862void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
863{
864 struct ath_atx_tid *txtid;
865 struct ath_node *an;
866
867 an = (struct ath_node *)sta->drv_priv;
868
869 if (sc->sc_flags & SC_OP_TXAGGR) {
870 txtid = ATH_AN_2_TID(an, tid);
871 txtid->baw_size =
872 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
873 txtid->state |= AGGR_ADDBA_COMPLETE;
874 txtid->state &= ~AGGR_ADDBA_PROGRESS;
875 ath_tx_resume_tid(sc, txtid);
876 }
877}
878
Sujithe8324352009-01-16 21:38:42 +0530879/********************/
880/* Queue Management */
881/********************/
882
Sujithe8324352009-01-16 21:38:42 +0530883static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
884 struct ath_txq *txq)
885{
886 struct ath_atx_ac *ac, *ac_tmp;
887 struct ath_atx_tid *tid, *tid_tmp;
888
889 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
890 list_del(&ac->list);
891 ac->sched = false;
892 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
893 list_del(&tid->list);
894 tid->sched = false;
895 ath_tid_drain(sc, txq, tid);
896 }
897 }
898}
899
900struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
901{
Sujithcbe61d82009-02-09 13:27:12 +0530902 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700903 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530904 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100905 static const int subtype_txq_to_hwq[] = {
906 [WME_AC_BE] = ATH_TXQ_AC_BE,
907 [WME_AC_BK] = ATH_TXQ_AC_BK,
908 [WME_AC_VI] = ATH_TXQ_AC_VI,
909 [WME_AC_VO] = ATH_TXQ_AC_VO,
910 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400911 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530912
913 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100914 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530915 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
916 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
917 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
918 qi.tqi_physCompBuf = 0;
919
920 /*
921 * Enable interrupts only for EOL and DESC conditions.
922 * We mark tx descriptors to receive a DESC interrupt
923 * when a tx queue gets deep; otherwise waiting for the
924 * EOL to reap descriptors. Note that this is done to
925 * reduce interrupt load and this only defers reaping
926 * descriptors, never transmitting frames. Aside from
927 * reducing interrupts this also permits more concurrency.
928 * The only potential downside is if the tx queue backs
929 * up in which case the top half of the kernel may backup
930 * due to a lack of tx descriptors.
931 *
932 * The UAPSD queue is an exception, since we take a desc-
933 * based intr on the EOSP frames.
934 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400935 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
936 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
937 TXQ_FLAG_TXERRINT_ENABLE;
938 } else {
939 if (qtype == ATH9K_TX_QUEUE_UAPSD)
940 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
941 else
942 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
943 TXQ_FLAG_TXDESCINT_ENABLE;
944 }
Sujithe8324352009-01-16 21:38:42 +0530945 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
946 if (qnum == -1) {
947 /*
948 * NB: don't print a message, this happens
949 * normally on parts with too few tx queues
950 */
951 return NULL;
952 }
953 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700954 ath_print(common, ATH_DBG_FATAL,
955 "qnum %u out of range, max %u!\n",
956 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530957 ath9k_hw_releasetxqueue(ah, qnum);
958 return NULL;
959 }
960 if (!ATH_TXQ_SETUP(sc, qnum)) {
961 struct ath_txq *txq = &sc->tx.txq[qnum];
962
963 txq->axq_qnum = qnum;
964 txq->axq_link = NULL;
965 INIT_LIST_HEAD(&txq->axq_q);
966 INIT_LIST_HEAD(&txq->axq_acq);
967 spin_lock_init(&txq->axq_lock);
968 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400969 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530970 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400971
972 txq->txq_headidx = txq->txq_tailidx = 0;
973 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
974 INIT_LIST_HEAD(&txq->txq_fifo[i]);
975 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530976 }
977 return &sc->tx.txq[qnum];
978}
979
Sujithe8324352009-01-16 21:38:42 +0530980int ath_txq_update(struct ath_softc *sc, int qnum,
981 struct ath9k_tx_queue_info *qinfo)
982{
Sujithcbe61d82009-02-09 13:27:12 +0530983 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530984 int error = 0;
985 struct ath9k_tx_queue_info qi;
986
987 if (qnum == sc->beacon.beaconq) {
988 /*
989 * XXX: for beacon queue, we just save the parameter.
990 * It will be picked up by ath_beaconq_config when
991 * it's necessary.
992 */
993 sc->beacon.beacon_qi = *qinfo;
994 return 0;
995 }
996
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700997 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530998
999 ath9k_hw_get_txq_props(ah, qnum, &qi);
1000 qi.tqi_aifs = qinfo->tqi_aifs;
1001 qi.tqi_cwmin = qinfo->tqi_cwmin;
1002 qi.tqi_cwmax = qinfo->tqi_cwmax;
1003 qi.tqi_burstTime = qinfo->tqi_burstTime;
1004 qi.tqi_readyTime = qinfo->tqi_readyTime;
1005
1006 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001007 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1008 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301009 error = -EIO;
1010 } else {
1011 ath9k_hw_resettxqueue(ah, qnum);
1012 }
1013
1014 return error;
1015}
1016
1017int ath_cabq_update(struct ath_softc *sc)
1018{
1019 struct ath9k_tx_queue_info qi;
1020 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301021
1022 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1023 /*
1024 * Ensure the readytime % is within the bounds.
1025 */
Sujith17d79042009-02-09 13:27:03 +05301026 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1027 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1028 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1029 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301030
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001031 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301032 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301033 ath_txq_update(sc, qnum, &qi);
1034
1035 return 0;
1036}
1037
Sujith043a0402009-01-16 21:38:47 +05301038/*
1039 * Drain a given TX queue (could be Beacon or Data)
1040 *
1041 * This assumes output has been stopped and
1042 * we do not need to block ath_tx_tasklet.
1043 */
1044void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301045{
1046 struct ath_buf *bf, *lastbf;
1047 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001048 struct ath_tx_status ts;
1049
1050 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301051 INIT_LIST_HEAD(&bf_head);
1052
Sujithe8324352009-01-16 21:38:42 +05301053 for (;;) {
1054 spin_lock_bh(&txq->axq_lock);
1055
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001056 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1057 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1058 txq->txq_headidx = txq->txq_tailidx = 0;
1059 spin_unlock_bh(&txq->axq_lock);
1060 break;
1061 } else {
1062 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1063 struct ath_buf, list);
1064 }
1065 } else {
1066 if (list_empty(&txq->axq_q)) {
1067 txq->axq_link = NULL;
1068 spin_unlock_bh(&txq->axq_lock);
1069 break;
1070 }
1071 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1072 list);
Sujithe8324352009-01-16 21:38:42 +05301073
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001074 if (bf->bf_stale) {
1075 list_del(&bf->list);
1076 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301077
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001078 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001079 continue;
1080 }
Sujithe8324352009-01-16 21:38:42 +05301081 }
1082
1083 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001084 if (!retry_tx)
1085 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301086
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001087 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1088 list_cut_position(&bf_head,
1089 &txq->txq_fifo[txq->txq_tailidx],
1090 &lastbf->list);
1091 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1092 } else {
1093 /* remove ath_buf's of the same mpdu from txq */
1094 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1095 }
1096
Sujithe8324352009-01-16 21:38:42 +05301097 txq->axq_depth--;
1098
1099 spin_unlock_bh(&txq->axq_lock);
1100
1101 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001102 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301103 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001104 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301105 }
1106
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001107 spin_lock_bh(&txq->axq_lock);
1108 txq->axq_tx_inprogress = false;
1109 spin_unlock_bh(&txq->axq_lock);
1110
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001111 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1112 spin_lock_bh(&txq->axq_lock);
1113 while (!list_empty(&txq->txq_fifo_pending)) {
1114 bf = list_first_entry(&txq->txq_fifo_pending,
1115 struct ath_buf, list);
1116 list_cut_position(&bf_head,
1117 &txq->txq_fifo_pending,
1118 &bf->bf_lastbf->list);
1119 spin_unlock_bh(&txq->axq_lock);
1120
1121 if (bf_isampdu(bf))
1122 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1123 &ts, 0);
1124 else
1125 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1126 &ts, 0, 0);
1127 spin_lock_bh(&txq->axq_lock);
1128 }
1129 spin_unlock_bh(&txq->axq_lock);
1130 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001131
1132 /* flush any pending frames if aggregation is enabled */
1133 if (sc->sc_flags & SC_OP_TXAGGR) {
1134 if (!retry_tx) {
1135 spin_lock_bh(&txq->axq_lock);
1136 ath_txq_drain_pending_buffers(sc, txq);
1137 spin_unlock_bh(&txq->axq_lock);
1138 }
1139 }
Sujithe8324352009-01-16 21:38:42 +05301140}
1141
Sujith043a0402009-01-16 21:38:47 +05301142void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1143{
Sujithcbe61d82009-02-09 13:27:12 +05301144 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001145 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301146 struct ath_txq *txq;
1147 int i, npend = 0;
1148
1149 if (sc->sc_flags & SC_OP_INVALID)
1150 return;
1151
1152 /* Stop beacon queue */
1153 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1154
1155 /* Stop data queues */
1156 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1157 if (ATH_TXQ_SETUP(sc, i)) {
1158 txq = &sc->tx.txq[i];
1159 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1160 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1161 }
1162 }
1163
1164 if (npend) {
1165 int r;
1166
Sujithe8009e92009-12-14 14:57:08 +05301167 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001168 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301169
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001170 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301171 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001172 ath_print(common, ATH_DBG_FATAL,
1173 "Unable to reset hardware; reset status %d\n",
1174 r);
Sujith043a0402009-01-16 21:38:47 +05301175 }
1176
1177 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1178 if (ATH_TXQ_SETUP(sc, i))
1179 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1180 }
1181}
1182
Sujithe8324352009-01-16 21:38:42 +05301183void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1184{
1185 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1186 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1187}
1188
Sujithe8324352009-01-16 21:38:42 +05301189void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1190{
1191 struct ath_atx_ac *ac;
1192 struct ath_atx_tid *tid;
1193
1194 if (list_empty(&txq->axq_acq))
1195 return;
1196
1197 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1198 list_del(&ac->list);
1199 ac->sched = false;
1200
1201 do {
1202 if (list_empty(&ac->tid_q))
1203 return;
1204
1205 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1206 list_del(&tid->list);
1207 tid->sched = false;
1208
1209 if (tid->paused)
1210 continue;
1211
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001212 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301213
1214 /*
1215 * add tid to round-robin queue if more frames
1216 * are pending for the tid
1217 */
1218 if (!list_empty(&tid->buf_q))
1219 ath_tx_queue_tid(txq, tid);
1220
1221 break;
1222 } while (!list_empty(&ac->tid_q));
1223
1224 if (!list_empty(&ac->tid_q)) {
1225 if (!ac->sched) {
1226 ac->sched = true;
1227 list_add_tail(&ac->list, &txq->axq_acq);
1228 }
1229 }
1230}
1231
Sujithe8324352009-01-16 21:38:42 +05301232/***********/
1233/* TX, DMA */
1234/***********/
1235
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001236/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001237 * Insert a chain of ath_buf (descriptors) on a txq and
1238 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001239 */
Sujith102e0572008-10-29 10:15:16 +05301240static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1241 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001242{
Sujithcbe61d82009-02-09 13:27:12 +05301243 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001244 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001245 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301246
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001247 /*
1248 * Insert the frame on the outbound list and
1249 * pass it on to the hardware.
1250 */
1251
1252 if (list_empty(head))
1253 return;
1254
1255 bf = list_first_entry(head, struct ath_buf, list);
1256
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001257 ath_print(common, ATH_DBG_QUEUE,
1258 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001259
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001260 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1261 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1262 list_splice_tail_init(head, &txq->txq_fifo_pending);
1263 return;
1264 }
1265 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1266 ath_print(common, ATH_DBG_XMIT,
1267 "Initializing tx fifo %d which "
1268 "is non-empty\n",
1269 txq->txq_headidx);
1270 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1271 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1272 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001274 ath_print(common, ATH_DBG_XMIT,
1275 "TXDP[%u] = %llx (%p)\n",
1276 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001277 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001278 list_splice_tail_init(head, &txq->axq_q);
1279
1280 if (txq->axq_link == NULL) {
1281 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1282 ath_print(common, ATH_DBG_XMIT,
1283 "TXDP[%u] = %llx (%p)\n",
1284 txq->axq_qnum, ito64(bf->bf_daddr),
1285 bf->bf_desc);
1286 } else {
1287 *txq->axq_link = bf->bf_daddr;
1288 ath_print(common, ATH_DBG_XMIT,
1289 "link[%u] (%p)=%llx (%p)\n",
1290 txq->axq_qnum, txq->axq_link,
1291 ito64(bf->bf_daddr), bf->bf_desc);
1292 }
1293 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1294 &txq->axq_link);
1295 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001296 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001297 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001298}
1299
Sujithe8324352009-01-16 21:38:42 +05301300static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1301 struct list_head *bf_head,
1302 struct ath_tx_control *txctl)
1303{
1304 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001305 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301306
Sujithe8324352009-01-16 21:38:42 +05301307 bf = list_first_entry(bf_head, struct ath_buf, list);
1308 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301309 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001310 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301311
1312 /*
1313 * Do not queue to h/w when any of the following conditions is true:
1314 * - there are pending frames in software queue
1315 * - the TID is currently paused for ADDBA/BAR request
1316 * - seqno is not within block-ack window
1317 * - h/w queue depth exceeds low water mark
1318 */
1319 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001320 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301321 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001322 /*
Sujithe8324352009-01-16 21:38:42 +05301323 * Add this frame to software queue for scheduling later
1324 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001325 */
Sujithd43f30152009-01-16 21:38:53 +05301326 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301327 ath_tx_queue_tid(txctl->txq, tid);
1328 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001329 }
1330
Sujithe8324352009-01-16 21:38:42 +05301331 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001332 if (!bf_isretried(bf))
1333 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301334
1335 /* Queue to h/w without aggregation */
1336 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301337 bf->bf_lastbf = bf;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001338 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +05301339 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301340}
1341
Felix Fietkau82b873a2010-11-11 03:18:37 +01001342static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1343 struct ath_atx_tid *tid,
1344 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001345{
Sujithe8324352009-01-16 21:38:42 +05301346 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001347
Sujithe8324352009-01-16 21:38:42 +05301348 bf = list_first_entry(bf_head, struct ath_buf, list);
1349 bf->bf_state.bf_type &= ~BUF_AMPDU;
1350
1351 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001352 if (tid)
1353 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301354
1355 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301356 bf->bf_lastbf = bf;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001357 ath_buf_set_rate(sc, bf, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +05301358 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301359 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001360}
1361
Sujith528f0c62008-10-29 10:14:26 +05301362static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001363{
Sujith528f0c62008-10-29 10:14:26 +05301364 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001365 enum ath9k_pkt_type htype;
1366 __le16 fc;
1367
Sujith528f0c62008-10-29 10:14:26 +05301368 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001369 fc = hdr->frame_control;
1370
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001371 if (ieee80211_is_beacon(fc))
1372 htype = ATH9K_PKT_TYPE_BEACON;
1373 else if (ieee80211_is_probe_resp(fc))
1374 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1375 else if (ieee80211_is_atim(fc))
1376 htype = ATH9K_PKT_TYPE_ATIM;
1377 else if (ieee80211_is_pspoll(fc))
1378 htype = ATH9K_PKT_TYPE_PSPOLL;
1379 else
1380 htype = ATH9K_PKT_TYPE_NORMAL;
1381
1382 return htype;
1383}
1384
Sujith528f0c62008-10-29 10:14:26 +05301385static void assign_aggr_tid_seqno(struct sk_buff *skb,
1386 struct ath_buf *bf)
1387{
1388 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1389 struct ieee80211_hdr *hdr;
1390 struct ath_node *an;
1391 struct ath_atx_tid *tid;
1392 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001393 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301394
1395 if (!tx_info->control.sta)
1396 return;
1397
1398 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1399 hdr = (struct ieee80211_hdr *)skb->data;
1400 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001401 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001402
Sujithe8324352009-01-16 21:38:42 +05301403 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001404 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301405 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301406 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001407 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301408 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301409 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301410}
1411
Felix Fietkau82b873a2010-11-11 03:18:37 +01001412static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301413{
1414 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1415 int flags = 0;
1416
1417 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1418 flags |= ATH9K_TXDESC_INTREQ;
1419
1420 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1421 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301422
Felix Fietkau82b873a2010-11-11 03:18:37 +01001423 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001424 flags |= ATH9K_TXDESC_LDPC;
1425
Sujith528f0c62008-10-29 10:14:26 +05301426 return flags;
1427}
1428
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001429/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001430 * rix - rate index
1431 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1432 * width - 0 for 20 MHz, 1 for 40 MHz
1433 * half_gi - to use 4us v/s 3.6 us for symbol time
1434 */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001435static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
Sujith102e0572008-10-29 10:15:16 +05301436 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001437{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001438 u32 nbits, nsymbits, duration, nsymbols;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001439 int streams;
Sujithe63835b2008-11-18 09:07:53 +05301440
1441 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001442 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001443 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001444 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001445 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1446
1447 if (!half_gi)
1448 duration = SYMBOL_TIME(nsymbols);
1449 else
1450 duration = SYMBOL_TIME_HALFGI(nsymbols);
1451
Sujithe63835b2008-11-18 09:07:53 +05301452 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001453 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301454
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001455 return duration;
1456}
1457
Felix Fietkau269c44b2010-11-14 15:20:06 +01001458static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001459{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001460 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001461 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301462 struct sk_buff *skb;
1463 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301464 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001465 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301466 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301467 int i, flags = 0;
1468 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301469 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301470
1471 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301472
Sujitha22be222009-03-30 15:28:36 +05301473 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301474 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301475 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301476 hdr = (struct ieee80211_hdr *)skb->data;
1477 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301478
Sujithc89424d2009-01-30 14:29:28 +05301479 /*
1480 * We check if Short Preamble is needed for the CTS rate by
1481 * checking the BSS's global flag.
1482 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1483 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001484 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1485 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301486 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001487 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001488
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001489 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001490 bool is_40, is_sgi, is_sp;
1491 int phy;
1492
Sujithe63835b2008-11-18 09:07:53 +05301493 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001494 continue;
1495
Sujitha8efee42008-11-18 09:07:30 +05301496 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301497 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001498 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001499
Felix Fietkau27032052010-01-17 21:08:50 +01001500 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1501 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301502 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001503 flags |= ATH9K_TXDESC_RTSENA;
1504 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1505 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1506 flags |= ATH9K_TXDESC_CTSENA;
1507 }
1508
Sujithc89424d2009-01-30 14:29:28 +05301509 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1510 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1511 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1512 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001513
Felix Fietkau545750d2009-11-23 22:21:01 +01001514 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1515 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1516 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1517
1518 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1519 /* MCS rates */
1520 series[i].Rate = rix | 0x80;
Felix Fietkau269c44b2010-11-14 15:20:06 +01001521 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
Felix Fietkau545750d2009-11-23 22:21:01 +01001522 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001523 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1524 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001525 continue;
1526 }
1527
1528 /* legcay rates */
1529 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1530 !(rate->flags & IEEE80211_RATE_ERP_G))
1531 phy = WLAN_RC_PHY_CCK;
1532 else
1533 phy = WLAN_RC_PHY_OFDM;
1534
1535 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1536 series[i].Rate = rate->hw_value;
1537 if (rate->hw_value_short) {
1538 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1539 series[i].Rate |= rate->hw_value_short;
1540 } else {
1541 is_sp = false;
1542 }
1543
1544 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
Felix Fietkau269c44b2010-11-14 15:20:06 +01001545 phy, rate->bitrate * 100, len, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001546 }
1547
Felix Fietkau27032052010-01-17 21:08:50 +01001548 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
Felix Fietkau269c44b2010-11-14 15:20:06 +01001549 if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
Felix Fietkau27032052010-01-17 21:08:50 +01001550 flags &= ~ATH9K_TXDESC_RTSENA;
1551
1552 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1553 if (flags & ATH9K_TXDESC_RTSENA)
1554 flags &= ~ATH9K_TXDESC_CTSENA;
1555
Sujithe63835b2008-11-18 09:07:53 +05301556 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301557 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1558 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301559 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301560 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301561
Sujith17d79042009-02-09 13:27:03 +05301562 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301563 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001564}
1565
Felix Fietkau82b873a2010-11-11 03:18:37 +01001566static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1567 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301568{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001569 struct ath_wiphy *aphy = hw->priv;
1570 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001571 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301572 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1573 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001574 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301575 int hdrlen;
1576 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001577 int padpos, padsize;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001578
1579 bf = ath_tx_get_buffer(sc);
1580 if (!bf) {
1581 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1582 return NULL;
1583 }
Sujithe8324352009-01-16 21:38:42 +05301584
Sujithe8324352009-01-16 21:38:42 +05301585 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1586 fc = hdr->frame_control;
1587
1588 ATH_TXBUF_RESET(bf);
1589
Felix Fietkau827e69b2009-11-15 23:09:25 +01001590 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001591 bf->bf_frmlen = skb->len + FCS_LEN;
1592 /* Remove the padding size from bf_frmlen, if any */
1593 padpos = ath9k_cmn_padpos(hdr->frame_control);
1594 padsize = padpos & 3;
1595 if (padsize && skb->len>padpos+padsize) {
1596 bf->bf_frmlen -= padsize;
1597 }
Sujithe8324352009-01-16 21:38:42 +05301598
Felix Fietkau82b873a2010-11-11 03:18:37 +01001599 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301600 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001601 if (sc->sc_flags & SC_OP_TXAGGR)
1602 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001603 }
Sujithe8324352009-01-16 21:38:42 +05301604
Felix Fietkau82b873a2010-11-11 03:18:37 +01001605 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301606
Felix Fietkau30170472010-11-14 15:20:05 +01001607 if (tx_info->control.hw_key)
Sujithe8324352009-01-16 21:38:42 +05301608 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
Sujithe8324352009-01-16 21:38:42 +05301609
Sujithe8324352009-01-16 21:38:42 +05301610 bf->bf_mpdu = skb;
1611
Ben Greearc1739eb32010-10-14 12:45:29 -07001612 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1613 skb->len, DMA_TO_DEVICE);
1614 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301615 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001616 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001617 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1618 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001619 ath_tx_return_buffer(sc, bf);
1620 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301621 }
1622
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001623 bf->bf_tx_aborted = false;
1624
Felix Fietkau82b873a2010-11-11 03:18:37 +01001625 return bf;
Sujithe8324352009-01-16 21:38:42 +05301626}
1627
1628/* FIXME: tx power */
1629static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1630 struct ath_tx_control *txctl)
1631{
Sujitha22be222009-03-30 15:28:36 +05301632 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301633 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301634 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301635 struct ath_node *an = NULL;
1636 struct list_head bf_head;
1637 struct ath_desc *ds;
1638 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301639 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001640 enum ath9k_key_type keytype;
Felix Fietkau30170472010-11-14 15:20:05 +01001641 u32 keyix;
Sujithe8324352009-01-16 21:38:42 +05301642 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301643 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001644 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301645
1646 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301647 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301648
1649 INIT_LIST_HEAD(&bf_head);
1650 list_add_tail(&bf->list, &bf_head);
1651
1652 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001653 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301654
Felix Fietkau952cd692010-11-14 15:20:03 +01001655 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Felix Fietkau30170472010-11-14 15:20:05 +01001656 if (tx_info->control.hw_key)
1657 keyix = tx_info->control.hw_key->hw_key_idx;
1658 else
1659 keyix = ATH9K_TXKEYIX_INVALID;
1660
Sujithe8324352009-01-16 21:38:42 +05301661 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau30170472010-11-14 15:20:05 +01001662 keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301663
1664 ath9k_hw_filltxdesc(ah, ds,
1665 skb->len, /* segment length */
1666 true, /* first segment */
1667 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001668 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001669 bf->bf_buf_addr,
1670 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301671
Sujithe8324352009-01-16 21:38:42 +05301672 spin_lock_bh(&txctl->txq->axq_lock);
1673
1674 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1675 tx_info->control.sta) {
1676 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001677 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1678 IEEE80211_QOS_CTL_TID_MASK;
1679 tid = ATH_AN_2_TID(an, tidno);
1680
Sujithe8324352009-01-16 21:38:42 +05301681
Felix Fietkau066dae92010-11-07 14:59:39 +01001682 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001683 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301684 /*
1685 * Try aggregation if it's a unicast data frame
1686 * and the destination is HT capable.
1687 */
1688 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1689 } else {
1690 /*
1691 * Send this frame as regular when ADDBA
1692 * exchange is neither complete nor pending.
1693 */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001694 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301695 }
1696 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001697 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001698 bf->bf_state.bfs_paprd = txctl->paprd;
1699
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001700 if (bf->bf_state.bfs_paprd)
1701 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1702
Felix Fietkau82b873a2010-11-11 03:18:37 +01001703 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301704 }
1705
1706 spin_unlock_bh(&txctl->txq->axq_lock);
1707}
1708
1709/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001710int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301711 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001712{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001713 struct ath_wiphy *aphy = hw->priv;
1714 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001715 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001716 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001717 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001718
Felix Fietkau82b873a2010-11-11 03:18:37 +01001719 bf = ath_tx_setup_buffer(hw, skb);
1720 if (unlikely(!bf))
1721 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001722
Felix Fietkau066dae92010-11-07 14:59:39 +01001723 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001724 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001725 if (txq == sc->tx.txq_map[q] &&
1726 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1727 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001728 txq->stopped = 1;
1729 }
1730 spin_unlock_bh(&txq->axq_lock);
1731
Sujithe8324352009-01-16 21:38:42 +05301732 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001733
1734 return 0;
1735}
1736
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001737void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
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);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001742 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1743 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301744 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1745 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001746
Sujithe8324352009-01-16 21:38:42 +05301747 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748
Sujithe8324352009-01-16 21:38:42 +05301749 /*
1750 * As a temporary workaround, assign seq# here; this will likely need
1751 * to be cleaned up to work better with Beacon transmission and virtual
1752 * BSSes.
1753 */
1754 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301755 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1756 sc->tx.seq_no += 0x10;
1757 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1758 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001759 }
1760
Sujithe8324352009-01-16 21:38:42 +05301761 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001762 padpos = ath9k_cmn_padpos(hdr->frame_control);
1763 padsize = padpos & 3;
1764 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301765 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001766 ath_print(common, ATH_DBG_XMIT,
1767 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301768 dev_kfree_skb_any(skb);
1769 return;
1770 }
1771 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001772 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001773 }
1774
Sujithe8324352009-01-16 21:38:42 +05301775 txctl.txq = sc->beacon.cabq;
1776
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001777 ath_print(common, ATH_DBG_XMIT,
1778 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301779
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001780 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001781 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301782 goto exit;
1783 }
1784
1785 return;
1786exit:
1787 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001788}
1789
Sujithe8324352009-01-16 21:38:42 +05301790/*****************/
1791/* TX Completion */
1792/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001793
Sujithe8324352009-01-16 21:38:42 +05301794static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001795 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001796 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001797{
Sujithe8324352009-01-16 21:38:42 +05301798 struct ieee80211_hw *hw = sc->hw;
1799 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001800 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001801 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001802 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301803
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001804 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301805
Felix Fietkau827e69b2009-11-15 23:09:25 +01001806 if (aphy)
1807 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301808
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301809 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301810 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301811
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301812 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301813 /* Frame was ACKed */
1814 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1815 }
1816
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001817 padpos = ath9k_cmn_padpos(hdr->frame_control);
1818 padsize = padpos & 3;
1819 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301820 /*
1821 * Remove MAC header padding before giving the frame back to
1822 * mac80211.
1823 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001824 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301825 skb_pull(skb, padsize);
1826 }
1827
Sujith1b04b932010-01-08 10:36:05 +05301828 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1829 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001830 ath_print(common, ATH_DBG_PS,
1831 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001832 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301833 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1834 PS_WAIT_FOR_CAB |
1835 PS_WAIT_FOR_PSPOLL_DATA |
1836 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001837 }
1838
Felix Fietkau61117f02010-11-11 03:18:36 +01001839 if (unlikely(ftype))
1840 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001841 else {
1842 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001843 if (txq == sc->tx.txq_map[q]) {
1844 spin_lock_bh(&txq->axq_lock);
1845 if (WARN_ON(--txq->pending_frames < 0))
1846 txq->pending_frames = 0;
1847 spin_unlock_bh(&txq->axq_lock);
1848 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001849
Felix Fietkau827e69b2009-11-15 23:09:25 +01001850 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001851 }
Sujithe8324352009-01-16 21:38:42 +05301852}
1853
1854static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001855 struct ath_txq *txq, struct list_head *bf_q,
1856 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301857{
1858 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301859 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301860 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301861
Sujithe8324352009-01-16 21:38:42 +05301862 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301863 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301864
1865 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301866 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301867
1868 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301869 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301870 }
1871
Ben Greearc1739eb32010-10-14 12:45:29 -07001872 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001873 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001874
1875 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001876 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001877 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001878 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001879 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001880 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001881 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001882 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1883 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001884 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001885 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1886 * accidentally reference it later.
1887 */
1888 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301889
1890 /*
1891 * Return the list of ath_buf of this mpdu to free queue
1892 */
1893 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1894 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1895 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1896}
1897
1898static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001899 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301900{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001901 u16 seq_st = 0;
1902 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301903 int ba_index;
1904 int nbad = 0;
1905 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001906
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001907 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301908 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301909
Sujithcd3d39a2008-08-11 14:03:34 +05301910 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001911 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001912 seq_st = ts->ts_seqnum;
1913 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001914 }
1915
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001916 while (bf) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001917 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +05301918 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1919 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001920
Sujithe8324352009-01-16 21:38:42 +05301921 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001922 }
1923
Sujithe8324352009-01-16 21:38:42 +05301924 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001925}
1926
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001927static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301928 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301929{
Sujitha22be222009-03-30 15:28:36 +05301930 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301931 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301932 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001933 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001934 struct ath_softc *sc = bf->aphy->sc;
1935 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301936 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301937
Sujith95e4acb2009-03-13 08:56:09 +05301938 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001939 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301940
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001941 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301942 WARN_ON(tx_rateindex >= hw->max_rates);
1943
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001944 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301945 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001946 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001947 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301948
Björn Smedmanebd02282010-10-10 22:44:39 +02001949 BUG_ON(nbad > bf->bf_nframes);
1950
1951 tx_info->status.ampdu_len = bf->bf_nframes;
1952 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1953 }
1954
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001955 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301956 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001957 /*
1958 * If an underrun error is seen assume it as an excessive
1959 * retry only if max frame trigger level has been reached
1960 * (2 KB for single stream, and 4 KB for dual stream).
1961 * Adjust the long retry as if the frame was tried
1962 * hw->max_rate_tries times to affect how rate control updates
1963 * PER for the failed rate.
1964 * In case of congestion on the bus penalizing this type of
1965 * underruns should help hardware actually transmit new frames
1966 * successfully by eventually preferring slower rates.
1967 * This itself should also alleviate congestion on the bus.
1968 */
1969 if (ieee80211_is_data(hdr->frame_control) &&
1970 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1971 ATH9K_TX_DELIM_UNDERRUN)) &&
1972 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1973 tx_info->status.rates[tx_rateindex].count =
1974 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301975 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301976
Felix Fietkau545750d2009-11-23 22:21:01 +01001977 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301978 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001979 tx_info->status.rates[i].idx = -1;
1980 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301981
Felix Fietkau78c46532010-06-25 01:26:16 +02001982 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301983}
1984
Felix Fietkau066dae92010-11-07 14:59:39 +01001985static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301986{
Felix Fietkau066dae92010-11-07 14:59:39 +01001987 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301988
Felix Fietkau066dae92010-11-07 14:59:39 +01001989 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301990 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001991 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001992 if (ath_mac80211_start_queue(sc, qnum))
1993 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301994 }
1995 spin_unlock_bh(&txq->axq_lock);
1996}
1997
Sujithc4288392008-11-18 09:09:30 +05301998static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001999{
Sujithcbe61d82009-02-09 13:27:12 +05302000 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002001 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002002 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2003 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302004 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002005 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302006 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002007 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002008 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002009
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002010 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2011 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2012 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002013
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002014 for (;;) {
2015 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002016 if (list_empty(&txq->axq_q)) {
2017 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002018 spin_unlock_bh(&txq->axq_lock);
2019 break;
2020 }
2021 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2022
2023 /*
2024 * There is a race condition that a BH gets scheduled
2025 * after sw writes TxE and before hw re-load the last
2026 * descriptor to get the newly chained one.
2027 * Software must keep the last DONE descriptor as a
2028 * holding descriptor - software does so by marking
2029 * it with the STALE flag.
2030 */
2031 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302032 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002033 bf_held = bf;
2034 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302035 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002036 break;
2037 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002038 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302039 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002040 }
2041 }
2042
2043 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302044 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002045
Felix Fietkau29bffa92010-03-29 20:14:23 -07002046 memset(&ts, 0, sizeof(ts));
2047 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002048 if (status == -EINPROGRESS) {
2049 spin_unlock_bh(&txq->axq_lock);
2050 break;
2051 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002052
2053 /*
2054 * Remove ath_buf's of the same transmit unit from txq,
2055 * however leave the last descriptor back as the holding
2056 * descriptor for hw.
2057 */
Sujitha119cc42009-03-30 15:28:38 +05302058 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002059 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060 if (!list_is_singular(&lastbf->list))
2061 list_cut_position(&bf_head,
2062 &txq->axq_q, lastbf->list.prev);
2063
2064 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002065 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002066 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002067 if (bf_held)
2068 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002069 spin_unlock_bh(&txq->axq_lock);
2070
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002071 if (bf_held)
2072 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002073
Sujithcd3d39a2008-08-11 14:03:34 +05302074 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002075 /*
2076 * This frame is sent out as a single frame.
2077 * Use hardware retry status for this frame.
2078 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002079 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302080 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002081 ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002082 }
Johannes Berge6a98542008-10-21 12:40:02 +02002083
Felix Fietkau066dae92010-11-07 14:59:39 +01002084 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2085
Sujithcd3d39a2008-08-11 14:03:34 +05302086 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002087 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002088 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002089 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002090
Felix Fietkau066dae92010-11-07 14:59:39 +01002091 if (txq == sc->tx.txq_map[qnum])
2092 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302093
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302095 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002096 ath_txq_schedule(sc, txq);
2097 spin_unlock_bh(&txq->axq_lock);
2098 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002099}
2100
Sujith305fe472009-07-23 15:32:29 +05302101static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002102{
2103 struct ath_softc *sc = container_of(work, struct ath_softc,
2104 tx_complete_work.work);
2105 struct ath_txq *txq;
2106 int i;
2107 bool needreset = false;
2108
2109 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2110 if (ATH_TXQ_SETUP(sc, i)) {
2111 txq = &sc->tx.txq[i];
2112 spin_lock_bh(&txq->axq_lock);
2113 if (txq->axq_depth) {
2114 if (txq->axq_tx_inprogress) {
2115 needreset = true;
2116 spin_unlock_bh(&txq->axq_lock);
2117 break;
2118 } else {
2119 txq->axq_tx_inprogress = true;
2120 }
2121 }
2122 spin_unlock_bh(&txq->axq_lock);
2123 }
2124
2125 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002126 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2127 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302128 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002129 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302130 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002131 }
2132
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002133 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002134 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2135}
2136
2137
Sujithe8324352009-01-16 21:38:42 +05302138
2139void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002140{
Sujithe8324352009-01-16 21:38:42 +05302141 int i;
2142 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002143
Sujithe8324352009-01-16 21:38:42 +05302144 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002145
2146 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302147 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2148 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002149 }
2150}
2151
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002152void ath_tx_edma_tasklet(struct ath_softc *sc)
2153{
2154 struct ath_tx_status txs;
2155 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2156 struct ath_hw *ah = sc->sc_ah;
2157 struct ath_txq *txq;
2158 struct ath_buf *bf, *lastbf;
2159 struct list_head bf_head;
2160 int status;
2161 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002162 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002163
2164 for (;;) {
2165 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2166 if (status == -EINPROGRESS)
2167 break;
2168 if (status == -EIO) {
2169 ath_print(common, ATH_DBG_XMIT,
2170 "Error processing tx status\n");
2171 break;
2172 }
2173
2174 /* Skip beacon completions */
2175 if (txs.qid == sc->beacon.beaconq)
2176 continue;
2177
2178 txq = &sc->tx.txq[txs.qid];
2179
2180 spin_lock_bh(&txq->axq_lock);
2181 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2182 spin_unlock_bh(&txq->axq_lock);
2183 return;
2184 }
2185
2186 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2187 struct ath_buf, list);
2188 lastbf = bf->bf_lastbf;
2189
2190 INIT_LIST_HEAD(&bf_head);
2191 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2192 &lastbf->list);
2193 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2194 txq->axq_depth--;
2195 txq->axq_tx_inprogress = false;
2196 spin_unlock_bh(&txq->axq_lock);
2197
2198 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2199
2200 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002201 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2202 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002203 ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002204 }
2205
Felix Fietkau066dae92010-11-07 14:59:39 +01002206 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2207
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002208 if (bf_isampdu(bf))
2209 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2210 else
2211 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2212 &txs, txok, 0);
2213
Felix Fietkau066dae92010-11-07 14:59:39 +01002214 if (txq == sc->tx.txq_map[qnum])
2215 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002216
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002217 spin_lock_bh(&txq->axq_lock);
2218 if (!list_empty(&txq->txq_fifo_pending)) {
2219 INIT_LIST_HEAD(&bf_head);
2220 bf = list_first_entry(&txq->txq_fifo_pending,
2221 struct ath_buf, list);
2222 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2223 &bf->bf_lastbf->list);
2224 ath_tx_txqaddbuf(sc, txq, &bf_head);
2225 } else if (sc->sc_flags & SC_OP_TXAGGR)
2226 ath_txq_schedule(sc, txq);
2227 spin_unlock_bh(&txq->axq_lock);
2228 }
2229}
2230
Sujithe8324352009-01-16 21:38:42 +05302231/*****************/
2232/* Init, Cleanup */
2233/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002234
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002235static int ath_txstatus_setup(struct ath_softc *sc, int size)
2236{
2237 struct ath_descdma *dd = &sc->txsdma;
2238 u8 txs_len = sc->sc_ah->caps.txs_len;
2239
2240 dd->dd_desc_len = size * txs_len;
2241 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2242 &dd->dd_desc_paddr, GFP_KERNEL);
2243 if (!dd->dd_desc)
2244 return -ENOMEM;
2245
2246 return 0;
2247}
2248
2249static int ath_tx_edma_init(struct ath_softc *sc)
2250{
2251 int err;
2252
2253 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2254 if (!err)
2255 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2256 sc->txsdma.dd_desc_paddr,
2257 ATH_TXSTATUS_RING_SIZE);
2258
2259 return err;
2260}
2261
2262static void ath_tx_edma_cleanup(struct ath_softc *sc)
2263{
2264 struct ath_descdma *dd = &sc->txsdma;
2265
2266 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2267 dd->dd_desc_paddr);
2268}
2269
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002270int ath_tx_init(struct ath_softc *sc, int nbufs)
2271{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002272 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002273 int error = 0;
2274
Sujith797fe5cb2009-03-30 15:28:45 +05302275 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002276
Sujith797fe5cb2009-03-30 15:28:45 +05302277 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002278 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302279 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002280 ath_print(common, ATH_DBG_FATAL,
2281 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302282 goto err;
2283 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002284
Sujith797fe5cb2009-03-30 15:28:45 +05302285 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002286 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302287 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002288 ath_print(common, ATH_DBG_FATAL,
2289 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302290 goto err;
2291 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002292
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002293 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2294
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002295 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2296 error = ath_tx_edma_init(sc);
2297 if (error)
2298 goto err;
2299 }
2300
Sujith797fe5cb2009-03-30 15:28:45 +05302301err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002302 if (error != 0)
2303 ath_tx_cleanup(sc);
2304
2305 return error;
2306}
2307
Sujith797fe5cb2009-03-30 15:28:45 +05302308void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002309{
Sujithb77f4832008-12-07 21:44:03 +05302310 if (sc->beacon.bdma.dd_desc_len != 0)
2311 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002312
Sujithb77f4832008-12-07 21:44:03 +05302313 if (sc->tx.txdma.dd_desc_len != 0)
2314 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002315
2316 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2317 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002318}
2319
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002320void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2321{
Sujithc5170162008-10-29 10:13:59 +05302322 struct ath_atx_tid *tid;
2323 struct ath_atx_ac *ac;
2324 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002325
Sujith8ee5afb2008-12-07 21:43:36 +05302326 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302327 tidno < WME_NUM_TID;
2328 tidno++, tid++) {
2329 tid->an = an;
2330 tid->tidno = tidno;
2331 tid->seq_start = tid->seq_next = 0;
2332 tid->baw_size = WME_MAX_BA;
2333 tid->baw_head = tid->baw_tail = 0;
2334 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302335 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302336 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302337 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302338 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302339 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302340 tid->state &= ~AGGR_ADDBA_COMPLETE;
2341 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302342 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002343
Sujith8ee5afb2008-12-07 21:43:36 +05302344 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302345 acno < WME_NUM_AC; acno++, ac++) {
2346 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002347 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302348 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002349 }
2350}
2351
Sujithb5aa9bf2008-10-29 10:13:31 +05302352void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002353{
Felix Fietkau2b409942010-07-07 19:42:08 +02002354 struct ath_atx_ac *ac;
2355 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002356 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002357 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302358
Felix Fietkau2b409942010-07-07 19:42:08 +02002359 for (tidno = 0, tid = &an->tid[tidno];
2360 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002361
Felix Fietkau2b409942010-07-07 19:42:08 +02002362 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002363 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002364
Felix Fietkau2b409942010-07-07 19:42:08 +02002365 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366
Felix Fietkau2b409942010-07-07 19:42:08 +02002367 if (tid->sched) {
2368 list_del(&tid->list);
2369 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002370 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002371
2372 if (ac->sched) {
2373 list_del(&ac->list);
2374 tid->ac->sched = false;
2375 }
2376
2377 ath_tid_drain(sc, txq, tid);
2378 tid->state &= ~AGGR_ADDBA_COMPLETE;
2379 tid->state &= ~AGGR_CLEANUP;
2380
2381 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002382 }
2383}