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>
27 #include "wlc_types.h"
33 #include "phy/wlc_phy_hal.h"
34 #include "wlc_antsel.h"
35 #include "wl_export.h"
37 #include "wlc_bsscfg.h"
38 #include "wlc_channel.h"
40 #include "wlc_ampdu.h"
43 * Disable AMPDU statistics counters for now
46 #define WLCNTADD(a, b)
48 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
49 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
50 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
51 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
52 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
53 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
54 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
55 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
56 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
57 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
58 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
59 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
60 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
62 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
63 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
66 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
67 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
68 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
69 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
70 * accumulate between resets.
73 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
75 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
76 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
77 AMPDU_DELIMITER_LEN + 3\
78 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
87 WL_AMPDU_HW_VAL | WL_AMPDU_HWTXS_VAL | WL_AMPDU_HWDBG_VAL;
90 /* structure to hold tx fifo information and pre-loading state
91 * counters specific to tx underflows of ampdus
92 * some counters might be redundant with the ones in wlc or ampdu structures.
93 * This allows to maintain a specific state independantly of
94 * how often and/or when the wlc counters are updated.
96 typedef struct wlc_fifo_info {
97 u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
98 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
99 u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
100 u32 accum_txfunfl; /* num of underflows since we modified pld params */
101 u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
102 u32 prev_txampdu; /* previous reading of tx ampdu */
103 u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
106 /* AMPDU module specific state */
108 struct wlc_info *wlc; /* pointer to main wlc structure */
109 int scb_handle; /* scb cubby handle to retrieve data from scb */
110 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
111 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
112 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
113 u8 retry_limit; /* mpdu transmit retry limit */
114 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
115 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
116 /* per-tid mpdu transmit retry limit at regular rate */
117 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
118 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
119 s8 max_pdu; /* max pdus allowed in ampdu */
120 u8 dur; /* max duration of an ampdu (in msec) */
121 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
122 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
123 u32 ffpld_rsvd; /* number of bytes to reserve for preload */
124 u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
125 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
126 bool mfbr; /* enable multiple fallback rate */
127 u32 tx_max_funl; /* underflows should be kept such that
128 * (tx_max_funfl*underflows) < tx frames
130 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
134 #define AMPDU_CLEANUPFLAG_RX (0x1)
135 #define AMPDU_CLEANUPFLAG_TX (0x2)
137 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
138 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
140 static void wlc_ffpld_init(struct ampdu_info *ampdu);
141 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
142 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
144 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
145 scb_ampdu_t *scb_ampdu,
146 u8 tid, bool override);
147 static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu,
148 scb_ampdu_t *scb_ampdu,
150 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
151 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
152 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
154 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
156 static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
158 struct sk_buff *p, tx_status_t *txs,
159 u32 frmtxstatus, u32 frmtxstatus2);
160 static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
161 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
163 struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
165 struct ampdu_info *ampdu;
168 /* some code depends on packed structures */
169 ASSERT(DOT11_MAXNUMFRAGS == NBITS(u16));
170 ASSERT(ISPOWEROF2(AMPDU_TX_BA_MAX_WSIZE));
171 ASSERT(ISPOWEROF2(AMPDU_RX_BA_MAX_WSIZE));
172 ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
173 ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
175 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
177 WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n",
183 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
184 ampdu->ini_enable[i] = true;
185 /* Disable ampdu for VO by default */
186 ampdu->ini_enable[PRIO_8021D_VO] = false;
187 ampdu->ini_enable[PRIO_8021D_NC] = false;
189 /* Disable ampdu for BK by default since not enough fifo space */
190 ampdu->ini_enable[PRIO_8021D_NONE] = false;
191 ampdu->ini_enable[PRIO_8021D_BK] = false;
193 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
194 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
195 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
196 ampdu->max_pdu = AUTO;
197 ampdu->dur = AMPDU_MAX_DUR;
198 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
200 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
201 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
202 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
203 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
205 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
206 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
207 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
209 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
210 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
211 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
214 ampdu_update_max_txlen(ampdu, ampdu->dur);
216 /* try to set ampdu to the default value */
217 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
219 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
220 wlc_ffpld_init(ampdu);
225 void wlc_ampdu_detach(struct ampdu_info *ampdu)
232 /* free all ini's which were to be freed on callbacks which were never called */
233 for (i = 0; i < AMPDU_INI_FREE; i++) {
234 kfree(ampdu->ini_free[i]);
237 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
241 void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb)
243 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
246 WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n");
249 for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
250 ampdu_cleanup_tid_ini(ampdu, scb_ampdu, tid, false);
254 /* reset the ampdu state machine so that it can gracefully handle packets that were
255 * freed from the dma and tx queues during reinit
257 void wlc_ampdu_reset(struct ampdu_info *ampdu)
259 WL_NONE("%s: Entering\n", __func__);
262 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
264 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
267 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
269 /* go back to legacy size if some preloading is occuring */
270 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
271 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
272 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
275 /* apply user override */
276 if (ampdu->max_pdu != AUTO)
277 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
279 scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
281 if (scb_ampdu->max_rxlen)
283 min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
285 scb_ampdu->release = min(scb_ampdu->release,
286 ampdu->fifo_tb[TX_AC_BE_FIFO].
287 mcs2ampdu_table[FFPLD_MAX_MCS]);
289 ASSERT(scb_ampdu->release);
292 void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
294 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
297 static void wlc_ffpld_init(struct ampdu_info *ampdu)
300 wlc_fifo_info_t *fifo;
302 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
303 fifo = (ampdu->fifo_tb + j);
304 fifo->ampdu_pld_size = 0;
305 for (i = 0; i <= FFPLD_MAX_MCS; i++)
306 fifo->mcs2ampdu_table[i] = 255;
307 fifo->dmaxferrate = 0;
308 fifo->accum_txampdu = 0;
309 fifo->prev_txfunfl = 0;
310 fifo->accum_txfunfl = 0;
315 /* evaluate the dma transfer rate using the tx underflows as feedback.
316 * If necessary, increase tx fifo preloading. If not enough,
317 * decrease maximum ampdu size for each mcs till underflows stop
318 * Return 1 if pre-loading not active, -1 if not an underflow event,
319 * 0 if pre-loading module took care of the event.
321 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
323 struct ampdu_info *ampdu = wlc->ampdu;
324 u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
327 u32 current_ampdu_cnt = 0;
330 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
334 /* return if we got here for a different reason than underflows */
337 M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
338 new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
339 if (new_txunfl == 0) {
340 WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n");
343 fifo->prev_txfunfl = cur_txunfl;
345 if (!ampdu->tx_max_funl)
348 /* check if fifo is big enough */
349 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
350 WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n");
354 if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
357 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
358 fifo->accum_txfunfl += new_txunfl;
360 /* we need to wait for at least 10 underflows */
361 if (fifo->accum_txfunfl < 10)
364 WL_FFPLD("ampdu_count %d tx_underflows %d\n",
365 current_ampdu_cnt, fifo->accum_txfunfl);
368 compute the current ratio of tx unfl per ampdu.
369 When the current ampdu count becomes too
370 big while the ratio remains small, we reset
371 the current count in order to not
372 introduce too big of a latency in detecting a
373 large amount of tx underflows later.
376 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
378 if (txunfl_ratio > ampdu->tx_max_funl) {
379 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
380 fifo->accum_txfunfl = 0;
385 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
387 /* In case max value max_pdu is already lower than
388 the fifo depth, there is nothing more we can do.
391 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
392 WL_FFPLD(("tx fifo pld : max ampdu fits in fifo\n)"));
393 fifo->accum_txfunfl = 0;
397 if (fifo->ampdu_pld_size < max_pld_size) {
399 /* increment by TX_FIFO_PLD_INC bytes */
400 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
401 if (fifo->ampdu_pld_size > max_pld_size)
402 fifo->ampdu_pld_size = max_pld_size;
404 /* update scb release size */
405 scb_ampdu_update_config_all(ampdu);
408 compute a new dma xfer rate for max_mpdu @ max mcs.
409 This is the minimum dma rate that
410 can acheive no unferflow condition for the current mpdu size.
412 /* note : we divide/multiply by 100 to avoid integer overflows */
415 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
416 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
418 WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n",
419 fifo->dmaxferrate, fifo->ampdu_pld_size);
422 /* decrease ampdu size */
423 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
424 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
425 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
426 AMPDU_NUM_MPDU_LEGACY - 1;
428 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
430 /* recompute the table */
431 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
433 /* update scb release size */
434 scb_ampdu_update_config_all(ampdu);
437 fifo->accum_txfunfl = 0;
441 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
444 u32 phy_rate, dma_rate, tmp;
446 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
448 /* recompute the dma rate */
449 /* note : we divide/multiply by 100 to avoid integer overflows */
451 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
452 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
455 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
456 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
457 fifo->dmaxferrate = dma_rate;
459 /* fill up the mcs2ampdu table; do not recalc the last mcs */
460 dma_rate = dma_rate >> 7;
461 for (i = 0; i < FFPLD_MAX_MCS; i++) {
462 /* shifting to keep it within integer range */
463 phy_rate = MCS_RATE(i, true, false) >> 7;
464 if (phy_rate > dma_rate) {
465 tmp = ((fifo->ampdu_pld_size * phy_rate) /
466 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
467 tmp = min_t(u32, tmp, 255);
468 fifo->mcs2ampdu_table[i] = (u8) tmp;
473 static void BCMFASTPATH
474 wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
477 scb_ampdu_t *scb_ampdu;
478 scb_ampdu_tid_ini_t *ini;
479 u8 tid = (u8) (p->priority);
481 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
483 /* initialize initiator on first packet; sends addba req */
484 ini = SCB_AMPDU_INI(scb_ampdu, tid);
485 if (ini->magic != INI_MAGIC) {
486 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
492 wlc_sendampdu(struct ampdu_info *ampdu, struct wlc_txq_info *qi,
493 struct sk_buff **pdu, int prec)
495 struct wlc_info *wlc;
496 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
499 u8 preamble_type = WLC_GF_PREAMBLE;
500 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
501 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
502 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
504 bool rr = true, fbr = false;
505 uint i, count = 0, fifo, seg_cnt = 0;
506 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
507 u32 ampdu_len, maxlen = 0;
508 d11txh_t *txh = NULL;
510 struct ieee80211_hdr *h;
512 scb_ampdu_t *scb_ampdu;
513 scb_ampdu_tid_ini_t *ini;
515 bool use_rts = false, use_cts = false;
516 ratespec_t rspec = 0, rspec_fallback = 0;
517 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
518 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
519 struct ieee80211_rts *rts;
523 struct ieee80211_tx_info *tx_info;
531 tid = (u8) (p->priority);
532 ASSERT(tid < AMPDU_MAX_SCB_TID);
534 f = ampdu->fifo_tb + prio2fifo[tid];
536 scb = wlc->pub->global_scb;
537 ASSERT(scb->magic == SCB_MAGIC);
539 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
541 ini = &scb_ampdu->ini[tid];
543 /* Let pressure continue to build ... */
544 qlen = pktq_plen(&qi->q, prec);
545 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
549 wlc_ampdu_agg(ampdu, scb, p, tid);
551 if (wlc->block_datafifo) {
552 WL_ERROR("%s: Fifo blocked\n", __func__);
555 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
559 struct ieee80211_tx_rate *txrate;
561 tx_info = IEEE80211_SKB_CB(p);
562 txrate = tx_info->status.rates;
564 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
565 err = wlc_prep_pdu(wlc, p, &fifo);
567 WL_ERROR("%s: AMPDU flag is off!\n", __func__);
574 if (err == BCME_BUSY) {
575 WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n",
576 wlc->pub->unit, seq);
577 WLCNTINCR(ampdu->cnt->sduretry);
582 /* error in the packet; reject it */
583 WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n",
584 wlc->pub->unit, seq);
585 WLCNTINCR(ampdu->cnt->sdurejected);
591 /* pkt is good to be aggregated */
592 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
593 txh = (d11txh_t *) p->data;
594 plcp = (u8 *) (txh + 1);
595 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
596 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
597 index = TX_SEQ_TO_INDEX(seq);
599 /* check mcl fields and test whether it can be agg'd */
600 mcl = le16_to_cpu(txh->MacTxControlLow);
601 mcl &= ~TXC_AMPDU_MASK;
602 fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
604 txh->PreloadSize = 0; /* always default to 0 */
606 /* Handle retry limits */
607 if (txrate[0].count <= rr_retry_limit) {
618 /* extract the length info */
619 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
620 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
622 /* retrieve null delimiter count */
623 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
626 WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
627 wlc->pub->unit, count, len);
630 * aggregateable mpdu. For ucode/hw agg,
631 * test whether need to break or change the epoch
634 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
635 /* refill the bits since might be a retx mpdu */
636 mcl |= TXC_STARTMSDU;
637 rts = (struct ieee80211_rts *)&txh->rts_frame;
639 if (ieee80211_is_rts(rts->frame_control)) {
643 if (ieee80211_is_cts(rts->frame_control)) {
648 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
649 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
652 len = roundup(len, 4);
653 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
655 dma_len += (u16) pkttotlen(p);
657 WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
658 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
660 txh->MacTxControlLow = cpu_to_le16(mcl);
662 /* this packet is added */
665 /* patch the first MPDU */
667 u8 plcp0, plcp3, is40, sgi;
668 struct ieee80211_sta *sta;
670 sta = tx_info->control.sta;
676 plcp0 = txh->FragPLCPFallback[0];
677 plcp3 = txh->FragPLCPFallback[3];
680 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
681 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
682 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
683 ASSERT(mcs < MCS_TABLE_SIZE);
685 min(scb_ampdu->max_rxlen,
686 ampdu->max_txlen[mcs][is40][sgi]);
688 WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n",
691 maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
695 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
696 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
698 /* rebuild the rspec and rspec_fallback */
699 rspec = RSPEC_MIMORATE;
700 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
701 if (plcp[0] & MIMO_PLCP_40MHZ)
702 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
704 if (fbr_iscck) /* CCK */
706 CCK_RSPEC(CCK_PHY2MAC_RATE
707 (txh->FragPLCPFallback[0]));
709 rspec_fallback = RSPEC_MIMORATE;
711 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
712 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
714 (PHY_TXC1_BW_40MHZ <<
718 if (use_rts || use_cts) {
720 wlc_rspec_to_rts_rspec(wlc, rspec, false,
723 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
724 false, mimo_ctlchbw);
728 /* if (first mpdu for host agg) */
729 /* test whether to add more */
730 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
731 (count == f->mcs2ampdu_table[mcs])) {
732 WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
733 wlc->pub->unit, count, mcs);
737 if (count == scb_ampdu->max_pdu) {
738 WL_NONE("Stop taking from q, reached %d deep\n",
743 /* check to see if the next pkt is a candidate for aggregation */
744 p = pktq_ppeek(&qi->q, prec);
745 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
748 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
749 ((u8) (p->priority) == tid)) {
752 pkttotlen(p) + AMPDU_MAX_MPDU_OVERHEAD;
753 plen = max(scb_ampdu->min_len, plen);
755 if ((plen + ampdu_len) > maxlen) {
757 WL_ERROR("%s: Bogus plen #1\n",
763 /* check if there are enough descriptors available */
764 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
765 WL_ERROR("%s: No fifo space !!!!!!\n",
770 p = pktq_pdeq(&qi->q, prec);
778 ini->tx_in_transit += count;
781 WLCNTADD(ampdu->cnt->txmpdu, count);
783 /* patch up the last txh */
784 txh = (d11txh_t *) pkt[count - 1]->data;
785 mcl = le16_to_cpu(txh->MacTxControlLow);
786 mcl &= ~TXC_AMPDU_MASK;
787 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
788 txh->MacTxControlLow = cpu_to_le16(mcl);
790 /* remove the null delimiter after last mpdu */
791 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
792 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
793 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
795 /* remove the pad len from last mpdu */
796 fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
797 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
798 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
799 ampdu_len -= roundup(len, 4) - len;
801 /* patch up the first txh & plcp */
802 txh = (d11txh_t *) pkt[0]->data;
803 plcp = (u8 *) (txh + 1);
805 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
806 /* mark plcp to indicate ampdu */
807 WLC_SET_MIMO_PLCP_AMPDU(plcp);
809 /* reset the mixed mode header durations */
812 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
813 txh->MModeLen = cpu_to_le16(mmodelen);
814 preamble_type = WLC_MM_PREAMBLE;
816 if (txh->MModeFbrLen) {
818 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
819 txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
820 fbr_preamble_type = WLC_MM_PREAMBLE;
823 /* set the preload length */
824 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
825 dma_len = min(dma_len, f->ampdu_pld_size);
826 txh->PreloadSize = cpu_to_le16(dma_len);
828 txh->PreloadSize = 0;
830 mch = le16_to_cpu(txh->MacTxControlHigh);
832 /* update RTS dur fields */
833 if (use_rts || use_cts) {
835 rts = (struct ieee80211_rts *)&txh->rts_frame;
836 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
837 TXC_PREAMBLE_RTS_MAIN_SHORT)
838 rts_preamble_type = WLC_SHORT_PREAMBLE;
840 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
841 TXC_PREAMBLE_RTS_FB_SHORT)
842 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
845 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
846 rspec, rts_preamble_type,
847 preamble_type, ampdu_len,
849 rts->duration = cpu_to_le16(durid);
850 durid = wlc_compute_rtscts_dur(wlc, use_cts,
853 rts_fbr_preamble_type,
856 txh->RTSDurFallback = cpu_to_le16(durid);
857 /* set TxFesTimeNormal */
858 txh->TxFesTimeNormal = rts->duration;
859 /* set fallback rate version of TxFesTimeNormal */
860 txh->TxFesTimeFallback = txh->RTSDurFallback;
863 /* set flag and plcp for fallback rate */
865 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
866 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
867 mch |= TXC_AMPDU_FBR;
868 txh->MacTxControlHigh = cpu_to_le16(mch);
869 WLC_SET_MIMO_PLCP_AMPDU(plcp);
870 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
873 WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
874 wlc->pub->unit, count, ampdu_len);
876 /* inform rate_sel if it this is a rate probe pkt */
877 frameid = le16_to_cpu(txh->TxFrameID);
878 if (frameid & TXFID_RATE_PROBE_MASK) {
879 WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n",
882 for (i = 0; i < count; i++)
883 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
884 ampdu->txpkt_weight);
892 wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
893 struct sk_buff *p, tx_status_t *txs)
895 scb_ampdu_t *scb_ampdu;
896 struct wlc_info *wlc = ampdu->wlc;
897 scb_ampdu_tid_ini_t *ini;
899 struct ieee80211_tx_info *tx_info;
901 tx_info = IEEE80211_SKB_CB(p);
902 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
903 ASSERT(txs->status & TX_STATUS_AMPDU);
905 /* BMAC_NOTE: For the split driver, second level txstatus comes later
906 * So if the ACK was received then wait for the second level else just
909 if (txs->status & TX_STATUS_ACK_RCV) {
912 /* wait till the next 8 bytes of txstatus is available */
913 while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
916 if (status_delay > 10) {
917 ASSERT(status_delay <= 10);
922 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
923 ASSERT(s1 & TX_STATUS_AMPDU);
924 s2 = R_REG(&wlc->regs->frmtxstatus2);
928 ASSERT(scb->magic == SCB_MAGIC);
929 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
931 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
932 ASSERT(ini->scb == scb);
933 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
935 /* loop through all pkts and free */
936 u8 queue = txs->frameid & TXFID_QUEUE_MASK;
940 tx_info = IEEE80211_SKB_CB(p);
941 txh = (d11txh_t *) p->data;
942 mcl = le16_to_cpu(txh->MacTxControlLow);
943 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
945 /* break out if last packet of ampdu */
946 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
949 p = GETNEXTTXP(wlc, queue);
952 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
954 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
958 rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
959 tx_status_t *txs, u8 mcs)
961 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
964 /* clear the rest of the rates */
965 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
971 #define SHORTNAME "AMPDU status"
973 static void BCMFASTPATH
974 wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
975 struct sk_buff *p, tx_status_t *txs,
978 scb_ampdu_t *scb_ampdu;
979 struct wlc_info *wlc = ampdu->wlc;
980 scb_ampdu_tid_ini_t *ini;
981 u8 bitmap[8], queue, tid;
984 struct ieee80211_hdr *h;
985 u16 seq, start_seq = 0, bindex, index, mcl;
987 bool ba_recd = false, ack_recd = false;
988 u8 suc_mpdu = 0, tot_mpdu = 0;
990 bool update_rate = true, retry = true, tx_error = false;
993 u8 retry_limit, rr_retry_limit;
994 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
997 u8 hole[AMPDU_MAX_MPDU];
998 memset(hole, 0, sizeof(hole));
1001 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1002 ASSERT(txs->status & TX_STATUS_AMPDU);
1004 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1007 tid = (u8) (p->priority);
1009 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1010 retry_limit = ampdu->retry_limit_tid[tid];
1011 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
1013 ASSERT(ini->scb == scb);
1015 memset(bitmap, 0, sizeof(bitmap));
1016 queue = txs->frameid & TXFID_QUEUE_MASK;
1017 ASSERT(queue < AC_COUNT);
1019 supr_status = txs->status & TX_STATUS_SUPR_MASK;
1021 if (txs->status & TX_STATUS_ACK_RCV) {
1022 if (TX_STATUS_SUPR_UF == supr_status) {
1023 update_rate = false;
1026 ASSERT(txs->status & TX_STATUS_INTERMEDIATE);
1027 start_seq = txs->sequence >> SEQNUM_SHIFT;
1028 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
1029 TX_STATUS_BA_BMAP03_SHIFT;
1031 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
1032 ASSERT(s1 & TX_STATUS_AMPDU);
1035 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
1036 TX_STATUS_BA_BMAP47_SHIFT;
1037 bitmap[1] = (s1 >> 8) & 0xff;
1038 bitmap[2] = (s1 >> 16) & 0xff;
1039 bitmap[3] = (s1 >> 24) & 0xff;
1041 bitmap[4] = s2 & 0xff;
1042 bitmap[5] = (s2 >> 8) & 0xff;
1043 bitmap[6] = (s2 >> 16) & 0xff;
1044 bitmap[7] = (s2 >> 24) & 0xff;
1048 WLCNTINCR(ampdu->cnt->noba);
1050 update_rate = false;
1051 if (supr_status == TX_STATUS_SUPR_BADCH) {
1052 WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n",
1054 CHSPEC_CHANNEL(wlc->default_bss->chanspec));
1056 if (supr_status == TX_STATUS_SUPR_FRAG)
1057 WL_NONE("%s: AMPDU frag err\n",
1060 WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n",
1061 __func__, supr_status);
1063 /* no need to retry for badch; will fail again */
1064 if (supr_status == TX_STATUS_SUPR_BADCH ||
1065 supr_status == TX_STATUS_SUPR_EXPTIME) {
1067 wlc->pub->_cnt->txchanrej++;
1068 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1070 wlc->pub->_cnt->txexptime++;
1072 /* TX underflow : try tuning pre-loading or ampdu size */
1073 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1074 /* if there were underflows, but pre-loading is not active,
1075 notify rate adaptation.
1077 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1082 } else if (txs->phyerr) {
1083 update_rate = false;
1084 wlc->pub->_cnt->txphyerr++;
1085 WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
1086 wlc->pub->unit, txs->phyerr);
1088 if (WL_ERROR_ON()) {
1089 prpkt("txpkt (AMPDU)", p);
1090 wlc_print_txdesc((d11txh_t *) p->data);
1092 wlc_print_txstatus(txs);
1096 /* loop through all pkts and retry if not acked */
1098 tx_info = IEEE80211_SKB_CB(p);
1099 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1100 txh = (d11txh_t *) p->data;
1101 mcl = le16_to_cpu(txh->MacTxControlLow);
1102 plcp = (u8 *) (txh + 1);
1103 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
1104 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
1106 if (tot_mpdu == 0) {
1107 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1108 mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
1111 index = TX_SEQ_TO_INDEX(seq);
1114 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1116 WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
1117 __func__, tid, seq, start_seq, bindex,
1118 isset(bitmap, bindex), index);
1120 /* if acked then clear bit and free packet */
1121 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1122 && isset(bitmap, bindex)) {
1123 ini->tx_in_transit--;
1124 ini->txretry[index] = 0;
1126 /* ampdu_ack_len: number of acked aggregated frames */
1127 /* ampdu_ack_map: block ack bit map for the aggregation */
1128 /* ampdu_len: number of aggregated frames */
1129 rate_status(wlc, tx_info, txs, mcs);
1130 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1131 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1133 /* XXX TODO: Make these accurate. */
1134 tx_info->status.ampdu_ack_len =
1136 status & TX_STATUS_FRM_RTX_MASK) >>
1137 TX_STATUS_FRM_RTX_SHIFT;
1138 tx_info->status.ampdu_len =
1140 status & TX_STATUS_FRM_RTX_MASK) >>
1141 TX_STATUS_FRM_RTX_SHIFT;
1143 skb_pull(p, D11_PHY_HDR_LEN);
1144 skb_pull(p, D11_TXH_LEN);
1146 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1152 /* either retransmit or send bar if ack not recd */
1154 struct ieee80211_tx_rate *txrate =
1155 tx_info->status.rates;
1156 if (retry && (txrate[0].count < (int)retry_limit)) {
1157 ini->txretry[index]++;
1158 ini->tx_in_transit--;
1159 /* Use high prededence for retransmit to give some punch */
1160 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1161 wlc_txq_enq(wlc, scb, p,
1162 WLC_PRIO_TO_HI_PREC(tid));
1165 ini->tx_in_transit--;
1166 ieee80211_tx_info_clear_status(tx_info);
1168 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1169 skb_pull(p, D11_PHY_HDR_LEN);
1170 skb_pull(p, D11_TXH_LEN);
1171 WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n",
1172 SHORTNAME, seq, ini->tx_in_transit);
1173 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1179 /* break out if last packet of ampdu */
1180 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1184 p = GETNEXTTXP(wlc, queue);
1190 wlc_send_q(wlc, wlc->active_queue);
1192 /* update rate state */
1193 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1195 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1199 ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
1202 scb_ampdu_tid_ini_t *ini;
1203 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1207 WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1208 ampdu->wlc->pub->unit, tid);
1210 if (ini->tx_in_transit && !force)
1213 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1214 ASSERT(ini == &scb_ampdu->ini[ini->tid]);
1216 /* free all buffered tx packets */
1217 pktq_pflush(&scb_ampdu->txq, ini->tid, true, NULL, 0);
1220 /* initialize the initiator code for tid */
1221 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
1222 scb_ampdu_t *scb_ampdu,
1223 u8 tid, bool override)
1225 scb_ampdu_tid_ini_t *ini;
1228 ASSERT(scb_ampdu->scb);
1229 ASSERT(SCB_AMPDU(scb_ampdu->scb));
1230 ASSERT(tid < AMPDU_MAX_SCB_TID);
1232 /* check for per-tid control of ampdu */
1233 if (!ampdu->ini_enable[tid]) {
1234 WL_ERROR("%s: Rejecting tid %d\n", __func__, tid);
1238 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1240 ini->scb = scb_ampdu->scb;
1241 ini->magic = INI_MAGIC;
1242 WLCNTINCR(ampdu->cnt->txaddbareq);
1247 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
1249 struct wlc_info *wlc = ampdu->wlc;
1251 wlc->pub->_ampdu = false;
1254 if (!N_ENAB(wlc->pub)) {
1255 WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
1257 return BCME_UNSUPPORTED;
1259 if (!wlc_ampdu_cap(ampdu)) {
1260 WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
1262 return BCME_UNSUPPORTED;
1264 wlc->pub->_ampdu = on;
1270 static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
1272 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1278 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
1282 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1283 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1285 rate = MCS_RATE(mcs, false, false);
1286 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1287 /* 40 MHz, No SGI */
1288 rate = MCS_RATE(mcs, true, false);
1289 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1291 rate = MCS_RATE(mcs, false, true);
1292 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1294 rate = MCS_RATE(mcs, true, true);
1295 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1300 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
1301 ratespec_t rspec, int phylen)
1303 scb_ampdu_t *scb_ampdu;
1304 int bytes, cnt, tmp;
1308 ASSERT(SCB_AMPDU(scb));
1310 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1313 if (scb_ampdu->mpdu_density == 0)
1316 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1317 density x is in 2^(x-4) usec
1318 ==> # of bytes needed for req density = rate/2^(17-x)
1319 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1322 tx_density = scb_ampdu->mpdu_density;
1324 ASSERT(tx_density <= AMPDU_MAX_MPDU_DENSITY);
1325 tmp = 1 << (17 - tx_density);
1326 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1328 if (bytes > phylen) {
1329 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1336 void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
1338 char template[T_RAM_ACCESS_SZ * 2];
1340 /* driver needs to write the ta in the template; ta is at offset 16 */
1341 memset(template, 0, sizeof(template));
1342 memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
1343 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1347 bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
1349 return wlc->ampdu->ini_enable[tid];
1352 void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
1354 struct wlc_info *wlc = ampdu->wlc;
1356 /* Extend ucode internal watchdog timer to match larger received frames */
1357 if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
1358 IEEE80211_HT_MAX_AMPDU_64K) {
1359 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1360 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1362 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1363 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
1367 struct cb_del_ampdu_pars {
1368 struct ieee80211_sta *sta;
1373 * callback function that helps flushing ampdu packets from a priority queue
1375 static bool cb_del_ampdu_pkt(void *p, int arg_a)
1377 struct sk_buff *mpdu = (struct sk_buff *)p;
1378 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
1379 struct cb_del_ampdu_pars *ampdu_pars =
1380 (struct cb_del_ampdu_pars *)arg_a;
1383 rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
1384 rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
1385 tx_info->control.sta == ampdu_pars->sta);
1386 rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
1391 * callback function that helps invalidating ampdu packets in a DMA queue
1393 static void dma_cb_fn_ampdu(void *txi, void *arg_a)
1395 struct ieee80211_sta *sta = arg_a;
1396 struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
1398 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
1399 (tx_info->control.sta == sta || sta == NULL))
1400 tx_info->control.sta = NULL;
1404 * When a remote party is no longer available for ampdu communication, any
1405 * pending tx ampdu packets in the driver have to be flushed.
1407 void wlc_ampdu_flush(struct wlc_info *wlc,
1408 struct ieee80211_sta *sta, u16 tid)
1410 struct wlc_txq_info *qi = wlc->active_queue;
1411 struct pktq *pq = &qi->q;
1413 struct cb_del_ampdu_pars ampdu_pars;
1415 ampdu_pars.sta = sta;
1416 ampdu_pars.tid = tid;
1417 for (prec = 0; prec < pq->num_prec; prec++) {
1418 pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
1421 wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);