blob: e84c9c282cdcdb3796c7d977d7a3c2ccd34f0a60 [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;
Sujithe8324352009-01-16 21:38:42 +0530326
Sujitha22be222009-03-30 15:28:36 +0530327 skb = bf->bf_mpdu;
Sujith1286ec62009-01-27 13:30:37 +0530328 hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +0530329
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800330 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +0100331 hw = bf->aphy->hw;
Luis R. Rodriguez76d5a9e2009-11-02 16:08:34 -0800332
Felix Fietkau78c46532010-06-25 01:26:16 +0200333 memcpy(rates, tx_info->control.rates, sizeof(rates));
Björn Smedmanebd02282010-10-10 22:44:39 +0200334 nframes = bf->bf_nframes;
Felix Fietkau78c46532010-06-25 01:26:16 +0200335
Sujith1286ec62009-01-27 13:30:37 +0530336 rcu_read_lock();
337
Ben Greear686b9cb2010-09-23 09:44:36 -0700338 sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
Sujith1286ec62009-01-27 13:30:37 +0530339 if (!sta) {
340 rcu_read_unlock();
Felix Fietkau73e19462010-07-07 19:42:09 +0200341
Felix Fietkau31e79a52010-07-12 23:16:34 +0200342 INIT_LIST_HEAD(&bf_head);
343 while (bf) {
344 bf_next = bf->bf_next;
345
346 bf->bf_state.bf_type |= BUF_XRETRY;
347 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
348 !bf->bf_stale || bf_next != NULL)
349 list_move_tail(&bf->list, &bf_head);
350
Björn Smedmanebd02282010-10-10 22:44:39 +0200351 ath_tx_rc_status(bf, ts, 1, 0, false);
Felix Fietkau31e79a52010-07-12 23:16:34 +0200352 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
353 0, 0);
354
355 bf = bf_next;
356 }
Sujith1286ec62009-01-27 13:30:37 +0530357 return;
Sujithe8324352009-01-16 21:38:42 +0530358 }
359
Sujith1286ec62009-01-27 13:30:37 +0530360 an = (struct ath_node *)sta->drv_priv;
361 tid = ATH_AN_2_TID(an, bf->bf_tidno);
362
Felix Fietkaub11b1602010-07-11 12:48:44 +0200363 /*
364 * The hardware occasionally sends a tx status for the wrong TID.
365 * In this case, the BA status cannot be considered valid and all
366 * subframes need to be retransmitted
367 */
368 if (bf->bf_tidno != ts->tid)
369 txok = false;
370
Sujithe8324352009-01-16 21:38:42 +0530371 isaggr = bf_isaggr(bf);
Sujithd43f30152009-01-16 21:38:53 +0530372 memset(ba, 0, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530373
Sujithd43f30152009-01-16 21:38:53 +0530374 if (isaggr && txok) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700375 if (ts->ts_flags & ATH9K_TX_BA) {
376 seq_st = ts->ts_seqnum;
377 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Sujithe8324352009-01-16 21:38:42 +0530378 } else {
Sujithd43f30152009-01-16 21:38:53 +0530379 /*
380 * AR5416 can become deaf/mute when BA
381 * issue happens. Chip needs to be reset.
382 * But AP code may have sychronization issues
383 * when perform internal reset in this routine.
384 * Only enable reset in STA mode for now.
385 */
Sujith2660b812009-02-09 13:27:26 +0530386 if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
Sujithd43f30152009-01-16 21:38:53 +0530387 needreset = 1;
Sujithe8324352009-01-16 21:38:42 +0530388 }
389 }
390
391 INIT_LIST_HEAD(&bf_pending);
392 INIT_LIST_HEAD(&bf_head);
393
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700394 nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
Sujithe8324352009-01-16 21:38:42 +0530395 while (bf) {
396 txfail = txpending = 0;
397 bf_next = bf->bf_next;
398
Felix Fietkau78c46532010-06-25 01:26:16 +0200399 skb = bf->bf_mpdu;
400 tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100401 bf_seqno = ath_frame_seqno(skb);
Felix Fietkau78c46532010-06-25 01:26:16 +0200402
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100403 if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) {
Sujithe8324352009-01-16 21:38:42 +0530404 /* transmit completion, subframe is
405 * acked by block ack */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530406 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530407 } else if (!isaggr && txok) {
408 /* transmit completion */
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530409 acked_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530410 } else {
Sujithe8324352009-01-16 21:38:42 +0530411 if (!(tid->state & AGGR_CLEANUP) &&
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -0400412 !bf_last->bf_tx_aborted) {
Sujithe8324352009-01-16 21:38:42 +0530413 if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
Sujithfec247c2009-07-27 12:08:16 +0530414 ath_tx_set_retry(sc, txq, bf);
Sujithe8324352009-01-16 21:38:42 +0530415 txpending = 1;
416 } else {
417 bf->bf_state.bf_type |= BUF_XRETRY;
418 txfail = 1;
419 sendbar = 1;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +0530420 txfail_cnt++;
Sujithe8324352009-01-16 21:38:42 +0530421 }
422 } else {
423 /*
424 * cleanup in progress, just fail
425 * the un-acked sub-frames
426 */
427 txfail = 1;
428 }
429 }
430
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400431 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
432 bf_next == NULL) {
Vasanthakumar Thiagarajancbfe89c2009-06-24 18:58:47 +0530433 /*
434 * Make sure the last desc is reclaimed if it
435 * not a holding desc.
436 */
437 if (!bf_last->bf_stale)
438 list_move_tail(&bf->list, &bf_head);
439 else
440 INIT_LIST_HEAD(&bf_head);
Sujithe8324352009-01-16 21:38:42 +0530441 } else {
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700442 BUG_ON(list_empty(bf_q));
Sujithd43f30152009-01-16 21:38:53 +0530443 list_move_tail(&bf->list, &bf_head);
Sujithe8324352009-01-16 21:38:42 +0530444 }
445
Felix Fietkau90fa5392010-09-20 13:45:38 +0200446 if (!txpending || (tid->state & AGGR_CLEANUP)) {
Sujithe8324352009-01-16 21:38:42 +0530447 /*
448 * complete the acked-ones/xretried ones; update
449 * block-ack window
450 */
451 spin_lock_bh(&txq->axq_lock);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100452 ath_tx_update_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +0530453 spin_unlock_bh(&txq->axq_lock);
454
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530455 if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
Felix Fietkau78c46532010-06-25 01:26:16 +0200456 memcpy(tx_info->control.rates, rates, sizeof(rates));
Björn Smedmanebd02282010-10-10 22:44:39 +0200457 bf->bf_nframes = nframes;
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700458 ath_tx_rc_status(bf, ts, nbad, txok, true);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530459 rc_update = false;
460 } else {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700461 ath_tx_rc_status(bf, ts, nbad, txok, false);
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +0530462 }
463
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700464 ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
465 !txfail, sendbar);
Sujithe8324352009-01-16 21:38:42 +0530466 } else {
Sujithd43f30152009-01-16 21:38:53 +0530467 /* retry the un-acked ones */
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400468 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
469 if (bf->bf_next == NULL && bf_last->bf_stale) {
470 struct ath_buf *tbf;
Sujithe8324352009-01-16 21:38:42 +0530471
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400472 tbf = ath_clone_txbuf(sc, bf_last);
473 /*
474 * Update tx baw and complete the
475 * frame with failed status if we
476 * run out of tx buf.
477 */
478 if (!tbf) {
479 spin_lock_bh(&txq->axq_lock);
480 ath_tx_update_baw(sc, tid,
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100481 bf_seqno);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400482 spin_unlock_bh(&txq->axq_lock);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400483
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400484 bf->bf_state.bf_type |=
485 BUF_XRETRY;
486 ath_tx_rc_status(bf, ts, nbad,
487 0, false);
488 ath_tx_complete_buf(sc, bf, txq,
489 &bf_head,
490 ts, 0, 0);
491 break;
492 }
493
494 ath9k_hw_cleartxdesc(sc->sc_ah,
495 tbf->bf_desc);
496 list_add_tail(&tbf->list, &bf_head);
497 } else {
498 /*
499 * Clear descriptor status words for
500 * software retry
501 */
502 ath9k_hw_cleartxdesc(sc->sc_ah,
503 bf->bf_desc);
Vasanthakumar Thiagarajanc41d92d2009-07-14 20:17:11 -0400504 }
Sujithe8324352009-01-16 21:38:42 +0530505 }
506
507 /*
508 * Put this buffer to the temporary pending
509 * queue to retain ordering
510 */
511 list_splice_tail_init(&bf_head, &bf_pending);
512 }
513
514 bf = bf_next;
515 }
516
Felix Fietkau4cee7862010-07-23 03:53:16 +0200517 /* prepend un-acked frames to the beginning of the pending frame queue */
518 if (!list_empty(&bf_pending)) {
519 spin_lock_bh(&txq->axq_lock);
520 list_splice(&bf_pending, &tid->buf_q);
521 ath_tx_queue_tid(txq, tid);
522 spin_unlock_bh(&txq->axq_lock);
523 }
524
Sujithe8324352009-01-16 21:38:42 +0530525 if (tid->state & AGGR_CLEANUP) {
Felix Fietkau90fa5392010-09-20 13:45:38 +0200526 ath_tx_flush_tid(sc, tid);
527
Sujithe8324352009-01-16 21:38:42 +0530528 if (tid->baw_head == tid->baw_tail) {
529 tid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithe8324352009-01-16 21:38:42 +0530530 tid->state &= ~AGGR_CLEANUP;
Sujithd43f30152009-01-16 21:38:53 +0530531 }
Sujithe8324352009-01-16 21:38:42 +0530532 }
533
Sujith1286ec62009-01-27 13:30:37 +0530534 rcu_read_unlock();
535
Sujithe8324352009-01-16 21:38:42 +0530536 if (needreset)
537 ath_reset(sc, false);
Sujithe8324352009-01-16 21:38:42 +0530538}
539
540static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
541 struct ath_atx_tid *tid)
542{
Sujithe8324352009-01-16 21:38:42 +0530543 struct sk_buff *skb;
544 struct ieee80211_tx_info *tx_info;
545 struct ieee80211_tx_rate *rates;
Sujithd43f30152009-01-16 21:38:53 +0530546 u32 max_4ms_framelen, frmlen;
Sujith4ef70842009-07-23 15:32:41 +0530547 u16 aggr_limit, legacy = 0;
Sujithe8324352009-01-16 21:38:42 +0530548 int i;
549
Sujitha22be222009-03-30 15:28:36 +0530550 skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +0530551 tx_info = IEEE80211_SKB_CB(skb);
552 rates = tx_info->control.rates;
Sujithe8324352009-01-16 21:38:42 +0530553
554 /*
555 * Find the lowest frame length among the rate series that will have a
556 * 4ms transmit duration.
557 * TODO - TXOP limit needs to be considered.
558 */
559 max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
560
561 for (i = 0; i < 4; i++) {
562 if (rates[i].count) {
Felix Fietkau545750d2009-11-23 22:21:01 +0100563 int modeidx;
564 if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
Sujithe8324352009-01-16 21:38:42 +0530565 legacy = 1;
566 break;
567 }
568
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200569 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
Felix Fietkau545750d2009-11-23 22:21:01 +0100570 modeidx = MCS_HT40;
571 else
Felix Fietkau0e668cd2010-04-19 19:57:32 +0200572 modeidx = MCS_HT20;
573
574 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
575 modeidx++;
Felix Fietkau545750d2009-11-23 22:21:01 +0100576
577 frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
Sujithd43f30152009-01-16 21:38:53 +0530578 max_4ms_framelen = min(max_4ms_framelen, frmlen);
Sujithe8324352009-01-16 21:38:42 +0530579 }
580 }
581
582 /*
583 * limit aggregate size by the minimum rate if rate selected is
584 * not a probe rate, if rate selected is a probe rate then
585 * avoid aggregation of this packet.
586 */
587 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
588 return 0;
589
Vasanthakumar Thiagarajan17739122009-08-26 21:08:50 +0530590 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
591 aggr_limit = min((max_4ms_framelen * 3) / 8,
592 (u32)ATH_AMPDU_LIMIT_MAX);
593 else
594 aggr_limit = min(max_4ms_framelen,
595 (u32)ATH_AMPDU_LIMIT_MAX);
Sujithe8324352009-01-16 21:38:42 +0530596
597 /*
598 * h/w can accept aggregates upto 16 bit lengths (65535).
599 * The IE, however can hold upto 65536, which shows up here
600 * as zero. Ignore 65536 since we are constrained by hw.
601 */
Sujith4ef70842009-07-23 15:32:41 +0530602 if (tid->an->maxampdu)
603 aggr_limit = min(aggr_limit, tid->an->maxampdu);
Sujithe8324352009-01-16 21:38:42 +0530604
605 return aggr_limit;
606}
607
608/*
Sujithd43f30152009-01-16 21:38:53 +0530609 * Returns the number of delimiters to be added to
Sujithe8324352009-01-16 21:38:42 +0530610 * meet the minimum required mpdudensity.
Sujithe8324352009-01-16 21:38:42 +0530611 */
612static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
613 struct ath_buf *bf, u16 frmlen)
614{
Sujithe8324352009-01-16 21:38:42 +0530615 struct sk_buff *skb = bf->bf_mpdu;
616 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujith4ef70842009-07-23 15:32:41 +0530617 u32 nsymbits, nsymbols;
Sujithe8324352009-01-16 21:38:42 +0530618 u16 minlen;
Felix Fietkau545750d2009-11-23 22:21:01 +0100619 u8 flags, rix;
Felix Fietkauc6663872010-04-19 19:57:33 +0200620 int width, streams, half_gi, ndelim, mindelim;
Sujithe8324352009-01-16 21:38:42 +0530621
622 /* Select standard number of delimiters based on frame length alone */
623 ndelim = ATH_AGGR_GET_NDELIM(frmlen);
624
625 /*
626 * If encryption enabled, hardware requires some more padding between
627 * subframes.
628 * TODO - this could be improved to be dependent on the rate.
629 * The hardware can keep up at lower rates, but not higher rates
630 */
631 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
632 ndelim += ATH_AGGR_ENCRYPTDELIM;
633
634 /*
635 * Convert desired mpdu density from microeconds to bytes based
636 * on highest rate in rate series (i.e. first rate) to determine
637 * required minimum length for subframe. Take into account
638 * whether high rate is 20 or 40Mhz and half or full GI.
Sujith4ef70842009-07-23 15:32:41 +0530639 *
Sujithe8324352009-01-16 21:38:42 +0530640 * If there is no mpdu density restriction, no further calculation
641 * is needed.
642 */
Sujith4ef70842009-07-23 15:32:41 +0530643
644 if (tid->an->mpdudensity == 0)
Sujithe8324352009-01-16 21:38:42 +0530645 return ndelim;
646
647 rix = tx_info->control.rates[0].idx;
648 flags = tx_info->control.rates[0].flags;
Sujithe8324352009-01-16 21:38:42 +0530649 width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
650 half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
651
652 if (half_gi)
Sujith4ef70842009-07-23 15:32:41 +0530653 nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530654 else
Sujith4ef70842009-07-23 15:32:41 +0530655 nsymbols = NUM_SYMBOLS_PER_USEC(tid->an->mpdudensity);
Sujithe8324352009-01-16 21:38:42 +0530656
657 if (nsymbols == 0)
658 nsymbols = 1;
659
Felix Fietkauc6663872010-04-19 19:57:33 +0200660 streams = HT_RC_2_STREAMS(rix);
661 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Sujithe8324352009-01-16 21:38:42 +0530662 minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
663
Sujithe8324352009-01-16 21:38:42 +0530664 if (frmlen < minlen) {
Sujithe8324352009-01-16 21:38:42 +0530665 mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
666 ndelim = max(mindelim, ndelim);
667 }
668
669 return ndelim;
670}
671
672static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
Sujithfec247c2009-07-27 12:08:16 +0530673 struct ath_txq *txq,
Sujithd43f30152009-01-16 21:38:53 +0530674 struct ath_atx_tid *tid,
675 struct list_head *bf_q)
Sujithe8324352009-01-16 21:38:42 +0530676{
677#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
Sujithd43f30152009-01-16 21:38:53 +0530678 struct ath_buf *bf, *bf_first, *bf_prev = NULL;
679 int rl = 0, nframes = 0, ndelim, prev_al = 0;
Sujithe8324352009-01-16 21:38:42 +0530680 u16 aggr_limit = 0, al = 0, bpad = 0,
681 al_delta, h_baw = tid->baw_size / 2;
682 enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
Felix Fietkau0299a502010-10-21 02:47:24 +0200683 struct ieee80211_tx_info *tx_info;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100684 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +0530685
686 bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
687
688 do {
689 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100690 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +0530691
Sujithd43f30152009-01-16 21:38:53 +0530692 /* do not step over block-ack window */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100693 if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) {
Sujithe8324352009-01-16 21:38:42 +0530694 status = ATH_AGGR_BAW_CLOSED;
695 break;
696 }
697
698 if (!rl) {
699 aggr_limit = ath_lookup_rate(sc, bf, tid);
700 rl = 1;
701 }
702
Sujithd43f30152009-01-16 21:38:53 +0530703 /* do not exceed aggregation limit */
Sujithe8324352009-01-16 21:38:42 +0530704 al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
705
Sujithd43f30152009-01-16 21:38:53 +0530706 if (nframes &&
707 (aggr_limit < (al + bpad + al_delta + prev_al))) {
Sujithe8324352009-01-16 21:38:42 +0530708 status = ATH_AGGR_LIMITED;
709 break;
710 }
711
Felix Fietkau0299a502010-10-21 02:47:24 +0200712 tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
713 if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
714 !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
715 break;
716
Sujithd43f30152009-01-16 21:38:53 +0530717 /* do not exceed subframe limit */
718 if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
Sujithe8324352009-01-16 21:38:42 +0530719 status = ATH_AGGR_LIMITED;
720 break;
721 }
Sujithd43f30152009-01-16 21:38:53 +0530722 nframes++;
Sujithe8324352009-01-16 21:38:42 +0530723
Sujithd43f30152009-01-16 21:38:53 +0530724 /* add padding for previous frame to aggregation length */
Sujithe8324352009-01-16 21:38:42 +0530725 al += bpad + al_delta;
726
727 /*
728 * Get the delimiters needed to meet the MPDU
729 * density for this node.
730 */
731 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
Sujithe8324352009-01-16 21:38:42 +0530732 bpad = PADBYTES(al_delta) + (ndelim << 2);
733
734 bf->bf_next = NULL;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400735 ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
Sujithe8324352009-01-16 21:38:42 +0530736
Sujithd43f30152009-01-16 21:38:53 +0530737 /* link buffers of this frame to the aggregate */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +0100738 if (!bf_isretried(bf))
739 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithd43f30152009-01-16 21:38:53 +0530740 ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
741 list_move_tail(&bf->list, bf_q);
Sujithe8324352009-01-16 21:38:42 +0530742 if (bf_prev) {
743 bf_prev->bf_next = bf;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -0400744 ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
745 bf->bf_daddr);
Sujithe8324352009-01-16 21:38:42 +0530746 }
747 bf_prev = bf;
Sujithfec247c2009-07-27 12:08:16 +0530748
Sujithe8324352009-01-16 21:38:42 +0530749 } while (!list_empty(&tid->buf_q));
750
751 bf_first->bf_al = al;
752 bf_first->bf_nframes = nframes;
Sujithd43f30152009-01-16 21:38:53 +0530753
Sujithe8324352009-01-16 21:38:42 +0530754 return status;
755#undef PADBYTES
756}
757
758static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
759 struct ath_atx_tid *tid)
760{
Sujithd43f30152009-01-16 21:38:53 +0530761 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +0530762 enum ATH_AGGR_STATUS status;
763 struct list_head bf_q;
Sujithe8324352009-01-16 21:38:42 +0530764
765 do {
766 if (list_empty(&tid->buf_q))
767 return;
768
769 INIT_LIST_HEAD(&bf_q);
770
Sujithfec247c2009-07-27 12:08:16 +0530771 status = ath_tx_form_aggr(sc, txq, tid, &bf_q);
Sujithe8324352009-01-16 21:38:42 +0530772
773 /*
Sujithd43f30152009-01-16 21:38:53 +0530774 * no frames picked up to be aggregated;
775 * block-ack window is not open.
Sujithe8324352009-01-16 21:38:42 +0530776 */
777 if (list_empty(&bf_q))
778 break;
779
780 bf = list_first_entry(&bf_q, struct ath_buf, list);
Sujithd43f30152009-01-16 21:38:53 +0530781 bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
Sujithe8324352009-01-16 21:38:42 +0530782
Sujithd43f30152009-01-16 21:38:53 +0530783 /* if only one frame, send as non-aggregate */
Sujithe8324352009-01-16 21:38:42 +0530784 if (bf->bf_nframes == 1) {
Sujithe8324352009-01-16 21:38:42 +0530785 bf->bf_state.bf_type &= ~BUF_AGGR;
Sujithd43f30152009-01-16 21:38:53 +0530786 ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530787 ath_buf_set_rate(sc, bf);
788 ath_tx_txqaddbuf(sc, txq, &bf_q);
789 continue;
790 }
791
Sujithd43f30152009-01-16 21:38:53 +0530792 /* setup first desc of aggregate */
Sujithe8324352009-01-16 21:38:42 +0530793 bf->bf_state.bf_type |= BUF_AGGR;
794 ath_buf_set_rate(sc, bf);
795 ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
796
Sujithd43f30152009-01-16 21:38:53 +0530797 /* anchor last desc of aggregate */
798 ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
Sujithe8324352009-01-16 21:38:42 +0530799
Sujithe8324352009-01-16 21:38:42 +0530800 ath_tx_txqaddbuf(sc, txq, &bf_q);
Sujithfec247c2009-07-27 12:08:16 +0530801 TX_STAT_INC(txq->axq_qnum, a_aggr);
Sujithe8324352009-01-16 21:38:42 +0530802
803 } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
804 status != ATH_AGGR_BAW_CLOSED);
805}
806
Felix Fietkau231c3a12010-09-20 19:35:28 +0200807int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
808 u16 tid, u16 *ssn)
Sujithe8324352009-01-16 21:38:42 +0530809{
810 struct ath_atx_tid *txtid;
811 struct ath_node *an;
812
813 an = (struct ath_node *)sta->drv_priv;
Sujithf83da962009-07-23 15:32:37 +0530814 txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau231c3a12010-09-20 19:35:28 +0200815
816 if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
817 return -EAGAIN;
818
Sujithf83da962009-07-23 15:32:37 +0530819 txtid->state |= AGGR_ADDBA_PROGRESS;
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200820 txtid->paused = true;
Sujithf83da962009-07-23 15:32:37 +0530821 *ssn = txtid->seq_start;
Felix Fietkau231c3a12010-09-20 19:35:28 +0200822
823 return 0;
Sujithe8324352009-01-16 21:38:42 +0530824}
825
Sujithf83da962009-07-23 15:32:37 +0530826void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
Sujithe8324352009-01-16 21:38:42 +0530827{
828 struct ath_node *an = (struct ath_node *)sta->drv_priv;
829 struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
Felix Fietkau066dae92010-11-07 14:59:39 +0100830 struct ath_txq *txq = txtid->ac->txq;
Sujithe8324352009-01-16 21:38:42 +0530831
832 if (txtid->state & AGGR_CLEANUP)
Sujithf83da962009-07-23 15:32:37 +0530833 return;
Sujithe8324352009-01-16 21:38:42 +0530834
835 if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
Vasanthakumar Thiagarajan5eae6592009-06-09 15:28:21 +0530836 txtid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithf83da962009-07-23 15:32:37 +0530837 return;
Sujithe8324352009-01-16 21:38:42 +0530838 }
839
Sujithe8324352009-01-16 21:38:42 +0530840 spin_lock_bh(&txq->axq_lock);
Lorenzo Bianconi75401842010-08-01 15:47:32 +0200841 txtid->paused = true;
Felix Fietkau90fa5392010-09-20 13:45:38 +0200842
843 /*
844 * If frames are still being transmitted for this TID, they will be
845 * cleaned up during tx completion. To prevent race conditions, this
846 * TID can only be reused after all in-progress subframes have been
847 * completed.
848 */
849 if (txtid->baw_head != txtid->baw_tail)
850 txtid->state |= AGGR_CLEANUP;
851 else
852 txtid->state &= ~AGGR_ADDBA_COMPLETE;
Sujithd43f30152009-01-16 21:38:53 +0530853 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +0530854
Felix Fietkau90fa5392010-09-20 13:45:38 +0200855 ath_tx_flush_tid(sc, txtid);
Sujithe8324352009-01-16 21:38:42 +0530856}
857
858void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
859{
860 struct ath_atx_tid *txtid;
861 struct ath_node *an;
862
863 an = (struct ath_node *)sta->drv_priv;
864
865 if (sc->sc_flags & SC_OP_TXAGGR) {
866 txtid = ATH_AN_2_TID(an, tid);
867 txtid->baw_size =
868 IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
869 txtid->state |= AGGR_ADDBA_COMPLETE;
870 txtid->state &= ~AGGR_ADDBA_PROGRESS;
871 ath_tx_resume_tid(sc, txtid);
872 }
873}
874
Sujithe8324352009-01-16 21:38:42 +0530875/********************/
876/* Queue Management */
877/********************/
878
Sujithe8324352009-01-16 21:38:42 +0530879static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
880 struct ath_txq *txq)
881{
882 struct ath_atx_ac *ac, *ac_tmp;
883 struct ath_atx_tid *tid, *tid_tmp;
884
885 list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
886 list_del(&ac->list);
887 ac->sched = false;
888 list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
889 list_del(&tid->list);
890 tid->sched = false;
891 ath_tid_drain(sc, txq, tid);
892 }
893 }
894}
895
896struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
897{
Sujithcbe61d82009-02-09 13:27:12 +0530898 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700899 struct ath_common *common = ath9k_hw_common(ah);
Sujithe8324352009-01-16 21:38:42 +0530900 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +0100901 static const int subtype_txq_to_hwq[] = {
902 [WME_AC_BE] = ATH_TXQ_AC_BE,
903 [WME_AC_BK] = ATH_TXQ_AC_BK,
904 [WME_AC_VI] = ATH_TXQ_AC_VI,
905 [WME_AC_VO] = ATH_TXQ_AC_VO,
906 };
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400907 int qnum, i;
Sujithe8324352009-01-16 21:38:42 +0530908
909 memset(&qi, 0, sizeof(qi));
Felix Fietkau066dae92010-11-07 14:59:39 +0100910 qi.tqi_subtype = subtype_txq_to_hwq[subtype];
Sujithe8324352009-01-16 21:38:42 +0530911 qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
912 qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
913 qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
914 qi.tqi_physCompBuf = 0;
915
916 /*
917 * Enable interrupts only for EOL and DESC conditions.
918 * We mark tx descriptors to receive a DESC interrupt
919 * when a tx queue gets deep; otherwise waiting for the
920 * EOL to reap descriptors. Note that this is done to
921 * reduce interrupt load and this only defers reaping
922 * descriptors, never transmitting frames. Aside from
923 * reducing interrupts this also permits more concurrency.
924 * The only potential downside is if the tx queue backs
925 * up in which case the top half of the kernel may backup
926 * due to a lack of tx descriptors.
927 *
928 * The UAPSD queue is an exception, since we take a desc-
929 * based intr on the EOSP frames.
930 */
Vasanthakumar Thiagarajanafe754d2010-04-15 17:39:40 -0400931 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
932 qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
933 TXQ_FLAG_TXERRINT_ENABLE;
934 } else {
935 if (qtype == ATH9K_TX_QUEUE_UAPSD)
936 qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
937 else
938 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
939 TXQ_FLAG_TXDESCINT_ENABLE;
940 }
Sujithe8324352009-01-16 21:38:42 +0530941 qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
942 if (qnum == -1) {
943 /*
944 * NB: don't print a message, this happens
945 * normally on parts with too few tx queues
946 */
947 return NULL;
948 }
949 if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700950 ath_print(common, ATH_DBG_FATAL,
951 "qnum %u out of range, max %u!\n",
952 qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
Sujithe8324352009-01-16 21:38:42 +0530953 ath9k_hw_releasetxqueue(ah, qnum);
954 return NULL;
955 }
956 if (!ATH_TXQ_SETUP(sc, qnum)) {
957 struct ath_txq *txq = &sc->tx.txq[qnum];
958
959 txq->axq_qnum = qnum;
960 txq->axq_link = NULL;
961 INIT_LIST_HEAD(&txq->axq_q);
962 INIT_LIST_HEAD(&txq->axq_acq);
963 spin_lock_init(&txq->axq_lock);
964 txq->axq_depth = 0;
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400965 txq->axq_tx_inprogress = false;
Sujithe8324352009-01-16 21:38:42 +0530966 sc->tx.txqsetup |= 1<<qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400967
968 txq->txq_headidx = txq->txq_tailidx = 0;
969 for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
970 INIT_LIST_HEAD(&txq->txq_fifo[i]);
971 INIT_LIST_HEAD(&txq->txq_fifo_pending);
Sujithe8324352009-01-16 21:38:42 +0530972 }
973 return &sc->tx.txq[qnum];
974}
975
Sujithe8324352009-01-16 21:38:42 +0530976int ath_txq_update(struct ath_softc *sc, int qnum,
977 struct ath9k_tx_queue_info *qinfo)
978{
Sujithcbe61d82009-02-09 13:27:12 +0530979 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +0530980 int error = 0;
981 struct ath9k_tx_queue_info qi;
982
983 if (qnum == sc->beacon.beaconq) {
984 /*
985 * XXX: for beacon queue, we just save the parameter.
986 * It will be picked up by ath_beaconq_config when
987 * it's necessary.
988 */
989 sc->beacon.beacon_qi = *qinfo;
990 return 0;
991 }
992
Luis R. Rodriguez9680e8a2009-09-13 23:28:00 -0700993 BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
Sujithe8324352009-01-16 21:38:42 +0530994
995 ath9k_hw_get_txq_props(ah, qnum, &qi);
996 qi.tqi_aifs = qinfo->tqi_aifs;
997 qi.tqi_cwmin = qinfo->tqi_cwmin;
998 qi.tqi_cwmax = qinfo->tqi_cwmax;
999 qi.tqi_burstTime = qinfo->tqi_burstTime;
1000 qi.tqi_readyTime = qinfo->tqi_readyTime;
1001
1002 if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001003 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1004 "Unable to update hardware queue %u!\n", qnum);
Sujithe8324352009-01-16 21:38:42 +05301005 error = -EIO;
1006 } else {
1007 ath9k_hw_resettxqueue(ah, qnum);
1008 }
1009
1010 return error;
1011}
1012
1013int ath_cabq_update(struct ath_softc *sc)
1014{
1015 struct ath9k_tx_queue_info qi;
1016 int qnum = sc->beacon.cabq->axq_qnum;
Sujithe8324352009-01-16 21:38:42 +05301017
1018 ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
1019 /*
1020 * Ensure the readytime % is within the bounds.
1021 */
Sujith17d79042009-02-09 13:27:03 +05301022 if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
1023 sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
1024 else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
1025 sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
Sujithe8324352009-01-16 21:38:42 +05301026
Johannes Berg57c4d7b2009-04-23 16:10:04 +02001027 qi.tqi_readyTime = (sc->beacon_interval *
Sujithfdbf7332009-02-17 15:36:35 +05301028 sc->config.cabqReadytime) / 100;
Sujithe8324352009-01-16 21:38:42 +05301029 ath_txq_update(sc, qnum, &qi);
1030
1031 return 0;
1032}
1033
Sujith043a0402009-01-16 21:38:47 +05301034/*
1035 * Drain a given TX queue (could be Beacon or Data)
1036 *
1037 * This assumes output has been stopped and
1038 * we do not need to block ath_tx_tasklet.
1039 */
1040void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
Sujithe8324352009-01-16 21:38:42 +05301041{
1042 struct ath_buf *bf, *lastbf;
1043 struct list_head bf_head;
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001044 struct ath_tx_status ts;
1045
1046 memset(&ts, 0, sizeof(ts));
Sujithe8324352009-01-16 21:38:42 +05301047 INIT_LIST_HEAD(&bf_head);
1048
Sujithe8324352009-01-16 21:38:42 +05301049 for (;;) {
1050 spin_lock_bh(&txq->axq_lock);
1051
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001052 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1053 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
1054 txq->txq_headidx = txq->txq_tailidx = 0;
1055 spin_unlock_bh(&txq->axq_lock);
1056 break;
1057 } else {
1058 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
1059 struct ath_buf, list);
1060 }
1061 } else {
1062 if (list_empty(&txq->axq_q)) {
1063 txq->axq_link = NULL;
1064 spin_unlock_bh(&txq->axq_lock);
1065 break;
1066 }
1067 bf = list_first_entry(&txq->axq_q, struct ath_buf,
1068 list);
Sujithe8324352009-01-16 21:38:42 +05301069
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001070 if (bf->bf_stale) {
1071 list_del(&bf->list);
1072 spin_unlock_bh(&txq->axq_lock);
Sujithe8324352009-01-16 21:38:42 +05301073
Felix Fietkau0a8cea82010-04-19 19:57:30 +02001074 ath_tx_return_buffer(sc, bf);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001075 continue;
1076 }
Sujithe8324352009-01-16 21:38:42 +05301077 }
1078
1079 lastbf = bf->bf_lastbf;
Vasanthakumar Thiagarajan6d913f72010-04-15 17:38:46 -04001080 if (!retry_tx)
1081 lastbf->bf_tx_aborted = true;
Sujithe8324352009-01-16 21:38:42 +05301082
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001083 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1084 list_cut_position(&bf_head,
1085 &txq->txq_fifo[txq->txq_tailidx],
1086 &lastbf->list);
1087 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
1088 } else {
1089 /* remove ath_buf's of the same mpdu from txq */
1090 list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
1091 }
1092
Sujithe8324352009-01-16 21:38:42 +05301093 txq->axq_depth--;
1094
1095 spin_unlock_bh(&txq->axq_lock);
1096
1097 if (bf_isampdu(bf))
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001098 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
Sujithe8324352009-01-16 21:38:42 +05301099 else
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001100 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
Sujithe8324352009-01-16 21:38:42 +05301101 }
1102
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001103 spin_lock_bh(&txq->axq_lock);
1104 txq->axq_tx_inprogress = false;
1105 spin_unlock_bh(&txq->axq_lock);
1106
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001107 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1108 spin_lock_bh(&txq->axq_lock);
1109 while (!list_empty(&txq->txq_fifo_pending)) {
1110 bf = list_first_entry(&txq->txq_fifo_pending,
1111 struct ath_buf, list);
1112 list_cut_position(&bf_head,
1113 &txq->txq_fifo_pending,
1114 &bf->bf_lastbf->list);
1115 spin_unlock_bh(&txq->axq_lock);
1116
1117 if (bf_isampdu(bf))
1118 ath_tx_complete_aggr(sc, txq, bf, &bf_head,
1119 &ts, 0);
1120 else
1121 ath_tx_complete_buf(sc, bf, txq, &bf_head,
1122 &ts, 0, 0);
1123 spin_lock_bh(&txq->axq_lock);
1124 }
1125 spin_unlock_bh(&txq->axq_lock);
1126 }
Felix Fietkaue609e2e2010-10-27 02:15:05 +02001127
1128 /* flush any pending frames if aggregation is enabled */
1129 if (sc->sc_flags & SC_OP_TXAGGR) {
1130 if (!retry_tx) {
1131 spin_lock_bh(&txq->axq_lock);
1132 ath_txq_drain_pending_buffers(sc, txq);
1133 spin_unlock_bh(&txq->axq_lock);
1134 }
1135 }
Sujithe8324352009-01-16 21:38:42 +05301136}
1137
Sujith043a0402009-01-16 21:38:47 +05301138void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
1139{
Sujithcbe61d82009-02-09 13:27:12 +05301140 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001141 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith043a0402009-01-16 21:38:47 +05301142 struct ath_txq *txq;
1143 int i, npend = 0;
1144
1145 if (sc->sc_flags & SC_OP_INVALID)
1146 return;
1147
1148 /* Stop beacon queue */
1149 ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
1150
1151 /* Stop data queues */
1152 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1153 if (ATH_TXQ_SETUP(sc, i)) {
1154 txq = &sc->tx.txq[i];
1155 ath9k_hw_stoptxdma(ah, txq->axq_qnum);
1156 npend += ath9k_hw_numtxpending(ah, txq->axq_qnum);
1157 }
1158 }
1159
1160 if (npend) {
1161 int r;
1162
Sujithe8009e92009-12-14 14:57:08 +05301163 ath_print(common, ATH_DBG_FATAL,
Justin P. Mattock9be8ab22010-05-26 11:00:04 -07001164 "Failed to stop TX DMA. Resetting hardware!\n");
Sujith043a0402009-01-16 21:38:47 +05301165
Felix Fietkau20bd2a02010-07-31 00:12:00 +02001166 r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
Sujith043a0402009-01-16 21:38:47 +05301167 if (r)
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001168 ath_print(common, ATH_DBG_FATAL,
1169 "Unable to reset hardware; reset status %d\n",
1170 r);
Sujith043a0402009-01-16 21:38:47 +05301171 }
1172
1173 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1174 if (ATH_TXQ_SETUP(sc, i))
1175 ath_draintxq(sc, &sc->tx.txq[i], retry_tx);
1176 }
1177}
1178
Sujithe8324352009-01-16 21:38:42 +05301179void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
1180{
1181 ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
1182 sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
1183}
1184
Sujithe8324352009-01-16 21:38:42 +05301185void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
1186{
1187 struct ath_atx_ac *ac;
1188 struct ath_atx_tid *tid;
1189
1190 if (list_empty(&txq->axq_acq))
1191 return;
1192
1193 ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
1194 list_del(&ac->list);
1195 ac->sched = false;
1196
1197 do {
1198 if (list_empty(&ac->tid_q))
1199 return;
1200
1201 tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
1202 list_del(&tid->list);
1203 tid->sched = false;
1204
1205 if (tid->paused)
1206 continue;
1207
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04001208 ath_tx_sched_aggr(sc, txq, tid);
Sujithe8324352009-01-16 21:38:42 +05301209
1210 /*
1211 * add tid to round-robin queue if more frames
1212 * are pending for the tid
1213 */
1214 if (!list_empty(&tid->buf_q))
1215 ath_tx_queue_tid(txq, tid);
1216
1217 break;
1218 } while (!list_empty(&ac->tid_q));
1219
1220 if (!list_empty(&ac->tid_q)) {
1221 if (!ac->sched) {
1222 ac->sched = true;
1223 list_add_tail(&ac->list, &txq->axq_acq);
1224 }
1225 }
1226}
1227
Sujithe8324352009-01-16 21:38:42 +05301228/***********/
1229/* TX, DMA */
1230/***********/
1231
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001232/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001233 * Insert a chain of ath_buf (descriptors) on a txq and
1234 * assume the descriptors are already chained together by caller.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001235 */
Sujith102e0572008-10-29 10:15:16 +05301236static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
1237 struct list_head *head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001238{
Sujithcbe61d82009-02-09 13:27:12 +05301239 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001240 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001241 struct ath_buf *bf;
Sujith102e0572008-10-29 10:15:16 +05301242
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001243 /*
1244 * Insert the frame on the outbound list and
1245 * pass it on to the hardware.
1246 */
1247
1248 if (list_empty(head))
1249 return;
1250
1251 bf = list_first_entry(head, struct ath_buf, list);
1252
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001253 ath_print(common, ATH_DBG_QUEUE,
1254 "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001255
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001256 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
1257 if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
1258 list_splice_tail_init(head, &txq->txq_fifo_pending);
1259 return;
1260 }
1261 if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
1262 ath_print(common, ATH_DBG_XMIT,
1263 "Initializing tx fifo %d which "
1264 "is non-empty\n",
1265 txq->txq_headidx);
1266 INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
1267 list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
1268 INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001269 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001270 ath_print(common, ATH_DBG_XMIT,
1271 "TXDP[%u] = %llx (%p)\n",
1272 txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001274 list_splice_tail_init(head, &txq->axq_q);
1275
1276 if (txq->axq_link == NULL) {
1277 ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
1278 ath_print(common, ATH_DBG_XMIT,
1279 "TXDP[%u] = %llx (%p)\n",
1280 txq->axq_qnum, ito64(bf->bf_daddr),
1281 bf->bf_desc);
1282 } else {
1283 *txq->axq_link = bf->bf_daddr;
1284 ath_print(common, ATH_DBG_XMIT,
1285 "link[%u] (%p)=%llx (%p)\n",
1286 txq->axq_qnum, txq->axq_link,
1287 ito64(bf->bf_daddr), bf->bf_desc);
1288 }
1289 ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
1290 &txq->axq_link);
1291 ath9k_hw_txstart(ah, txq->axq_qnum);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001292 }
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04001293 txq->axq_depth++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001294}
1295
Sujithe8324352009-01-16 21:38:42 +05301296static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
1297 struct list_head *bf_head,
1298 struct ath_tx_control *txctl)
1299{
1300 struct ath_buf *bf;
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001301 u16 bf_seqno;
Sujithe8324352009-01-16 21:38:42 +05301302
Sujithe8324352009-01-16 21:38:42 +05301303 bf = list_first_entry(bf_head, struct ath_buf, list);
1304 bf->bf_state.bf_type |= BUF_AMPDU;
Sujithfec247c2009-07-27 12:08:16 +05301305 TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001306 bf_seqno = ath_frame_seqno(bf->bf_mpdu);
Sujithe8324352009-01-16 21:38:42 +05301307
1308 /*
1309 * Do not queue to h/w when any of the following conditions is true:
1310 * - there are pending frames in software queue
1311 * - the TID is currently paused for ADDBA/BAR request
1312 * - seqno is not within block-ack window
1313 * - h/w queue depth exceeds low water mark
1314 */
1315 if (!list_empty(&tid->buf_q) || tid->paused ||
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001316 !BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) ||
Sujithe8324352009-01-16 21:38:42 +05301317 txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001318 /*
Sujithe8324352009-01-16 21:38:42 +05301319 * Add this frame to software queue for scheduling later
1320 * for aggregation.
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001321 */
Sujithd43f30152009-01-16 21:38:53 +05301322 list_move_tail(&bf->list, &tid->buf_q);
Sujithe8324352009-01-16 21:38:42 +05301323 ath_tx_queue_tid(txctl->txq, tid);
1324 return;
Jouni Malinenf7a276a2008-12-15 16:02:04 +02001325 }
1326
Sujithe8324352009-01-16 21:38:42 +05301327 /* Add sub-frame to BAW */
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001328 if (!bf_isretried(bf))
1329 ath_tx_addto_baw(sc, tid, bf_seqno);
Sujithe8324352009-01-16 21:38:42 +05301330
1331 /* Queue to h/w without aggregation */
1332 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301333 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301334 ath_buf_set_rate(sc, bf);
1335 ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
Sujithc4288392008-11-18 09:09:30 +05301336}
1337
Felix Fietkau82b873a2010-11-11 03:18:37 +01001338static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
1339 struct ath_atx_tid *tid,
1340 struct list_head *bf_head)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001341{
Sujithe8324352009-01-16 21:38:42 +05301342 struct ath_buf *bf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001343
Sujithe8324352009-01-16 21:38:42 +05301344 bf = list_first_entry(bf_head, struct ath_buf, list);
1345 bf->bf_state.bf_type &= ~BUF_AMPDU;
1346
1347 /* update starting sequence number for subsequent ADDBA request */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001348 if (tid)
1349 INCR(tid->seq_start, IEEE80211_SEQ_MAX);
Sujithe8324352009-01-16 21:38:42 +05301350
1351 bf->bf_nframes = 1;
Sujithd43f30152009-01-16 21:38:53 +05301352 bf->bf_lastbf = bf;
Sujithe8324352009-01-16 21:38:42 +05301353 ath_buf_set_rate(sc, bf);
1354 ath_tx_txqaddbuf(sc, txq, bf_head);
Sujithfec247c2009-07-27 12:08:16 +05301355 TX_STAT_INC(txq->axq_qnum, queued);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001356}
1357
Sujith528f0c62008-10-29 10:14:26 +05301358static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001359{
Sujith528f0c62008-10-29 10:14:26 +05301360 struct ieee80211_hdr *hdr;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001361 enum ath9k_pkt_type htype;
1362 __le16 fc;
1363
Sujith528f0c62008-10-29 10:14:26 +05301364 hdr = (struct ieee80211_hdr *)skb->data;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001365 fc = hdr->frame_control;
1366
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001367 if (ieee80211_is_beacon(fc))
1368 htype = ATH9K_PKT_TYPE_BEACON;
1369 else if (ieee80211_is_probe_resp(fc))
1370 htype = ATH9K_PKT_TYPE_PROBE_RESP;
1371 else if (ieee80211_is_atim(fc))
1372 htype = ATH9K_PKT_TYPE_ATIM;
1373 else if (ieee80211_is_pspoll(fc))
1374 htype = ATH9K_PKT_TYPE_PSPOLL;
1375 else
1376 htype = ATH9K_PKT_TYPE_NORMAL;
1377
1378 return htype;
1379}
1380
Sujith528f0c62008-10-29 10:14:26 +05301381static void assign_aggr_tid_seqno(struct sk_buff *skb,
1382 struct ath_buf *bf)
1383{
1384 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1385 struct ieee80211_hdr *hdr;
1386 struct ath_node *an;
1387 struct ath_atx_tid *tid;
1388 __le16 fc;
1389 u8 *qc;
1390
1391 if (!tx_info->control.sta)
1392 return;
1393
1394 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1395 hdr = (struct ieee80211_hdr *)skb->data;
1396 fc = hdr->frame_control;
1397
Sujith528f0c62008-10-29 10:14:26 +05301398 if (ieee80211_is_data_qos(fc)) {
1399 qc = ieee80211_get_qos_ctl(hdr);
1400 bf->bf_tidno = qc[0] & 0xf;
Sujith98deeea2008-08-11 14:05:46 +05301401 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001402
Sujithe8324352009-01-16 21:38:42 +05301403 /*
1404 * For HT capable stations, we save tidno for later use.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301405 * We also override seqno set by upper layer with the one
1406 * in tx aggregation state.
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301407 */
1408 tid = ATH_AN_2_TID(an, bf->bf_tidno);
Sujith17b182e2009-12-14 14:56:56 +05301409 hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
Senthil Balasubramaniand3a1db12008-12-22 16:31:58 +05301410 INCR(tid->seq_next, IEEE80211_SEQ_MAX);
Sujith528f0c62008-10-29 10:14:26 +05301411}
1412
Felix Fietkau82b873a2010-11-11 03:18:37 +01001413static int setup_tx_flags(struct sk_buff *skb)
Sujith528f0c62008-10-29 10:14:26 +05301414{
1415 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1416 int flags = 0;
1417
1418 flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
1419 flags |= ATH9K_TXDESC_INTREQ;
1420
1421 if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
1422 flags |= ATH9K_TXDESC_NOACK;
Sujith528f0c62008-10-29 10:14:26 +05301423
Felix Fietkau82b873a2010-11-11 03:18:37 +01001424 if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001425 flags |= ATH9K_TXDESC_LDPC;
1426
Sujith528f0c62008-10-29 10:14:26 +05301427 return flags;
1428}
1429
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001430/*
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001431 * rix - rate index
1432 * pktlen - total bytes (delims + data + fcs + pads + pad delims)
1433 * width - 0 for 20 MHz, 1 for 40 MHz
1434 * half_gi - to use 4us v/s 3.6 us for symbol time
1435 */
Sujith102e0572008-10-29 10:15:16 +05301436static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
1437 int width, int half_gi, bool shortPreamble)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001438{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001439 u32 nbits, nsymbits, duration, nsymbols;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001440 int streams, pktlen;
1441
Sujithcd3d39a2008-08-11 14:03:34 +05301442 pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
Sujithe63835b2008-11-18 09:07:53 +05301443
1444 /* find number of symbols: PLCP + data */
Felix Fietkauc6663872010-04-19 19:57:33 +02001445 streams = HT_RC_2_STREAMS(rix);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001446 nbits = (pktlen << 3) + OFDM_PLCP_BITS;
Felix Fietkauc6663872010-04-19 19:57:33 +02001447 nsymbits = bits_per_symbol[rix % 8][width] * streams;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001448 nsymbols = (nbits + nsymbits - 1) / nsymbits;
1449
1450 if (!half_gi)
1451 duration = SYMBOL_TIME(nsymbols);
1452 else
1453 duration = SYMBOL_TIME_HALFGI(nsymbols);
1454
Sujithe63835b2008-11-18 09:07:53 +05301455 /* addup duration for legacy/ht training and signal fields */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456 duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
Sujith102e0572008-10-29 10:15:16 +05301457
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001458 return duration;
1459}
1460
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001461static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
1462{
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001463 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 struct ath9k_11n_rate_series series[4];
Sujith528f0c62008-10-29 10:14:26 +05301465 struct sk_buff *skb;
1466 struct ieee80211_tx_info *tx_info;
Sujitha8efee42008-11-18 09:07:30 +05301467 struct ieee80211_tx_rate *rates;
Felix Fietkau545750d2009-11-23 22:21:01 +01001468 const struct ieee80211_rate *rate;
Sujith254ad0f2009-02-04 08:10:19 +05301469 struct ieee80211_hdr *hdr;
Sujithc89424d2009-01-30 14:29:28 +05301470 int i, flags = 0;
1471 u8 rix = 0, ctsrate = 0;
Sujith254ad0f2009-02-04 08:10:19 +05301472 bool is_pspoll;
Sujithe63835b2008-11-18 09:07:53 +05301473
1474 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
Sujith528f0c62008-10-29 10:14:26 +05301475
Sujitha22be222009-03-30 15:28:36 +05301476 skb = bf->bf_mpdu;
Sujith528f0c62008-10-29 10:14:26 +05301477 tx_info = IEEE80211_SKB_CB(skb);
Sujithe63835b2008-11-18 09:07:53 +05301478 rates = tx_info->control.rates;
Sujith254ad0f2009-02-04 08:10:19 +05301479 hdr = (struct ieee80211_hdr *)skb->data;
1480 is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
Sujith528f0c62008-10-29 10:14:26 +05301481
Sujithc89424d2009-01-30 14:29:28 +05301482 /*
1483 * We check if Short Preamble is needed for the CTS rate by
1484 * checking the BSS's global flag.
1485 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
1486 */
Felix Fietkau545750d2009-11-23 22:21:01 +01001487 rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
1488 ctsrate = rate->hw_value;
Sujithc89424d2009-01-30 14:29:28 +05301489 if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
Felix Fietkau545750d2009-11-23 22:21:01 +01001490 ctsrate |= rate->hw_value_short;
Luis R. Rodriguez96742252008-12-23 15:58:38 -08001491
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001492 for (i = 0; i < 4; i++) {
Felix Fietkau545750d2009-11-23 22:21:01 +01001493 bool is_40, is_sgi, is_sp;
1494 int phy;
1495
Sujithe63835b2008-11-18 09:07:53 +05301496 if (!rates[i].count || (rates[i].idx < 0))
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001497 continue;
1498
Sujitha8efee42008-11-18 09:07:30 +05301499 rix = rates[i].idx;
Sujitha8efee42008-11-18 09:07:30 +05301500 series[i].Tries = rates[i].count;
Luis R. Rodriguez43c27612009-09-13 21:07:07 -07001501 series[i].ChSel = common->tx_chainmask;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001502
Felix Fietkau27032052010-01-17 21:08:50 +01001503 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1504 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
Sujithc89424d2009-01-30 14:29:28 +05301505 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
Felix Fietkau27032052010-01-17 21:08:50 +01001506 flags |= ATH9K_TXDESC_RTSENA;
1507 } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
1508 series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
1509 flags |= ATH9K_TXDESC_CTSENA;
1510 }
1511
Sujithc89424d2009-01-30 14:29:28 +05301512 if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1513 series[i].RateFlags |= ATH9K_RATESERIES_2040;
1514 if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
1515 series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001516
Felix Fietkau545750d2009-11-23 22:21:01 +01001517 is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
1518 is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
1519 is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
1520
1521 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1522 /* MCS rates */
1523 series[i].Rate = rix | 0x80;
1524 series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
1525 is_40, is_sgi, is_sp);
Felix Fietkau074a8c02010-04-19 19:57:36 +02001526 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
1527 series[i].RateFlags |= ATH9K_RATESERIES_STBC;
Felix Fietkau545750d2009-11-23 22:21:01 +01001528 continue;
1529 }
1530
1531 /* legcay rates */
1532 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1533 !(rate->flags & IEEE80211_RATE_ERP_G))
1534 phy = WLAN_RC_PHY_CCK;
1535 else
1536 phy = WLAN_RC_PHY_OFDM;
1537
1538 rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
1539 series[i].Rate = rate->hw_value;
1540 if (rate->hw_value_short) {
1541 if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
1542 series[i].Rate |= rate->hw_value_short;
1543 } else {
1544 is_sp = false;
1545 }
1546
1547 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1548 phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001549 }
1550
Felix Fietkau27032052010-01-17 21:08:50 +01001551 /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
1552 if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
1553 flags &= ~ATH9K_TXDESC_RTSENA;
1554
1555 /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
1556 if (flags & ATH9K_TXDESC_RTSENA)
1557 flags &= ~ATH9K_TXDESC_CTSENA;
1558
Sujithe63835b2008-11-18 09:07:53 +05301559 /* set dur_update_en for l-sig computation except for PS-Poll frames */
Sujithc89424d2009-01-30 14:29:28 +05301560 ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
1561 bf->bf_lastbf->bf_desc,
Sujith254ad0f2009-02-04 08:10:19 +05301562 !is_pspoll, ctsrate,
Sujithc89424d2009-01-30 14:29:28 +05301563 0, series, 4, flags);
Sujith102e0572008-10-29 10:15:16 +05301564
Sujith17d79042009-02-09 13:27:03 +05301565 if (sc->config.ath_aggr_prot && flags)
Sujithc89424d2009-01-30 14:29:28 +05301566 ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001567}
1568
Felix Fietkau82b873a2010-11-11 03:18:37 +01001569static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
1570 struct sk_buff *skb)
Sujithe8324352009-01-16 21:38:42 +05301571{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001572 struct ath_wiphy *aphy = hw->priv;
1573 struct ath_softc *sc = aphy->sc;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001574 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujithe8324352009-01-16 21:38:42 +05301575 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
1576 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001577 struct ath_buf *bf;
Sujithe8324352009-01-16 21:38:42 +05301578 int hdrlen;
1579 __le16 fc;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001580 int padpos, padsize;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001581
1582 bf = ath_tx_get_buffer(sc);
1583 if (!bf) {
1584 ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
1585 return NULL;
1586 }
Sujithe8324352009-01-16 21:38:42 +05301587
Sujithe8324352009-01-16 21:38:42 +05301588 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1589 fc = hdr->frame_control;
1590
1591 ATH_TXBUF_RESET(bf);
1592
Felix Fietkau827e69b2009-11-15 23:09:25 +01001593 bf->aphy = aphy;
Benoit Papillault1bc14882009-11-24 15:49:18 +01001594 bf->bf_frmlen = skb->len + FCS_LEN;
1595 /* Remove the padding size from bf_frmlen, if any */
1596 padpos = ath9k_cmn_padpos(hdr->frame_control);
1597 padsize = padpos & 3;
1598 if (padsize && skb->len>padpos+padsize) {
1599 bf->bf_frmlen -= padsize;
1600 }
Sujithe8324352009-01-16 21:38:42 +05301601
Felix Fietkau82b873a2010-11-11 03:18:37 +01001602 if (ieee80211_is_data_qos(fc) && conf_is_ht(&hw->conf)) {
Sujithc656bbb2009-01-16 21:38:56 +05301603 bf->bf_state.bf_type |= BUF_HT;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001604 if (sc->sc_flags & SC_OP_TXAGGR)
1605 assign_aggr_tid_seqno(skb, bf);
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -04001606 }
Sujithe8324352009-01-16 21:38:42 +05301607
Felix Fietkau82b873a2010-11-11 03:18:37 +01001608 bf->bf_flags = setup_tx_flags(skb);
Sujithe8324352009-01-16 21:38:42 +05301609
Luis R. Rodriguezc17512d2010-08-05 17:56:54 -04001610 bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
Sujithe8324352009-01-16 21:38:42 +05301611 if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
1612 bf->bf_frmlen += tx_info->control.hw_key->icv_len;
1613 bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
1614 } else {
1615 bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
1616 }
1617
Sujithe8324352009-01-16 21:38:42 +05301618 bf->bf_mpdu = skb;
1619
Ben Greearc1739eb32010-10-14 12:45:29 -07001620 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
1621 skb->len, DMA_TO_DEVICE);
1622 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
Sujithe8324352009-01-16 21:38:42 +05301623 bf->bf_mpdu = NULL;
Ben Greear6cf9e992010-10-14 12:45:30 -07001624 bf->bf_buf_addr = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001625 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
1626 "dma_mapping_error() on TX\n");
Felix Fietkau82b873a2010-11-11 03:18:37 +01001627 ath_tx_return_buffer(sc, bf);
1628 return NULL;
Sujithe8324352009-01-16 21:38:42 +05301629 }
1630
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001631 bf->bf_tx_aborted = false;
1632
Felix Fietkau82b873a2010-11-11 03:18:37 +01001633 return bf;
Sujithe8324352009-01-16 21:38:42 +05301634}
1635
1636/* FIXME: tx power */
1637static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
1638 struct ath_tx_control *txctl)
1639{
Sujitha22be222009-03-30 15:28:36 +05301640 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301641 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Sujithc37452b2009-03-09 09:31:57 +05301642 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithe8324352009-01-16 21:38:42 +05301643 struct ath_node *an = NULL;
1644 struct list_head bf_head;
1645 struct ath_desc *ds;
1646 struct ath_atx_tid *tid;
Sujithcbe61d82009-02-09 13:27:12 +05301647 struct ath_hw *ah = sc->sc_ah;
Sujithe8324352009-01-16 21:38:42 +05301648 int frm_type;
Sujithc37452b2009-03-09 09:31:57 +05301649 __le16 fc;
Sujithe8324352009-01-16 21:38:42 +05301650
1651 frm_type = get_hw_packet_type(skb);
Sujithc37452b2009-03-09 09:31:57 +05301652 fc = hdr->frame_control;
Sujithe8324352009-01-16 21:38:42 +05301653
1654 INIT_LIST_HEAD(&bf_head);
1655 list_add_tail(&bf->list, &bf_head);
1656
1657 ds = bf->bf_desc;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -04001658 ath9k_hw_set_desc_link(ah, ds, 0);
Sujithe8324352009-01-16 21:38:42 +05301659
1660 ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
1661 bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
1662
1663 ath9k_hw_filltxdesc(ah, ds,
1664 skb->len, /* segment length */
1665 true, /* first segment */
1666 true, /* last segment */
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -04001667 ds, /* first descriptor */
Vasanthakumar Thiagarajancc610ac02010-04-15 17:39:26 -04001668 bf->bf_buf_addr,
1669 txctl->txq->axq_qnum);
Sujithe8324352009-01-16 21:38:42 +05301670
Sujithe8324352009-01-16 21:38:42 +05301671 spin_lock_bh(&txctl->txq->axq_lock);
1672
1673 if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
1674 tx_info->control.sta) {
1675 an = (struct ath_node *)tx_info->control.sta->drv_priv;
1676 tid = ATH_AN_2_TID(an, bf->bf_tidno);
1677
Felix Fietkau066dae92010-11-07 14:59:39 +01001678 WARN_ON(tid->ac->txq != txctl->txq);
Felix Fietkau4fdec032010-03-12 04:02:43 +01001679 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
Sujithe8324352009-01-16 21:38:42 +05301680 /*
1681 * Try aggregation if it's a unicast data frame
1682 * and the destination is HT capable.
1683 */
1684 ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
1685 } else {
1686 /*
1687 * Send this frame as regular when ADDBA
1688 * exchange is neither complete nor pending.
1689 */
Felix Fietkau82b873a2010-11-11 03:18:37 +01001690 ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301691 }
1692 } else {
Felix Fietkau61117f02010-11-11 03:18:36 +01001693 bf->bf_state.bfs_ftype = txctl->frame_type;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001694 bf->bf_state.bfs_paprd = txctl->paprd;
1695
Felix Fietkau9a6b8272010-11-14 00:03:01 +01001696 if (bf->bf_state.bfs_paprd)
1697 ar9003_hw_set_paprd_txdesc(ah, ds, bf->bf_state.bfs_paprd);
1698
Felix Fietkau82b873a2010-11-11 03:18:37 +01001699 if (txctl->paprd)
1700 bf->bf_state.bfs_paprd_timestamp = jiffies;
1701
1702 ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
Sujithe8324352009-01-16 21:38:42 +05301703 }
1704
1705 spin_unlock_bh(&txctl->txq->axq_lock);
1706}
1707
1708/* Upon failure caller should free skb */
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001709int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
Sujithe8324352009-01-16 21:38:42 +05301710 struct ath_tx_control *txctl)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001711{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001712 struct ath_wiphy *aphy = hw->priv;
1713 struct ath_softc *sc = aphy->sc;
Felix Fietkau84642d62010-06-01 21:33:13 +02001714 struct ath_txq *txq = txctl->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001715 struct ath_buf *bf;
Felix Fietkau82b873a2010-11-11 03:18:37 +01001716 int q;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001717
Felix Fietkau82b873a2010-11-11 03:18:37 +01001718 bf = ath_tx_setup_buffer(hw, skb);
1719 if (unlikely(!bf))
1720 return -ENOMEM;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001721
Felix Fietkau066dae92010-11-07 14:59:39 +01001722 q = skb_get_queue_mapping(skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001723 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001724 if (txq == sc->tx.txq_map[q] &&
1725 ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
1726 ath_mac80211_stop_queue(sc, q);
Felix Fietkau97923b12010-06-12 00:33:55 -04001727 txq->stopped = 1;
1728 }
1729 spin_unlock_bh(&txq->axq_lock);
1730
Sujithe8324352009-01-16 21:38:42 +05301731 ath_tx_start_dma(sc, bf, txctl);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001732
1733 return 0;
1734}
1735
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001736void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001737{
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001738 struct ath_wiphy *aphy = hw->priv;
1739 struct ath_softc *sc = aphy->sc;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001740 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001741 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1742 int padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301743 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1744 struct ath_tx_control txctl;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001745
Sujithe8324352009-01-16 21:38:42 +05301746 memset(&txctl, 0, sizeof(struct ath_tx_control));
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001747
Sujithe8324352009-01-16 21:38:42 +05301748 /*
1749 * As a temporary workaround, assign seq# here; this will likely need
1750 * to be cleaned up to work better with Beacon transmission and virtual
1751 * BSSes.
1752 */
1753 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
Sujithe8324352009-01-16 21:38:42 +05301754 if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
1755 sc->tx.seq_no += 0x10;
1756 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1757 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001758 }
1759
Sujithe8324352009-01-16 21:38:42 +05301760 /* Add the padding after the header if this is not already done */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001761 padpos = ath9k_cmn_padpos(hdr->frame_control);
1762 padsize = padpos & 3;
1763 if (padsize && skb->len>padpos) {
Sujithe8324352009-01-16 21:38:42 +05301764 if (skb_headroom(skb) < padsize) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001765 ath_print(common, ATH_DBG_XMIT,
1766 "TX CABQ padding failed\n");
Sujithe8324352009-01-16 21:38:42 +05301767 dev_kfree_skb_any(skb);
1768 return;
1769 }
1770 skb_push(skb, padsize);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001771 memmove(skb->data, skb->data + padsize, padpos);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001772 }
1773
Sujithe8324352009-01-16 21:38:42 +05301774 txctl.txq = sc->beacon.cabq;
1775
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001776 ath_print(common, ATH_DBG_XMIT,
1777 "transmitting CABQ packet, skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301778
Jouni Malinenc52f33d2009-03-03 19:23:29 +02001779 if (ath_tx_start(hw, skb, &txctl) != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001780 ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
Sujithe8324352009-01-16 21:38:42 +05301781 goto exit;
1782 }
1783
1784 return;
1785exit:
1786 dev_kfree_skb_any(skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001787}
1788
Sujithe8324352009-01-16 21:38:42 +05301789/*****************/
1790/* TX Completion */
1791/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001792
Sujithe8324352009-01-16 21:38:42 +05301793static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
Felix Fietkau61117f02010-11-11 03:18:36 +01001794 struct ath_wiphy *aphy, int tx_flags, int ftype,
Felix Fietkau066dae92010-11-07 14:59:39 +01001795 struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001796{
Sujithe8324352009-01-16 21:38:42 +05301797 struct ieee80211_hw *hw = sc->hw;
1798 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001799 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001800 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
Felix Fietkau97923b12010-06-12 00:33:55 -04001801 int q, padpos, padsize;
Sujithe8324352009-01-16 21:38:42 +05301802
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001803 ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
Sujithe8324352009-01-16 21:38:42 +05301804
Felix Fietkau827e69b2009-11-15 23:09:25 +01001805 if (aphy)
1806 hw = aphy->hw;
Sujithe8324352009-01-16 21:38:42 +05301807
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301808 if (tx_flags & ATH_TX_BAR)
Sujithe8324352009-01-16 21:38:42 +05301809 tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
Sujithe8324352009-01-16 21:38:42 +05301810
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301811 if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
Sujithe8324352009-01-16 21:38:42 +05301812 /* Frame was ACKed */
1813 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1814 }
1815
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001816 padpos = ath9k_cmn_padpos(hdr->frame_control);
1817 padsize = padpos & 3;
1818 if (padsize && skb->len>padpos+padsize) {
Sujithe8324352009-01-16 21:38:42 +05301819 /*
1820 * Remove MAC header padding before giving the frame back to
1821 * mac80211.
1822 */
Benoit Papillault4d91f9f2009-12-12 00:22:35 +01001823 memmove(skb->data + padsize, skb->data, padpos);
Sujithe8324352009-01-16 21:38:42 +05301824 skb_pull(skb, padsize);
1825 }
1826
Sujith1b04b932010-01-08 10:36:05 +05301827 if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
1828 sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001829 ath_print(common, ATH_DBG_PS,
1830 "Going back to sleep after having "
Pavel Roskinf643e512010-01-29 17:22:12 -05001831 "received TX status (0x%lx)\n",
Sujith1b04b932010-01-08 10:36:05 +05301832 sc->ps_flags & (PS_WAIT_FOR_BEACON |
1833 PS_WAIT_FOR_CAB |
1834 PS_WAIT_FOR_PSPOLL_DATA |
1835 PS_WAIT_FOR_TX_ACK));
Jouni Malinen9a23f9c2009-05-19 17:01:38 +03001836 }
1837
Felix Fietkau61117f02010-11-11 03:18:36 +01001838 if (unlikely(ftype))
1839 ath9k_tx_status(hw, skb, ftype);
Felix Fietkau97923b12010-06-12 00:33:55 -04001840 else {
1841 q = skb_get_queue_mapping(skb);
Felix Fietkau066dae92010-11-07 14:59:39 +01001842 if (txq == sc->tx.txq_map[q]) {
1843 spin_lock_bh(&txq->axq_lock);
1844 if (WARN_ON(--txq->pending_frames < 0))
1845 txq->pending_frames = 0;
1846 spin_unlock_bh(&txq->axq_lock);
1847 }
Felix Fietkau97923b12010-06-12 00:33:55 -04001848
Felix Fietkau827e69b2009-11-15 23:09:25 +01001849 ieee80211_tx_status(hw, skb);
Felix Fietkau97923b12010-06-12 00:33:55 -04001850 }
Sujithe8324352009-01-16 21:38:42 +05301851}
1852
1853static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001854 struct ath_txq *txq, struct list_head *bf_q,
1855 struct ath_tx_status *ts, int txok, int sendbar)
Sujithe8324352009-01-16 21:38:42 +05301856{
1857 struct sk_buff *skb = bf->bf_mpdu;
Sujithe8324352009-01-16 21:38:42 +05301858 unsigned long flags;
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301859 int tx_flags = 0;
Sujithe8324352009-01-16 21:38:42 +05301860
Sujithe8324352009-01-16 21:38:42 +05301861 if (sendbar)
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301862 tx_flags = ATH_TX_BAR;
Sujithe8324352009-01-16 21:38:42 +05301863
1864 if (!txok) {
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301865 tx_flags |= ATH_TX_ERROR;
Sujithe8324352009-01-16 21:38:42 +05301866
1867 if (bf_isxretried(bf))
Vasanthakumar Thiagarajan6b2c4032009-03-20 15:27:50 +05301868 tx_flags |= ATH_TX_XRETRY;
Sujithe8324352009-01-16 21:38:42 +05301869 }
1870
Ben Greearc1739eb32010-10-14 12:45:29 -07001871 dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
Ben Greear6cf9e992010-10-14 12:45:30 -07001872 bf->bf_buf_addr = 0;
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001873
1874 if (bf->bf_state.bfs_paprd) {
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001875 if (time_after(jiffies,
1876 bf->bf_state.bfs_paprd_timestamp +
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001877 msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001878 dev_kfree_skb_any(skb);
Vasanthakumar Thiagarajan78a18172010-06-24 02:42:46 -07001879 else
Vasanthakumar Thiagarajanca369eb2010-06-24 02:42:44 -07001880 complete(&sc->paprd_complete);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001881 } else {
Felix Fietkau066dae92010-11-07 14:59:39 +01001882 ath_debug_stat_tx(sc, bf, ts);
Felix Fietkau61117f02010-11-11 03:18:36 +01001883 ath_tx_complete(sc, skb, bf->aphy, tx_flags,
1884 bf->bf_state.bfs_ftype, txq);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -04001885 }
Ben Greear6cf9e992010-10-14 12:45:30 -07001886 /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
1887 * accidentally reference it later.
1888 */
1889 bf->bf_mpdu = NULL;
Sujithe8324352009-01-16 21:38:42 +05301890
1891 /*
1892 * Return the list of ath_buf of this mpdu to free queue
1893 */
1894 spin_lock_irqsave(&sc->tx.txbuflock, flags);
1895 list_splice_tail_init(bf_q, &sc->tx.txbuf);
1896 spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
1897}
1898
1899static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001900 struct ath_tx_status *ts, int txok)
Sujithe8324352009-01-16 21:38:42 +05301901{
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001902 u16 seq_st = 0;
1903 u32 ba[WME_BA_BMP_SIZE >> 5];
Sujithe8324352009-01-16 21:38:42 +05301904 int ba_index;
1905 int nbad = 0;
1906 int isaggr = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001907
Vasanthakumar Thiagarajan7c9fd602010-05-26 19:06:53 -07001908 if (bf->bf_lastbf->bf_tx_aborted)
Sujithe8324352009-01-16 21:38:42 +05301909 return 0;
Sujith528f0c62008-10-29 10:14:26 +05301910
Sujithcd3d39a2008-08-11 14:03:34 +05301911 isaggr = bf_isaggr(bf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001912 if (isaggr) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001913 seq_st = ts->ts_seqnum;
1914 memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001915 }
1916
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001917 while (bf) {
Felix Fietkau2d3bcba2010-11-14 15:20:01 +01001918 ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu));
Sujithe8324352009-01-16 21:38:42 +05301919 if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
1920 nbad++;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001921
Sujithe8324352009-01-16 21:38:42 +05301922 bf = bf->bf_next;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001923 }
1924
Sujithe8324352009-01-16 21:38:42 +05301925 return nbad;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001926}
1927
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001928static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301929 int nbad, int txok, bool update_rc)
Sujithc4288392008-11-18 09:09:30 +05301930{
Sujitha22be222009-03-30 15:28:36 +05301931 struct sk_buff *skb = bf->bf_mpdu;
Sujith254ad0f2009-02-04 08:10:19 +05301932 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
Sujithc4288392008-11-18 09:09:30 +05301933 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
Felix Fietkau827e69b2009-11-15 23:09:25 +01001934 struct ieee80211_hw *hw = bf->aphy->hw;
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001935 struct ath_softc *sc = bf->aphy->sc;
1936 struct ath_hw *ah = sc->sc_ah;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301937 u8 i, tx_rateindex;
Sujithc4288392008-11-18 09:09:30 +05301938
Sujith95e4acb2009-03-13 08:56:09 +05301939 if (txok)
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001940 tx_info->status.ack_signal = ts->ts_rssi;
Sujith95e4acb2009-03-13 08:56:09 +05301941
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001942 tx_rateindex = ts->ts_rateindex;
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301943 WARN_ON(tx_rateindex >= hw->max_rates);
1944
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001945 if (ts->ts_status & ATH9K_TXERR_FILT)
Sujithc4288392008-11-18 09:09:30 +05301946 tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
Björn Smedmanebd02282010-10-10 22:44:39 +02001947 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
Felix Fietkaud9698472010-03-01 13:32:11 +01001948 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
Sujithc4288392008-11-18 09:09:30 +05301949
Björn Smedmanebd02282010-10-10 22:44:39 +02001950 BUG_ON(nbad > bf->bf_nframes);
1951
1952 tx_info->status.ampdu_len = bf->bf_nframes;
1953 tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
1954 }
1955
Felix Fietkaudb1a0522010-03-29 20:07:11 -07001956 if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301957 (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
Felix Fietkauf0c255a2010-11-11 03:18:35 +01001958 /*
1959 * If an underrun error is seen assume it as an excessive
1960 * retry only if max frame trigger level has been reached
1961 * (2 KB for single stream, and 4 KB for dual stream).
1962 * Adjust the long retry as if the frame was tried
1963 * hw->max_rate_tries times to affect how rate control updates
1964 * PER for the failed rate.
1965 * In case of congestion on the bus penalizing this type of
1966 * underruns should help hardware actually transmit new frames
1967 * successfully by eventually preferring slower rates.
1968 * This itself should also alleviate congestion on the bus.
1969 */
1970 if (ieee80211_is_data(hdr->frame_control) &&
1971 (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
1972 ATH9K_TX_DELIM_UNDERRUN)) &&
1973 ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
1974 tx_info->status.rates[tx_rateindex].count =
1975 hw->max_rate_tries;
Sujithc4288392008-11-18 09:09:30 +05301976 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301977
Felix Fietkau545750d2009-11-23 22:21:01 +01001978 for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301979 tx_info->status.rates[i].count = 0;
Felix Fietkau545750d2009-11-23 22:21:01 +01001980 tx_info->status.rates[i].idx = -1;
1981 }
Vasanthakumar Thiagarajan8a92e2e2009-03-20 15:27:49 +05301982
Felix Fietkau78c46532010-06-25 01:26:16 +02001983 tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
Sujithc4288392008-11-18 09:09:30 +05301984}
1985
Felix Fietkau066dae92010-11-07 14:59:39 +01001986static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
Sujith059d8062009-01-16 21:38:49 +05301987{
Felix Fietkau066dae92010-11-07 14:59:39 +01001988 struct ath_txq *txq;
Sujith059d8062009-01-16 21:38:49 +05301989
Felix Fietkau066dae92010-11-07 14:59:39 +01001990 txq = sc->tx.txq_map[qnum];
Sujith059d8062009-01-16 21:38:49 +05301991 spin_lock_bh(&txq->axq_lock);
Felix Fietkau066dae92010-11-07 14:59:39 +01001992 if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
Vasanthakumar Thiagarajan68e8f2f2010-07-22 02:24:11 -07001993 if (ath_mac80211_start_queue(sc, qnum))
1994 txq->stopped = 0;
Sujith059d8062009-01-16 21:38:49 +05301995 }
1996 spin_unlock_bh(&txq->axq_lock);
1997}
1998
Sujithc4288392008-11-18 09:09:30 +05301999static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002000{
Sujithcbe61d82009-02-09 13:27:12 +05302001 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002002 struct ath_common *common = ath9k_hw_common(ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002003 struct ath_buf *bf, *lastbf, *bf_held = NULL;
2004 struct list_head bf_head;
Sujithc4288392008-11-18 09:09:30 +05302005 struct ath_desc *ds;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002006 struct ath_tx_status ts;
Vasanthakumar Thiagarajan0934af22009-03-18 20:22:00 +05302007 int txok;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002008 int status;
Felix Fietkau066dae92010-11-07 14:59:39 +01002009 int qnum;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002010
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002011 ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
2012 txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
2013 txq->axq_link);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002014
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002015 for (;;) {
2016 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002017 if (list_empty(&txq->axq_q)) {
2018 txq->axq_link = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002019 spin_unlock_bh(&txq->axq_lock);
2020 break;
2021 }
2022 bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
2023
2024 /*
2025 * There is a race condition that a BH gets scheduled
2026 * after sw writes TxE and before hw re-load the last
2027 * descriptor to get the newly chained one.
2028 * Software must keep the last DONE descriptor as a
2029 * holding descriptor - software does so by marking
2030 * it with the STALE flag.
2031 */
2032 bf_held = NULL;
Sujitha119cc42009-03-30 15:28:38 +05302033 if (bf->bf_stale) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002034 bf_held = bf;
2035 if (list_is_last(&bf_held->list, &txq->axq_q)) {
Sujith6ef9b132009-01-16 21:38:51 +05302036 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002037 break;
2038 } else {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002039 bf = list_entry(bf_held->list.next,
Sujith6ef9b132009-01-16 21:38:51 +05302040 struct ath_buf, list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002041 }
2042 }
2043
2044 lastbf = bf->bf_lastbf;
Sujithe8324352009-01-16 21:38:42 +05302045 ds = lastbf->bf_desc;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002046
Felix Fietkau29bffa92010-03-29 20:14:23 -07002047 memset(&ts, 0, sizeof(ts));
2048 status = ath9k_hw_txprocdesc(ah, ds, &ts);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002049 if (status == -EINPROGRESS) {
2050 spin_unlock_bh(&txq->axq_lock);
2051 break;
2052 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002053
2054 /*
2055 * Remove ath_buf's of the same transmit unit from txq,
2056 * however leave the last descriptor back as the holding
2057 * descriptor for hw.
2058 */
Sujitha119cc42009-03-30 15:28:38 +05302059 lastbf->bf_stale = true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002060 INIT_LIST_HEAD(&bf_head);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002061 if (!list_is_singular(&lastbf->list))
2062 list_cut_position(&bf_head,
2063 &txq->axq_q, lastbf->list.prev);
2064
2065 txq->axq_depth--;
Felix Fietkau29bffa92010-03-29 20:14:23 -07002066 txok = !(ts.ts_status & ATH9K_TXERR_MASK);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002067 txq->axq_tx_inprogress = false;
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002068 if (bf_held)
2069 list_del(&bf_held->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002070 spin_unlock_bh(&txq->axq_lock);
2071
Felix Fietkau0a8cea82010-04-19 19:57:30 +02002072 if (bf_held)
2073 ath_tx_return_buffer(sc, bf_held);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002074
Sujithcd3d39a2008-08-11 14:03:34 +05302075 if (!bf_isampdu(bf)) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002076 /*
2077 * This frame is sent out as a single frame.
2078 * Use hardware retry status for this frame.
2079 */
Felix Fietkau29bffa92010-03-29 20:14:23 -07002080 if (ts.ts_status & ATH9K_TXERR_XRETRY)
Sujithcd3d39a2008-08-11 14:03:34 +05302081 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002082 ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002083 }
Johannes Berge6a98542008-10-21 12:40:02 +02002084
Felix Fietkau066dae92010-11-07 14:59:39 +01002085 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2086
Sujithcd3d39a2008-08-11 14:03:34 +05302087 if (bf_isampdu(bf))
Felix Fietkau29bffa92010-03-29 20:14:23 -07002088 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002089 else
Felix Fietkau29bffa92010-03-29 20:14:23 -07002090 ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002091
Felix Fietkau066dae92010-11-07 14:59:39 +01002092 if (txq == sc->tx.txq_map[qnum])
2093 ath_wake_mac80211_queue(sc, qnum);
Sujith059d8062009-01-16 21:38:49 +05302094
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002095 spin_lock_bh(&txq->axq_lock);
Sujith672840a2008-08-11 14:05:08 +05302096 if (sc->sc_flags & SC_OP_TXAGGR)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002097 ath_txq_schedule(sc, txq);
2098 spin_unlock_bh(&txq->axq_lock);
2099 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002100}
2101
Sujith305fe472009-07-23 15:32:29 +05302102static void ath_tx_complete_poll_work(struct work_struct *work)
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002103{
2104 struct ath_softc *sc = container_of(work, struct ath_softc,
2105 tx_complete_work.work);
2106 struct ath_txq *txq;
2107 int i;
2108 bool needreset = false;
2109
2110 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
2111 if (ATH_TXQ_SETUP(sc, i)) {
2112 txq = &sc->tx.txq[i];
2113 spin_lock_bh(&txq->axq_lock);
2114 if (txq->axq_depth) {
2115 if (txq->axq_tx_inprogress) {
2116 needreset = true;
2117 spin_unlock_bh(&txq->axq_lock);
2118 break;
2119 } else {
2120 txq->axq_tx_inprogress = true;
2121 }
2122 }
2123 spin_unlock_bh(&txq->axq_lock);
2124 }
2125
2126 if (needreset) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002127 ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
2128 "tx hung, resetting the chip\n");
Sujith332c5562009-10-09 09:51:28 +05302129 ath9k_ps_wakeup(sc);
Felix Fietkaufac6b6a2010-10-23 17:45:38 +02002130 ath_reset(sc, true);
Sujith332c5562009-10-09 09:51:28 +05302131 ath9k_ps_restore(sc);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002132 }
2133
Luis R. Rodriguez42935ec2009-07-29 20:08:07 -04002134 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002135 msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
2136}
2137
2138
Sujithe8324352009-01-16 21:38:42 +05302139
2140void ath_tx_tasklet(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002141{
Sujithe8324352009-01-16 21:38:42 +05302142 int i;
2143 u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002144
Sujithe8324352009-01-16 21:38:42 +05302145 ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002146
2147 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
Sujithe8324352009-01-16 21:38:42 +05302148 if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
2149 ath_tx_processq(sc, &sc->tx.txq[i]);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002150 }
2151}
2152
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002153void ath_tx_edma_tasklet(struct ath_softc *sc)
2154{
2155 struct ath_tx_status txs;
2156 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2157 struct ath_hw *ah = sc->sc_ah;
2158 struct ath_txq *txq;
2159 struct ath_buf *bf, *lastbf;
2160 struct list_head bf_head;
2161 int status;
2162 int txok;
Felix Fietkau066dae92010-11-07 14:59:39 +01002163 int qnum;
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002164
2165 for (;;) {
2166 status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
2167 if (status == -EINPROGRESS)
2168 break;
2169 if (status == -EIO) {
2170 ath_print(common, ATH_DBG_XMIT,
2171 "Error processing tx status\n");
2172 break;
2173 }
2174
2175 /* Skip beacon completions */
2176 if (txs.qid == sc->beacon.beaconq)
2177 continue;
2178
2179 txq = &sc->tx.txq[txs.qid];
2180
2181 spin_lock_bh(&txq->axq_lock);
2182 if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
2183 spin_unlock_bh(&txq->axq_lock);
2184 return;
2185 }
2186
2187 bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
2188 struct ath_buf, list);
2189 lastbf = bf->bf_lastbf;
2190
2191 INIT_LIST_HEAD(&bf_head);
2192 list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
2193 &lastbf->list);
2194 INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
2195 txq->axq_depth--;
2196 txq->axq_tx_inprogress = false;
2197 spin_unlock_bh(&txq->axq_lock);
2198
2199 txok = !(txs.ts_status & ATH9K_TXERR_MASK);
2200
2201 if (!bf_isampdu(bf)) {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002202 if (txs.ts_status & ATH9K_TXERR_XRETRY)
2203 bf->bf_state.bf_type |= BUF_XRETRY;
Björn Smedmanebd02282010-10-10 22:44:39 +02002204 ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002205 }
2206
Felix Fietkau066dae92010-11-07 14:59:39 +01002207 qnum = skb_get_queue_mapping(bf->bf_mpdu);
2208
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002209 if (bf_isampdu(bf))
2210 ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
2211 else
2212 ath_tx_complete_buf(sc, bf, txq, &bf_head,
2213 &txs, txok, 0);
2214
Felix Fietkau066dae92010-11-07 14:59:39 +01002215 if (txq == sc->tx.txq_map[qnum])
2216 ath_wake_mac80211_queue(sc, qnum);
Felix Fietkau7f9f3602010-04-26 15:04:36 -04002217
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -04002218 spin_lock_bh(&txq->axq_lock);
2219 if (!list_empty(&txq->txq_fifo_pending)) {
2220 INIT_LIST_HEAD(&bf_head);
2221 bf = list_first_entry(&txq->txq_fifo_pending,
2222 struct ath_buf, list);
2223 list_cut_position(&bf_head, &txq->txq_fifo_pending,
2224 &bf->bf_lastbf->list);
2225 ath_tx_txqaddbuf(sc, txq, &bf_head);
2226 } else if (sc->sc_flags & SC_OP_TXAGGR)
2227 ath_txq_schedule(sc, txq);
2228 spin_unlock_bh(&txq->axq_lock);
2229 }
2230}
2231
Sujithe8324352009-01-16 21:38:42 +05302232/*****************/
2233/* Init, Cleanup */
2234/*****************/
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002235
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002236static int ath_txstatus_setup(struct ath_softc *sc, int size)
2237{
2238 struct ath_descdma *dd = &sc->txsdma;
2239 u8 txs_len = sc->sc_ah->caps.txs_len;
2240
2241 dd->dd_desc_len = size * txs_len;
2242 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
2243 &dd->dd_desc_paddr, GFP_KERNEL);
2244 if (!dd->dd_desc)
2245 return -ENOMEM;
2246
2247 return 0;
2248}
2249
2250static int ath_tx_edma_init(struct ath_softc *sc)
2251{
2252 int err;
2253
2254 err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
2255 if (!err)
2256 ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
2257 sc->txsdma.dd_desc_paddr,
2258 ATH_TXSTATUS_RING_SIZE);
2259
2260 return err;
2261}
2262
2263static void ath_tx_edma_cleanup(struct ath_softc *sc)
2264{
2265 struct ath_descdma *dd = &sc->txsdma;
2266
2267 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
2268 dd->dd_desc_paddr);
2269}
2270
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002271int ath_tx_init(struct ath_softc *sc, int nbufs)
2272{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002273 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002274 int error = 0;
2275
Sujith797fe5cb2009-03-30 15:28:45 +05302276 spin_lock_init(&sc->tx.txbuflock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002277
Sujith797fe5cb2009-03-30 15:28:45 +05302278 error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -04002279 "tx", nbufs, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302280 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002281 ath_print(common, ATH_DBG_FATAL,
2282 "Failed to allocate tx descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302283 goto err;
2284 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002285
Sujith797fe5cb2009-03-30 15:28:45 +05302286 error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002287 "beacon", ATH_BCBUF, 1, 1);
Sujith797fe5cb2009-03-30 15:28:45 +05302288 if (error != 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07002289 ath_print(common, ATH_DBG_FATAL,
2290 "Failed to allocate beacon descriptors: %d\n", error);
Sujith797fe5cb2009-03-30 15:28:45 +05302291 goto err;
2292 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002293
Senthil Balasubramanian164ace32009-07-14 20:17:09 -04002294 INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
2295
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002296 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
2297 error = ath_tx_edma_init(sc);
2298 if (error)
2299 goto err;
2300 }
2301
Sujith797fe5cb2009-03-30 15:28:45 +05302302err:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002303 if (error != 0)
2304 ath_tx_cleanup(sc);
2305
2306 return error;
2307}
2308
Sujith797fe5cb2009-03-30 15:28:45 +05302309void ath_tx_cleanup(struct ath_softc *sc)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002310{
Sujithb77f4832008-12-07 21:44:03 +05302311 if (sc->beacon.bdma.dd_desc_len != 0)
2312 ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002313
Sujithb77f4832008-12-07 21:44:03 +05302314 if (sc->tx.txdma.dd_desc_len != 0)
2315 ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
Vasanthakumar Thiagarajan5088c2f2010-04-15 17:39:34 -04002316
2317 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
2318 ath_tx_edma_cleanup(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002319}
2320
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002321void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2322{
Sujithc5170162008-10-29 10:13:59 +05302323 struct ath_atx_tid *tid;
2324 struct ath_atx_ac *ac;
2325 int tidno, acno;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002326
Sujith8ee5afb2008-12-07 21:43:36 +05302327 for (tidno = 0, tid = &an->tid[tidno];
Sujithc5170162008-10-29 10:13:59 +05302328 tidno < WME_NUM_TID;
2329 tidno++, tid++) {
2330 tid->an = an;
2331 tid->tidno = tidno;
2332 tid->seq_start = tid->seq_next = 0;
2333 tid->baw_size = WME_MAX_BA;
2334 tid->baw_head = tid->baw_tail = 0;
2335 tid->sched = false;
Sujithe8324352009-01-16 21:38:42 +05302336 tid->paused = false;
Sujitha37c2c72008-10-29 10:15:40 +05302337 tid->state &= ~AGGR_CLEANUP;
Sujithc5170162008-10-29 10:13:59 +05302338 INIT_LIST_HEAD(&tid->buf_q);
Sujithc5170162008-10-29 10:13:59 +05302339 acno = TID_TO_WME_AC(tidno);
Sujith8ee5afb2008-12-07 21:43:36 +05302340 tid->ac = &an->ac[acno];
Sujitha37c2c72008-10-29 10:15:40 +05302341 tid->state &= ~AGGR_ADDBA_COMPLETE;
2342 tid->state &= ~AGGR_ADDBA_PROGRESS;
Sujithc5170162008-10-29 10:13:59 +05302343 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002344
Sujith8ee5afb2008-12-07 21:43:36 +05302345 for (acno = 0, ac = &an->ac[acno];
Sujithc5170162008-10-29 10:13:59 +05302346 acno < WME_NUM_AC; acno++, ac++) {
2347 ac->sched = false;
Felix Fietkau066dae92010-11-07 14:59:39 +01002348 ac->txq = sc->tx.txq_map[acno];
Sujithc5170162008-10-29 10:13:59 +05302349 INIT_LIST_HEAD(&ac->tid_q);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002350 }
2351}
2352
Sujithb5aa9bf2008-10-29 10:13:31 +05302353void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002354{
Felix Fietkau2b409942010-07-07 19:42:08 +02002355 struct ath_atx_ac *ac;
2356 struct ath_atx_tid *tid;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002357 struct ath_txq *txq;
Felix Fietkau066dae92010-11-07 14:59:39 +01002358 int tidno;
Sujithe8324352009-01-16 21:38:42 +05302359
Felix Fietkau2b409942010-07-07 19:42:08 +02002360 for (tidno = 0, tid = &an->tid[tidno];
2361 tidno < WME_NUM_TID; tidno++, tid++) {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002362
Felix Fietkau2b409942010-07-07 19:42:08 +02002363 ac = tid->ac;
Felix Fietkau066dae92010-11-07 14:59:39 +01002364 txq = ac->txq;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002365
Felix Fietkau2b409942010-07-07 19:42:08 +02002366 spin_lock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002367
Felix Fietkau2b409942010-07-07 19:42:08 +02002368 if (tid->sched) {
2369 list_del(&tid->list);
2370 tid->sched = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002371 }
Felix Fietkau2b409942010-07-07 19:42:08 +02002372
2373 if (ac->sched) {
2374 list_del(&ac->list);
2375 tid->ac->sched = false;
2376 }
2377
2378 ath_tid_drain(sc, txq, tid);
2379 tid->state &= ~AGGR_ADDBA_COMPLETE;
2380 tid->state &= ~AGGR_CLEANUP;
2381
2382 spin_unlock_bh(&txq->axq_lock);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002383 }
2384}