blob: 9f3d23a4e5802d4f0f048b340f9ea711b11f646e [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);
59static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +053060static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -070061 struct ath_tx_status *ts, int txok);
62static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +053063 int nbad, int txok, bool update_rc);
Felix Fietkau90fa5392010-09-20 13:45:38 +020064static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
65 int seqno);
Sujithe8324352009-01-16 21:38:42 +053066
Felix Fietkau545750d2009-11-23 22:21:01 +010067enum {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020068 MCS_HT20,
69 MCS_HT20_SGI,
Felix Fietkau545750d2009-11-23 22:21:01 +010070 MCS_HT40,
71 MCS_HT40_SGI,
72};
73
Felix Fietkau0e668cd2010-04-19 19:57:32 +020074static int ath_max_4ms_framelen[4][32] = {
75 [MCS_HT20] = {
76 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
77 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
78 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
79 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
80 },
81 [MCS_HT20_SGI] = {
82 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
83 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
84 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
85 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010086 },
87 [MCS_HT40] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020088 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
89 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
90 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
91 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010092 },
93 [MCS_HT40_SGI] = {
Felix Fietkau0e668cd2010-04-19 19:57:32 +020094 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
95 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
96 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
97 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
Felix Fietkau545750d2009-11-23 22:21:01 +010098 }
99};
100
Sujithe8324352009-01-16 21:38:42 +0530101/*********************/
102/* Aggregation logic */
103/*********************/
104
Sujithe8324352009-01-16 21:38:42 +0530105static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
106{
107 struct ath_atx_ac *ac = tid->ac;
108
109 if (tid->paused)
110 return;
111
112 if (tid->sched)
113 return;
114
115 tid->sched = true;
116 list_add_tail(&tid->list, &ac->tid_q);
117
118 if (ac->sched)
119 return;
120
121 ac->sched = true;
122 list_add_tail(&ac->list, &txq->axq_acq);
123}
124
Sujithe8324352009-01-16 21:38:42 +0530125static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
126{
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,
677 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530678{
679#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530680 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
681 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530682 u16 aggr_limit = 0, al = 0, bpad = 0,
683 al_delta, h_baw = tid->baw_size / 2;
684 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200685 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100686 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530687
688 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
689
690 do {
691 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100692 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530693
Sujithd43f30152009-01-16 21:38:53 +0530694 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100695 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530696 status = ATH_AGGR_BAW_CLOSED;
697 break;
698 }
699
700 if (!rl) {
701 aggr_limit = ath_lookup_rate(sc, bf, tid);
702 rl = 1;
703 }
704
Sujithd43f30152009-01-16 21:38:53 +0530705 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530706 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
707
Sujithd43f30152009-01-16 21:38:53 +0530708 if (nframes &&
709 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530710 status = ATH_AGGR_LIMITED;
711 break;
712 }
713
Felix Fietkau0299a502010-10-21 02:47:24 +0200714 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
715 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
716 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
717 break;
718
Sujithd43f30152009-01-16 21:38:53 +0530719 /* do not exceed subframe limit */
720 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530721 status = ATH_AGGR_LIMITED;
722 break;
723 }
Sujithd43f30152009-01-16 21:38:53 +0530724 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530725
Sujithd43f30152009-01-16 21:38:53 +0530726 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530727 al += bpad + al_delta;
728
729 /*
730 * Get the delimiters needed to meet the MPDU
731 * density for this node.
732 */
733 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530734 bpad = PADBYTES(al_delta) + (ndelim << 2);
735
736 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400737 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530738
Sujithd43f30152009-01-16 21:38:53 +0530739 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100740 if (!bf_isretried(bf))
741 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530742 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
743 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530744 if (bf_prev) {
745 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400746 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
747 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530748 }
749 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530750
Sujithe8324352009-01-16 21:38:42 +0530751 } while (!list_empty(&tid->buf_q));
752
753 bf_first->bf_al = al;
754 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530755
Sujithe8324352009-01-16 21:38:42 +0530756 return status;
757#undef PADBYTES
758}
759
760static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
761 struct ath_atx_tid *tid)
762{
Sujithd43f30152009-01-16 21:38:53 +0530763 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530764 enum ATH_AGGR_STATUS status;
765 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530766
767 do {
768 if (list_empty(&tid->buf_q))
769 return;
770
771 INIT_LIST_HEAD(&bf_q);
772
Sujithfec247c2009-07-27 12:08:16 +0530773 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530774
775 /*
Sujithd43f30152009-01-16 21:38:53 +0530776 * no frames picked up to be aggregated;
777 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530778 */
779 if (list_empty(&bf_q))
780 break;
781
782 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530783 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530784
Sujithd43f30152009-01-16 21:38:53 +0530785 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530786 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530787 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530788 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530789 ath_buf_set_rate(sc, bf);
790 ath_tx_txqaddbuf(sc, txq, &bf_q);
791 continue;
792 }
793
Sujithd43f30152009-01-16 21:38:53 +0530794 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530795 bf->bf_state.bf_type |= BUF_AGGR;
796 ath_buf_set_rate(sc, bf);
797 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
798
Sujithd43f30152009-01-16 21:38:53 +0530799 /* anchor last desc of aggregate */
800 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530801
Sujithe8324352009-01-16 21:38:42 +0530802 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530803 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530804
805 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
806 status != ATH_AGGR_BAW_CLOSED);
807}
808
Felix Fietkau231c3a12010-09-20 19:35:28 +0200809int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
810 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530811{
812 struct ath_atx_tid *txtid;
813 struct ath_node *an;
814
815 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530816 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200817
818 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
819 return -EAGAIN;
820
Sujithf83da962009-07-23 15:32:37 +0530821 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200822 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530823 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200824
825 return 0;
Sujithe8324352009-01-16 21:38:42 +0530826}
827
Sujithf83da962009-07-23 15:32:37 +0530828void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530829{
830 struct ath_node *an = (struct ath_node *)sta->drv_priv;
831 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100832 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530833
834 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530835 return;
Sujithe8324352009-01-16 21:38:42 +0530836
837 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530838 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530839 return;
Sujithe8324352009-01-16 21:38:42 +0530840 }
841
Sujithe8324352009-01-16 21:38:42 +0530842 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200843 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200844
845 /*
846 * If frames are still being transmitted for this TID, they will be
847 * cleaned up during tx completion. To prevent race conditions, this
848 * TID can only be reused after all in-progress subframes have been
849 * completed.
850 */
851 if (txtid->baw_head != txtid->baw_tail)
852 txtid->state |= AGGR_CLEANUP;
853 else
854 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530855 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530856
Felix Fietkau90fa5392010-09-20 13:45:38 +0200857 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530858}
859
860void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
861{
862 struct ath_atx_tid *txtid;
863 struct ath_node *an;
864
865 an = (struct ath_node *)sta->drv_priv;
866
867 if (sc->sc_flags & SC_OP_TXAGGR) {
868 txtid = ATH_AN_2_TID(an, tid);
869 txtid->baw_size =
870 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
871 txtid->state |= AGGR_ADDBA_COMPLETE;
872 txtid->state &= ~AGGR_ADDBA_PROGRESS;
873 ath_tx_resume_tid(sc, txtid);
874 }
875}
876
Sujithe8324352009-01-16 21:38:42 +0530877/********************/
878/* Queue Management */
879/********************/
880
Sujithe8324352009-01-16 21:38:42 +0530881static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
882 struct ath_txq *txq)
883{
884 struct ath_atx_ac *ac, *ac_tmp;
885 struct ath_atx_tid *tid, *tid_tmp;
886
887 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
888 list_del(&ac->list);
889 ac->sched = false;
890 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
891 list_del(&tid->list);
892 tid->sched = false;
893 ath_tid_drain(sc, txq, tid);
894 }
895 }
896}
897
898struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
899{
Sujithcbe61d82009-02-09 13:27:12 +0530900 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700901 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530902 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100903 static const int subtype_txq_to_hwq[] = {
904 [WME_AC_BE] = ATH_TXQ_AC_BE,
905 [WME_AC_BK] = ATH_TXQ_AC_BK,
906 [WME_AC_VI] = ATH_TXQ_AC_VI,
907 [WME_AC_VO] = ATH_TXQ_AC_VO,
908 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400909 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530910
911 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100912 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530913 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
914 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
915 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
916 qi.tqi_physCompBuf = 0;
917
918 /*
919 * Enable interrupts only for EOL and DESC conditions.
920 * We mark tx descriptors to receive a DESC interrupt
921 * when a tx queue gets deep; otherwise waiting for the
922 * EOL to reap descriptors. Note that this is done to
923 * reduce interrupt load and this only defers reaping
924 * descriptors, never transmitting frames. Aside from
925 * reducing interrupts this also permits more concurrency.
926 * The only potential downside is if the tx queue backs
927 * up in which case the top half of the kernel may backup
928 * due to a lack of tx descriptors.
929 *
930 * The UAPSD queue is an exception, since we take a desc-
931 * based intr on the EOSP frames.
932 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400933 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
934 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
935 TXQ_FLAG_TXERRINT_ENABLE;
936 } else {
937 if (qtype == ATH9K_TX_QUEUE_UAPSD)
938 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
939 else
940 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
941 TXQ_FLAG_TXDESCINT_ENABLE;
942 }
Sujithe8324352009-01-16 21:38:42 +0530943 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
944 if (qnum == -1) {
945 /*
946 * NB: don't print a message, this happens
947 * normally on parts with too few tx queues
948 */
949 return NULL;
950 }
951 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700952 ath_print(common, ATH_DBG_FATAL,
953 "qnum %u out of range, max %u!\n",
954 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530955 ath9k_hw_releasetxqueue(ah, qnum);
956 return NULL;
957 }
958 if (!ATH_TXQ_SETUP(sc, qnum)) {
959 struct ath_txq *txq = &sc->tx.txq[qnum];
960
961 txq->axq_qnum = qnum;
962 txq->axq_link = NULL;
963 INIT_LIST_HEAD(&txq->axq_q);
964 INIT_LIST_HEAD(&txq->axq_acq);
965 spin_lock_init(&txq->axq_lock);
966 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400967 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530968 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400969
970 txq->txq_headidx = txq->txq_tailidx = 0;
971 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
972 INIT_LIST_HEAD(&txq->txq_fifo[i]);
973 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530974 }
975 return &sc->tx.txq[qnum];
976}
977
Sujithe8324352009-01-16 21:38:42 +0530978int ath_txq_update(struct ath_softc *sc, int qnum,
979 struct ath9k_tx_queue_info *qinfo)
980{
Sujithcbe61d82009-02-09 13:27:12 +0530981 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530982 int error = 0;
983 struct ath9k_tx_queue_info qi;
984
985 if (qnum == sc->beacon.beaconq) {
986 /*
987 * XXX: for beacon queue, we just save the parameter.
988 * It will be picked up by ath_beaconq_config when
989 * it's necessary.
990 */
991 sc->beacon.beacon_qi = *qinfo;
992 return 0;
993 }
994
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700995 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530996
997 ath9k_hw_get_txq_props(ah, qnum, &qi);
998 qi.tqi_aifs = qinfo->tqi_aifs;
999 qi.tqi_cwmin = qinfo->tqi_cwmin;
1000 qi.tqi_cwmax = qinfo->tqi_cwmax;
1001 qi.tqi_burstTime = qinfo->tqi_burstTime;
1002 qi.tqi_readyTime = qinfo->tqi_readyTime;
1003
1004 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001005 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1006 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301007 error = -EIO;
1008 } else {
1009 ath9k_hw_resettxqueue(ah, qnum);
1010 }
1011
1012 return error;
1013}
1014
1015int ath_cabq_update(struct ath_softc *sc)
1016{
1017 struct ath9k_tx_queue_info qi;
1018 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301019
1020 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1021 /*
1022 * Ensure the readytime % is within the bounds.
1023 */
Sujith17d79042009-02-09 13:27:03 +05301024 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1025 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1026 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1027 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301028
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001029 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301030 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301031 ath_txq_update(sc, qnum, &qi);
1032
1033 return 0;
1034}
1035
Sujith043a0402009-01-16 21:38:47 +05301036/*
1037 * Drain a given TX queue (could be Beacon or Data)
1038 *
1039 * This assumes output has been stopped and
1040 * we do not need to block ath_tx_tasklet.
1041 */
1042void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301043{
1044 struct ath_buf *bf, *lastbf;
1045 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001046 struct ath_tx_status ts;
1047
1048 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301049 INIT_LIST_HEAD(&bf_head);
1050
Sujithe8324352009-01-16 21:38:42 +05301051 for (;;) {
1052 spin_lock_bh(&txq->axq_lock);
1053
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001054 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1055 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1056 txq->txq_headidx = txq->txq_tailidx = 0;
1057 spin_unlock_bh(&txq->axq_lock);
1058 break;
1059 } else {
1060 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1061 struct ath_buf, list);
1062 }
1063 } else {
1064 if (list_empty(&txq->axq_q)) {
1065 txq->axq_link = NULL;
1066 spin_unlock_bh(&txq->axq_lock);
1067 break;
1068 }
1069 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1070 list);
Sujithe8324352009-01-16 21:38:42 +05301071
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001072 if (bf->bf_stale) {
1073 list_del(&bf->list);
1074 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301075
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001076 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001077 continue;
1078 }
Sujithe8324352009-01-16 21:38:42 +05301079 }
1080
1081 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001082 if (!retry_tx)
1083 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301084
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001085 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1086 list_cut_position(&bf_head,
1087 &txq->txq_fifo[txq->txq_tailidx],
1088 &lastbf->list);
1089 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1090 } else {
1091 /* remove ath_buf's of the same mpdu from txq */
1092 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1093 }
1094
Sujithe8324352009-01-16 21:38:42 +05301095 txq->axq_depth--;
1096
1097 spin_unlock_bh(&txq->axq_lock);
1098
1099 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001100 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301101 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001102 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301103 }
1104
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001105 spin_lock_bh(&txq->axq_lock);
1106 txq->axq_tx_inprogress = false;
1107 spin_unlock_bh(&txq->axq_lock);
1108
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001109 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1110 spin_lock_bh(&txq->axq_lock);
1111 while (!list_empty(&txq->txq_fifo_pending)) {
1112 bf = list_first_entry(&txq->txq_fifo_pending,
1113 struct ath_buf, list);
1114 list_cut_position(&bf_head,
1115 &txq->txq_fifo_pending,
1116 &bf->bf_lastbf->list);
1117 spin_unlock_bh(&txq->axq_lock);
1118
1119 if (bf_isampdu(bf))
1120 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1121 &ts, 0);
1122 else
1123 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1124 &ts, 0, 0);
1125 spin_lock_bh(&txq->axq_lock);
1126 }
1127 spin_unlock_bh(&txq->axq_lock);
1128 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001129
1130 /* flush any pending frames if aggregation is enabled */
1131 if (sc->sc_flags & SC_OP_TXAGGR) {
1132 if (!retry_tx) {
1133 spin_lock_bh(&txq->axq_lock);
1134 ath_txq_drain_pending_buffers(sc, txq);
1135 spin_unlock_bh(&txq->axq_lock);
1136 }
1137 }
Sujithe8324352009-01-16 21:38:42 +05301138}
1139
Sujith043a0402009-01-16 21:38:47 +05301140void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1141{
Sujithcbe61d82009-02-09 13:27:12 +05301142 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001143 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301144 struct ath_txq *txq;
1145 int i, npend = 0;
1146
1147 if (sc->sc_flags & SC_OP_INVALID)
1148 return;
1149
1150 /* Stop beacon queue */
1151 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1152
1153 /* Stop data queues */
1154 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1155 if (ATH_TXQ_SETUP(sc, i)) {
1156 txq = &sc->tx.txq[i];
1157 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1158 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1159 }
1160 }
1161
1162 if (npend) {
1163 int r;
1164
Sujithe8009e92009-12-14 14:57:08 +05301165 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001166 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301167
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001168 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301169 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001170 ath_print(common, ATH_DBG_FATAL,
1171 "Unable to reset hardware; reset status %d\n",
1172 r);
Sujith043a0402009-01-16 21:38:47 +05301173 }
1174
1175 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1176 if (ATH_TXQ_SETUP(sc, i))
1177 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1178 }
1179}
1180
Sujithe8324352009-01-16 21:38:42 +05301181void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1182{
1183 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1184 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1185}
1186
Sujithe8324352009-01-16 21:38:42 +05301187void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1188{
1189 struct ath_atx_ac *ac;
1190 struct ath_atx_tid *tid;
1191
1192 if (list_empty(&txq->axq_acq))
1193 return;
1194
1195 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1196 list_del(&ac->list);
1197 ac->sched = false;
1198
1199 do {
1200 if (list_empty(&ac->tid_q))
1201 return;
1202
1203 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1204 list_del(&tid->list);
1205 tid->sched = false;
1206
1207 if (tid->paused)
1208 continue;
1209
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001210 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301211
1212 /*
1213 * add tid to round-robin queue if more frames
1214 * are pending for the tid
1215 */
1216 if (!list_empty(&tid->buf_q))
1217 ath_tx_queue_tid(txq, tid);
1218
1219 break;
1220 } while (!list_empty(&ac->tid_q));
1221
1222 if (!list_empty(&ac->tid_q)) {
1223 if (!ac->sched) {
1224 ac->sched = true;
1225 list_add_tail(&ac->list, &txq->axq_acq);
1226 }
1227 }
1228}
1229
Sujithe8324352009-01-16 21:38:42 +05301230/***********/
1231/* TX, DMA */
1232/***********/
1233
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001234/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001235 * Insert a chain of ath_buf (descriptors) on a txq and
1236 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001237 */
Sujith102e0572008-10-29 10:15:16 +05301238static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1239 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001240{
Sujithcbe61d82009-02-09 13:27:12 +05301241 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001242 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001243 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301244
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001245 /*
1246 * Insert the frame on the outbound list and
1247 * pass it on to the hardware.
1248 */
1249
1250 if (list_empty(head))
1251 return;
1252
1253 bf = list_first_entry(head, struct ath_buf, list);
1254
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001255 ath_print(common, ATH_DBG_QUEUE,
1256 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001257
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001258 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1259 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1260 list_splice_tail_init(head, &txq->txq_fifo_pending);
1261 return;
1262 }
1263 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1264 ath_print(common, ATH_DBG_XMIT,
1265 "Initializing tx fifo %d which "
1266 "is non-empty\n",
1267 txq->txq_headidx);
1268 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1269 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1270 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001271 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001272 ath_print(common, ATH_DBG_XMIT,
1273 "TXDP[%u] = %llx (%p)\n",
1274 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001275 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001276 list_splice_tail_init(head, &txq->axq_q);
1277
1278 if (txq->axq_link == NULL) {
1279 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1280 ath_print(common, ATH_DBG_XMIT,
1281 "TXDP[%u] = %llx (%p)\n",
1282 txq->axq_qnum, ito64(bf->bf_daddr),
1283 bf->bf_desc);
1284 } else {
1285 *txq->axq_link = bf->bf_daddr;
1286 ath_print(common, ATH_DBG_XMIT,
1287 "link[%u] (%p)=%llx (%p)\n",
1288 txq->axq_qnum, txq->axq_link,
1289 ito64(bf->bf_daddr), bf->bf_desc);
1290 }
1291 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1292 &txq->axq_link);
1293 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001294 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001295 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001296}
1297
Sujithe8324352009-01-16 21:38:42 +05301298static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1299 struct list_head *bf_head,
1300 struct ath_tx_control *txctl)
1301{
1302 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001303 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301304
Sujithe8324352009-01-16 21:38:42 +05301305 bf = list_first_entry(bf_head, struct ath_buf, list);
1306 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301307 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001308 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301309
1310 /*
1311 * Do not queue to h/w when any of the following conditions is true:
1312 * - there are pending frames in software queue
1313 * - the TID is currently paused for ADDBA/BAR request
1314 * - seqno is not within block-ack window
1315 * - h/w queue depth exceeds low water mark
1316 */
1317 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001318 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301319 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001320 /*
Sujithe8324352009-01-16 21:38:42 +05301321 * Add this frame to software queue for scheduling later
1322 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001323 */
Sujithd43f30152009-01-16 21:38:53 +05301324 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301325 ath_tx_queue_tid(txctl->txq, tid);
1326 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001327 }
1328
Sujithe8324352009-01-16 21:38:42 +05301329 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001330 if (!bf_isretried(bf))
1331 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301332
1333 /* Queue to h/w without aggregation */
1334 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301335 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301336 ath_buf_set_rate(sc, bf);
1337 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301338}
1339
Felix Fietkau82b873a2010-11-11 03:18:37 +01001340static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1341 struct ath_atx_tid *tid,
1342 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001343{
Sujithe8324352009-01-16 21:38:42 +05301344 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001345
Sujithe8324352009-01-16 21:38:42 +05301346 bf = list_first_entry(bf_head, struct ath_buf, list);
1347 bf->bf_state.bf_type &= ~BUF_AMPDU;
1348
1349 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001350 if (tid)
1351 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301352
1353 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301354 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301355 ath_buf_set_rate(sc, bf);
1356 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301357 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001358}
1359
Sujith528f0c62008-10-29 10:14:26 +05301360static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001361{
Sujith528f0c62008-10-29 10:14:26 +05301362 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001363 enum ath9k_pkt_type htype;
1364 __le16 fc;
1365
Sujith528f0c62008-10-29 10:14:26 +05301366 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001367 fc = hdr->frame_control;
1368
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001369 if (ieee80211_is_beacon(fc))
1370 htype = ATH9K_PKT_TYPE_BEACON;
1371 else if (ieee80211_is_probe_resp(fc))
1372 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1373 else if (ieee80211_is_atim(fc))
1374 htype = ATH9K_PKT_TYPE_ATIM;
1375 else if (ieee80211_is_pspoll(fc))
1376 htype = ATH9K_PKT_TYPE_PSPOLL;
1377 else
1378 htype = ATH9K_PKT_TYPE_NORMAL;
1379
1380 return htype;
1381}
1382
Sujith528f0c62008-10-29 10:14:26 +05301383static void assign_aggr_tid_seqno(struct sk_buff *skb,
1384 struct ath_buf *bf)
1385{
1386 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1387 struct ieee80211_hdr *hdr;
1388 struct ath_node *an;
1389 struct ath_atx_tid *tid;
1390 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001391 u8 tidno;
Sujith528f0c62008-10-29 10:14:26 +05301392
1393 if (!tx_info->control.sta)
1394 return;
1395
1396 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1397 hdr = (struct ieee80211_hdr *)skb->data;
1398 fc = hdr->frame_control;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001399 tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001400
Sujithe8324352009-01-16 21:38:42 +05301401 /*
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001402 * Override seqno set by upper layer with the one
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301403 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301404 */
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001405 tid = ATH_AN_2_TID(an, tidno);
Sujith17b182e2009-12-14 14:56:56 +05301406 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301407 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301408}
1409
Felix Fietkau82b873a2010-11-11 03:18:37 +01001410static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301411{
1412 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1413 int flags = 0;
1414
1415 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1416 flags |= ATH9K_TXDESC_INTREQ;
1417
1418 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1419 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301420
Felix Fietkau82b873a2010-11-11 03:18:37 +01001421 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001422 flags |= ATH9K_TXDESC_LDPC;
1423
Sujith528f0c62008-10-29 10:14:26 +05301424 return flags;
1425}
1426
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001427/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001428 * rix - rate index
1429 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1430 * width - 0 for 20 MHz, 1 for 40 MHz
1431 * half_gi - to use 4us v/s 3.6 us for symbol time
1432 */
Sujith102e0572008-10-29 10:15:16 +05301433static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1434 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001435{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001436 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001437 int streams, pktlen;
1438
Sujithcd3d39a2008-08-11 14:03:34 +05301439 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
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
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001458static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1459{
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;
1521 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1522 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,
1545 phy, rate->bitrate * 100, bf->bf_frmlen, 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 */
1549 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1550 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 Fietkau952cd692010-11-14 15:20:03 +01001607 if (tx_info->control.hw_key) {
Sujithe8324352009-01-16 21:38:42 +05301608 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1609 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1610 } else {
1611 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1612 }
1613
Sujithe8324352009-01-16 21:38:42 +05301614 bf->bf_mpdu = skb;
1615
Ben Greearc1739eb32010-10-14 12:45:29 -07001616 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1617 skb->len, DMA_TO_DEVICE);
1618 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301619 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001620 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001621 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1622 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001623 ath_tx_return_buffer(sc, bf);
1624 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301625 }
1626
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001627 bf->bf_tx_aborted = false;
1628
Felix Fietkau82b873a2010-11-11 03:18:37 +01001629 return bf;
Sujithe8324352009-01-16 21:38:42 +05301630}
1631
1632/* FIXME: tx power */
1633static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1634 struct ath_tx_control *txctl)
1635{
Sujitha22be222009-03-30 15:28:36 +05301636 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301637 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301638 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301639 struct ath_node *an = NULL;
1640 struct list_head bf_head;
1641 struct ath_desc *ds;
1642 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301643 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau952cd692010-11-14 15:20:03 +01001644 enum ath9k_key_type keytype;
Sujithe8324352009-01-16 21:38:42 +05301645 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301646 __le16 fc;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001647 u8 tidno;
Sujithe8324352009-01-16 21:38:42 +05301648
1649 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301650 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301651
1652 INIT_LIST_HEAD(&bf_head);
1653 list_add_tail(&bf->list, &bf_head);
1654
1655 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001656 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301657
Felix Fietkau952cd692010-11-14 15:20:03 +01001658 keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301659 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
Felix Fietkau952cd692010-11-14 15:20:03 +01001660 bf->bf_keyix, keytype, bf->bf_flags);
Sujithe8324352009-01-16 21:38:42 +05301661
1662 ath9k_hw_filltxdesc(ah, ds,
1663 skb->len, /* segment length */
1664 true, /* first segment */
1665 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001666 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001667 bf->bf_buf_addr,
1668 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301669
Sujithe8324352009-01-16 21:38:42 +05301670 spin_lock_bh(&txctl->txq->axq_lock);
1671
1672 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1673 tx_info->control.sta) {
1674 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001675 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1676 IEEE80211_QOS_CTL_TID_MASK;
1677 tid = ATH_AN_2_TID(an, tidno);
1678
Sujithe8324352009-01-16 21:38:42 +05301679
Felix Fietkau066dae92010-11-07 14:59:39 +01001680 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001681 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301682 /*
1683 * Try aggregation if it's a unicast data frame
1684 * and the destination is HT capable.
1685 */
1686 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1687 } else {
1688 /*
1689 * Send this frame as regular when ADDBA
1690 * exchange is neither complete nor pending.
1691 */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001692 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301693 }
1694 } else {
Felix Fietkau61117f012010-11-11 03:18:36 +01001695 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001696 bf->bf_state.bfs_paprd = txctl->paprd;
1697
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001698 if (bf->bf_state.bfs_paprd)
1699 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1700
Felix Fietkau82b873a2010-11-11 03:18:37 +01001701 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301702 }
1703
1704 spin_unlock_bh(&txctl->txq->axq_lock);
1705}
1706
1707/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001708int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301709 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001710{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001711 struct ath_wiphy *aphy = hw->priv;
1712 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001713 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001714 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001715 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001716
Felix Fietkau82b873a2010-11-11 03:18:37 +01001717 bf = ath_tx_setup_buffer(hw, skb);
1718 if (unlikely(!bf))
1719 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001720
Felix Fietkau066dae92010-11-07 14:59:39 +01001721 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001722 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001723 if (txq == sc->tx.txq_map[q] &&
1724 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1725 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001726 txq->stopped = 1;
1727 }
1728 spin_unlock_bh(&txq->axq_lock);
1729
Sujithe8324352009-01-16 21:38:42 +05301730 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001731
1732 return 0;
1733}
1734
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001735void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001736{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001737 struct ath_wiphy *aphy = hw->priv;
1738 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001739 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001740 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1741 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301742 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1743 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001744
Sujithe8324352009-01-16 21:38:42 +05301745 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001746
Sujithe8324352009-01-16 21:38:42 +05301747 /*
1748 * As a temporary workaround, assign seq# here; this will likely need
1749 * to be cleaned up to work better with Beacon transmission and virtual
1750 * BSSes.
1751 */
1752 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301753 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1754 sc->tx.seq_no += 0x10;
1755 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1756 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001757 }
1758
Sujithe8324352009-01-16 21:38:42 +05301759 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001760 padpos = ath9k_cmn_padpos(hdr->frame_control);
1761 padsize = padpos & 3;
1762 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301763 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001764 ath_print(common, ATH_DBG_XMIT,
1765 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301766 dev_kfree_skb_any(skb);
1767 return;
1768 }
1769 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001770 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001771 }
1772
Sujithe8324352009-01-16 21:38:42 +05301773 txctl.txq = sc->beacon.cabq;
1774
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001775 ath_print(common, ATH_DBG_XMIT,
1776 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301777
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001778 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001779 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301780 goto exit;
1781 }
1782
1783 return;
1784exit:
1785 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001786}
1787
Sujithe8324352009-01-16 21:38:42 +05301788/*****************/
1789/* TX Completion */
1790/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001791
Sujithe8324352009-01-16 21:38:42 +05301792static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f012010-11-11 03:18:36 +01001793 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001794 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001795{
Sujithe8324352009-01-16 21:38:42 +05301796 struct ieee80211_hw *hw = sc->hw;
1797 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001798 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001799 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001800 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301801
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001802 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301803
Felix Fietkau827e69b2009-11-15 23:09:25 +01001804 if (aphy)
1805 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301806
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301807 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301808 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301809
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301810 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301811 /* Frame was ACKed */
1812 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1813 }
1814
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001815 padpos = ath9k_cmn_padpos(hdr->frame_control);
1816 padsize = padpos & 3;
1817 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301818 /*
1819 * Remove MAC header padding before giving the frame back to
1820 * mac80211.
1821 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001822 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301823 skb_pull(skb, padsize);
1824 }
1825
Sujith1b04b932010-01-08 10:36:05 +05301826 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1827 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001828 ath_print(common, ATH_DBG_PS,
1829 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001830 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301831 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1832 PS_WAIT_FOR_CAB |
1833 PS_WAIT_FOR_PSPOLL_DATA |
1834 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001835 }
1836
Felix Fietkau61117f012010-11-11 03:18:36 +01001837 if (unlikely(ftype))
1838 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001839 else {
1840 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001841 if (txq == sc->tx.txq_map[q]) {
1842 spin_lock_bh(&txq->axq_lock);
1843 if (WARN_ON(--txq->pending_frames < 0))
1844 txq->pending_frames = 0;
1845 spin_unlock_bh(&txq->axq_lock);
1846 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001847
Felix Fietkau827e69b2009-11-15 23:09:25 +01001848 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001849 }
Sujithe8324352009-01-16 21:38:42 +05301850}
1851
1852static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001853 struct ath_txq *txq, struct list_head *bf_q,
1854 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301855{
1856 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301857 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301858 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301859
Sujithe8324352009-01-16 21:38:42 +05301860 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301861 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301862
1863 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301864 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301865
1866 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301867 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301868 }
1869
Ben Greearc1739eb32010-10-14 12:45:29 -07001870 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001871 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001872
1873 if (bf->bf_state.bfs_paprd) {
Felix Fietkau82259b72010-11-14 15:20:04 +01001874 if (!sc->paprd_pending)
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001875 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001876 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001877 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001878 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001879 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f012010-11-11 03:18:36 +01001880 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1881 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001882 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001883 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1884 * accidentally reference it later.
1885 */
1886 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301887
1888 /*
1889 * Return the list of ath_buf of this mpdu to free queue
1890 */
1891 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1892 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1893 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1894}
1895
1896static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001897 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301898{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001899 u16 seq_st = 0;
1900 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301901 int ba_index;
1902 int nbad = 0;
1903 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001904
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001905 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301906 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301907
Sujithcd3d39a2008-08-11 14:03:34 +05301908 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001909 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001910 seq_st = ts->ts_seqnum;
1911 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001912 }
1913
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001914 while (bf) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001915 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +05301916 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1917 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001918
Sujithe8324352009-01-16 21:38:42 +05301919 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001920 }
1921
Sujithe8324352009-01-16 21:38:42 +05301922 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001923}
1924
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001925static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301926 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301927{
Sujitha22be222009-03-30 15:28:36 +05301928 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301929 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301930 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001931 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001932 struct ath_softc *sc = bf->aphy->sc;
1933 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301934 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301935
Sujith95e4acb2009-03-13 08:56:09 +05301936 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001937 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301938
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001939 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301940 WARN_ON(tx_rateindex >= hw->max_rates);
1941
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001942 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301943 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001944 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001945 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301946
Björn Smedmanebd02282010-10-10 22:44:39 +02001947 BUG_ON(nbad > bf->bf_nframes);
1948
1949 tx_info->status.ampdu_len = bf->bf_nframes;
1950 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1951 }
1952
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001953 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301954 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001955 /*
1956 * If an underrun error is seen assume it as an excessive
1957 * retry only if max frame trigger level has been reached
1958 * (2 KB for single stream, and 4 KB for dual stream).
1959 * Adjust the long retry as if the frame was tried
1960 * hw->max_rate_tries times to affect how rate control updates
1961 * PER for the failed rate.
1962 * In case of congestion on the bus penalizing this type of
1963 * underruns should help hardware actually transmit new frames
1964 * successfully by eventually preferring slower rates.
1965 * This itself should also alleviate congestion on the bus.
1966 */
1967 if (ieee80211_is_data(hdr->frame_control) &&
1968 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1969 ATH9K_TX_DELIM_UNDERRUN)) &&
1970 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1971 tx_info->status.rates[tx_rateindex].count =
1972 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301973 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301974
Felix Fietkau545750d2009-11-23 22:21:01 +01001975 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301976 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001977 tx_info->status.rates[i].idx = -1;
1978 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301979
Felix Fietkau78c46532010-06-25 01:26:16 +02001980 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301981}
1982
Felix Fietkau066dae92010-11-07 14:59:39 +01001983static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301984{
Felix Fietkau066dae92010-11-07 14:59:39 +01001985 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301986
Felix Fietkau066dae92010-11-07 14:59:39 +01001987 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301988 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001989 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001990 if (ath_mac80211_start_queue(sc, qnum))
1991 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301992 }
1993 spin_unlock_bh(&txq->axq_lock);
1994}
1995
Sujithc4288392008-11-18 09:09:30 +05301996static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001997{
Sujithcbe61d82009-02-09 13:27:12 +05301998 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001999 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002000 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2001 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302002 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002003 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302004 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002005 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002006 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002007
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002008 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2009 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2010 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002011
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002012 for (;;) {
2013 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002014 if (list_empty(&txq->axq_q)) {
2015 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002016 spin_unlock_bh(&txq->axq_lock);
2017 break;
2018 }
2019 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2020
2021 /*
2022 * There is a race condition that a BH gets scheduled
2023 * after sw writes TxE and before hw re-load the last
2024 * descriptor to get the newly chained one.
2025 * Software must keep the last DONE descriptor as a
2026 * holding descriptor - software does so by marking
2027 * it with the STALE flag.
2028 */
2029 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302030 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002031 bf_held = bf;
2032 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302033 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002034 break;
2035 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002036 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302037 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002038 }
2039 }
2040
2041 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302042 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002043
Felix Fietkau29bffa92010-03-29 20:14:23 -07002044 memset(&ts, 0, sizeof(ts));
2045 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002046 if (status == -EINPROGRESS) {
2047 spin_unlock_bh(&txq->axq_lock);
2048 break;
2049 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002050
2051 /*
2052 * Remove ath_buf's of the same transmit unit from txq,
2053 * however leave the last descriptor back as the holding
2054 * descriptor for hw.
2055 */
Sujitha119cc42009-03-30 15:28:38 +05302056 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002057 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002058 if (!list_is_singular(&lastbf->list))
2059 list_cut_position(&bf_head,
2060 &txq->axq_q, lastbf->list.prev);
2061
2062 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002063 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002064 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002065 if (bf_held)
2066 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002067 spin_unlock_bh(&txq->axq_lock);
2068
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002069 if (bf_held)
2070 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002071
Sujithcd3d39a2008-08-11 14:03:34 +05302072 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002073 /*
2074 * This frame is sent out as a single frame.
2075 * Use hardware retry status for this frame.
2076 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002077 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302078 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002079 ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002080 }
Johannes Berge6a98542008-10-21 12:40:02 +02002081
Felix Fietkau066dae92010-11-07 14:59:39 +01002082 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2083
Sujithcd3d39a2008-08-11 14:03:34 +05302084 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002085 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002086 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002087 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002088
Felix Fietkau066dae92010-11-07 14:59:39 +01002089 if (txq == sc->tx.txq_map[qnum])
2090 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302091
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002092 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302093 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002094 ath_txq_schedule(sc, txq);
2095 spin_unlock_bh(&txq->axq_lock);
2096 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002097}
2098
Sujith305fe472009-07-23 15:32:29 +05302099static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002100{
2101 struct ath_softc *sc = container_of(work, struct ath_softc,
2102 tx_complete_work.work);
2103 struct ath_txq *txq;
2104 int i;
2105 bool needreset = false;
2106
2107 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2108 if (ATH_TXQ_SETUP(sc, i)) {
2109 txq = &sc->tx.txq[i];
2110 spin_lock_bh(&txq->axq_lock);
2111 if (txq->axq_depth) {
2112 if (txq->axq_tx_inprogress) {
2113 needreset = true;
2114 spin_unlock_bh(&txq->axq_lock);
2115 break;
2116 } else {
2117 txq->axq_tx_inprogress = true;
2118 }
2119 }
2120 spin_unlock_bh(&txq->axq_lock);
2121 }
2122
2123 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002124 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2125 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302126 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002127 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302128 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002129 }
2130
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002131 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002132 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2133}
2134
2135
Sujithe8324352009-01-16 21:38:42 +05302136
2137void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002138{
Sujithe8324352009-01-16 21:38:42 +05302139 int i;
2140 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002141
Sujithe8324352009-01-16 21:38:42 +05302142 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002143
2144 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302145 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2146 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002147 }
2148}
2149
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002150void ath_tx_edma_tasklet(struct ath_softc *sc)
2151{
2152 struct ath_tx_status txs;
2153 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2154 struct ath_hw *ah = sc->sc_ah;
2155 struct ath_txq *txq;
2156 struct ath_buf *bf, *lastbf;
2157 struct list_head bf_head;
2158 int status;
2159 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002160 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002161
2162 for (;;) {
2163 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2164 if (status == -EINPROGRESS)
2165 break;
2166 if (status == -EIO) {
2167 ath_print(common, ATH_DBG_XMIT,
2168 "Error processing tx status\n");
2169 break;
2170 }
2171
2172 /* Skip beacon completions */
2173 if (txs.qid == sc->beacon.beaconq)
2174 continue;
2175
2176 txq = &sc->tx.txq[txs.qid];
2177
2178 spin_lock_bh(&txq->axq_lock);
2179 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2180 spin_unlock_bh(&txq->axq_lock);
2181 return;
2182 }
2183
2184 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2185 struct ath_buf, list);
2186 lastbf = bf->bf_lastbf;
2187
2188 INIT_LIST_HEAD(&bf_head);
2189 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2190 &lastbf->list);
2191 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2192 txq->axq_depth--;
2193 txq->axq_tx_inprogress = false;
2194 spin_unlock_bh(&txq->axq_lock);
2195
2196 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2197
2198 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002199 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2200 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002201 ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002202 }
2203
Felix Fietkau066dae92010-11-07 14:59:39 +01002204 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2205
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002206 if (bf_isampdu(bf))
2207 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2208 else
2209 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2210 &txs, txok, 0);
2211
Felix Fietkau066dae92010-11-07 14:59:39 +01002212 if (txq == sc->tx.txq_map[qnum])
2213 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002214
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002215 spin_lock_bh(&txq->axq_lock);
2216 if (!list_empty(&txq->txq_fifo_pending)) {
2217 INIT_LIST_HEAD(&bf_head);
2218 bf = list_first_entry(&txq->txq_fifo_pending,
2219 struct ath_buf, list);
2220 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2221 &bf->bf_lastbf->list);
2222 ath_tx_txqaddbuf(sc, txq, &bf_head);
2223 } else if (sc->sc_flags & SC_OP_TXAGGR)
2224 ath_txq_schedule(sc, txq);
2225 spin_unlock_bh(&txq->axq_lock);
2226 }
2227}
2228
Sujithe8324352009-01-16 21:38:42 +05302229/*****************/
2230/* Init, Cleanup */
2231/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002232
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002233static int ath_txstatus_setup(struct ath_softc *sc, int size)
2234{
2235 struct ath_descdma *dd = &sc->txsdma;
2236 u8 txs_len = sc->sc_ah->caps.txs_len;
2237
2238 dd->dd_desc_len = size * txs_len;
2239 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2240 &dd->dd_desc_paddr, GFP_KERNEL);
2241 if (!dd->dd_desc)
2242 return -ENOMEM;
2243
2244 return 0;
2245}
2246
2247static int ath_tx_edma_init(struct ath_softc *sc)
2248{
2249 int err;
2250
2251 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2252 if (!err)
2253 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2254 sc->txsdma.dd_desc_paddr,
2255 ATH_TXSTATUS_RING_SIZE);
2256
2257 return err;
2258}
2259
2260static void ath_tx_edma_cleanup(struct ath_softc *sc)
2261{
2262 struct ath_descdma *dd = &sc->txsdma;
2263
2264 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2265 dd->dd_desc_paddr);
2266}
2267
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002268int ath_tx_init(struct ath_softc *sc, int nbufs)
2269{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002270 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002271 int error = 0;
2272
Sujith797fe5cb2009-03-30 15:28:45 +05302273 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002274
Sujith797fe5cb2009-03-30 15:28:45 +05302275 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002276 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302277 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002278 ath_print(common, ATH_DBG_FATAL,
2279 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302280 goto err;
2281 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002282
Sujith797fe5cb2009-03-30 15:28:45 +05302283 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002284 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302285 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002286 ath_print(common, ATH_DBG_FATAL,
2287 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302288 goto err;
2289 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002290
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002291 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2292
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002293 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2294 error = ath_tx_edma_init(sc);
2295 if (error)
2296 goto err;
2297 }
2298
Sujith797fe5cb2009-03-30 15:28:45 +05302299err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002300 if (error != 0)
2301 ath_tx_cleanup(sc);
2302
2303 return error;
2304}
2305
Sujith797fe5cb2009-03-30 15:28:45 +05302306void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002307{
Sujithb77f4832008-12-07 21:44:03 +05302308 if (sc->beacon.bdma.dd_desc_len != 0)
2309 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002310
Sujithb77f4832008-12-07 21:44:03 +05302311 if (sc->tx.txdma.dd_desc_len != 0)
2312 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002313
2314 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2315 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002316}
2317
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002318void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2319{
Sujithc5170162008-10-29 10:13:59 +05302320 struct ath_atx_tid *tid;
2321 struct ath_atx_ac *ac;
2322 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002323
Sujith8ee5afb2008-12-07 21:43:36 +05302324 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302325 tidno < WME_NUM_TID;
2326 tidno++, tid++) {
2327 tid->an = an;
2328 tid->tidno = tidno;
2329 tid->seq_start = tid->seq_next = 0;
2330 tid->baw_size = WME_MAX_BA;
2331 tid->baw_head = tid->baw_tail = 0;
2332 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302333 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302334 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302335 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302336 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302337 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302338 tid->state &= ~AGGR_ADDBA_COMPLETE;
2339 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302340 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002341
Sujith8ee5afb2008-12-07 21:43:36 +05302342 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302343 acno < WME_NUM_AC; acno++, ac++) {
2344 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002345 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302346 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002347 }
2348}
2349
Sujithb5aa9bf2008-10-29 10:13:31 +05302350void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002351{
Felix Fietkau2b409942010-07-07 19:42:08 +02002352 struct ath_atx_ac *ac;
2353 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002355 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302356
Felix Fietkau2b409942010-07-07 19:42:08 +02002357 for (tidno = 0, tid = &an->tid[tidno];
2358 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002359
Felix Fietkau2b409942010-07-07 19:42:08 +02002360 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002361 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002362
Felix Fietkau2b409942010-07-07 19:42:08 +02002363 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002364
Felix Fietkau2b409942010-07-07 19:42:08 +02002365 if (tid->sched) {
2366 list_del(&tid->list);
2367 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002368 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002369
2370 if (ac->sched) {
2371 list_del(&ac->list);
2372 tid->ac->sched = false;
2373 }
2374
2375 ath_tid_drain(sc, txq, tid);
2376 tid->state &= ~AGGR_ADDBA_COMPLETE;
2377 tid->state &= ~AGGR_CLEANUP;
2378
2379 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002380 }
2381}