staging: brcm80211: remove nested include statements
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / brcmsmac / wlc_ampdu.c
blob68b65a0c896b3406fcb9f23dc6e96f9c9537ce81
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
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.
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 ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include <linux/kernel.h>
17 #include <net/mac80211.h>
19 #include <proto/802.1d.h>
20 #include <osl.h>
21 #include <bcmdefs.h>
22 #include <bcmutils.h>
23 #include <siutils.h>
24 #include <wlioctl.h>
25 #include <sbhndpio.h>
26 #include <sbhnddma.h>
27 #include <hnddma.h>
28 #include <d11.h>
30 #include "wlc_types.h"
31 #include "wlc_cfg.h"
32 #include "wlc_rate.h"
33 #include "wlc_scb.h"
34 #include "wlc_pub.h"
35 #include "wlc_key.h"
36 #include "phy/wlc_phy_hal.h"
37 #include "wlc_antsel.h"
38 #include "wl_export.h"
39 #include "wl_dbg.h"
40 #include "wlc_bsscfg.h"
41 #include "wlc_channel.h"
42 #include "wlc_mac80211.h"
43 #include "wlc_ampdu.h"
46 * Disable AMPDU statistics counters for now
48 #define WLCNTINCR(a)
49 #define WLCNTADD(a, b)
51 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
52 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
53 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
54 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
55 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
56 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
57 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
58 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
59 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
60 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
61 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
62 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
63 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
65 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
66 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
67 * without underflows
69 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
70 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
71 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
72 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
73 * accumulate between resets.
76 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
78 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
79 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
80 AMPDU_DELIMITER_LEN + 3\
81 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
83 #ifdef BCMDBG
84 u32 wl_ampdu_dbg =
85 WL_AMPDU_UPDN_VAL |
86 WL_AMPDU_ERR_VAL |
87 WL_AMPDU_TX_VAL |
88 WL_AMPDU_RX_VAL |
89 WL_AMPDU_CTL_VAL |
90 WL_AMPDU_HW_VAL | WL_AMPDU_HWTXS_VAL | WL_AMPDU_HWDBG_VAL;
91 #endif
93 /* structure to hold tx fifo information and pre-loading state
94 * counters specific to tx underflows of ampdus
95 * some counters might be redundant with the ones in wlc or ampdu structures.
96 * This allows to maintain a specific state independantly of
97 * how often and/or when the wlc counters are updated.
99 typedef struct wlc_fifo_info {
100 u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
101 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
102 u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
103 u32 accum_txfunfl; /* num of underflows since we modified pld params */
104 u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
105 u32 prev_txampdu; /* previous reading of tx ampdu */
106 u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
107 } wlc_fifo_info_t;
109 /* AMPDU module specific state */
110 struct ampdu_info {
111 struct wlc_info *wlc; /* pointer to main wlc structure */
112 int scb_handle; /* scb cubby handle to retrieve data from scb */
113 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
114 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
115 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
116 u8 retry_limit; /* mpdu transmit retry limit */
117 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
118 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
119 /* per-tid mpdu transmit retry limit at regular rate */
120 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
121 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
122 s8 max_pdu; /* max pdus allowed in ampdu */
123 u8 dur; /* max duration of an ampdu (in msec) */
124 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
125 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
126 u32 ffpld_rsvd; /* number of bytes to reserve for preload */
127 u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
128 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
129 bool mfbr; /* enable multiple fallback rate */
130 u32 tx_max_funl; /* underflows should be kept such that
131 * (tx_max_funfl*underflows) < tx frames
133 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
137 #define AMPDU_CLEANUPFLAG_RX (0x1)
138 #define AMPDU_CLEANUPFLAG_TX (0x2)
140 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
141 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
143 static void wlc_ffpld_init(struct ampdu_info *ampdu);
144 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
145 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
147 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
148 scb_ampdu_t *scb_ampdu,
149 u8 tid, bool override);
150 static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu,
151 scb_ampdu_t *scb_ampdu,
152 u8 tid, bool force);
153 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
154 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
155 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
157 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
159 static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
160 struct scb *scb,
161 struct sk_buff *p, tx_status_t *txs,
162 u32 frmtxstatus, u32 frmtxstatus2);
163 static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
164 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
166 struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
168 struct ampdu_info *ampdu;
169 int i;
171 /* some code depends on packed structures */
172 ASSERT(DOT11_MAXNUMFRAGS == NBITS(u16));
173 ASSERT(ISPOWEROF2(AMPDU_TX_BA_MAX_WSIZE));
174 ASSERT(ISPOWEROF2(AMPDU_RX_BA_MAX_WSIZE));
175 ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
176 ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
178 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
179 if (!ampdu) {
180 WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n",
181 wlc->pub->unit);
182 return NULL;
184 ampdu->wlc = wlc;
186 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
187 ampdu->ini_enable[i] = true;
188 /* Disable ampdu for VO by default */
189 ampdu->ini_enable[PRIO_8021D_VO] = false;
190 ampdu->ini_enable[PRIO_8021D_NC] = false;
192 /* Disable ampdu for BK by default since not enough fifo space */
193 ampdu->ini_enable[PRIO_8021D_NONE] = false;
194 ampdu->ini_enable[PRIO_8021D_BK] = false;
196 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
197 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
198 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
199 ampdu->max_pdu = AUTO;
200 ampdu->dur = AMPDU_MAX_DUR;
201 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
203 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
204 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
205 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
206 ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
207 else
208 ampdu->rx_factor = AMPDU_RX_FACTOR_64K;
209 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
210 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
212 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
213 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
214 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
217 ampdu_update_max_txlen(ampdu, ampdu->dur);
218 ampdu->mfbr = false;
219 /* try to set ampdu to the default value */
220 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
222 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
223 wlc_ffpld_init(ampdu);
225 return ampdu;
228 void wlc_ampdu_detach(struct ampdu_info *ampdu)
230 int i;
232 if (!ampdu)
233 return;
235 /* free all ini's which were to be freed on callbacks which were never called */
236 for (i = 0; i < AMPDU_INI_FREE; i++) {
237 if (ampdu->ini_free[i]) {
238 kfree(ampdu->ini_free[i]);
242 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
243 kfree(ampdu);
246 void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb)
248 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
249 u8 tid;
251 WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n");
252 ASSERT(scb_ampdu);
254 for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
255 ampdu_cleanup_tid_ini(ampdu, scb_ampdu, tid, false);
259 /* reset the ampdu state machine so that it can gracefully handle packets that were
260 * freed from the dma and tx queues during reinit
262 void wlc_ampdu_reset(struct ampdu_info *ampdu)
264 WL_NONE("%s: Entering\n", __func__);
267 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
269 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
270 int i;
272 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
274 /* go back to legacy size if some preloading is occuring */
275 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
276 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
277 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
280 /* apply user override */
281 if (ampdu->max_pdu != AUTO)
282 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
284 scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
286 if (scb_ampdu->max_rxlen)
287 scb_ampdu->release =
288 min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
290 scb_ampdu->release = min(scb_ampdu->release,
291 ampdu->fifo_tb[TX_AC_BE_FIFO].
292 mcs2ampdu_table[FFPLD_MAX_MCS]);
294 ASSERT(scb_ampdu->release);
297 void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
299 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
302 static void wlc_ffpld_init(struct ampdu_info *ampdu)
304 int i, j;
305 wlc_fifo_info_t *fifo;
307 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
308 fifo = (ampdu->fifo_tb + j);
309 fifo->ampdu_pld_size = 0;
310 for (i = 0; i <= FFPLD_MAX_MCS; i++)
311 fifo->mcs2ampdu_table[i] = 255;
312 fifo->dmaxferrate = 0;
313 fifo->accum_txampdu = 0;
314 fifo->prev_txfunfl = 0;
315 fifo->accum_txfunfl = 0;
320 /* evaluate the dma transfer rate using the tx underflows as feedback.
321 * If necessary, increase tx fifo preloading. If not enough,
322 * decrease maximum ampdu size for each mcs till underflows stop
323 * Return 1 if pre-loading not active, -1 if not an underflow event,
324 * 0 if pre-loading module took care of the event.
326 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
328 struct ampdu_info *ampdu = wlc->ampdu;
329 u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
330 u32 txunfl_ratio;
331 u8 max_mpdu;
332 u32 current_ampdu_cnt = 0;
333 u16 max_pld_size;
334 u32 new_txunfl;
335 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
336 uint xmtfifo_sz;
337 u16 cur_txunfl;
339 /* return if we got here for a different reason than underflows */
340 cur_txunfl =
341 wlc_read_shm(wlc,
342 M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
343 new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
344 if (new_txunfl == 0) {
345 WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n");
346 return -1;
348 fifo->prev_txfunfl = cur_txunfl;
350 if (!ampdu->tx_max_funl)
351 return 1;
353 /* check if fifo is big enough */
354 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
355 WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n");
356 return -1;
359 if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
360 return 1;
362 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
363 fifo->accum_txfunfl += new_txunfl;
365 /* we need to wait for at least 10 underflows */
366 if (fifo->accum_txfunfl < 10)
367 return 0;
369 WL_FFPLD("ampdu_count %d tx_underflows %d\n",
370 current_ampdu_cnt, fifo->accum_txfunfl);
373 compute the current ratio of tx unfl per ampdu.
374 When the current ampdu count becomes too
375 big while the ratio remains small, we reset
376 the current count in order to not
377 introduce too big of a latency in detecting a
378 large amount of tx underflows later.
381 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
383 if (txunfl_ratio > ampdu->tx_max_funl) {
384 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
385 fifo->accum_txfunfl = 0;
387 return 0;
389 max_mpdu =
390 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
392 /* In case max value max_pdu is already lower than
393 the fifo depth, there is nothing more we can do.
396 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
397 WL_FFPLD(("tx fifo pld : max ampdu fits in fifo\n)"));
398 fifo->accum_txfunfl = 0;
399 return 0;
402 if (fifo->ampdu_pld_size < max_pld_size) {
404 /* increment by TX_FIFO_PLD_INC bytes */
405 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
406 if (fifo->ampdu_pld_size > max_pld_size)
407 fifo->ampdu_pld_size = max_pld_size;
409 /* update scb release size */
410 scb_ampdu_update_config_all(ampdu);
413 compute a new dma xfer rate for max_mpdu @ max mcs.
414 This is the minimum dma rate that
415 can acheive no unferflow condition for the current mpdu size.
417 /* note : we divide/multiply by 100 to avoid integer overflows */
418 fifo->dmaxferrate =
419 (((phy_rate / 100) *
420 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
421 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
423 WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n",
424 fifo->dmaxferrate, fifo->ampdu_pld_size);
425 } else {
427 /* decrease ampdu size */
428 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
429 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
430 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
431 AMPDU_NUM_MPDU_LEGACY - 1;
432 else
433 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
435 /* recompute the table */
436 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
438 /* update scb release size */
439 scb_ampdu_update_config_all(ampdu);
442 fifo->accum_txfunfl = 0;
443 return 0;
446 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
448 int i;
449 u32 phy_rate, dma_rate, tmp;
450 u8 max_mpdu;
451 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
453 /* recompute the dma rate */
454 /* note : we divide/multiply by 100 to avoid integer overflows */
455 max_mpdu =
456 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
457 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
458 dma_rate =
459 (((phy_rate / 100) *
460 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
461 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
462 fifo->dmaxferrate = dma_rate;
464 /* fill up the mcs2ampdu table; do not recalc the last mcs */
465 dma_rate = dma_rate >> 7;
466 for (i = 0; i < FFPLD_MAX_MCS; i++) {
467 /* shifting to keep it within integer range */
468 phy_rate = MCS_RATE(i, true, false) >> 7;
469 if (phy_rate > dma_rate) {
470 tmp = ((fifo->ampdu_pld_size * phy_rate) /
471 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
472 tmp = min_t(u32, tmp, 255);
473 fifo->mcs2ampdu_table[i] = (u8) tmp;
478 static void BCMFASTPATH
479 wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
480 uint prec)
482 scb_ampdu_t *scb_ampdu;
483 scb_ampdu_tid_ini_t *ini;
484 u8 tid = (u8) (p->priority);
486 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
488 /* initialize initiator on first packet; sends addba req */
489 ini = SCB_AMPDU_INI(scb_ampdu, tid);
490 if (ini->magic != INI_MAGIC) {
491 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
493 return;
496 int BCMFASTPATH
497 wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi,
498 struct sk_buff **pdu, int prec)
500 struct wlc_info *wlc;
501 struct osl_info *osh;
502 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
503 u8 tid, ndelim;
504 int err = 0;
505 u8 preamble_type = WLC_GF_PREAMBLE;
506 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
507 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
508 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
510 bool rr = true, fbr = false;
511 uint i, count = 0, fifo, seg_cnt = 0;
512 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
513 u32 ampdu_len, maxlen = 0;
514 d11txh_t *txh = NULL;
515 u8 *plcp;
516 struct ieee80211_hdr *h;
517 struct scb *scb;
518 scb_ampdu_t *scb_ampdu;
519 scb_ampdu_tid_ini_t *ini;
520 u8 mcs = 0;
521 bool use_rts = false, use_cts = false;
522 ratespec_t rspec = 0, rspec_fallback = 0;
523 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
524 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
525 struct ieee80211_rts *rts;
526 u8 rr_retry_limit;
527 wlc_fifo_info_t *f;
528 bool fbr_iscck;
529 struct ieee80211_tx_info *tx_info;
530 u16 qlen;
532 wlc = ampdu->wlc;
533 osh = wlc->osh;
534 p = *pdu;
536 ASSERT(p);
538 tid = (u8) (p->priority);
539 ASSERT(tid < AMPDU_MAX_SCB_TID);
541 f = ampdu->fifo_tb + prio2fifo[tid];
543 scb = wlc->pub->global_scb;
544 ASSERT(scb->magic == SCB_MAGIC);
546 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
547 ASSERT(scb_ampdu);
548 ini = &scb_ampdu->ini[tid];
550 /* Let pressure continue to build ... */
551 qlen = pktq_plen(&qi->q, prec);
552 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
553 return BCME_BUSY;
556 wlc_ampdu_agg(ampdu, scb, p, tid);
558 if (wlc->block_datafifo) {
559 WL_ERROR("%s: Fifo blocked\n", __func__);
560 return BCME_BUSY;
562 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
563 ampdu_len = 0;
564 dma_len = 0;
565 while (p) {
566 struct ieee80211_tx_rate *txrate;
568 tx_info = IEEE80211_SKB_CB(p);
569 txrate = tx_info->status.rates;
571 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
572 err = wlc_prep_pdu(wlc, p, &fifo);
573 } else {
574 WL_ERROR("%s: AMPDU flag is off!\n", __func__);
575 *pdu = NULL;
576 err = 0;
577 break;
580 if (err) {
581 if (err == BCME_BUSY) {
582 WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n",
583 wlc->pub->unit, seq);
584 WLCNTINCR(ampdu->cnt->sduretry);
585 *pdu = p;
586 break;
589 /* error in the packet; reject it */
590 WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n",
591 wlc->pub->unit, seq);
592 WLCNTINCR(ampdu->cnt->sdurejected);
594 *pdu = NULL;
595 break;
598 /* pkt is good to be aggregated */
599 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
600 txh = (d11txh_t *) p->data;
601 plcp = (u8 *) (txh + 1);
602 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
603 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
604 index = TX_SEQ_TO_INDEX(seq);
606 /* check mcl fields and test whether it can be agg'd */
607 mcl = le16_to_cpu(txh->MacTxControlLow);
608 mcl &= ~TXC_AMPDU_MASK;
609 fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
610 ASSERT(!fbr_iscck);
611 txh->PreloadSize = 0; /* always default to 0 */
613 /* Handle retry limits */
614 if (txrate[0].count <= rr_retry_limit) {
615 txrate[0].count++;
616 rr = true;
617 fbr = false;
618 ASSERT(!fbr);
619 } else {
620 fbr = true;
621 rr = false;
622 txrate[1].count++;
625 /* extract the length info */
626 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
627 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
629 /* retrieve null delimiter count */
630 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
631 seg_cnt += 1;
633 WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
634 wlc->pub->unit, count, len);
637 * aggregateable mpdu. For ucode/hw agg,
638 * test whether need to break or change the epoch
640 if (count == 0) {
641 u16 fc;
642 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
643 /* refill the bits since might be a retx mpdu */
644 mcl |= TXC_STARTMSDU;
645 rts = (struct ieee80211_rts *)&txh->rts_frame;
646 fc = le16_to_cpu(rts->frame_control);
647 if ((fc & FC_KIND_MASK) == FC_RTS) {
648 mcl |= TXC_SENDRTS;
649 use_rts = true;
651 if ((fc & FC_KIND_MASK) == FC_CTS) {
652 mcl |= TXC_SENDCTS;
653 use_cts = true;
655 } else {
656 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
657 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
660 len = roundup(len, 4);
661 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
663 dma_len += (u16) pkttotlen(osh, p);
665 WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
666 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
668 txh->MacTxControlLow = cpu_to_le16(mcl);
670 /* this packet is added */
671 pkt[count++] = p;
673 /* patch the first MPDU */
674 if (count == 1) {
675 u8 plcp0, plcp3, is40, sgi;
676 struct ieee80211_sta *sta;
678 sta = tx_info->control.sta;
680 if (rr) {
681 plcp0 = plcp[0];
682 plcp3 = plcp[3];
683 } else {
684 plcp0 = txh->FragPLCPFallback[0];
685 plcp3 = txh->FragPLCPFallback[3];
688 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
689 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
690 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
691 ASSERT(mcs < MCS_TABLE_SIZE);
692 maxlen =
693 min(scb_ampdu->max_rxlen,
694 ampdu->max_txlen[mcs][is40][sgi]);
696 WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n",
697 sgi, is40, mcs);
699 maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
701 if (is40)
702 mimo_ctlchbw =
703 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
704 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
706 /* rebuild the rspec and rspec_fallback */
707 rspec = RSPEC_MIMORATE;
708 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
709 if (plcp[0] & MIMO_PLCP_40MHZ)
710 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
712 if (fbr_iscck) /* CCK */
713 rspec_fallback =
714 CCK_RSPEC(CCK_PHY2MAC_RATE
715 (txh->FragPLCPFallback[0]));
716 else { /* MIMO */
717 rspec_fallback = RSPEC_MIMORATE;
718 rspec_fallback |=
719 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
720 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
721 rspec_fallback |=
722 (PHY_TXC1_BW_40MHZ <<
723 RSPEC_BW_SHIFT);
726 if (use_rts || use_cts) {
727 rts_rspec =
728 wlc_rspec_to_rts_rspec(wlc, rspec, false,
729 mimo_ctlchbw);
730 rts_rspec_fallback =
731 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
732 false, mimo_ctlchbw);
736 /* if (first mpdu for host agg) */
737 /* test whether to add more */
738 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
739 (count == f->mcs2ampdu_table[mcs])) {
740 WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
741 wlc->pub->unit, count, mcs);
742 break;
745 if (count == scb_ampdu->max_pdu) {
746 WL_NONE("Stop taking from q, reached %d deep\n",
747 scb_ampdu->max_pdu);
748 break;
751 /* check to see if the next pkt is a candidate for aggregation */
752 p = pktq_ppeek(&qi->q, prec);
753 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
755 if (p) {
756 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
757 ((u8) (p->priority) == tid)) {
759 plen =
760 pkttotlen(osh, p) + AMPDU_MAX_MPDU_OVERHEAD;
761 plen = max(scb_ampdu->min_len, plen);
763 if ((plen + ampdu_len) > maxlen) {
764 p = NULL;
765 WL_ERROR("%s: Bogus plen #1\n",
766 __func__);
767 ASSERT(3 == 4);
768 continue;
771 /* check if there are enough descriptors available */
772 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
773 WL_ERROR("%s: No fifo space !!!!!!\n",
774 __func__);
775 p = NULL;
776 continue;
778 p = pktq_pdeq(&qi->q, prec);
779 ASSERT(p);
780 } else {
781 p = NULL;
784 } /* end while(p) */
786 ini->tx_in_transit += count;
788 if (count) {
789 WLCNTADD(ampdu->cnt->txmpdu, count);
791 /* patch up the last txh */
792 txh = (d11txh_t *) pkt[count - 1]->data;
793 mcl = le16_to_cpu(txh->MacTxControlLow);
794 mcl &= ~TXC_AMPDU_MASK;
795 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
796 txh->MacTxControlLow = cpu_to_le16(mcl);
798 /* remove the null delimiter after last mpdu */
799 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
800 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
801 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
803 /* remove the pad len from last mpdu */
804 fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
805 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
806 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
807 ampdu_len -= roundup(len, 4) - len;
809 /* patch up the first txh & plcp */
810 txh = (d11txh_t *) pkt[0]->data;
811 plcp = (u8 *) (txh + 1);
813 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
814 /* mark plcp to indicate ampdu */
815 WLC_SET_MIMO_PLCP_AMPDU(plcp);
817 /* reset the mixed mode header durations */
818 if (txh->MModeLen) {
819 u16 mmodelen =
820 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
821 txh->MModeLen = cpu_to_le16(mmodelen);
822 preamble_type = WLC_MM_PREAMBLE;
824 if (txh->MModeFbrLen) {
825 u16 mmfbrlen =
826 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
827 txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
828 fbr_preamble_type = WLC_MM_PREAMBLE;
831 /* set the preload length */
832 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
833 dma_len = min(dma_len, f->ampdu_pld_size);
834 txh->PreloadSize = cpu_to_le16(dma_len);
835 } else
836 txh->PreloadSize = 0;
838 mch = le16_to_cpu(txh->MacTxControlHigh);
840 /* update RTS dur fields */
841 if (use_rts || use_cts) {
842 u16 durid;
843 rts = (struct ieee80211_rts *)&txh->rts_frame;
844 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
845 TXC_PREAMBLE_RTS_MAIN_SHORT)
846 rts_preamble_type = WLC_SHORT_PREAMBLE;
848 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
849 TXC_PREAMBLE_RTS_FB_SHORT)
850 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
852 durid =
853 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
854 rspec, rts_preamble_type,
855 preamble_type, ampdu_len,
856 true);
857 rts->duration = cpu_to_le16(durid);
858 durid = wlc_compute_rtscts_dur(wlc, use_cts,
859 rts_rspec_fallback,
860 rspec_fallback,
861 rts_fbr_preamble_type,
862 fbr_preamble_type,
863 ampdu_len, true);
864 txh->RTSDurFallback = cpu_to_le16(durid);
865 /* set TxFesTimeNormal */
866 txh->TxFesTimeNormal = rts->duration;
867 /* set fallback rate version of TxFesTimeNormal */
868 txh->TxFesTimeFallback = txh->RTSDurFallback;
871 /* set flag and plcp for fallback rate */
872 if (fbr) {
873 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
874 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
875 mch |= TXC_AMPDU_FBR;
876 txh->MacTxControlHigh = cpu_to_le16(mch);
877 WLC_SET_MIMO_PLCP_AMPDU(plcp);
878 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
881 WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
882 wlc->pub->unit, count, ampdu_len);
884 /* inform rate_sel if it this is a rate probe pkt */
885 frameid = le16_to_cpu(txh->TxFrameID);
886 if (frameid & TXFID_RATE_PROBE_MASK) {
887 WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n",
888 __func__);
890 for (i = 0; i < count; i++)
891 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
892 ampdu->txpkt_weight);
895 /* endif (count) */
896 return err;
899 void BCMFASTPATH
900 wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
901 struct sk_buff *p, tx_status_t *txs)
903 scb_ampdu_t *scb_ampdu;
904 struct wlc_info *wlc = ampdu->wlc;
905 scb_ampdu_tid_ini_t *ini;
906 u32 s1 = 0, s2 = 0;
907 struct ieee80211_tx_info *tx_info;
909 tx_info = IEEE80211_SKB_CB(p);
910 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
911 ASSERT(scb);
912 ASSERT(scb->magic == SCB_MAGIC);
913 ASSERT(txs->status & TX_STATUS_AMPDU);
914 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
915 ASSERT(scb_ampdu);
916 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
917 ASSERT(ini->scb == scb);
919 /* BMAC_NOTE: For the split driver, second level txstatus comes later
920 * So if the ACK was received then wait for the second level else just
921 * call the first one
923 if (txs->status & TX_STATUS_ACK_RCV) {
924 u8 status_delay = 0;
926 /* wait till the next 8 bytes of txstatus is available */
927 while (((s1 =
928 R_REG(wlc->osh,
929 &wlc->regs->frmtxstatus)) & TXS_V) == 0) {
930 udelay(1);
931 status_delay++;
932 if (status_delay > 10) {
933 ASSERT(status_delay <= 10);
934 return;
938 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
939 ASSERT(s1 & TX_STATUS_AMPDU);
940 s2 = R_REG(wlc->osh, &wlc->regs->frmtxstatus2);
943 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
944 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
947 void
948 rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
949 tx_status_t *txs, u8 mcs)
951 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
952 int i;
954 /* clear the rest of the rates */
955 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
956 txrate[i].idx = -1;
957 txrate[i].count = 0;
961 #define SHORTNAME "AMPDU status"
963 static void BCMFASTPATH
964 wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
965 struct sk_buff *p, tx_status_t *txs,
966 u32 s1, u32 s2)
968 scb_ampdu_t *scb_ampdu;
969 struct wlc_info *wlc = ampdu->wlc;
970 scb_ampdu_tid_ini_t *ini;
971 u8 bitmap[8], queue, tid;
972 d11txh_t *txh;
973 u8 *plcp;
974 struct ieee80211_hdr *h;
975 u16 seq, start_seq = 0, bindex, index, mcl;
976 u8 mcs = 0;
977 bool ba_recd = false, ack_recd = false;
978 u8 suc_mpdu = 0, tot_mpdu = 0;
979 uint supr_status;
980 bool update_rate = true, retry = true, tx_error = false;
981 u16 mimoantsel = 0;
982 u8 antselid = 0;
983 u8 retry_limit, rr_retry_limit;
984 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
986 #ifdef BCMDBG
987 u8 hole[AMPDU_MAX_MPDU];
988 memset(hole, 0, sizeof(hole));
989 #endif
991 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
992 ASSERT(txs->status & TX_STATUS_AMPDU);
994 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
995 ASSERT(scb_ampdu);
997 tid = (u8) (p->priority);
999 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1000 retry_limit = ampdu->retry_limit_tid[tid];
1001 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
1003 ASSERT(ini->scb == scb);
1005 memset(bitmap, 0, sizeof(bitmap));
1006 queue = txs->frameid & TXFID_QUEUE_MASK;
1007 ASSERT(queue < AC_COUNT);
1009 supr_status = txs->status & TX_STATUS_SUPR_MASK;
1011 if (txs->status & TX_STATUS_ACK_RCV) {
1012 if (TX_STATUS_SUPR_UF == supr_status) {
1013 update_rate = false;
1016 ASSERT(txs->status & TX_STATUS_INTERMEDIATE);
1017 start_seq = txs->sequence >> SEQNUM_SHIFT;
1018 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
1019 TX_STATUS_BA_BMAP03_SHIFT;
1021 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
1022 ASSERT(s1 & TX_STATUS_AMPDU);
1024 bitmap[0] |=
1025 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
1026 TX_STATUS_BA_BMAP47_SHIFT;
1027 bitmap[1] = (s1 >> 8) & 0xff;
1028 bitmap[2] = (s1 >> 16) & 0xff;
1029 bitmap[3] = (s1 >> 24) & 0xff;
1031 bitmap[4] = s2 & 0xff;
1032 bitmap[5] = (s2 >> 8) & 0xff;
1033 bitmap[6] = (s2 >> 16) & 0xff;
1034 bitmap[7] = (s2 >> 24) & 0xff;
1036 ba_recd = true;
1037 } else {
1038 WLCNTINCR(ampdu->cnt->noba);
1039 if (supr_status) {
1040 update_rate = false;
1041 if (supr_status == TX_STATUS_SUPR_BADCH) {
1042 WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n",
1043 __func__,
1044 CHSPEC_CHANNEL(wlc->default_bss->chanspec));
1045 } else {
1046 if (supr_status == TX_STATUS_SUPR_FRAG)
1047 WL_NONE("%s: AMPDU frag err\n",
1048 __func__);
1049 else
1050 WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n",
1051 __func__, supr_status);
1053 /* no need to retry for badch; will fail again */
1054 if (supr_status == TX_STATUS_SUPR_BADCH ||
1055 supr_status == TX_STATUS_SUPR_EXPTIME) {
1056 retry = false;
1057 wlc->pub->_cnt->txchanrej++;
1058 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1060 wlc->pub->_cnt->txexptime++;
1062 /* TX underflow : try tuning pre-loading or ampdu size */
1063 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1064 /* if there were underflows, but pre-loading is not active,
1065 notify rate adaptation.
1067 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1068 > 0) {
1069 tx_error = true;
1072 } else if (txs->phyerr) {
1073 update_rate = false;
1074 wlc->pub->_cnt->txphyerr++;
1075 WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
1076 wlc->pub->unit, txs->phyerr);
1078 if (WL_ERROR_ON()) {
1079 prpkt("txpkt (AMPDU)", wlc->osh, p);
1080 wlc_print_txdesc((d11txh_t *) p->data);
1082 wlc_print_txstatus(txs);
1086 /* loop through all pkts and retry if not acked */
1087 while (p) {
1088 tx_info = IEEE80211_SKB_CB(p);
1089 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1090 txh = (d11txh_t *) p->data;
1091 mcl = le16_to_cpu(txh->MacTxControlLow);
1092 plcp = (u8 *) (txh + 1);
1093 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
1094 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
1096 if (tot_mpdu == 0) {
1097 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1098 mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
1101 index = TX_SEQ_TO_INDEX(seq);
1102 ack_recd = false;
1103 if (ba_recd) {
1104 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1106 WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
1107 __func__, tid, seq, start_seq, bindex,
1108 isset(bitmap, bindex), index);
1110 /* if acked then clear bit and free packet */
1111 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1112 && isset(bitmap, bindex)) {
1113 ini->tx_in_transit--;
1114 ini->txretry[index] = 0;
1116 /* ampdu_ack_len: number of acked aggregated frames */
1117 /* ampdu_ack_map: block ack bit map for the aggregation */
1118 /* ampdu_len: number of aggregated frames */
1119 rate_status(wlc, tx_info, txs, mcs);
1120 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1121 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1123 /* XXX TODO: Make these accurate. */
1124 tx_info->status.ampdu_ack_len =
1125 (txs->
1126 status & TX_STATUS_FRM_RTX_MASK) >>
1127 TX_STATUS_FRM_RTX_SHIFT;
1128 tx_info->status.ampdu_len =
1129 (txs->
1130 status & TX_STATUS_FRM_RTX_MASK) >>
1131 TX_STATUS_FRM_RTX_SHIFT;
1133 skb_pull(p, D11_PHY_HDR_LEN);
1134 skb_pull(p, D11_TXH_LEN);
1136 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1138 ack_recd = true;
1139 suc_mpdu++;
1142 /* either retransmit or send bar if ack not recd */
1143 if (!ack_recd) {
1144 struct ieee80211_tx_rate *txrate =
1145 tx_info->status.rates;
1146 if (retry && (txrate[0].count < (int)retry_limit)) {
1147 ini->txretry[index]++;
1148 ini->tx_in_transit--;
1149 /* Use high prededence for retransmit to give some punch */
1150 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1151 wlc_txq_enq(wlc, scb, p,
1152 WLC_PRIO_TO_HI_PREC(tid));
1153 } else {
1154 /* Retry timeout */
1155 ini->tx_in_transit--;
1156 ieee80211_tx_info_clear_status(tx_info);
1157 tx_info->flags |=
1158 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1159 skb_pull(p, D11_PHY_HDR_LEN);
1160 skb_pull(p, D11_TXH_LEN);
1161 WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n",
1162 SHORTNAME, seq, ini->tx_in_transit);
1163 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1167 tot_mpdu++;
1169 /* break out if last packet of ampdu */
1170 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1171 TXC_AMPDU_LAST)
1172 break;
1174 p = GETNEXTTXP(wlc, queue);
1175 if (p == NULL) {
1176 ASSERT(p);
1177 break;
1180 wlc_send_q(wlc, wlc->active_queue);
1182 /* update rate state */
1183 if (WLANTSEL_ENAB(wlc))
1184 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1186 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1189 static void
1190 ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
1191 bool force)
1193 scb_ampdu_tid_ini_t *ini;
1194 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1195 if (!ini)
1196 return;
1198 WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1199 ampdu->wlc->pub->unit, tid);
1201 if (ini->tx_in_transit && !force)
1202 return;
1204 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1205 ASSERT(ini == &scb_ampdu->ini[ini->tid]);
1207 /* free all buffered tx packets */
1208 pktq_pflush(ampdu->wlc->osh, &scb_ampdu->txq, ini->tid, true, NULL, 0);
1211 /* initialize the initiator code for tid */
1212 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
1213 scb_ampdu_t *scb_ampdu,
1214 u8 tid, bool override)
1216 scb_ampdu_tid_ini_t *ini;
1218 ASSERT(scb_ampdu);
1219 ASSERT(scb_ampdu->scb);
1220 ASSERT(SCB_AMPDU(scb_ampdu->scb));
1221 ASSERT(tid < AMPDU_MAX_SCB_TID);
1223 /* check for per-tid control of ampdu */
1224 if (!ampdu->ini_enable[tid]) {
1225 WL_ERROR("%s: Rejecting tid %d\n", __func__, tid);
1226 return NULL;
1229 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1230 ini->tid = tid;
1231 ini->scb = scb_ampdu->scb;
1232 ini->magic = INI_MAGIC;
1233 WLCNTINCR(ampdu->cnt->txaddbareq);
1235 return ini;
1238 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
1240 struct wlc_info *wlc = ampdu->wlc;
1242 wlc->pub->_ampdu = false;
1244 if (on) {
1245 if (!N_ENAB(wlc->pub)) {
1246 WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
1247 wlc->pub->unit);
1248 return BCME_UNSUPPORTED;
1250 if (!wlc_ampdu_cap(ampdu)) {
1251 WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
1252 wlc->pub->unit);
1253 return BCME_UNSUPPORTED;
1255 wlc->pub->_ampdu = on;
1258 return 0;
1261 static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
1263 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1264 return true;
1265 else
1266 return false;
1269 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
1271 u32 rate, mcs;
1273 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1274 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1275 /* 20MHz, No SGI */
1276 rate = MCS_RATE(mcs, false, false);
1277 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1278 /* 40 MHz, No SGI */
1279 rate = MCS_RATE(mcs, true, false);
1280 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1281 /* 20MHz, SGI */
1282 rate = MCS_RATE(mcs, false, true);
1283 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1284 /* 40 MHz, SGI */
1285 rate = MCS_RATE(mcs, true, true);
1286 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1290 u8 BCMFASTPATH
1291 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
1292 ratespec_t rspec, int phylen)
1294 scb_ampdu_t *scb_ampdu;
1295 int bytes, cnt, tmp;
1296 u8 tx_density;
1298 ASSERT(scb);
1299 ASSERT(SCB_AMPDU(scb));
1301 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1302 ASSERT(scb_ampdu);
1304 if (scb_ampdu->mpdu_density == 0)
1305 return 0;
1307 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1308 density x is in 2^(x-4) usec
1309 ==> # of bytes needed for req density = rate/2^(17-x)
1310 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1313 tx_density = scb_ampdu->mpdu_density;
1315 ASSERT(tx_density <= AMPDU_MAX_MPDU_DENSITY);
1316 tmp = 1 << (17 - tx_density);
1317 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1319 if (bytes > phylen) {
1320 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1321 ASSERT(cnt <= 255);
1322 return (u8) cnt;
1323 } else
1324 return 0;
1327 void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
1329 char template[T_RAM_ACCESS_SZ * 2];
1331 /* driver needs to write the ta in the template; ta is at offset 16 */
1332 memset(template, 0, sizeof(template));
1333 memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
1334 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1335 template);
1338 bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
1340 return wlc->ampdu->ini_enable[tid];
1343 void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
1345 struct wlc_info *wlc = ampdu->wlc;
1347 /* Extend ucode internal watchdog timer to match larger received frames */
1348 if ((ampdu->rx_factor & HT_PARAMS_RX_FACTOR_MASK) ==
1349 AMPDU_RX_FACTOR_64K) {
1350 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1351 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1352 } else {
1353 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1354 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);