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 <net/mac80211.h>
20 #include "phy/phy_hal.h"
25 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
26 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
27 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
28 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
29 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
30 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
31 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
32 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
33 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
34 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
35 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
36 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
37 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
39 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
40 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
43 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
44 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
45 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
46 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
47 * accumulate between resets.
50 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
52 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
53 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
54 AMPDU_DELIMITER_LEN + 3\
55 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
57 /* structure to hold tx fifo information and pre-loading state
58 * counters specific to tx underflows of ampdus
59 * some counters might be redundant with the ones in wlc or ampdu structures.
60 * This allows to maintain a specific state independently of
61 * how often and/or when the wlc counters are updated.
63 typedef struct wlc_fifo_info {
64 u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
65 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
66 u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
67 u32 accum_txfunfl; /* num of underflows since we modified pld params */
68 u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
69 u32 prev_txampdu; /* previous reading of tx ampdu */
70 u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
73 /* AMPDU module specific state */
75 struct wlc_info *wlc; /* pointer to main wlc structure */
76 int scb_handle; /* scb cubby handle to retrieve data from scb */
77 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
78 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
79 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
80 u8 retry_limit; /* mpdu transmit retry limit */
81 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
82 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
83 /* per-tid mpdu transmit retry limit at regular rate */
84 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
85 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
86 s8 max_pdu; /* max pdus allowed in ampdu */
87 u8 dur; /* max duration of an ampdu (in msec) */
88 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
89 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
90 u32 ffpld_rsvd; /* number of bytes to reserve for preload */
91 u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
92 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
93 bool mfbr; /* enable multiple fallback rate */
94 u32 tx_max_funl; /* underflows should be kept such that
95 * (tx_max_funfl*underflows) < tx frames
97 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
101 /* used for flushing ampdu packets */
102 struct cb_del_ampdu_pars {
103 struct ieee80211_sta *sta;
107 #define AMPDU_CLEANUPFLAG_RX (0x1)
108 #define AMPDU_CLEANUPFLAG_TX (0x2)
110 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
111 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
113 static void wlc_ffpld_init(struct ampdu_info *ampdu);
114 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
115 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
117 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
118 scb_ampdu_t *scb_ampdu,
119 u8 tid, bool override);
120 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
121 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
122 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
124 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
126 static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
128 struct sk_buff *p, tx_status_t *txs,
129 u32 frmtxstatus, u32 frmtxstatus2);
130 static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
131 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
133 struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
135 struct ampdu_info *ampdu;
138 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
140 wiphy_err(wlc->wiphy, "wl%d: wlc_ampdu_attach: out of mem\n",
146 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
147 ampdu->ini_enable[i] = true;
148 /* Disable ampdu for VO by default */
149 ampdu->ini_enable[PRIO_8021D_VO] = false;
150 ampdu->ini_enable[PRIO_8021D_NC] = false;
152 /* Disable ampdu for BK by default since not enough fifo space */
153 ampdu->ini_enable[PRIO_8021D_NONE] = false;
154 ampdu->ini_enable[PRIO_8021D_BK] = false;
156 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
157 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
158 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
159 ampdu->max_pdu = AUTO;
160 ampdu->dur = AMPDU_MAX_DUR;
161 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
163 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
164 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
165 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
166 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
168 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
169 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
170 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
172 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
173 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
174 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
177 ampdu_update_max_txlen(ampdu, ampdu->dur);
179 /* try to set ampdu to the default value */
180 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
182 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
183 wlc_ffpld_init(ampdu);
188 void wlc_ampdu_detach(struct ampdu_info *ampdu)
195 /* free all ini's which were to be freed on callbacks which were never called */
196 for (i = 0; i < AMPDU_INI_FREE; i++) {
197 kfree(ampdu->ini_free[i]);
200 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
204 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
206 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
209 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
211 /* go back to legacy size if some preloading is occurring */
212 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
213 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
214 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
217 /* apply user override */
218 if (ampdu->max_pdu != AUTO)
219 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
221 scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
223 if (scb_ampdu->max_rxlen)
225 min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
227 scb_ampdu->release = min(scb_ampdu->release,
228 ampdu->fifo_tb[TX_AC_BE_FIFO].
229 mcs2ampdu_table[FFPLD_MAX_MCS]);
232 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
234 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
237 static void wlc_ffpld_init(struct ampdu_info *ampdu)
240 wlc_fifo_info_t *fifo;
242 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
243 fifo = (ampdu->fifo_tb + j);
244 fifo->ampdu_pld_size = 0;
245 for (i = 0; i <= FFPLD_MAX_MCS; i++)
246 fifo->mcs2ampdu_table[i] = 255;
247 fifo->dmaxferrate = 0;
248 fifo->accum_txampdu = 0;
249 fifo->prev_txfunfl = 0;
250 fifo->accum_txfunfl = 0;
255 /* evaluate the dma transfer rate using the tx underflows as feedback.
256 * If necessary, increase tx fifo preloading. If not enough,
257 * decrease maximum ampdu size for each mcs till underflows stop
258 * Return 1 if pre-loading not active, -1 if not an underflow event,
259 * 0 if pre-loading module took care of the event.
261 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
263 struct ampdu_info *ampdu = wlc->ampdu;
264 u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
267 u32 current_ampdu_cnt = 0;
270 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
274 /* return if we got here for a different reason than underflows */
277 M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
278 new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
279 if (new_txunfl == 0) {
280 BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n");
283 fifo->prev_txfunfl = cur_txunfl;
285 if (!ampdu->tx_max_funl)
288 /* check if fifo is big enough */
289 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
293 if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
296 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
297 fifo->accum_txfunfl += new_txunfl;
299 /* we need to wait for at least 10 underflows */
300 if (fifo->accum_txfunfl < 10)
303 BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n",
304 current_ampdu_cnt, fifo->accum_txfunfl);
307 compute the current ratio of tx unfl per ampdu.
308 When the current ampdu count becomes too
309 big while the ratio remains small, we reset
310 the current count in order to not
311 introduce too big of a latency in detecting a
312 large amount of tx underflows later.
315 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
317 if (txunfl_ratio > ampdu->tx_max_funl) {
318 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
319 fifo->accum_txfunfl = 0;
324 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
326 /* In case max value max_pdu is already lower than
327 the fifo depth, there is nothing more we can do.
330 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
331 fifo->accum_txfunfl = 0;
335 if (fifo->ampdu_pld_size < max_pld_size) {
337 /* increment by TX_FIFO_PLD_INC bytes */
338 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
339 if (fifo->ampdu_pld_size > max_pld_size)
340 fifo->ampdu_pld_size = max_pld_size;
342 /* update scb release size */
343 scb_ampdu_update_config_all(ampdu);
346 compute a new dma xfer rate for max_mpdu @ max mcs.
347 This is the minimum dma rate that
348 can achieve no underflow condition for the current mpdu size.
350 /* note : we divide/multiply by 100 to avoid integer overflows */
353 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
354 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
356 BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; "
357 "pre-load size %d\n",
358 fifo->dmaxferrate, fifo->ampdu_pld_size);
361 /* decrease ampdu size */
362 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
363 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
364 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
365 AMPDU_NUM_MPDU_LEGACY - 1;
367 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
369 /* recompute the table */
370 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
372 /* update scb release size */
373 scb_ampdu_update_config_all(ampdu);
376 fifo->accum_txfunfl = 0;
380 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
383 u32 phy_rate, dma_rate, tmp;
385 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
387 /* recompute the dma rate */
388 /* note : we divide/multiply by 100 to avoid integer overflows */
390 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
391 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
394 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
395 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
396 fifo->dmaxferrate = dma_rate;
398 /* fill up the mcs2ampdu table; do not recalc the last mcs */
399 dma_rate = dma_rate >> 7;
400 for (i = 0; i < FFPLD_MAX_MCS; i++) {
401 /* shifting to keep it within integer range */
402 phy_rate = MCS_RATE(i, true, false) >> 7;
403 if (phy_rate > dma_rate) {
404 tmp = ((fifo->ampdu_pld_size * phy_rate) /
405 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
406 tmp = min_t(u32, tmp, 255);
407 fifo->mcs2ampdu_table[i] = (u8) tmp;
413 wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
416 scb_ampdu_t *scb_ampdu;
417 scb_ampdu_tid_ini_t *ini;
418 u8 tid = (u8) (p->priority);
420 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
422 /* initialize initiator on first packet; sends addba req */
423 ini = SCB_AMPDU_INI(scb_ampdu, tid);
424 if (ini->magic != INI_MAGIC) {
425 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
431 wlc_sendampdu(struct ampdu_info *ampdu, struct wlc_txq_info *qi,
432 struct sk_buff **pdu, int prec)
434 struct wlc_info *wlc;
435 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
438 u8 preamble_type = WLC_GF_PREAMBLE;
439 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
440 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
441 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
443 bool rr = true, fbr = false;
444 uint i, count = 0, fifo, seg_cnt = 0;
445 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
446 u32 ampdu_len, maxlen = 0;
447 d11txh_t *txh = NULL;
449 struct ieee80211_hdr *h;
451 scb_ampdu_t *scb_ampdu;
452 scb_ampdu_tid_ini_t *ini;
454 bool use_rts = false, use_cts = false;
455 ratespec_t rspec = 0, rspec_fallback = 0;
456 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
457 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
458 struct ieee80211_rts *rts;
462 struct ieee80211_tx_info *tx_info;
470 tid = (u8) (p->priority);
472 f = ampdu->fifo_tb + prio2fifo[tid];
474 scb = wlc->pub->global_scb;
475 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
476 ini = &scb_ampdu->ini[tid];
478 /* Let pressure continue to build ... */
479 qlen = pktq_plen(&qi->q, prec);
480 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
484 wlc_ampdu_agg(ampdu, scb, p, tid);
486 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
490 struct ieee80211_tx_rate *txrate;
492 tx_info = IEEE80211_SKB_CB(p);
493 txrate = tx_info->status.rates;
495 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
496 err = wlc_prep_pdu(wlc, p, &fifo);
498 wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
506 wiphy_err(wiphy, "wl%d: wlc_sendampdu: "
507 "prep_xdu retry; seq 0x%x\n",
508 wlc->pub->unit, seq);
513 /* error in the packet; reject it */
514 wiphy_err(wiphy, "wl%d: wlc_sendampdu: prep_xdu "
515 "rejected; seq 0x%x\n", wlc->pub->unit, seq);
520 /* pkt is good to be aggregated */
521 txh = (d11txh_t *) p->data;
522 plcp = (u8 *) (txh + 1);
523 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
524 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
525 index = TX_SEQ_TO_INDEX(seq);
527 /* check mcl fields and test whether it can be agg'd */
528 mcl = le16_to_cpu(txh->MacTxControlLow);
529 mcl &= ~TXC_AMPDU_MASK;
530 fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
531 txh->PreloadSize = 0; /* always default to 0 */
533 /* Handle retry limits */
534 if (txrate[0].count <= rr_retry_limit) {
544 /* extract the length info */
545 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
546 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
548 /* retrieve null delimiter count */
549 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
552 BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n",
553 wlc->pub->unit, count, len);
556 * aggregateable mpdu. For ucode/hw agg,
557 * test whether need to break or change the epoch
560 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
561 /* refill the bits since might be a retx mpdu */
562 mcl |= TXC_STARTMSDU;
563 rts = (struct ieee80211_rts *)&txh->rts_frame;
565 if (ieee80211_is_rts(rts->frame_control)) {
569 if (ieee80211_is_cts(rts->frame_control)) {
574 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
575 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
578 len = roundup(len, 4);
579 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
581 dma_len += (u16) brcmu_pkttotlen(p);
583 BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
584 " seg_cnt %d null delim %d\n",
585 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
587 txh->MacTxControlLow = cpu_to_le16(mcl);
589 /* this packet is added */
592 /* patch the first MPDU */
594 u8 plcp0, plcp3, is40, sgi;
595 struct ieee80211_sta *sta;
597 sta = tx_info->control.sta;
603 plcp0 = txh->FragPLCPFallback[0];
604 plcp3 = txh->FragPLCPFallback[3];
607 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
608 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
609 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
611 min(scb_ampdu->max_rxlen,
612 ampdu->max_txlen[mcs][is40][sgi]);
614 /* XXX Fix me to honor real max_rxlen */
615 /* can fix this as soon as ampdu_action() in mac80211.h
616 * gets extra u8buf_size par */
621 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
622 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
624 /* rebuild the rspec and rspec_fallback */
625 rspec = RSPEC_MIMORATE;
626 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
627 if (plcp[0] & MIMO_PLCP_40MHZ)
628 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
630 if (fbr_iscck) /* CCK */
632 CCK_RSPEC(CCK_PHY2MAC_RATE
633 (txh->FragPLCPFallback[0]));
635 rspec_fallback = RSPEC_MIMORATE;
637 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
638 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
640 (PHY_TXC1_BW_40MHZ <<
644 if (use_rts || use_cts) {
646 wlc_rspec_to_rts_rspec(wlc, rspec, false,
649 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
650 false, mimo_ctlchbw);
654 /* if (first mpdu for host agg) */
655 /* test whether to add more */
656 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
657 (count == f->mcs2ampdu_table[mcs])) {
658 BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
659 " ampdu at %d for mcs %d\n",
660 wlc->pub->unit, count, mcs);
664 if (count == scb_ampdu->max_pdu) {
668 /* check to see if the next pkt is a candidate for aggregation */
669 p = pktq_ppeek(&qi->q, prec);
670 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
673 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
674 ((u8) (p->priority) == tid)) {
676 plen = brcmu_pkttotlen(p) +
677 AMPDU_MAX_MPDU_OVERHEAD;
678 plen = max(scb_ampdu->min_len, plen);
680 if ((plen + ampdu_len) > maxlen) {
682 wiphy_err(wiphy, "%s: Bogus plen #1\n",
687 /* check if there are enough descriptors available */
688 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
689 wiphy_err(wiphy, "%s: No fifo space "
694 p = brcmu_pktq_pdeq(&qi->q, prec);
701 ini->tx_in_transit += count;
704 /* patch up the last txh */
705 txh = (d11txh_t *) pkt[count - 1]->data;
706 mcl = le16_to_cpu(txh->MacTxControlLow);
707 mcl &= ~TXC_AMPDU_MASK;
708 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
709 txh->MacTxControlLow = cpu_to_le16(mcl);
711 /* remove the null delimiter after last mpdu */
712 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
713 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
714 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
716 /* remove the pad len from last mpdu */
717 fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
718 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
719 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
720 ampdu_len -= roundup(len, 4) - len;
722 /* patch up the first txh & plcp */
723 txh = (d11txh_t *) pkt[0]->data;
724 plcp = (u8 *) (txh + 1);
726 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
727 /* mark plcp to indicate ampdu */
728 WLC_SET_MIMO_PLCP_AMPDU(plcp);
730 /* reset the mixed mode header durations */
733 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
734 txh->MModeLen = cpu_to_le16(mmodelen);
735 preamble_type = WLC_MM_PREAMBLE;
737 if (txh->MModeFbrLen) {
739 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
740 txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
741 fbr_preamble_type = WLC_MM_PREAMBLE;
744 /* set the preload length */
745 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
746 dma_len = min(dma_len, f->ampdu_pld_size);
747 txh->PreloadSize = cpu_to_le16(dma_len);
749 txh->PreloadSize = 0;
751 mch = le16_to_cpu(txh->MacTxControlHigh);
753 /* update RTS dur fields */
754 if (use_rts || use_cts) {
756 rts = (struct ieee80211_rts *)&txh->rts_frame;
757 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
758 TXC_PREAMBLE_RTS_MAIN_SHORT)
759 rts_preamble_type = WLC_SHORT_PREAMBLE;
761 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
762 TXC_PREAMBLE_RTS_FB_SHORT)
763 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
766 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
767 rspec, rts_preamble_type,
768 preamble_type, ampdu_len,
770 rts->duration = cpu_to_le16(durid);
771 durid = wlc_compute_rtscts_dur(wlc, use_cts,
774 rts_fbr_preamble_type,
777 txh->RTSDurFallback = cpu_to_le16(durid);
778 /* set TxFesTimeNormal */
779 txh->TxFesTimeNormal = rts->duration;
780 /* set fallback rate version of TxFesTimeNormal */
781 txh->TxFesTimeFallback = txh->RTSDurFallback;
784 /* set flag and plcp for fallback rate */
786 mch |= TXC_AMPDU_FBR;
787 txh->MacTxControlHigh = cpu_to_le16(mch);
788 WLC_SET_MIMO_PLCP_AMPDU(plcp);
789 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
792 BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n",
793 wlc->pub->unit, count, ampdu_len);
795 /* inform rate_sel if it this is a rate probe pkt */
796 frameid = le16_to_cpu(txh->TxFrameID);
797 if (frameid & TXFID_RATE_PROBE_MASK) {
798 wiphy_err(wiphy, "%s: XXX what to do with "
799 "TXFID_RATE_PROBE_MASK!?\n", __func__);
801 for (i = 0; i < count; i++)
802 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
803 ampdu->txpkt_weight);
811 wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
812 struct sk_buff *p, tx_status_t *txs)
814 scb_ampdu_t *scb_ampdu;
815 struct wlc_info *wlc = ampdu->wlc;
816 scb_ampdu_tid_ini_t *ini;
818 struct ieee80211_tx_info *tx_info;
820 tx_info = IEEE80211_SKB_CB(p);
822 /* BMAC_NOTE: For the split driver, second level txstatus comes later
823 * So if the ACK was received then wait for the second level else just
826 if (txs->status & TX_STATUS_ACK_RCV) {
829 /* wait till the next 8 bytes of txstatus is available */
830 while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
833 if (status_delay > 10) {
834 return; /* error condition */
838 s2 = R_REG(&wlc->regs->frmtxstatus2);
842 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
843 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
844 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
846 /* loop through all pkts and free */
847 u8 queue = txs->frameid & TXFID_QUEUE_MASK;
851 tx_info = IEEE80211_SKB_CB(p);
852 txh = (d11txh_t *) p->data;
853 mcl = le16_to_cpu(txh->MacTxControlLow);
854 brcmu_pkt_buf_free_skb(p);
855 /* break out if last packet of ampdu */
856 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
859 p = GETNEXTTXP(wlc, queue);
861 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
863 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
867 rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
868 tx_status_t *txs, u8 mcs)
870 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
873 /* clear the rest of the rates */
874 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
880 #define SHORTNAME "AMPDU status"
883 wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
884 struct sk_buff *p, tx_status_t *txs,
887 scb_ampdu_t *scb_ampdu;
888 struct wlc_info *wlc = ampdu->wlc;
889 scb_ampdu_tid_ini_t *ini;
890 u8 bitmap[8], queue, tid;
893 struct ieee80211_hdr *h;
894 u16 seq, start_seq = 0, bindex, index, mcl;
896 bool ba_recd = false, ack_recd = false;
897 u8 suc_mpdu = 0, tot_mpdu = 0;
899 bool update_rate = true, retry = true, tx_error = false;
902 u8 retry_limit, rr_retry_limit;
903 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
904 struct wiphy *wiphy = wlc->wiphy;
907 u8 hole[AMPDU_MAX_MPDU];
908 memset(hole, 0, sizeof(hole));
911 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
912 tid = (u8) (p->priority);
914 ini = SCB_AMPDU_INI(scb_ampdu, tid);
915 retry_limit = ampdu->retry_limit_tid[tid];
916 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
917 memset(bitmap, 0, sizeof(bitmap));
918 queue = txs->frameid & TXFID_QUEUE_MASK;
919 supr_status = txs->status & TX_STATUS_SUPR_MASK;
921 if (txs->status & TX_STATUS_ACK_RCV) {
922 if (TX_STATUS_SUPR_UF == supr_status) {
926 WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
927 start_seq = txs->sequence >> SEQNUM_SHIFT;
928 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
929 TX_STATUS_BA_BMAP03_SHIFT;
931 WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
932 WARN_ON(!(s1 & TX_STATUS_AMPDU));
935 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
936 TX_STATUS_BA_BMAP47_SHIFT;
937 bitmap[1] = (s1 >> 8) & 0xff;
938 bitmap[2] = (s1 >> 16) & 0xff;
939 bitmap[3] = (s1 >> 24) & 0xff;
941 bitmap[4] = s2 & 0xff;
942 bitmap[5] = (s2 >> 8) & 0xff;
943 bitmap[6] = (s2 >> 16) & 0xff;
944 bitmap[7] = (s2 >> 24) & 0xff;
950 if (supr_status == TX_STATUS_SUPR_BADCH) {
951 wiphy_err(wiphy, "%s: Pkt tx suppressed, "
952 "illegal channel possibly %d\n",
953 __func__, CHSPEC_CHANNEL(
954 wlc->default_bss->chanspec));
956 if (supr_status != TX_STATUS_SUPR_FRAG)
957 wiphy_err(wiphy, "%s: wlc_ampdu_dotx"
958 "status:supr_status 0x%x\n",
959 __func__, supr_status);
961 /* no need to retry for badch; will fail again */
962 if (supr_status == TX_STATUS_SUPR_BADCH ||
963 supr_status == TX_STATUS_SUPR_EXPTIME) {
965 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
966 /* TX underflow : try tuning pre-loading or ampdu size */
967 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
968 /* if there were underflows, but pre-loading is not active,
969 notify rate adaptation.
971 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
976 } else if (txs->phyerr) {
978 wiphy_err(wiphy, "wl%d: wlc_ampdu_dotxstatus: tx phy "
979 "error (0x%x)\n", wlc->pub->unit,
983 brcmu_prpkt("txpkt (AMPDU)", p);
984 wlc_print_txdesc((d11txh_t *) p->data);
986 wlc_print_txstatus(txs);
990 /* loop through all pkts and retry if not acked */
992 tx_info = IEEE80211_SKB_CB(p);
993 txh = (d11txh_t *) p->data;
994 mcl = le16_to_cpu(txh->MacTxControlLow);
995 plcp = (u8 *) (txh + 1);
996 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
997 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
1000 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1001 mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
1004 index = TX_SEQ_TO_INDEX(seq);
1007 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1008 BCMMSG(wlc->wiphy, "tid %d seq %d,"
1009 " start_seq %d, bindex %d set %d, index %d\n",
1010 tid, seq, start_seq, bindex,
1011 isset(bitmap, bindex), index);
1012 /* if acked then clear bit and free packet */
1013 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1014 && isset(bitmap, bindex)) {
1015 ini->tx_in_transit--;
1016 ini->txretry[index] = 0;
1018 /* ampdu_ack_len: number of acked aggregated frames */
1019 /* ampdu_len: number of aggregated frames */
1020 rate_status(wlc, tx_info, txs, mcs);
1021 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1022 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1023 tx_info->status.ampdu_ack_len =
1024 tx_info->status.ampdu_len = 1;
1026 skb_pull(p, D11_PHY_HDR_LEN);
1027 skb_pull(p, D11_TXH_LEN);
1029 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1035 /* either retransmit or send bar if ack not recd */
1037 struct ieee80211_tx_rate *txrate =
1038 tx_info->status.rates;
1039 if (retry && (txrate[0].count < (int)retry_limit)) {
1040 ini->txretry[index]++;
1041 ini->tx_in_transit--;
1042 /* Use high prededence for retransmit to give some punch */
1043 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1044 wlc_txq_enq(wlc, scb, p,
1045 WLC_PRIO_TO_HI_PREC(tid));
1048 ini->tx_in_transit--;
1049 ieee80211_tx_info_clear_status(tx_info);
1050 tx_info->status.ampdu_ack_len = 0;
1051 tx_info->status.ampdu_len = 1;
1053 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1054 skb_pull(p, D11_PHY_HDR_LEN);
1055 skb_pull(p, D11_TXH_LEN);
1056 wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
1057 "transit %d\n", SHORTNAME, seq,
1058 ini->tx_in_transit);
1059 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1065 /* break out if last packet of ampdu */
1066 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1070 p = GETNEXTTXP(wlc, queue);
1074 /* update rate state */
1075 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1077 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1080 /* initialize the initiator code for tid */
1081 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
1082 scb_ampdu_t *scb_ampdu,
1083 u8 tid, bool override)
1085 scb_ampdu_tid_ini_t *ini;
1087 /* check for per-tid control of ampdu */
1088 if (!ampdu->ini_enable[tid]) {
1089 wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
1094 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1096 ini->scb = scb_ampdu->scb;
1097 ini->magic = INI_MAGIC;
1101 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
1103 struct wlc_info *wlc = ampdu->wlc;
1105 wlc->pub->_ampdu = false;
1108 if (!N_ENAB(wlc->pub)) {
1109 wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
1110 "nmode enabled\n", wlc->pub->unit);
1113 if (!wlc_ampdu_cap(ampdu)) {
1114 wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
1115 "ampdu capable\n", wlc->pub->unit);
1118 wlc->pub->_ampdu = on;
1124 static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
1126 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1132 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
1136 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1137 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1139 rate = MCS_RATE(mcs, false, false);
1140 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1141 /* 40 MHz, No SGI */
1142 rate = MCS_RATE(mcs, true, false);
1143 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1145 rate = MCS_RATE(mcs, false, true);
1146 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1148 rate = MCS_RATE(mcs, true, true);
1149 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1153 void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
1155 char template[T_RAM_ACCESS_SZ * 2];
1157 /* driver needs to write the ta in the template; ta is at offset 16 */
1158 memset(template, 0, sizeof(template));
1159 memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
1160 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1164 bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
1166 return wlc->ampdu->ini_enable[tid];
1169 void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
1171 struct wlc_info *wlc = ampdu->wlc;
1173 /* Extend ucode internal watchdog timer to match larger received frames */
1174 if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
1175 IEEE80211_HT_MAX_AMPDU_64K) {
1176 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1177 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1179 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1180 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
1185 * callback function that helps flushing ampdu packets from a priority queue
1187 static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a)
1189 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
1190 struct cb_del_ampdu_pars *ampdu_pars =
1191 (struct cb_del_ampdu_pars *)arg_a;
1194 rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
1195 rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
1196 tx_info->control.sta == ampdu_pars->sta);
1197 rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
1202 * callback function that helps invalidating ampdu packets in a DMA queue
1204 static void dma_cb_fn_ampdu(void *txi, void *arg_a)
1206 struct ieee80211_sta *sta = arg_a;
1207 struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
1209 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
1210 (tx_info->control.sta == sta || sta == NULL))
1211 tx_info->control.sta = NULL;
1215 * When a remote party is no longer available for ampdu communication, any
1216 * pending tx ampdu packets in the driver have to be flushed.
1218 void wlc_ampdu_flush(struct wlc_info *wlc,
1219 struct ieee80211_sta *sta, u16 tid)
1221 struct wlc_txq_info *qi = wlc->pkt_queue;
1222 struct pktq *pq = &qi->q;
1224 struct cb_del_ampdu_pars ampdu_pars;
1226 ampdu_pars.sta = sta;
1227 ampdu_pars.tid = tid;
1228 for (prec = 0; prec < pq->num_prec; prec++) {
1229 brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
1230 (void *)&du_pars);
1232 wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);