Staging: brcm80211: s/int8/s8/
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / sys / wlc_ampdu.c
blob1d68400bc6d34600941520ad309d511e8987a2e8
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.
17 #include <wlc_cfg.h>
18 #include <typedefs.h>
19 #include <linuxver.h>
20 #include <bcmdefs.h>
21 #include <osl.h>
22 #include <bcmutils.h>
23 #include <siutils.h>
24 #include <bcmendian.h>
25 #include <wlioctl.h>
26 #include <sbhnddma.h>
27 #include <hnddma.h>
28 #include <d11.h>
29 #include <wlc_rate.h>
30 #include <wlc_pub.h>
31 #include <wlc_key.h>
32 #include <wlc_mac80211.h>
33 #include <wlc_phy_hal.h>
34 #include <wlc_antsel.h>
35 #include <wlc_scb.h>
36 #include <net/mac80211.h>
37 #include <wlc_ampdu.h>
38 #include <wl_export.h>
40 #ifdef WLC_HIGH_ONLY
41 #include <bcm_rpc_tp.h>
42 #include <wlc_rpctx.h>
43 #endif
45 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
46 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
47 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
48 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
49 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
50 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
51 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
52 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
53 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
54 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
55 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
56 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
57 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
59 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
60 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
61 * without underflows
63 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
64 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
65 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
66 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
67 * accumulate between resets.
70 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
72 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
73 #define AMPDU_MAX_MPDU_OVERHEAD (DOT11_FCS_LEN + DOT11_ICV_AES_LEN + AMPDU_DELIMITER_LEN + 3 \
74 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
76 #ifdef BCMDBG
77 uint32 wl_ampdu_dbg =
78 WL_AMPDU_UPDN_VAL |
79 WL_AMPDU_ERR_VAL |
80 WL_AMPDU_TX_VAL |
81 WL_AMPDU_RX_VAL |
82 WL_AMPDU_CTL_VAL |
83 WL_AMPDU_HW_VAL | WL_AMPDU_HWTXS_VAL | WL_AMPDU_HWDBG_VAL;
84 #endif
86 /* structure to hold tx fifo information and pre-loading state
87 * counters specific to tx underflows of ampdus
88 * some counters might be redundant with the ones in wlc or ampdu structures.
89 * This allows to maintain a specific state independantly of
90 * how often and/or when the wlc counters are updated.
92 typedef struct wlc_fifo_info {
93 uint16 ampdu_pld_size; /* number of bytes to be pre-loaded */
94 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
95 uint16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
96 uint32 accum_txfunfl; /* num of underflows since we modified pld params */
97 uint32 accum_txampdu; /* num of tx ampdu since we modified pld params */
98 uint32 prev_txampdu; /* previous reading of tx ampdu */
99 uint32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
100 } wlc_fifo_info_t;
102 /* AMPDU module specific state */
103 struct ampdu_info {
104 wlc_info_t *wlc; /* pointer to main wlc structure */
105 int scb_handle; /* scb cubby handle to retrieve data from scb */
106 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
107 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
108 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
109 u8 retry_limit; /* mpdu transmit retry limit */
110 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
111 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
112 /* per-tid mpdu transmit retry limit at regular rate */
113 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
114 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
115 s8 max_pdu; /* max pdus allowed in ampdu */
116 u8 dur; /* max duration of an ampdu (in msec) */
117 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
118 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
119 uint32 ffpld_rsvd; /* number of bytes to reserve for preload */
120 uint32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
121 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
122 bool mfbr; /* enable multiple fallback rate */
123 uint32 tx_max_funl; /* underflows should be kept such that
124 * (tx_max_funfl*underflows) < tx frames
126 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
128 #ifdef WLC_HIGH_ONLY
129 void *p;
130 tx_status_t txs;
131 bool waiting_status; /* To help sanity checks */
132 #endif
135 #define AMPDU_CLEANUPFLAG_RX (0x1)
136 #define AMPDU_CLEANUPFLAG_TX (0x2)
138 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
139 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
141 static void wlc_ffpld_init(ampdu_info_t *ampdu);
142 static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int f);
143 static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f);
145 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
146 scb_ampdu_t *scb_ampdu,
147 u8 tid, bool override);
148 static void ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu,
149 u8 tid, bool force);
150 static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur);
151 static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb);
152 static void scb_ampdu_update_config_all(ampdu_info_t *ampdu);
154 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
156 static void wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb,
157 void *p, tx_status_t *txs,
158 uint32 frmtxstatus,
159 uint32 frmtxstatus2);
161 static inline uint16 pkt_txh_seqnum(wlc_info_t *wlc, void *p)
163 d11txh_t *txh;
164 struct dot11_header *h;
165 txh = (d11txh_t *) PKTDATA(p);
166 h = (struct dot11_header *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
167 return ltoh16(h->seq) >> SEQNUM_SHIFT;
170 ampdu_info_t *BCMATTACHFN(wlc_ampdu_attach) (wlc_info_t *wlc)
172 ampdu_info_t *ampdu;
173 int i;
175 /* some code depends on packed structures */
176 ASSERT(DOT11_MAXNUMFRAGS == NBITS(uint16));
177 ASSERT(ISPOWEROF2(AMPDU_TX_BA_MAX_WSIZE));
178 ASSERT(ISPOWEROF2(AMPDU_RX_BA_MAX_WSIZE));
179 ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
180 ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
182 ampdu = (ampdu_info_t *) MALLOC(wlc->osh, sizeof(ampdu_info_t));
183 if (!ampdu) {
184 WL_ERROR(("wl%d: wlc_ampdu_attach: out of mem, malloced %d bytes\n", wlc->pub->unit, MALLOCED(wlc->osh)));
185 return NULL;
187 bzero((char *)ampdu, sizeof(ampdu_info_t));
188 ampdu->wlc = wlc;
190 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
191 ampdu->ini_enable[i] = TRUE;
192 /* Disable ampdu for VO by default */
193 ampdu->ini_enable[PRIO_8021D_VO] = FALSE;
194 ampdu->ini_enable[PRIO_8021D_NC] = FALSE;
196 /* Disable ampdu for BK by default since not enough fifo space */
197 ampdu->ini_enable[PRIO_8021D_NONE] = FALSE;
198 ampdu->ini_enable[PRIO_8021D_BK] = FALSE;
200 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
201 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
202 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
203 ampdu->max_pdu = AUTO;
204 ampdu->dur = AMPDU_MAX_DUR;
205 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
207 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
208 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
209 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
210 ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
211 else
212 ampdu->rx_factor = AMPDU_RX_FACTOR_64K;
213 #ifdef WLC_HIGH_ONLY
214 /* Restrict to smaller rcv size for BMAC dongle */
215 ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
216 #endif
217 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
218 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
220 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
221 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
222 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
225 ampdu_update_max_txlen(ampdu, ampdu->dur);
226 ampdu->mfbr = FALSE;
227 /* try to set ampdu to the default value */
228 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
230 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
231 wlc_ffpld_init(ampdu);
233 return ampdu;
236 void BCMATTACHFN(wlc_ampdu_detach) (ampdu_info_t *ampdu)
238 int i;
240 if (!ampdu)
241 return;
243 /* free all ini's which were to be freed on callbacks which were never called */
244 for (i = 0; i < AMPDU_INI_FREE; i++) {
245 if (ampdu->ini_free[i]) {
246 MFREE(ampdu->wlc->osh, ampdu->ini_free[i],
247 sizeof(scb_ampdu_tid_ini_t));
251 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
252 MFREE(ampdu->wlc->osh, ampdu, sizeof(ampdu_info_t));
255 void scb_ampdu_cleanup(ampdu_info_t *ampdu, struct scb *scb)
257 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
258 u8 tid;
260 WL_AMPDU_UPDN(("scb_ampdu_cleanup: enter\n"));
261 ASSERT(scb_ampdu);
263 for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
264 ampdu_cleanup_tid_ini(ampdu, scb_ampdu, tid, FALSE);
268 /* reset the ampdu state machine so that it can gracefully handle packets that were
269 * freed from the dma and tx queues during reinit
271 void wlc_ampdu_reset(ampdu_info_t *ampdu)
273 WL_NONE(("%s: Entering\n", __func__));
276 static void scb_ampdu_update_config(ampdu_info_t *ampdu, struct scb *scb)
278 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
279 int i;
281 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
283 /* go back to legacy size if some preloading is occuring */
284 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
285 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
286 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
289 /* apply user override */
290 if (ampdu->max_pdu != AUTO)
291 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
293 scb_ampdu->release = MIN(scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
295 if (scb_ampdu->max_rxlen)
296 scb_ampdu->release =
297 MIN(scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
299 scb_ampdu->release = MIN(scb_ampdu->release,
300 ampdu->fifo_tb[TX_AC_BE_FIFO].
301 mcs2ampdu_table[FFPLD_MAX_MCS]);
303 ASSERT(scb_ampdu->release);
306 void scb_ampdu_update_config_all(ampdu_info_t *ampdu)
308 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
311 static void wlc_ffpld_init(ampdu_info_t *ampdu)
313 int i, j;
314 wlc_fifo_info_t *fifo;
316 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
317 fifo = (ampdu->fifo_tb + j);
318 fifo->ampdu_pld_size = 0;
319 for (i = 0; i <= FFPLD_MAX_MCS; i++)
320 fifo->mcs2ampdu_table[i] = 255;
321 fifo->dmaxferrate = 0;
322 fifo->accum_txampdu = 0;
323 fifo->prev_txfunfl = 0;
324 fifo->accum_txfunfl = 0;
329 /* evaluate the dma transfer rate using the tx underflows as feedback.
330 * If necessary, increase tx fifo preloading. If not enough,
331 * decrease maximum ampdu size for each mcs till underflows stop
332 * Return 1 if pre-loading not active, -1 if not an underflow event,
333 * 0 if pre-loading module took care of the event.
335 static int wlc_ffpld_check_txfunfl(wlc_info_t *wlc, int fid)
337 ampdu_info_t *ampdu = wlc->ampdu;
338 uint32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, TRUE, FALSE);
339 uint32 txunfl_ratio;
340 u8 max_mpdu;
341 uint32 current_ampdu_cnt = 0;
342 uint16 max_pld_size;
343 uint32 new_txunfl;
344 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
345 uint xmtfifo_sz;
346 uint16 cur_txunfl;
348 /* return if we got here for a different reason than underflows */
349 cur_txunfl =
350 wlc_read_shm(wlc,
351 M_UCODE_MACSTAT + OFFSETOF(macstat_t, txfunfl[fid]));
352 new_txunfl = (uint16) (cur_txunfl - fifo->prev_txfunfl);
353 if (new_txunfl == 0) {
354 WL_FFPLD(("check_txunfl : TX status FRAG set but no tx underflows\n"));
355 return -1;
357 fifo->prev_txfunfl = cur_txunfl;
359 if (!ampdu->tx_max_funl)
360 return 1;
362 /* check if fifo is big enough */
363 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
364 WL_FFPLD(("check_txunfl : get xmtfifo_sz failed.\n"));
365 return -1;
368 if ((TXFIFO_SIZE_UNIT * (uint32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
369 return 1;
371 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
372 fifo->accum_txfunfl += new_txunfl;
374 /* we need to wait for at least 10 underflows */
375 if (fifo->accum_txfunfl < 10)
376 return 0;
378 WL_FFPLD(("ampdu_count %d tx_underflows %d\n",
379 current_ampdu_cnt, fifo->accum_txfunfl));
382 compute the current ratio of tx unfl per ampdu.
383 When the current ampdu count becomes too
384 big while the ratio remains small, we reset
385 the current count in order to not
386 introduce too big of a latency in detecting a
387 large amount of tx underflows later.
390 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
392 if (txunfl_ratio > ampdu->tx_max_funl) {
393 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
394 fifo->accum_txfunfl = 0;
396 return 0;
398 max_mpdu =
399 MIN(fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
401 /* In case max value max_pdu is already lower than
402 the fifo depth, there is nothing more we can do.
405 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
406 WL_FFPLD(("tx fifo pld : max ampdu fits in fifo\n)"));
407 fifo->accum_txfunfl = 0;
408 return 0;
411 if (fifo->ampdu_pld_size < max_pld_size) {
413 /* increment by TX_FIFO_PLD_INC bytes */
414 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
415 if (fifo->ampdu_pld_size > max_pld_size)
416 fifo->ampdu_pld_size = max_pld_size;
418 /* update scb release size */
419 scb_ampdu_update_config_all(ampdu);
422 compute a new dma xfer rate for max_mpdu @ max mcs.
423 This is the minimum dma rate that
424 can acheive no unferflow condition for the current mpdu size.
426 /* note : we divide/multiply by 100 to avoid integer overflows */
427 fifo->dmaxferrate =
428 (((phy_rate / 100) *
429 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
430 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
432 WL_FFPLD(("DMA estimated transfer rate %d; pre-load size %d\n",
433 fifo->dmaxferrate, fifo->ampdu_pld_size));
434 } else {
436 /* decrease ampdu size */
437 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
438 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
439 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
440 AMPDU_NUM_MPDU_LEGACY - 1;
441 else
442 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
444 /* recompute the table */
445 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
447 /* update scb release size */
448 scb_ampdu_update_config_all(ampdu);
451 fifo->accum_txfunfl = 0;
452 return 0;
455 static void wlc_ffpld_calc_mcs2ampdu_table(ampdu_info_t *ampdu, int f)
457 int i;
458 uint32 phy_rate, dma_rate, tmp;
459 u8 max_mpdu;
460 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
462 /* recompute the dma rate */
463 /* note : we divide/multiply by 100 to avoid integer overflows */
464 max_mpdu =
465 MIN(fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
466 phy_rate = MCS_RATE(FFPLD_MAX_MCS, TRUE, FALSE);
467 dma_rate =
468 (((phy_rate / 100) *
469 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
470 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
471 fifo->dmaxferrate = dma_rate;
473 /* fill up the mcs2ampdu table; do not recalc the last mcs */
474 dma_rate = dma_rate >> 7;
475 for (i = 0; i < FFPLD_MAX_MCS; i++) {
476 /* shifting to keep it within integer range */
477 phy_rate = MCS_RATE(i, TRUE, FALSE) >> 7;
478 if (phy_rate > dma_rate) {
479 tmp = ((fifo->ampdu_pld_size * phy_rate) /
480 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
481 tmp = MIN(tmp, 255);
482 fifo->mcs2ampdu_table[i] = (u8) tmp;
487 static void BCMFASTPATH
488 wlc_ampdu_agg(ampdu_info_t *ampdu, struct scb *scb, void *p, uint prec)
490 scb_ampdu_t *scb_ampdu;
491 scb_ampdu_tid_ini_t *ini;
492 u8 tid = (u8) PKTPRIO(p);
494 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
496 /* initialize initiator on first packet; sends addba req */
497 ini = SCB_AMPDU_INI(scb_ampdu, tid);
498 if (ini->magic != INI_MAGIC) {
499 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, FALSE);
501 return;
504 int BCMFASTPATH
505 wlc_sendampdu(ampdu_info_t *ampdu, wlc_txq_info_t *qi, void **pdu, int prec)
507 wlc_info_t *wlc;
508 osl_t *osh;
509 void *p, *pkt[AMPDU_MAX_MPDU];
510 u8 tid, ndelim;
511 int err = 0;
512 u8 preamble_type = WLC_GF_PREAMBLE;
513 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
514 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
515 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
517 bool rr = TRUE, fbr = FALSE;
518 uint i, count = 0, fifo, seg_cnt = 0;
519 uint16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
520 uint32 ampdu_len, maxlen = 0;
521 d11txh_t *txh = NULL;
522 u8 *plcp;
523 struct dot11_header *h;
524 struct scb *scb;
525 scb_ampdu_t *scb_ampdu;
526 scb_ampdu_tid_ini_t *ini;
527 u8 mcs = 0;
528 bool use_rts = FALSE, use_cts = FALSE;
529 ratespec_t rspec = 0, rspec_fallback = 0;
530 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
531 uint16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
532 struct dot11_rts_frame *rts;
533 u8 rr_retry_limit;
534 wlc_fifo_info_t *f;
535 bool fbr_iscck;
536 struct ieee80211_tx_info *tx_info;
537 uint16 qlen;
539 wlc = ampdu->wlc;
540 osh = wlc->osh;
541 p = *pdu;
543 ASSERT(p);
545 tid = (u8) PKTPRIO(p);
546 ASSERT(tid < AMPDU_MAX_SCB_TID);
548 f = ampdu->fifo_tb + prio2fifo[tid];
550 scb = wlc->pub->global_scb;
551 ASSERT(scb->magic == SCB_MAGIC);
553 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
554 ASSERT(scb_ampdu);
555 ini = &scb_ampdu->ini[tid];
557 /* Let pressure continue to build ... */
558 qlen = pktq_plen(&qi->q, prec);
559 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
560 return BCME_BUSY;
563 wlc_ampdu_agg(ampdu, scb, p, tid);
565 if (wlc->block_datafifo) {
566 WL_ERROR(("%s: Fifo blocked\n", __func__));
567 return BCME_BUSY;
569 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
570 ampdu_len = 0;
571 dma_len = 0;
572 while (p) {
573 struct ieee80211_tx_rate *txrate;
575 tx_info = IEEE80211_SKB_CB(p);
576 txrate = tx_info->status.rates;
578 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
579 err = wlc_prep_pdu(wlc, p, &fifo);
580 } else {
581 WL_ERROR(("%s: AMPDU flag is off!\n", __func__));
582 *pdu = NULL;
583 err = 0;
584 break;
587 if (err) {
588 if (err == BCME_BUSY) {
589 WL_ERROR(("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n", wlc->pub->unit, seq));
590 WLCNTINCR(ampdu->cnt->sduretry);
591 *pdu = p;
592 break;
595 /* error in the packet; reject it */
596 WL_AMPDU_ERR(("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n", wlc->pub->unit, seq));
597 WLCNTINCR(ampdu->cnt->sdurejected);
599 *pdu = NULL;
600 break;
603 /* pkt is good to be aggregated */
604 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
605 txh = (d11txh_t *) PKTDATA(p);
606 plcp = (u8 *) (txh + 1);
607 h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN);
608 seq = ltoh16(h->seq) >> SEQNUM_SHIFT;
609 index = TX_SEQ_TO_INDEX(seq);
611 /* check mcl fields and test whether it can be agg'd */
612 mcl = ltoh16(txh->MacTxControlLow);
613 mcl &= ~TXC_AMPDU_MASK;
614 fbr_iscck = !(ltoh16(txh->XtraFrameTypes) & 0x3);
615 ASSERT(!fbr_iscck);
616 txh->PreloadSize = 0; /* always default to 0 */
618 /* Handle retry limits */
619 if (txrate[0].count <= rr_retry_limit) {
620 txrate[0].count++;
621 rr = TRUE;
622 fbr = FALSE;
623 ASSERT(!fbr);
624 } else {
625 fbr = TRUE;
626 rr = FALSE;
627 txrate[1].count++;
630 /* extract the length info */
631 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
632 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
634 /* retrieve null delimiter count */
635 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
636 seg_cnt += 1;
638 WL_AMPDU_TX(("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
639 wlc->pub->unit, count, len));
642 * aggregateable mpdu. For ucode/hw agg,
643 * test whether need to break or change the epoch
645 if (count == 0) {
646 uint16 fc;
647 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
648 /* refill the bits since might be a retx mpdu */
649 mcl |= TXC_STARTMSDU;
650 rts = (struct dot11_rts_frame *)&txh->rts_frame;
651 fc = ltoh16(rts->fc);
652 if ((fc & FC_KIND_MASK) == FC_RTS) {
653 mcl |= TXC_SENDRTS;
654 use_rts = TRUE;
656 if ((fc & FC_KIND_MASK) == FC_CTS) {
657 mcl |= TXC_SENDCTS;
658 use_cts = TRUE;
660 } else {
661 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
662 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
665 len = ROUNDUP(len, 4);
666 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
668 dma_len += (uint16) pkttotlen(osh, p);
670 WL_AMPDU_TX(("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n", wlc->pub->unit, ampdu_len, seg_cnt, ndelim));
672 txh->MacTxControlLow = htol16(mcl);
674 /* this packet is added */
675 pkt[count++] = p;
677 /* patch the first MPDU */
678 if (count == 1) {
679 u8 plcp0, plcp3, is40, sgi;
680 struct ieee80211_sta *sta;
682 sta = tx_info->control.sta;
684 if (rr) {
685 plcp0 = plcp[0];
686 plcp3 = plcp[3];
687 } else {
688 plcp0 = txh->FragPLCPFallback[0];
689 plcp3 = txh->FragPLCPFallback[3];
692 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
693 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
694 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
695 ASSERT(mcs < MCS_TABLE_SIZE);
696 maxlen =
697 MIN(scb_ampdu->max_rxlen,
698 ampdu->max_txlen[mcs][is40][sgi]);
700 WL_NONE(("sendampdu: sgi %d, is40 %d, mcs %d\n", sgi,
701 is40, mcs));
703 maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
705 if (is40)
706 mimo_ctlchbw =
707 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
708 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
710 /* rebuild the rspec and rspec_fallback */
711 rspec = RSPEC_MIMORATE;
712 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
713 if (plcp[0] & MIMO_PLCP_40MHZ)
714 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
716 if (fbr_iscck) /* CCK */
717 rspec_fallback =
718 CCK_RSPEC(CCK_PHY2MAC_RATE
719 (txh->FragPLCPFallback[0]));
720 else { /* MIMO */
721 rspec_fallback = RSPEC_MIMORATE;
722 rspec_fallback |=
723 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
724 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
725 rspec_fallback |=
726 (PHY_TXC1_BW_40MHZ <<
727 RSPEC_BW_SHIFT);
730 if (use_rts || use_cts) {
731 rts_rspec =
732 wlc_rspec_to_rts_rspec(wlc, rspec, FALSE,
733 mimo_ctlchbw);
734 rts_rspec_fallback =
735 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
736 FALSE, mimo_ctlchbw);
740 /* if (first mpdu for host agg) */
741 /* test whether to add more */
742 if ((MCS_RATE(mcs, TRUE, FALSE) >= f->dmaxferrate) &&
743 (count == f->mcs2ampdu_table[mcs])) {
744 WL_AMPDU_ERR(("wl%d: PR 37644: stopping ampdu at %d for mcs %d", wlc->pub->unit, count, mcs));
745 break;
748 if (count == scb_ampdu->max_pdu) {
749 WL_NONE(("Stop taking from q, reached %d deep\n",
750 scb_ampdu->max_pdu));
751 break;
754 /* check to see if the next pkt is a candidate for aggregation */
755 p = pktq_ppeek(&qi->q, prec);
756 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
758 if (p) {
759 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
760 ((u8) PKTPRIO(p) == tid)) {
762 plen =
763 pkttotlen(osh, p) + AMPDU_MAX_MPDU_OVERHEAD;
764 plen = MAX(scb_ampdu->min_len, plen);
766 if ((plen + ampdu_len) > maxlen) {
767 p = NULL;
768 WL_ERROR(("%s: Bogus plen #1\n",
769 __func__));
770 ASSERT(3 == 4);
771 continue;
774 /* check if there are enough descriptors available */
775 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
776 WL_ERROR(("%s: No fifo space !!!!!!\n", __func__));
777 p = NULL;
778 continue;
780 p = pktq_pdeq(&qi->q, prec);
781 ASSERT(p);
782 } else {
783 p = NULL;
786 } /* end while(p) */
788 ini->tx_in_transit += count;
790 if (count) {
791 WLCNTADD(ampdu->cnt->txmpdu, count);
793 /* patch up the last txh */
794 txh = (d11txh_t *) PKTDATA(pkt[count - 1]);
795 mcl = ltoh16(txh->MacTxControlLow);
796 mcl &= ~TXC_AMPDU_MASK;
797 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
798 txh->MacTxControlLow = htol16(mcl);
800 /* remove the null delimiter after last mpdu */
801 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
802 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
803 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
805 /* remove the pad len from last mpdu */
806 fbr_iscck = ((ltoh16(txh->XtraFrameTypes) & 0x3) == 0);
807 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
808 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
809 ampdu_len -= ROUNDUP(len, 4) - len;
811 /* patch up the first txh & plcp */
812 txh = (d11txh_t *) PKTDATA(pkt[0]);
813 plcp = (u8 *) (txh + 1);
815 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
816 /* mark plcp to indicate ampdu */
817 WLC_SET_MIMO_PLCP_AMPDU(plcp);
819 /* reset the mixed mode header durations */
820 if (txh->MModeLen) {
821 uint16 mmodelen =
822 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
823 txh->MModeLen = htol16(mmodelen);
824 preamble_type = WLC_MM_PREAMBLE;
826 if (txh->MModeFbrLen) {
827 uint16 mmfbrlen =
828 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
829 txh->MModeFbrLen = htol16(mmfbrlen);
830 fbr_preamble_type = WLC_MM_PREAMBLE;
833 /* set the preload length */
834 if (MCS_RATE(mcs, TRUE, FALSE) >= f->dmaxferrate) {
835 dma_len = MIN(dma_len, f->ampdu_pld_size);
836 txh->PreloadSize = htol16(dma_len);
837 } else
838 txh->PreloadSize = 0;
840 mch = ltoh16(txh->MacTxControlHigh);
842 /* update RTS dur fields */
843 if (use_rts || use_cts) {
844 uint16 durid;
845 rts = (struct dot11_rts_frame *)&txh->rts_frame;
846 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
847 TXC_PREAMBLE_RTS_MAIN_SHORT)
848 rts_preamble_type = WLC_SHORT_PREAMBLE;
850 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
851 TXC_PREAMBLE_RTS_FB_SHORT)
852 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
854 durid =
855 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
856 rspec, rts_preamble_type,
857 preamble_type, ampdu_len,
858 TRUE);
859 rts->durid = htol16(durid);
860 durid = wlc_compute_rtscts_dur(wlc, use_cts,
861 rts_rspec_fallback,
862 rspec_fallback,
863 rts_fbr_preamble_type,
864 fbr_preamble_type,
865 ampdu_len, TRUE);
866 txh->RTSDurFallback = htol16(durid);
867 /* set TxFesTimeNormal */
868 txh->TxFesTimeNormal = rts->durid;
869 /* set fallback rate version of TxFesTimeNormal */
870 txh->TxFesTimeFallback = txh->RTSDurFallback;
873 /* set flag and plcp for fallback rate */
874 if (fbr) {
875 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
876 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
877 mch |= TXC_AMPDU_FBR;
878 txh->MacTxControlHigh = htol16(mch);
879 WLC_SET_MIMO_PLCP_AMPDU(plcp);
880 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
883 WL_AMPDU_TX(("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
884 wlc->pub->unit, count, ampdu_len));
886 /* inform rate_sel if it this is a rate probe pkt */
887 frameid = ltoh16(txh->TxFrameID);
888 if (frameid & TXFID_RATE_PROBE_MASK) {
889 WL_ERROR(("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n", __func__));
891 #ifdef WLC_HIGH_ONLY
892 if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU)
893 bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc),
894 BCM_RPC_TP_HOST_AGG_AMPDU, TRUE);
895 #endif
896 for (i = 0; i < count; i++)
897 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
898 ampdu->txpkt_weight);
899 #ifdef WLC_HIGH_ONLY
900 if (wlc->rpc_agg & BCM_RPC_TP_HOST_AGG_AMPDU)
901 bcm_rpc_tp_agg_set(bcm_rpc_tp_get(wlc->rpc),
902 BCM_RPC_TP_HOST_AGG_AMPDU, FALSE);
903 #endif
906 /* endif (count) */
907 return err;
910 void BCMFASTPATH
911 wlc_ampdu_dotxstatus(ampdu_info_t *ampdu, struct scb *scb, void *p,
912 tx_status_t *txs)
914 scb_ampdu_t *scb_ampdu;
915 wlc_info_t *wlc = ampdu->wlc;
916 scb_ampdu_tid_ini_t *ini;
917 uint32 s1 = 0, s2 = 0;
918 struct ieee80211_tx_info *tx_info;
920 tx_info = IEEE80211_SKB_CB(p);
921 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
922 ASSERT(scb);
923 ASSERT(scb->magic == SCB_MAGIC);
924 ASSERT(txs->status & TX_STATUS_AMPDU);
925 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
926 ASSERT(scb_ampdu);
927 ini = SCB_AMPDU_INI(scb_ampdu, PKTPRIO(p));
928 ASSERT(ini->scb == scb);
930 /* BMAC_NOTE: For the split driver, second level txstatus comes later
931 * So if the ACK was received then wait for the second level else just
932 * call the first one
934 if (txs->status & TX_STATUS_ACK_RCV) {
935 #ifdef WLC_LOW
936 u8 status_delay = 0;
938 /* wait till the next 8 bytes of txstatus is available */
939 while (((s1 =
940 R_REG(wlc->osh,
941 &wlc->regs->frmtxstatus)) & TXS_V) == 0) {
942 OSL_DELAY(1);
943 status_delay++;
944 if (status_delay > 10) {
945 ASSERT(status_delay <= 10);
946 return;
950 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
951 ASSERT(s1 & TX_STATUS_AMPDU);
952 s2 = R_REG(wlc->osh, &wlc->regs->frmtxstatus2);
953 #else /* WLC_LOW */
955 /* Store the relevant information in ampdu structure */
956 WL_AMPDU_TX(("wl%d: wlc_ampdu_dotxstatus: High Recvd\n",
957 wlc->pub->unit));
959 ASSERT(!ampdu->p);
960 ampdu->p = p;
961 bcopy(txs, &ampdu->txs, sizeof(tx_status_t));
962 ampdu->waiting_status = TRUE;
963 return;
964 #endif /* WLC_LOW */
967 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
968 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
971 #ifdef WLC_HIGH_ONLY
972 void wlc_ampdu_txstatus_complete(ampdu_info_t *ampdu, uint32 s1, uint32 s2)
974 WL_AMPDU_TX(("wl%d: wlc_ampdu_txstatus_complete: High Recvd 0x%x 0x%x p:%p\n", ampdu->wlc->pub->unit, s1, s2, ampdu->p));
976 ASSERT(ampdu->waiting_status);
978 /* The packet may have been freed if the SCB went away, if so, then still free the
979 * DMA chain
981 if (ampdu->p) {
982 struct ieee80211_tx_info *tx_info;
983 struct scb *scb;
985 tx_info = IEEE80211_SKB_CB(ampdu->p);
986 scb = (struct scb *)tx_info->control.sta->drv_priv;
988 wlc_ampdu_dotxstatus_complete(ampdu, scb, ampdu->p, &ampdu->txs,
989 s1, s2);
990 ampdu->p = NULL;
993 ampdu->waiting_status = FALSE;
995 #endif /* WLC_HIGH_ONLY */
996 void rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info,
997 tx_status_t *txs, u8 mcs);
999 void
1000 rate_status(wlc_info_t *wlc, struct ieee80211_tx_info *tx_info,
1001 tx_status_t *txs, u8 mcs)
1003 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
1004 int i;
1006 /* clear the rest of the rates */
1007 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
1008 txrate[i].idx = -1;
1009 txrate[i].count = 0;
1013 extern void wlc_txq_enq(wlc_info_t *wlc, struct scb *scb, void *sdu,
1014 uint prec);
1016 #define SHORTNAME "AMPDU status"
1018 static void BCMFASTPATH
1019 wlc_ampdu_dotxstatus_complete(ampdu_info_t *ampdu, struct scb *scb, void *p,
1020 tx_status_t *txs, uint32 s1, uint32 s2)
1022 scb_ampdu_t *scb_ampdu;
1023 wlc_info_t *wlc = ampdu->wlc;
1024 scb_ampdu_tid_ini_t *ini;
1025 u8 bitmap[8], queue, tid;
1026 d11txh_t *txh;
1027 u8 *plcp;
1028 struct dot11_header *h;
1029 uint16 seq, start_seq = 0, bindex, index, mcl;
1030 u8 mcs = 0;
1031 bool ba_recd = FALSE, ack_recd = FALSE;
1032 u8 suc_mpdu = 0, tot_mpdu = 0;
1033 uint supr_status;
1034 bool update_rate = TRUE, retry = TRUE, tx_error = FALSE;
1035 uint16 mimoantsel = 0;
1036 u8 antselid = 0;
1037 u8 retry_limit, rr_retry_limit;
1038 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
1040 #ifdef BCMDBG
1041 u8 hole[AMPDU_MAX_MPDU];
1042 bzero(hole, sizeof(hole));
1043 #endif
1045 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1046 ASSERT(txs->status & TX_STATUS_AMPDU);
1048 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1049 ASSERT(scb_ampdu);
1051 tid = (u8) PKTPRIO(p);
1053 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1054 retry_limit = ampdu->retry_limit_tid[tid];
1055 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
1057 ASSERT(ini->scb == scb);
1059 bzero(bitmap, sizeof(bitmap));
1060 queue = txs->frameid & TXFID_QUEUE_MASK;
1061 ASSERT(queue < AC_COUNT);
1063 supr_status = txs->status & TX_STATUS_SUPR_MASK;
1065 if (txs->status & TX_STATUS_ACK_RCV) {
1066 if (TX_STATUS_SUPR_UF == supr_status) {
1067 update_rate = FALSE;
1070 ASSERT(txs->status & TX_STATUS_INTERMEDIATE);
1071 start_seq = txs->sequence >> SEQNUM_SHIFT;
1072 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
1073 TX_STATUS_BA_BMAP03_SHIFT;
1075 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
1076 ASSERT(s1 & TX_STATUS_AMPDU);
1078 bitmap[0] |=
1079 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
1080 TX_STATUS_BA_BMAP47_SHIFT;
1081 bitmap[1] = (s1 >> 8) & 0xff;
1082 bitmap[2] = (s1 >> 16) & 0xff;
1083 bitmap[3] = (s1 >> 24) & 0xff;
1085 bitmap[4] = s2 & 0xff;
1086 bitmap[5] = (s2 >> 8) & 0xff;
1087 bitmap[6] = (s2 >> 16) & 0xff;
1088 bitmap[7] = (s2 >> 24) & 0xff;
1090 ba_recd = TRUE;
1091 } else {
1092 WLCNTINCR(ampdu->cnt->noba);
1093 if (supr_status) {
1094 update_rate = FALSE;
1095 if (supr_status == TX_STATUS_SUPR_BADCH) {
1096 WL_ERROR(("%s: Pkt tx suppressed, illegal channel possibly %d\n", __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)));
1097 } else {
1098 if (supr_status == TX_STATUS_SUPR_FRAG)
1099 WL_NONE(("%s: AMPDU frag err\n",
1100 __func__));
1101 else
1102 WL_ERROR(("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n", __func__, supr_status));
1104 /* no need to retry for badch; will fail again */
1105 if (supr_status == TX_STATUS_SUPR_BADCH ||
1106 supr_status == TX_STATUS_SUPR_EXPTIME) {
1107 retry = FALSE;
1108 WLCNTINCR(wlc->pub->_cnt->txchanrej);
1109 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1111 WLCNTINCR(wlc->pub->_cnt->txexptime);
1113 /* TX underflow : try tuning pre-loading or ampdu size */
1114 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1115 /* if there were underflows, but pre-loading is not active,
1116 notify rate adaptation.
1118 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1119 > 0) {
1120 tx_error = TRUE;
1121 #ifdef WLC_HIGH_ONLY
1122 /* With BMAC, TX Underflows should not happen */
1123 WL_ERROR(("wl%d: BMAC TX Underflow?",
1124 wlc->pub->unit));
1125 #endif
1128 } else if (txs->phyerr) {
1129 update_rate = FALSE;
1130 WLCNTINCR(wlc->pub->_cnt->txphyerr);
1131 WL_ERROR(("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n", wlc->pub->unit, txs->phyerr));
1133 #ifdef BCMDBG
1134 if (WL_ERROR_ON()) {
1135 prpkt("txpkt (AMPDU)", wlc->osh, p);
1136 wlc_print_txdesc((d11txh_t *) PKTDATA(p));
1137 wlc_print_txstatus(txs);
1139 #endif /* BCMDBG */
1143 /* loop through all pkts and retry if not acked */
1144 while (p) {
1145 tx_info = IEEE80211_SKB_CB(p);
1146 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1147 txh = (d11txh_t *) PKTDATA(p);
1148 mcl = ltoh16(txh->MacTxControlLow);
1149 plcp = (u8 *) (txh + 1);
1150 h = (struct dot11_header *)(plcp + D11_PHY_HDR_LEN);
1151 seq = ltoh16(h->seq) >> SEQNUM_SHIFT;
1153 if (tot_mpdu == 0) {
1154 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1155 mimoantsel = ltoh16(txh->ABI_MimoAntSel);
1158 index = TX_SEQ_TO_INDEX(seq);
1159 ack_recd = FALSE;
1160 if (ba_recd) {
1161 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1163 WL_AMPDU_TX(("%s: tid %d seq is %d, start_seq is %d, "
1164 "bindex is %d set %d, index %d\n",
1165 __func__, tid, seq, start_seq, bindex,
1166 isset(bitmap, bindex), index));
1168 /* if acked then clear bit and free packet */
1169 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1170 && isset(bitmap, bindex)) {
1171 ini->tx_in_transit--;
1172 ini->txretry[index] = 0;
1174 /* ampdu_ack_len: number of acked aggregated frames */
1175 /* ampdu_ack_map: block ack bit map for the aggregation */
1176 /* ampdu_len: number of aggregated frames */
1177 rate_status(wlc, tx_info, txs, mcs);
1178 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1179 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1181 /* XXX TODO: Make these accurate. */
1182 tx_info->status.ampdu_ack_len =
1183 (txs->
1184 status & TX_STATUS_FRM_RTX_MASK) >>
1185 TX_STATUS_FRM_RTX_SHIFT;
1186 tx_info->status.ampdu_len =
1187 (txs->
1188 status & TX_STATUS_FRM_RTX_MASK) >>
1189 TX_STATUS_FRM_RTX_SHIFT;
1191 PKTPULL(p, D11_PHY_HDR_LEN);
1192 PKTPULL(p, D11_TXH_LEN);
1194 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1196 ack_recd = TRUE;
1197 suc_mpdu++;
1200 /* either retransmit or send bar if ack not recd */
1201 if (!ack_recd) {
1202 struct ieee80211_tx_rate *txrate =
1203 tx_info->status.rates;
1204 if (retry && (txrate[0].count < (int)retry_limit)) {
1205 ini->txretry[index]++;
1206 ini->tx_in_transit--;
1207 /* Use high prededence for retransmit to give some punch */
1208 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1209 wlc_txq_enq(wlc, scb, p,
1210 WLC_PRIO_TO_HI_PREC(tid));
1211 } else {
1212 /* Retry timeout */
1213 ini->tx_in_transit--;
1214 ieee80211_tx_info_clear_status(tx_info);
1215 tx_info->flags |=
1216 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1217 PKTPULL(p, D11_PHY_HDR_LEN);
1218 PKTPULL(p, D11_TXH_LEN);
1219 WL_ERROR(("%s: BA Timeout, seq %d, in_transit %d\n", SHORTNAME, seq, ini->tx_in_transit));
1220 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1224 tot_mpdu++;
1226 /* break out if last packet of ampdu */
1227 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1228 TXC_AMPDU_LAST)
1229 break;
1231 p = GETNEXTTXP(wlc, queue);
1232 if (p == NULL) {
1233 ASSERT(p);
1234 break;
1237 wlc_send_q(wlc, wlc->active_queue);
1239 /* update rate state */
1240 if (WLANTSEL_ENAB(wlc))
1241 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1243 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1246 static void
1247 ampdu_cleanup_tid_ini(ampdu_info_t *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
1248 bool force)
1250 scb_ampdu_tid_ini_t *ini;
1251 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1252 if (!ini)
1253 return;
1255 WL_AMPDU_CTL(("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1256 ampdu->wlc->pub->unit, tid));
1258 if (ini->tx_in_transit && !force)
1259 return;
1261 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1262 ASSERT(ini == &scb_ampdu->ini[ini->tid]);
1264 /* free all buffered tx packets */
1265 pktq_pflush(ampdu->wlc->osh, &scb_ampdu->txq, ini->tid, TRUE, NULL, 0);
1268 /* initialize the initiator code for tid */
1269 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(ampdu_info_t *ampdu,
1270 scb_ampdu_t *scb_ampdu,
1271 u8 tid, bool override)
1273 scb_ampdu_tid_ini_t *ini;
1275 ASSERT(scb_ampdu);
1276 ASSERT(scb_ampdu->scb);
1277 ASSERT(SCB_AMPDU(scb_ampdu->scb));
1278 ASSERT(tid < AMPDU_MAX_SCB_TID);
1280 /* check for per-tid control of ampdu */
1281 if (!ampdu->ini_enable[tid]) {
1282 WL_ERROR(("%s: Rejecting tid %d\n", __func__, tid));
1283 return NULL;
1286 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1287 ini->tid = tid;
1288 ini->scb = scb_ampdu->scb;
1289 ini->magic = INI_MAGIC;
1290 WLCNTINCR(ampdu->cnt->txaddbareq);
1292 return ini;
1295 int wlc_ampdu_set(ampdu_info_t *ampdu, bool on)
1297 wlc_info_t *wlc = ampdu->wlc;
1299 wlc->pub->_ampdu = FALSE;
1301 if (on) {
1302 if (!N_ENAB(wlc->pub)) {
1303 WL_AMPDU_ERR(("wl%d: driver not nmode enabled\n",
1304 wlc->pub->unit));
1305 return BCME_UNSUPPORTED;
1307 if (!wlc_ampdu_cap(ampdu)) {
1308 WL_AMPDU_ERR(("wl%d: device not ampdu capable\n",
1309 wlc->pub->unit));
1310 return BCME_UNSUPPORTED;
1312 wlc->pub->_ampdu = on;
1315 return 0;
1318 bool wlc_ampdu_cap(ampdu_info_t *ampdu)
1320 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1321 return TRUE;
1322 else
1323 return FALSE;
1326 static void ampdu_update_max_txlen(ampdu_info_t *ampdu, u8 dur)
1328 uint32 rate, mcs;
1330 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1331 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1332 /* 20MHz, No SGI */
1333 rate = MCS_RATE(mcs, FALSE, FALSE);
1334 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1335 /* 40 MHz, No SGI */
1336 rate = MCS_RATE(mcs, TRUE, FALSE);
1337 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1338 /* 20MHz, SGI */
1339 rate = MCS_RATE(mcs, FALSE, TRUE);
1340 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1341 /* 40 MHz, SGI */
1342 rate = MCS_RATE(mcs, TRUE, TRUE);
1343 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1347 u8 BCMFASTPATH
1348 wlc_ampdu_null_delim_cnt(ampdu_info_t *ampdu, struct scb *scb,
1349 ratespec_t rspec, int phylen)
1351 scb_ampdu_t *scb_ampdu;
1352 int bytes, cnt, tmp;
1353 u8 tx_density;
1355 ASSERT(scb);
1356 ASSERT(SCB_AMPDU(scb));
1358 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1359 ASSERT(scb_ampdu);
1361 if (scb_ampdu->mpdu_density == 0)
1362 return 0;
1364 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1365 density x is in 2^(x-4) usec
1366 ==> # of bytes needed for req density = rate/2^(17-x)
1367 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1370 tx_density = scb_ampdu->mpdu_density;
1372 ASSERT(tx_density <= AMPDU_MAX_MPDU_DENSITY);
1373 tmp = 1 << (17 - tx_density);
1374 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1376 if (bytes > phylen) {
1377 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1378 ASSERT(cnt <= 255);
1379 return (u8) cnt;
1380 } else
1381 return 0;
1384 void wlc_ampdu_macaddr_upd(wlc_info_t *wlc)
1386 char template[T_RAM_ACCESS_SZ * 2];
1388 /* driver needs to write the ta in the template; ta is at offset 16 */
1389 bzero(template, sizeof(template));
1390 bcopy((char *)wlc->pub->cur_etheraddr.octet, template, ETHER_ADDR_LEN);
1391 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1392 template);
1395 bool wlc_aggregatable(wlc_info_t *wlc, u8 tid)
1397 return wlc->ampdu->ini_enable[tid];
1400 void wlc_ampdu_shm_upd(ampdu_info_t *ampdu)
1402 wlc_info_t *wlc = ampdu->wlc;
1404 /* Extend ucode internal watchdog timer to match larger received frames */
1405 if ((ampdu->rx_factor & HT_PARAMS_RX_FACTOR_MASK) ==
1406 AMPDU_RX_FACTOR_64K) {
1407 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1408 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1409 } else {
1410 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1411 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);