blob: c7097a5e33dad97a5219141e4e1217880447783f [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 */
633 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
634 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
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001607 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301608 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1609 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1610 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1611 } else {
1612 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1613 }
1614
Sujithe8324352009-01-16 21:38:42 +05301615 bf->bf_mpdu = skb;
1616
Ben Greearc1739eb32010-10-14 12:45:29 -07001617 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1618 skb->len, DMA_TO_DEVICE);
1619 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301620 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001621 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001622 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1623 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001624 ath_tx_return_buffer(sc, bf);
1625 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301626 }
1627
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001628 bf->bf_tx_aborted = false;
1629
Felix Fietkau82b873a2010-11-11 03:18:37 +01001630 return bf;
Sujithe8324352009-01-16 21:38:42 +05301631}
1632
1633/* FIXME: tx power */
1634static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1635 struct ath_tx_control *txctl)
1636{
Sujitha22be222009-03-30 15:28:36 +05301637 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301638 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301639 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301640 struct ath_node *an = NULL;
1641 struct list_head bf_head;
1642 struct ath_desc *ds;
1643 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301644 struct ath_hw *ah = sc->sc_ah;
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
1658 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1659 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1660
1661 ath9k_hw_filltxdesc(ah, ds,
1662 skb->len, /* segment length */
1663 true, /* first segment */
1664 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001665 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001666 bf->bf_buf_addr,
1667 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301668
Sujithe8324352009-01-16 21:38:42 +05301669 spin_lock_bh(&txctl->txq->axq_lock);
1670
1671 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1672 tx_info->control.sta) {
1673 an = (struct ath_node *)tx_info->control.sta->drv_priv;
Felix Fietkau5daefbd2010-11-14 15:20:02 +01001674 tidno = ieee80211_get_qos_ctl(hdr)[0] &
1675 IEEE80211_QOS_CTL_TID_MASK;
1676 tid = ATH_AN_2_TID(an, tidno);
1677
Sujithe8324352009-01-16 21:38:42 +05301678
Felix Fietkau066dae92010-11-07 14:59:39 +01001679 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001680 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301681 /*
1682 * Try aggregation if it's a unicast data frame
1683 * and the destination is HT capable.
1684 */
1685 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1686 } else {
1687 /*
1688 * Send this frame as regular when ADDBA
1689 * exchange is neither complete nor pending.
1690 */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001691 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301692 }
1693 } else {
Felix Fietkau61117f012010-11-11 03:18:36 +01001694 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001695 bf->bf_state.bfs_paprd = txctl->paprd;
1696
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001697 if (bf->bf_state.bfs_paprd)
1698 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1699
Felix Fietkau82b873a2010-11-11 03:18:37 +01001700 if (txctl->paprd)
1701 bf->bf_state.bfs_paprd_timestamp = jiffies;
1702
1703 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301704 }
1705
1706 spin_unlock_bh(&txctl->txq->axq_lock);
1707}
1708
1709/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001710int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301711 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001712{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001713 struct ath_wiphy *aphy = hw->priv;
1714 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001715 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001716 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001717 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001718
Felix Fietkau82b873a2010-11-11 03:18:37 +01001719 bf = ath_tx_setup_buffer(hw, skb);
1720 if (unlikely(!bf))
1721 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001722
Felix Fietkau066dae92010-11-07 14:59:39 +01001723 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001724 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001725 if (txq == sc->tx.txq_map[q] &&
1726 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1727 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001728 txq->stopped = 1;
1729 }
1730 spin_unlock_bh(&txq->axq_lock);
1731
Sujithe8324352009-01-16 21:38:42 +05301732 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001733
1734 return 0;
1735}
1736
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001737void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001738{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001739 struct ath_wiphy *aphy = hw->priv;
1740 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001741 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001742 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1743 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301744 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1745 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001746
Sujithe8324352009-01-16 21:38:42 +05301747 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748
Sujithe8324352009-01-16 21:38:42 +05301749 /*
1750 * As a temporary workaround, assign seq# here; this will likely need
1751 * to be cleaned up to work better with Beacon transmission and virtual
1752 * BSSes.
1753 */
1754 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301755 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1756 sc->tx.seq_no += 0x10;
1757 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1758 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001759 }
1760
Sujithe8324352009-01-16 21:38:42 +05301761 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001762 padpos = ath9k_cmn_padpos(hdr->frame_control);
1763 padsize = padpos & 3;
1764 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301765 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001766 ath_print(common, ATH_DBG_XMIT,
1767 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301768 dev_kfree_skb_any(skb);
1769 return;
1770 }
1771 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001772 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001773 }
1774
Sujithe8324352009-01-16 21:38:42 +05301775 txctl.txq = sc->beacon.cabq;
1776
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001777 ath_print(common, ATH_DBG_XMIT,
1778 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301779
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001780 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001781 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301782 goto exit;
1783 }
1784
1785 return;
1786exit:
1787 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001788}
1789
Sujithe8324352009-01-16 21:38:42 +05301790/*****************/
1791/* TX Completion */
1792/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001793
Sujithe8324352009-01-16 21:38:42 +05301794static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f012010-11-11 03:18:36 +01001795 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001796 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001797{
Sujithe8324352009-01-16 21:38:42 +05301798 struct ieee80211_hw *hw = sc->hw;
1799 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001800 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001801 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001802 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301803
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001804 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301805
Felix Fietkau827e69b2009-11-15 23:09:25 +01001806 if (aphy)
1807 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301808
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301809 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301810 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301811
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301812 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301813 /* Frame was ACKed */
1814 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1815 }
1816
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001817 padpos = ath9k_cmn_padpos(hdr->frame_control);
1818 padsize = padpos & 3;
1819 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301820 /*
1821 * Remove MAC header padding before giving the frame back to
1822 * mac80211.
1823 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001824 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301825 skb_pull(skb, padsize);
1826 }
1827
Sujith1b04b932010-01-08 10:36:05 +05301828 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1829 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001830 ath_print(common, ATH_DBG_PS,
1831 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001832 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301833 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1834 PS_WAIT_FOR_CAB |
1835 PS_WAIT_FOR_PSPOLL_DATA |
1836 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001837 }
1838
Felix Fietkau61117f012010-11-11 03:18:36 +01001839 if (unlikely(ftype))
1840 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001841 else {
1842 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001843 if (txq == sc->tx.txq_map[q]) {
1844 spin_lock_bh(&txq->axq_lock);
1845 if (WARN_ON(--txq->pending_frames < 0))
1846 txq->pending_frames = 0;
1847 spin_unlock_bh(&txq->axq_lock);
1848 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001849
Felix Fietkau827e69b2009-11-15 23:09:25 +01001850 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001851 }
Sujithe8324352009-01-16 21:38:42 +05301852}
1853
1854static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001855 struct ath_txq *txq, struct list_head *bf_q,
1856 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301857{
1858 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301859 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301860 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301861
Sujithe8324352009-01-16 21:38:42 +05301862 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301863 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301864
1865 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301866 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301867
1868 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301869 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301870 }
1871
Ben Greearc1739eb32010-10-14 12:45:29 -07001872 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001873 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001874
1875 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001876 if (time_after(jiffies,
1877 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001878 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001879 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001880 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001881 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001882 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001883 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f012010-11-11 03:18:36 +01001884 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1885 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001886 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001887 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1888 * accidentally reference it later.
1889 */
1890 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301891
1892 /*
1893 * Return the list of ath_buf of this mpdu to free queue
1894 */
1895 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1896 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1897 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1898}
1899
1900static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001901 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301902{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001903 u16 seq_st = 0;
1904 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301905 int ba_index;
1906 int nbad = 0;
1907 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001908
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001909 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301910 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301911
Sujithcd3d39a2008-08-11 14:03:34 +05301912 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001913 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001914 seq_st = ts->ts_seqnum;
1915 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001916 }
1917
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001918 while (bf) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001919 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +05301920 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1921 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001922
Sujithe8324352009-01-16 21:38:42 +05301923 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001924 }
1925
Sujithe8324352009-01-16 21:38:42 +05301926 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001927}
1928
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001929static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301930 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301931{
Sujitha22be222009-03-30 15:28:36 +05301932 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301933 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301934 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001935 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001936 struct ath_softc *sc = bf->aphy->sc;
1937 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301938 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301939
Sujith95e4acb2009-03-13 08:56:09 +05301940 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001941 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301942
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001943 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301944 WARN_ON(tx_rateindex >= hw->max_rates);
1945
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001946 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301947 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001948 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001949 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301950
Björn Smedmanebd02282010-10-10 22:44:39 +02001951 BUG_ON(nbad > bf->bf_nframes);
1952
1953 tx_info->status.ampdu_len = bf->bf_nframes;
1954 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1955 }
1956
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001957 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301958 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001959 /*
1960 * If an underrun error is seen assume it as an excessive
1961 * retry only if max frame trigger level has been reached
1962 * (2 KB for single stream, and 4 KB for dual stream).
1963 * Adjust the long retry as if the frame was tried
1964 * hw->max_rate_tries times to affect how rate control updates
1965 * PER for the failed rate.
1966 * In case of congestion on the bus penalizing this type of
1967 * underruns should help hardware actually transmit new frames
1968 * successfully by eventually preferring slower rates.
1969 * This itself should also alleviate congestion on the bus.
1970 */
1971 if (ieee80211_is_data(hdr->frame_control) &&
1972 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1973 ATH9K_TX_DELIM_UNDERRUN)) &&
1974 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1975 tx_info->status.rates[tx_rateindex].count =
1976 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301977 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301978
Felix Fietkau545750d2009-11-23 22:21:01 +01001979 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301980 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001981 tx_info->status.rates[i].idx = -1;
1982 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301983
Felix Fietkau78c46532010-06-25 01:26:16 +02001984 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301985}
1986
Felix Fietkau066dae92010-11-07 14:59:39 +01001987static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301988{
Felix Fietkau066dae92010-11-07 14:59:39 +01001989 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301990
Felix Fietkau066dae92010-11-07 14:59:39 +01001991 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301992 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001993 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001994 if (ath_mac80211_start_queue(sc, qnum))
1995 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301996 }
1997 spin_unlock_bh(&txq->axq_lock);
1998}
1999
Sujithc4288392008-11-18 09:09:30 +05302000static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002001{
Sujithcbe61d82009-02-09 13:27:12 +05302002 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002003 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002004 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2005 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302006 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002007 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302008 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002009 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002010 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002011
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002012 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2013 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2014 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002015
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002016 for (;;) {
2017 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002018 if (list_empty(&txq->axq_q)) {
2019 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002020 spin_unlock_bh(&txq->axq_lock);
2021 break;
2022 }
2023 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2024
2025 /*
2026 * There is a race condition that a BH gets scheduled
2027 * after sw writes TxE and before hw re-load the last
2028 * descriptor to get the newly chained one.
2029 * Software must keep the last DONE descriptor as a
2030 * holding descriptor - software does so by marking
2031 * it with the STALE flag.
2032 */
2033 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302034 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002035 bf_held = bf;
2036 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302037 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002038 break;
2039 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002040 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302041 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002042 }
2043 }
2044
2045 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302046 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002047
Felix Fietkau29bffa92010-03-29 20:14:23 -07002048 memset(&ts, 0, sizeof(ts));
2049 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002050 if (status == -EINPROGRESS) {
2051 spin_unlock_bh(&txq->axq_lock);
2052 break;
2053 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002054
2055 /*
2056 * Remove ath_buf's of the same transmit unit from txq,
2057 * however leave the last descriptor back as the holding
2058 * descriptor for hw.
2059 */
Sujitha119cc42009-03-30 15:28:38 +05302060 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002061 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002062 if (!list_is_singular(&lastbf->list))
2063 list_cut_position(&bf_head,
2064 &txq->axq_q, lastbf->list.prev);
2065
2066 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002067 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002068 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002069 if (bf_held)
2070 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002071 spin_unlock_bh(&txq->axq_lock);
2072
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002073 if (bf_held)
2074 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002075
Sujithcd3d39a2008-08-11 14:03:34 +05302076 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002077 /*
2078 * This frame is sent out as a single frame.
2079 * Use hardware retry status for this frame.
2080 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002081 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302082 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002083 ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002084 }
Johannes Berge6a98542008-10-21 12:40:02 +02002085
Felix Fietkau066dae92010-11-07 14:59:39 +01002086 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2087
Sujithcd3d39a2008-08-11 14:03:34 +05302088 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002089 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002090 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002091 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002092
Felix Fietkau066dae92010-11-07 14:59:39 +01002093 if (txq == sc->tx.txq_map[qnum])
2094 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302095
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002096 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302097 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002098 ath_txq_schedule(sc, txq);
2099 spin_unlock_bh(&txq->axq_lock);
2100 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002101}
2102
Sujith305fe472009-07-23 15:32:29 +05302103static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002104{
2105 struct ath_softc *sc = container_of(work, struct ath_softc,
2106 tx_complete_work.work);
2107 struct ath_txq *txq;
2108 int i;
2109 bool needreset = false;
2110
2111 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2112 if (ATH_TXQ_SETUP(sc, i)) {
2113 txq = &sc->tx.txq[i];
2114 spin_lock_bh(&txq->axq_lock);
2115 if (txq->axq_depth) {
2116 if (txq->axq_tx_inprogress) {
2117 needreset = true;
2118 spin_unlock_bh(&txq->axq_lock);
2119 break;
2120 } else {
2121 txq->axq_tx_inprogress = true;
2122 }
2123 }
2124 spin_unlock_bh(&txq->axq_lock);
2125 }
2126
2127 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002128 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2129 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302130 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002131 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302132 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002133 }
2134
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002135 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002136 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2137}
2138
2139
Sujithe8324352009-01-16 21:38:42 +05302140
2141void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002142{
Sujithe8324352009-01-16 21:38:42 +05302143 int i;
2144 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002145
Sujithe8324352009-01-16 21:38:42 +05302146 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002147
2148 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302149 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2150 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002151 }
2152}
2153
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002154void ath_tx_edma_tasklet(struct ath_softc *sc)
2155{
2156 struct ath_tx_status txs;
2157 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2158 struct ath_hw *ah = sc->sc_ah;
2159 struct ath_txq *txq;
2160 struct ath_buf *bf, *lastbf;
2161 struct list_head bf_head;
2162 int status;
2163 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002164 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002165
2166 for (;;) {
2167 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2168 if (status == -EINPROGRESS)
2169 break;
2170 if (status == -EIO) {
2171 ath_print(common, ATH_DBG_XMIT,
2172 "Error processing tx status\n");
2173 break;
2174 }
2175
2176 /* Skip beacon completions */
2177 if (txs.qid == sc->beacon.beaconq)
2178 continue;
2179
2180 txq = &sc->tx.txq[txs.qid];
2181
2182 spin_lock_bh(&txq->axq_lock);
2183 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2184 spin_unlock_bh(&txq->axq_lock);
2185 return;
2186 }
2187
2188 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2189 struct ath_buf, list);
2190 lastbf = bf->bf_lastbf;
2191
2192 INIT_LIST_HEAD(&bf_head);
2193 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2194 &lastbf->list);
2195 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2196 txq->axq_depth--;
2197 txq->axq_tx_inprogress = false;
2198 spin_unlock_bh(&txq->axq_lock);
2199
2200 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2201
2202 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002203 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2204 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002205 ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002206 }
2207
Felix Fietkau066dae92010-11-07 14:59:39 +01002208 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2209
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002210 if (bf_isampdu(bf))
2211 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2212 else
2213 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2214 &txs, txok, 0);
2215
Felix Fietkau066dae92010-11-07 14:59:39 +01002216 if (txq == sc->tx.txq_map[qnum])
2217 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002218
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002219 spin_lock_bh(&txq->axq_lock);
2220 if (!list_empty(&txq->txq_fifo_pending)) {
2221 INIT_LIST_HEAD(&bf_head);
2222 bf = list_first_entry(&txq->txq_fifo_pending,
2223 struct ath_buf, list);
2224 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2225 &bf->bf_lastbf->list);
2226 ath_tx_txqaddbuf(sc, txq, &bf_head);
2227 } else if (sc->sc_flags & SC_OP_TXAGGR)
2228 ath_txq_schedule(sc, txq);
2229 spin_unlock_bh(&txq->axq_lock);
2230 }
2231}
2232
Sujithe8324352009-01-16 21:38:42 +05302233/*****************/
2234/* Init, Cleanup */
2235/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002236
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002237static int ath_txstatus_setup(struct ath_softc *sc, int size)
2238{
2239 struct ath_descdma *dd = &sc->txsdma;
2240 u8 txs_len = sc->sc_ah->caps.txs_len;
2241
2242 dd->dd_desc_len = size * txs_len;
2243 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2244 &dd->dd_desc_paddr, GFP_KERNEL);
2245 if (!dd->dd_desc)
2246 return -ENOMEM;
2247
2248 return 0;
2249}
2250
2251static int ath_tx_edma_init(struct ath_softc *sc)
2252{
2253 int err;
2254
2255 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2256 if (!err)
2257 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2258 sc->txsdma.dd_desc_paddr,
2259 ATH_TXSTATUS_RING_SIZE);
2260
2261 return err;
2262}
2263
2264static void ath_tx_edma_cleanup(struct ath_softc *sc)
2265{
2266 struct ath_descdma *dd = &sc->txsdma;
2267
2268 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2269 dd->dd_desc_paddr);
2270}
2271
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002272int ath_tx_init(struct ath_softc *sc, int nbufs)
2273{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002274 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002275 int error = 0;
2276
Sujith797fe5cb2009-03-30 15:28:45 +05302277 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002278
Sujith797fe5cb2009-03-30 15:28:45 +05302279 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002280 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302281 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002282 ath_print(common, ATH_DBG_FATAL,
2283 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302284 goto err;
2285 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002286
Sujith797fe5cb2009-03-30 15:28:45 +05302287 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002288 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302289 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002290 ath_print(common, ATH_DBG_FATAL,
2291 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302292 goto err;
2293 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002294
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002295 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2296
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002297 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2298 error = ath_tx_edma_init(sc);
2299 if (error)
2300 goto err;
2301 }
2302
Sujith797fe5cb2009-03-30 15:28:45 +05302303err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002304 if (error != 0)
2305 ath_tx_cleanup(sc);
2306
2307 return error;
2308}
2309
Sujith797fe5cb2009-03-30 15:28:45 +05302310void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002311{
Sujithb77f4832008-12-07 21:44:03 +05302312 if (sc->beacon.bdma.dd_desc_len != 0)
2313 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002314
Sujithb77f4832008-12-07 21:44:03 +05302315 if (sc->tx.txdma.dd_desc_len != 0)
2316 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002317
2318 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2319 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002320}
2321
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002322void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2323{
Sujithc5170162008-10-29 10:13:59 +05302324 struct ath_atx_tid *tid;
2325 struct ath_atx_ac *ac;
2326 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002327
Sujith8ee5afb2008-12-07 21:43:36 +05302328 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302329 tidno < WME_NUM_TID;
2330 tidno++, tid++) {
2331 tid->an = an;
2332 tid->tidno = tidno;
2333 tid->seq_start = tid->seq_next = 0;
2334 tid->baw_size = WME_MAX_BA;
2335 tid->baw_head = tid->baw_tail = 0;
2336 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302337 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302338 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302339 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302340 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302341 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302342 tid->state &= ~AGGR_ADDBA_COMPLETE;
2343 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302344 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002345
Sujith8ee5afb2008-12-07 21:43:36 +05302346 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302347 acno < WME_NUM_AC; acno++, ac++) {
2348 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002349 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302350 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002351 }
2352}
2353
Sujithb5aa9bf2008-10-29 10:13:31 +05302354void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002355{
Felix Fietkau2b409942010-07-07 19:42:08 +02002356 struct ath_atx_ac *ac;
2357 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002358 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002359 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302360
Felix Fietkau2b409942010-07-07 19:42:08 +02002361 for (tidno = 0, tid = &an->tid[tidno];
2362 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002363
Felix Fietkau2b409942010-07-07 19:42:08 +02002364 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002365 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002366
Felix Fietkau2b409942010-07-07 19:42:08 +02002367 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002368
Felix Fietkau2b409942010-07-07 19:42:08 +02002369 if (tid->sched) {
2370 list_del(&tid->list);
2371 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002372 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002373
2374 if (ac->sched) {
2375 list_del(&ac->list);
2376 tid->ac->sched = false;
2377 }
2378
2379 ath_tid_drain(sc, txq, tid);
2380 tid->state &= ~AGGR_ADDBA_COMPLETE;
2381 tid->state &= ~AGGR_CLEANUP;
2382
2383 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002384 }
2385}