staging: brcm80211: removed unused inline function from wlc_ampdu.c
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / brcmsmac / wlc_ampdu.c
blobf5ca897c2dea95e2f129f35ac9e9e503634b5a4c
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 <wlc_cfg.h>
18 #include <bcmdefs.h>
19 #include <osl.h>
20 #include <bcmutils.h>
21 #include <siutils.h>
22 #include <bcmendian.h>
23 #include <wlioctl.h>
24 #include <sbhndpio.h>
25 #include <sbhnddma.h>
26 #include <hnddma.h>
27 #include <d11.h>
28 #include <wlc_rate.h>
29 #include <wlc_pub.h>
30 #include <wlc_key.h>
31 #include <wlc_event.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>
39 #include <wl_dbg.h>
42 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
43 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
44 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
45 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
46 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
47 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
48 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
49 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
50 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
51 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
52 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
53 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
54 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
56 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
57 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
58 * without underflows
60 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
61 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
62 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
63 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
64 * accumulate between resets.
67 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
69 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
70 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
71 AMPDU_DELIMITER_LEN + 3\
72 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
74 #ifdef BCMDBG
75 u32 wl_ampdu_dbg =
76 WL_AMPDU_UPDN_VAL |
77 WL_AMPDU_ERR_VAL |
78 WL_AMPDU_TX_VAL |
79 WL_AMPDU_RX_VAL |
80 WL_AMPDU_CTL_VAL |
81 WL_AMPDU_HW_VAL | WL_AMPDU_HWTXS_VAL | WL_AMPDU_HWDBG_VAL;
82 #endif
84 /* structure to hold tx fifo information and pre-loading state
85 * counters specific to tx underflows of ampdus
86 * some counters might be redundant with the ones in wlc or ampdu structures.
87 * This allows to maintain a specific state independantly of
88 * how often and/or when the wlc counters are updated.
90 typedef struct wlc_fifo_info {
91 u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
92 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
93 u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
94 u32 accum_txfunfl; /* num of underflows since we modified pld params */
95 u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
96 u32 prev_txampdu; /* previous reading of tx ampdu */
97 u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
98 } wlc_fifo_info_t;
100 /* AMPDU module specific state */
101 struct ampdu_info {
102 struct wlc_info *wlc; /* pointer to main wlc structure */
103 int scb_handle; /* scb cubby handle to retrieve data from scb */
104 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
105 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
106 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
107 u8 retry_limit; /* mpdu transmit retry limit */
108 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
109 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
110 /* per-tid mpdu transmit retry limit at regular rate */
111 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
112 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
113 s8 max_pdu; /* max pdus allowed in ampdu */
114 u8 dur; /* max duration of an ampdu (in msec) */
115 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
116 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
117 u32 ffpld_rsvd; /* number of bytes to reserve for preload */
118 u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
119 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
120 bool mfbr; /* enable multiple fallback rate */
121 u32 tx_max_funl; /* underflows should be kept such that
122 * (tx_max_funfl*underflows) < tx frames
124 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
128 #define AMPDU_CLEANUPFLAG_RX (0x1)
129 #define AMPDU_CLEANUPFLAG_TX (0x2)
131 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
132 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
134 static void wlc_ffpld_init(struct ampdu_info *ampdu);
135 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
136 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
138 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
139 scb_ampdu_t *scb_ampdu,
140 u8 tid, bool override);
141 static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu,
142 scb_ampdu_t *scb_ampdu,
143 u8 tid, bool force);
144 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
145 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
146 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
148 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
150 static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
151 struct scb *scb,
152 struct sk_buff *p, tx_status_t *txs,
153 u32 frmtxstatus, u32 frmtxstatus2);
155 struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
157 struct ampdu_info *ampdu;
158 int i;
160 /* some code depends on packed structures */
161 ASSERT(DOT11_MAXNUMFRAGS == NBITS(u16));
162 ASSERT(ISPOWEROF2(AMPDU_TX_BA_MAX_WSIZE));
163 ASSERT(ISPOWEROF2(AMPDU_RX_BA_MAX_WSIZE));
164 ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
165 ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
167 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
168 if (!ampdu) {
169 WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n",
170 wlc->pub->unit);
171 return NULL;
173 ampdu->wlc = wlc;
175 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
176 ampdu->ini_enable[i] = true;
177 /* Disable ampdu for VO by default */
178 ampdu->ini_enable[PRIO_8021D_VO] = false;
179 ampdu->ini_enable[PRIO_8021D_NC] = false;
181 /* Disable ampdu for BK by default since not enough fifo space */
182 ampdu->ini_enable[PRIO_8021D_NONE] = false;
183 ampdu->ini_enable[PRIO_8021D_BK] = false;
185 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
186 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
187 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
188 ampdu->max_pdu = AUTO;
189 ampdu->dur = AMPDU_MAX_DUR;
190 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
192 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
193 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
194 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
195 ampdu->rx_factor = AMPDU_RX_FACTOR_32K;
196 else
197 ampdu->rx_factor = AMPDU_RX_FACTOR_64K;
198 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
199 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
201 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
202 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
203 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
206 ampdu_update_max_txlen(ampdu, ampdu->dur);
207 ampdu->mfbr = false;
208 /* try to set ampdu to the default value */
209 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
211 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
212 wlc_ffpld_init(ampdu);
214 return ampdu;
217 void wlc_ampdu_detach(struct ampdu_info *ampdu)
219 int i;
221 if (!ampdu)
222 return;
224 /* free all ini's which were to be freed on callbacks which were never called */
225 for (i = 0; i < AMPDU_INI_FREE; i++) {
226 if (ampdu->ini_free[i]) {
227 kfree(ampdu->ini_free[i]);
231 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
232 kfree(ampdu);
235 void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb)
237 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
238 u8 tid;
240 WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n");
241 ASSERT(scb_ampdu);
243 for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
244 ampdu_cleanup_tid_ini(ampdu, scb_ampdu, tid, false);
248 /* reset the ampdu state machine so that it can gracefully handle packets that were
249 * freed from the dma and tx queues during reinit
251 void wlc_ampdu_reset(struct ampdu_info *ampdu)
253 WL_NONE("%s: Entering\n", __func__);
256 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
258 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
259 int i;
261 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
263 /* go back to legacy size if some preloading is occuring */
264 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
265 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
266 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
269 /* apply user override */
270 if (ampdu->max_pdu != AUTO)
271 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
273 scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
275 if (scb_ampdu->max_rxlen)
276 scb_ampdu->release =
277 min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
279 scb_ampdu->release = min(scb_ampdu->release,
280 ampdu->fifo_tb[TX_AC_BE_FIFO].
281 mcs2ampdu_table[FFPLD_MAX_MCS]);
283 ASSERT(scb_ampdu->release);
286 void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
288 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
291 static void wlc_ffpld_init(struct ampdu_info *ampdu)
293 int i, j;
294 wlc_fifo_info_t *fifo;
296 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
297 fifo = (ampdu->fifo_tb + j);
298 fifo->ampdu_pld_size = 0;
299 for (i = 0; i <= FFPLD_MAX_MCS; i++)
300 fifo->mcs2ampdu_table[i] = 255;
301 fifo->dmaxferrate = 0;
302 fifo->accum_txampdu = 0;
303 fifo->prev_txfunfl = 0;
304 fifo->accum_txfunfl = 0;
309 /* evaluate the dma transfer rate using the tx underflows as feedback.
310 * If necessary, increase tx fifo preloading. If not enough,
311 * decrease maximum ampdu size for each mcs till underflows stop
312 * Return 1 if pre-loading not active, -1 if not an underflow event,
313 * 0 if pre-loading module took care of the event.
315 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
317 struct ampdu_info *ampdu = wlc->ampdu;
318 u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
319 u32 txunfl_ratio;
320 u8 max_mpdu;
321 u32 current_ampdu_cnt = 0;
322 u16 max_pld_size;
323 u32 new_txunfl;
324 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
325 uint xmtfifo_sz;
326 u16 cur_txunfl;
328 /* return if we got here for a different reason than underflows */
329 cur_txunfl =
330 wlc_read_shm(wlc,
331 M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
332 new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
333 if (new_txunfl == 0) {
334 WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n");
335 return -1;
337 fifo->prev_txfunfl = cur_txunfl;
339 if (!ampdu->tx_max_funl)
340 return 1;
342 /* check if fifo is big enough */
343 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
344 WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n");
345 return -1;
348 if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
349 return 1;
351 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
352 fifo->accum_txfunfl += new_txunfl;
354 /* we need to wait for at least 10 underflows */
355 if (fifo->accum_txfunfl < 10)
356 return 0;
358 WL_FFPLD("ampdu_count %d tx_underflows %d\n",
359 current_ampdu_cnt, fifo->accum_txfunfl);
362 compute the current ratio of tx unfl per ampdu.
363 When the current ampdu count becomes too
364 big while the ratio remains small, we reset
365 the current count in order to not
366 introduce too big of a latency in detecting a
367 large amount of tx underflows later.
370 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
372 if (txunfl_ratio > ampdu->tx_max_funl) {
373 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
374 fifo->accum_txfunfl = 0;
376 return 0;
378 max_mpdu =
379 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
381 /* In case max value max_pdu is already lower than
382 the fifo depth, there is nothing more we can do.
385 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
386 WL_FFPLD(("tx fifo pld : max ampdu fits in fifo\n)"));
387 fifo->accum_txfunfl = 0;
388 return 0;
391 if (fifo->ampdu_pld_size < max_pld_size) {
393 /* increment by TX_FIFO_PLD_INC bytes */
394 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
395 if (fifo->ampdu_pld_size > max_pld_size)
396 fifo->ampdu_pld_size = max_pld_size;
398 /* update scb release size */
399 scb_ampdu_update_config_all(ampdu);
402 compute a new dma xfer rate for max_mpdu @ max mcs.
403 This is the minimum dma rate that
404 can acheive no unferflow condition for the current mpdu size.
406 /* note : we divide/multiply by 100 to avoid integer overflows */
407 fifo->dmaxferrate =
408 (((phy_rate / 100) *
409 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
410 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
412 WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n",
413 fifo->dmaxferrate, fifo->ampdu_pld_size);
414 } else {
416 /* decrease ampdu size */
417 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
418 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
419 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
420 AMPDU_NUM_MPDU_LEGACY - 1;
421 else
422 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
424 /* recompute the table */
425 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
427 /* update scb release size */
428 scb_ampdu_update_config_all(ampdu);
431 fifo->accum_txfunfl = 0;
432 return 0;
435 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
437 int i;
438 u32 phy_rate, dma_rate, tmp;
439 u8 max_mpdu;
440 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
442 /* recompute the dma rate */
443 /* note : we divide/multiply by 100 to avoid integer overflows */
444 max_mpdu =
445 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
446 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
447 dma_rate =
448 (((phy_rate / 100) *
449 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
450 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
451 fifo->dmaxferrate = dma_rate;
453 /* fill up the mcs2ampdu table; do not recalc the last mcs */
454 dma_rate = dma_rate >> 7;
455 for (i = 0; i < FFPLD_MAX_MCS; i++) {
456 /* shifting to keep it within integer range */
457 phy_rate = MCS_RATE(i, true, false) >> 7;
458 if (phy_rate > dma_rate) {
459 tmp = ((fifo->ampdu_pld_size * phy_rate) /
460 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
461 tmp = min_t(u32, tmp, 255);
462 fifo->mcs2ampdu_table[i] = (u8) tmp;
467 static void BCMFASTPATH
468 wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
469 uint prec)
471 scb_ampdu_t *scb_ampdu;
472 scb_ampdu_tid_ini_t *ini;
473 u8 tid = (u8) (p->priority);
475 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
477 /* initialize initiator on first packet; sends addba req */
478 ini = SCB_AMPDU_INI(scb_ampdu, tid);
479 if (ini->magic != INI_MAGIC) {
480 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
482 return;
485 int BCMFASTPATH
486 wlc_sendampdu(struct ampdu_info *ampdu, wlc_txq_info_t *qi,
487 struct sk_buff **pdu, int prec)
489 struct wlc_info *wlc;
490 struct osl_info *osh;
491 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
492 u8 tid, ndelim;
493 int err = 0;
494 u8 preamble_type = WLC_GF_PREAMBLE;
495 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
496 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
497 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
499 bool rr = true, fbr = false;
500 uint i, count = 0, fifo, seg_cnt = 0;
501 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
502 u32 ampdu_len, maxlen = 0;
503 d11txh_t *txh = NULL;
504 u8 *plcp;
505 struct ieee80211_hdr *h;
506 struct scb *scb;
507 scb_ampdu_t *scb_ampdu;
508 scb_ampdu_tid_ini_t *ini;
509 u8 mcs = 0;
510 bool use_rts = false, use_cts = false;
511 ratespec_t rspec = 0, rspec_fallback = 0;
512 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
513 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
514 struct ieee80211_rts *rts;
515 u8 rr_retry_limit;
516 wlc_fifo_info_t *f;
517 bool fbr_iscck;
518 struct ieee80211_tx_info *tx_info;
519 u16 qlen;
521 wlc = ampdu->wlc;
522 osh = wlc->osh;
523 p = *pdu;
525 ASSERT(p);
527 tid = (u8) (p->priority);
528 ASSERT(tid < AMPDU_MAX_SCB_TID);
530 f = ampdu->fifo_tb + prio2fifo[tid];
532 scb = wlc->pub->global_scb;
533 ASSERT(scb->magic == SCB_MAGIC);
535 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
536 ASSERT(scb_ampdu);
537 ini = &scb_ampdu->ini[tid];
539 /* Let pressure continue to build ... */
540 qlen = pktq_plen(&qi->q, prec);
541 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
542 return BCME_BUSY;
545 wlc_ampdu_agg(ampdu, scb, p, tid);
547 if (wlc->block_datafifo) {
548 WL_ERROR("%s: Fifo blocked\n", __func__);
549 return BCME_BUSY;
551 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
552 ampdu_len = 0;
553 dma_len = 0;
554 while (p) {
555 struct ieee80211_tx_rate *txrate;
557 tx_info = IEEE80211_SKB_CB(p);
558 txrate = tx_info->status.rates;
560 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
561 err = wlc_prep_pdu(wlc, p, &fifo);
562 } else {
563 WL_ERROR("%s: AMPDU flag is off!\n", __func__);
564 *pdu = NULL;
565 err = 0;
566 break;
569 if (err) {
570 if (err == BCME_BUSY) {
571 WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n",
572 wlc->pub->unit, seq);
573 WLCNTINCR(ampdu->cnt->sduretry);
574 *pdu = p;
575 break;
578 /* error in the packet; reject it */
579 WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n",
580 wlc->pub->unit, seq);
581 WLCNTINCR(ampdu->cnt->sdurejected);
583 *pdu = NULL;
584 break;
587 /* pkt is good to be aggregated */
588 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
589 txh = (d11txh_t *) p->data;
590 plcp = (u8 *) (txh + 1);
591 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
592 seq = ltoh16(h->seq_ctrl) >> SEQNUM_SHIFT;
593 index = TX_SEQ_TO_INDEX(seq);
595 /* check mcl fields and test whether it can be agg'd */
596 mcl = ltoh16(txh->MacTxControlLow);
597 mcl &= ~TXC_AMPDU_MASK;
598 fbr_iscck = !(ltoh16(txh->XtraFrameTypes) & 0x3);
599 ASSERT(!fbr_iscck);
600 txh->PreloadSize = 0; /* always default to 0 */
602 /* Handle retry limits */
603 if (txrate[0].count <= rr_retry_limit) {
604 txrate[0].count++;
605 rr = true;
606 fbr = false;
607 ASSERT(!fbr);
608 } else {
609 fbr = true;
610 rr = false;
611 txrate[1].count++;
614 /* extract the length info */
615 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
616 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
618 /* retrieve null delimiter count */
619 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
620 seg_cnt += 1;
622 WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
623 wlc->pub->unit, count, len);
626 * aggregateable mpdu. For ucode/hw agg,
627 * test whether need to break or change the epoch
629 if (count == 0) {
630 u16 fc;
631 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
632 /* refill the bits since might be a retx mpdu */
633 mcl |= TXC_STARTMSDU;
634 rts = (struct ieee80211_rts *)&txh->rts_frame;
635 fc = ltoh16(rts->frame_control);
636 if ((fc & FC_KIND_MASK) == FC_RTS) {
637 mcl |= TXC_SENDRTS;
638 use_rts = true;
640 if ((fc & FC_KIND_MASK) == FC_CTS) {
641 mcl |= TXC_SENDCTS;
642 use_cts = true;
644 } else {
645 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
646 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
649 len = roundup(len, 4);
650 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
652 dma_len += (u16) pkttotlen(osh, p);
654 WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
655 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
657 txh->MacTxControlLow = htol16(mcl);
659 /* this packet is added */
660 pkt[count++] = p;
662 /* patch the first MPDU */
663 if (count == 1) {
664 u8 plcp0, plcp3, is40, sgi;
665 struct ieee80211_sta *sta;
667 sta = tx_info->control.sta;
669 if (rr) {
670 plcp0 = plcp[0];
671 plcp3 = plcp[3];
672 } else {
673 plcp0 = txh->FragPLCPFallback[0];
674 plcp3 = txh->FragPLCPFallback[3];
677 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
678 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
679 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
680 ASSERT(mcs < MCS_TABLE_SIZE);
681 maxlen =
682 min(scb_ampdu->max_rxlen,
683 ampdu->max_txlen[mcs][is40][sgi]);
685 WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n",
686 sgi, is40, mcs);
688 maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
690 if (is40)
691 mimo_ctlchbw =
692 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
693 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
695 /* rebuild the rspec and rspec_fallback */
696 rspec = RSPEC_MIMORATE;
697 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
698 if (plcp[0] & MIMO_PLCP_40MHZ)
699 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
701 if (fbr_iscck) /* CCK */
702 rspec_fallback =
703 CCK_RSPEC(CCK_PHY2MAC_RATE
704 (txh->FragPLCPFallback[0]));
705 else { /* MIMO */
706 rspec_fallback = RSPEC_MIMORATE;
707 rspec_fallback |=
708 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
709 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
710 rspec_fallback |=
711 (PHY_TXC1_BW_40MHZ <<
712 RSPEC_BW_SHIFT);
715 if (use_rts || use_cts) {
716 rts_rspec =
717 wlc_rspec_to_rts_rspec(wlc, rspec, false,
718 mimo_ctlchbw);
719 rts_rspec_fallback =
720 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
721 false, mimo_ctlchbw);
725 /* if (first mpdu for host agg) */
726 /* test whether to add more */
727 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
728 (count == f->mcs2ampdu_table[mcs])) {
729 WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
730 wlc->pub->unit, count, mcs);
731 break;
734 if (count == scb_ampdu->max_pdu) {
735 WL_NONE("Stop taking from q, reached %d deep\n",
736 scb_ampdu->max_pdu);
737 break;
740 /* check to see if the next pkt is a candidate for aggregation */
741 p = pktq_ppeek(&qi->q, prec);
742 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
744 if (p) {
745 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
746 ((u8) (p->priority) == tid)) {
748 plen =
749 pkttotlen(osh, p) + AMPDU_MAX_MPDU_OVERHEAD;
750 plen = max(scb_ampdu->min_len, plen);
752 if ((plen + ampdu_len) > maxlen) {
753 p = NULL;
754 WL_ERROR("%s: Bogus plen #1\n",
755 __func__);
756 ASSERT(3 == 4);
757 continue;
760 /* check if there are enough descriptors available */
761 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
762 WL_ERROR("%s: No fifo space !!!!!!\n",
763 __func__);
764 p = NULL;
765 continue;
767 p = pktq_pdeq(&qi->q, prec);
768 ASSERT(p);
769 } else {
770 p = NULL;
773 } /* end while(p) */
775 ini->tx_in_transit += count;
777 if (count) {
778 WLCNTADD(ampdu->cnt->txmpdu, count);
780 /* patch up the last txh */
781 txh = (d11txh_t *) pkt[count - 1]->data;
782 mcl = ltoh16(txh->MacTxControlLow);
783 mcl &= ~TXC_AMPDU_MASK;
784 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
785 txh->MacTxControlLow = htol16(mcl);
787 /* remove the null delimiter after last mpdu */
788 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
789 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
790 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
792 /* remove the pad len from last mpdu */
793 fbr_iscck = ((ltoh16(txh->XtraFrameTypes) & 0x3) == 0);
794 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
795 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
796 ampdu_len -= roundup(len, 4) - len;
798 /* patch up the first txh & plcp */
799 txh = (d11txh_t *) pkt[0]->data;
800 plcp = (u8 *) (txh + 1);
802 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
803 /* mark plcp to indicate ampdu */
804 WLC_SET_MIMO_PLCP_AMPDU(plcp);
806 /* reset the mixed mode header durations */
807 if (txh->MModeLen) {
808 u16 mmodelen =
809 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
810 txh->MModeLen = htol16(mmodelen);
811 preamble_type = WLC_MM_PREAMBLE;
813 if (txh->MModeFbrLen) {
814 u16 mmfbrlen =
815 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
816 txh->MModeFbrLen = htol16(mmfbrlen);
817 fbr_preamble_type = WLC_MM_PREAMBLE;
820 /* set the preload length */
821 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
822 dma_len = min(dma_len, f->ampdu_pld_size);
823 txh->PreloadSize = htol16(dma_len);
824 } else
825 txh->PreloadSize = 0;
827 mch = ltoh16(txh->MacTxControlHigh);
829 /* update RTS dur fields */
830 if (use_rts || use_cts) {
831 u16 durid;
832 rts = (struct ieee80211_rts *)&txh->rts_frame;
833 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
834 TXC_PREAMBLE_RTS_MAIN_SHORT)
835 rts_preamble_type = WLC_SHORT_PREAMBLE;
837 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
838 TXC_PREAMBLE_RTS_FB_SHORT)
839 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
841 durid =
842 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
843 rspec, rts_preamble_type,
844 preamble_type, ampdu_len,
845 true);
846 rts->duration = htol16(durid);
847 durid = wlc_compute_rtscts_dur(wlc, use_cts,
848 rts_rspec_fallback,
849 rspec_fallback,
850 rts_fbr_preamble_type,
851 fbr_preamble_type,
852 ampdu_len, true);
853 txh->RTSDurFallback = htol16(durid);
854 /* set TxFesTimeNormal */
855 txh->TxFesTimeNormal = rts->duration;
856 /* set fallback rate version of TxFesTimeNormal */
857 txh->TxFesTimeFallback = txh->RTSDurFallback;
860 /* set flag and plcp for fallback rate */
861 if (fbr) {
862 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
863 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
864 mch |= TXC_AMPDU_FBR;
865 txh->MacTxControlHigh = htol16(mch);
866 WLC_SET_MIMO_PLCP_AMPDU(plcp);
867 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
870 WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
871 wlc->pub->unit, count, ampdu_len);
873 /* inform rate_sel if it this is a rate probe pkt */
874 frameid = ltoh16(txh->TxFrameID);
875 if (frameid & TXFID_RATE_PROBE_MASK) {
876 WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n",
877 __func__);
879 for (i = 0; i < count; i++)
880 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
881 ampdu->txpkt_weight);
884 /* endif (count) */
885 return err;
888 void BCMFASTPATH
889 wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
890 struct sk_buff *p, tx_status_t *txs)
892 scb_ampdu_t *scb_ampdu;
893 struct wlc_info *wlc = ampdu->wlc;
894 scb_ampdu_tid_ini_t *ini;
895 u32 s1 = 0, s2 = 0;
896 struct ieee80211_tx_info *tx_info;
898 tx_info = IEEE80211_SKB_CB(p);
899 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
900 ASSERT(scb);
901 ASSERT(scb->magic == SCB_MAGIC);
902 ASSERT(txs->status & TX_STATUS_AMPDU);
903 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
904 ASSERT(scb_ampdu);
905 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
906 ASSERT(ini->scb == scb);
908 /* BMAC_NOTE: For the split driver, second level txstatus comes later
909 * So if the ACK was received then wait for the second level else just
910 * call the first one
912 if (txs->status & TX_STATUS_ACK_RCV) {
913 u8 status_delay = 0;
915 /* wait till the next 8 bytes of txstatus is available */
916 while (((s1 =
917 R_REG(wlc->osh,
918 &wlc->regs->frmtxstatus)) & TXS_V) == 0) {
919 udelay(1);
920 status_delay++;
921 if (status_delay > 10) {
922 ASSERT(status_delay <= 10);
923 return;
927 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
928 ASSERT(s1 & TX_STATUS_AMPDU);
929 s2 = R_REG(wlc->osh, &wlc->regs->frmtxstatus2);
932 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
933 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
936 void
937 rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
938 tx_status_t *txs, u8 mcs)
940 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
941 int i;
943 /* clear the rest of the rates */
944 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
945 txrate[i].idx = -1;
946 txrate[i].count = 0;
950 #define SHORTNAME "AMPDU status"
952 static void BCMFASTPATH
953 wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
954 struct sk_buff *p, tx_status_t *txs,
955 u32 s1, u32 s2)
957 scb_ampdu_t *scb_ampdu;
958 struct wlc_info *wlc = ampdu->wlc;
959 scb_ampdu_tid_ini_t *ini;
960 u8 bitmap[8], queue, tid;
961 d11txh_t *txh;
962 u8 *plcp;
963 struct ieee80211_hdr *h;
964 u16 seq, start_seq = 0, bindex, index, mcl;
965 u8 mcs = 0;
966 bool ba_recd = false, ack_recd = false;
967 u8 suc_mpdu = 0, tot_mpdu = 0;
968 uint supr_status;
969 bool update_rate = true, retry = true, tx_error = false;
970 u16 mimoantsel = 0;
971 u8 antselid = 0;
972 u8 retry_limit, rr_retry_limit;
973 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
975 #ifdef BCMDBG
976 u8 hole[AMPDU_MAX_MPDU];
977 memset(hole, 0, sizeof(hole));
978 #endif
980 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
981 ASSERT(txs->status & TX_STATUS_AMPDU);
983 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
984 ASSERT(scb_ampdu);
986 tid = (u8) (p->priority);
988 ini = SCB_AMPDU_INI(scb_ampdu, tid);
989 retry_limit = ampdu->retry_limit_tid[tid];
990 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
992 ASSERT(ini->scb == scb);
994 memset(bitmap, 0, sizeof(bitmap));
995 queue = txs->frameid & TXFID_QUEUE_MASK;
996 ASSERT(queue < AC_COUNT);
998 supr_status = txs->status & TX_STATUS_SUPR_MASK;
1000 if (txs->status & TX_STATUS_ACK_RCV) {
1001 if (TX_STATUS_SUPR_UF == supr_status) {
1002 update_rate = false;
1005 ASSERT(txs->status & TX_STATUS_INTERMEDIATE);
1006 start_seq = txs->sequence >> SEQNUM_SHIFT;
1007 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
1008 TX_STATUS_BA_BMAP03_SHIFT;
1010 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
1011 ASSERT(s1 & TX_STATUS_AMPDU);
1013 bitmap[0] |=
1014 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
1015 TX_STATUS_BA_BMAP47_SHIFT;
1016 bitmap[1] = (s1 >> 8) & 0xff;
1017 bitmap[2] = (s1 >> 16) & 0xff;
1018 bitmap[3] = (s1 >> 24) & 0xff;
1020 bitmap[4] = s2 & 0xff;
1021 bitmap[5] = (s2 >> 8) & 0xff;
1022 bitmap[6] = (s2 >> 16) & 0xff;
1023 bitmap[7] = (s2 >> 24) & 0xff;
1025 ba_recd = true;
1026 } else {
1027 WLCNTINCR(ampdu->cnt->noba);
1028 if (supr_status) {
1029 update_rate = false;
1030 if (supr_status == TX_STATUS_SUPR_BADCH) {
1031 WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n",
1032 __func__,
1033 CHSPEC_CHANNEL(wlc->default_bss->chanspec));
1034 } else {
1035 if (supr_status == TX_STATUS_SUPR_FRAG)
1036 WL_NONE("%s: AMPDU frag err\n",
1037 __func__);
1038 else
1039 WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n",
1040 __func__, supr_status);
1042 /* no need to retry for badch; will fail again */
1043 if (supr_status == TX_STATUS_SUPR_BADCH ||
1044 supr_status == TX_STATUS_SUPR_EXPTIME) {
1045 retry = false;
1046 WLCNTINCR(wlc->pub->_cnt->txchanrej);
1047 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1049 WLCNTINCR(wlc->pub->_cnt->txexptime);
1051 /* TX underflow : try tuning pre-loading or ampdu size */
1052 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1053 /* if there were underflows, but pre-loading is not active,
1054 notify rate adaptation.
1056 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1057 > 0) {
1058 tx_error = true;
1061 } else if (txs->phyerr) {
1062 update_rate = false;
1063 WLCNTINCR(wlc->pub->_cnt->txphyerr);
1064 WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
1065 wlc->pub->unit, txs->phyerr);
1067 #ifdef BCMDBG
1068 if (WL_ERROR_ON()) {
1069 prpkt("txpkt (AMPDU)", wlc->osh, p);
1070 wlc_print_txdesc((d11txh_t *) p->data);
1071 wlc_print_txstatus(txs);
1073 #endif /* BCMDBG */
1077 /* loop through all pkts and retry if not acked */
1078 while (p) {
1079 tx_info = IEEE80211_SKB_CB(p);
1080 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1081 txh = (d11txh_t *) p->data;
1082 mcl = ltoh16(txh->MacTxControlLow);
1083 plcp = (u8 *) (txh + 1);
1084 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
1085 seq = ltoh16(h->seq_ctrl) >> SEQNUM_SHIFT;
1087 if (tot_mpdu == 0) {
1088 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1089 mimoantsel = ltoh16(txh->ABI_MimoAntSel);
1092 index = TX_SEQ_TO_INDEX(seq);
1093 ack_recd = false;
1094 if (ba_recd) {
1095 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1097 WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
1098 __func__, tid, seq, start_seq, bindex,
1099 isset(bitmap, bindex), index);
1101 /* if acked then clear bit and free packet */
1102 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1103 && isset(bitmap, bindex)) {
1104 ini->tx_in_transit--;
1105 ini->txretry[index] = 0;
1107 /* ampdu_ack_len: number of acked aggregated frames */
1108 /* ampdu_ack_map: block ack bit map for the aggregation */
1109 /* ampdu_len: number of aggregated frames */
1110 rate_status(wlc, tx_info, txs, mcs);
1111 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1112 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1114 /* XXX TODO: Make these accurate. */
1115 tx_info->status.ampdu_ack_len =
1116 (txs->
1117 status & TX_STATUS_FRM_RTX_MASK) >>
1118 TX_STATUS_FRM_RTX_SHIFT;
1119 tx_info->status.ampdu_len =
1120 (txs->
1121 status & TX_STATUS_FRM_RTX_MASK) >>
1122 TX_STATUS_FRM_RTX_SHIFT;
1124 skb_pull(p, D11_PHY_HDR_LEN);
1125 skb_pull(p, D11_TXH_LEN);
1127 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1129 ack_recd = true;
1130 suc_mpdu++;
1133 /* either retransmit or send bar if ack not recd */
1134 if (!ack_recd) {
1135 struct ieee80211_tx_rate *txrate =
1136 tx_info->status.rates;
1137 if (retry && (txrate[0].count < (int)retry_limit)) {
1138 ini->txretry[index]++;
1139 ini->tx_in_transit--;
1140 /* Use high prededence for retransmit to give some punch */
1141 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1142 wlc_txq_enq(wlc, scb, p,
1143 WLC_PRIO_TO_HI_PREC(tid));
1144 } else {
1145 /* Retry timeout */
1146 ini->tx_in_transit--;
1147 ieee80211_tx_info_clear_status(tx_info);
1148 tx_info->flags |=
1149 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1150 skb_pull(p, D11_PHY_HDR_LEN);
1151 skb_pull(p, D11_TXH_LEN);
1152 WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n",
1153 SHORTNAME, seq, ini->tx_in_transit);
1154 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1158 tot_mpdu++;
1160 /* break out if last packet of ampdu */
1161 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1162 TXC_AMPDU_LAST)
1163 break;
1165 p = GETNEXTTXP(wlc, queue);
1166 if (p == NULL) {
1167 ASSERT(p);
1168 break;
1171 wlc_send_q(wlc, wlc->active_queue);
1173 /* update rate state */
1174 if (WLANTSEL_ENAB(wlc))
1175 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1177 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1180 static void
1181 ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
1182 bool force)
1184 scb_ampdu_tid_ini_t *ini;
1185 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1186 if (!ini)
1187 return;
1189 WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1190 ampdu->wlc->pub->unit, tid);
1192 if (ini->tx_in_transit && !force)
1193 return;
1195 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1196 ASSERT(ini == &scb_ampdu->ini[ini->tid]);
1198 /* free all buffered tx packets */
1199 pktq_pflush(ampdu->wlc->osh, &scb_ampdu->txq, ini->tid, true, NULL, 0);
1202 /* initialize the initiator code for tid */
1203 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
1204 scb_ampdu_t *scb_ampdu,
1205 u8 tid, bool override)
1207 scb_ampdu_tid_ini_t *ini;
1209 ASSERT(scb_ampdu);
1210 ASSERT(scb_ampdu->scb);
1211 ASSERT(SCB_AMPDU(scb_ampdu->scb));
1212 ASSERT(tid < AMPDU_MAX_SCB_TID);
1214 /* check for per-tid control of ampdu */
1215 if (!ampdu->ini_enable[tid]) {
1216 WL_ERROR("%s: Rejecting tid %d\n", __func__, tid);
1217 return NULL;
1220 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1221 ini->tid = tid;
1222 ini->scb = scb_ampdu->scb;
1223 ini->magic = INI_MAGIC;
1224 WLCNTINCR(ampdu->cnt->txaddbareq);
1226 return ini;
1229 int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
1231 struct wlc_info *wlc = ampdu->wlc;
1233 wlc->pub->_ampdu = false;
1235 if (on) {
1236 if (!N_ENAB(wlc->pub)) {
1237 WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
1238 wlc->pub->unit);
1239 return BCME_UNSUPPORTED;
1241 if (!wlc_ampdu_cap(ampdu)) {
1242 WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
1243 wlc->pub->unit);
1244 return BCME_UNSUPPORTED;
1246 wlc->pub->_ampdu = on;
1249 return 0;
1252 bool wlc_ampdu_cap(struct ampdu_info *ampdu)
1254 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1255 return true;
1256 else
1257 return false;
1260 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
1262 u32 rate, mcs;
1264 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1265 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1266 /* 20MHz, No SGI */
1267 rate = MCS_RATE(mcs, false, false);
1268 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1269 /* 40 MHz, No SGI */
1270 rate = MCS_RATE(mcs, true, false);
1271 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1272 /* 20MHz, SGI */
1273 rate = MCS_RATE(mcs, false, true);
1274 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1275 /* 40 MHz, SGI */
1276 rate = MCS_RATE(mcs, true, true);
1277 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1281 u8 BCMFASTPATH
1282 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
1283 ratespec_t rspec, int phylen)
1285 scb_ampdu_t *scb_ampdu;
1286 int bytes, cnt, tmp;
1287 u8 tx_density;
1289 ASSERT(scb);
1290 ASSERT(SCB_AMPDU(scb));
1292 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1293 ASSERT(scb_ampdu);
1295 if (scb_ampdu->mpdu_density == 0)
1296 return 0;
1298 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1299 density x is in 2^(x-4) usec
1300 ==> # of bytes needed for req density = rate/2^(17-x)
1301 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1304 tx_density = scb_ampdu->mpdu_density;
1306 ASSERT(tx_density <= AMPDU_MAX_MPDU_DENSITY);
1307 tmp = 1 << (17 - tx_density);
1308 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1310 if (bytes > phylen) {
1311 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1312 ASSERT(cnt <= 255);
1313 return (u8) cnt;
1314 } else
1315 return 0;
1318 void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
1320 char template[T_RAM_ACCESS_SZ * 2];
1322 /* driver needs to write the ta in the template; ta is at offset 16 */
1323 memset(template, 0, sizeof(template));
1324 bcopy((char *)wlc->pub->cur_etheraddr, template, ETH_ALEN);
1325 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1326 template);
1329 bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
1331 return wlc->ampdu->ini_enable[tid];
1334 void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
1336 struct wlc_info *wlc = ampdu->wlc;
1338 /* Extend ucode internal watchdog timer to match larger received frames */
1339 if ((ampdu->rx_factor & HT_PARAMS_RX_FACTOR_MASK) ==
1340 AMPDU_RX_FACTOR_64K) {
1341 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1342 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1343 } else {
1344 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1345 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);