staging: brcm80211: removed all ASSERTs from wlc_ampdu.c
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / brcm80211 / brcmsmac / wlc_ampdu.c
blob04493e9730ee945e8050a14605fc3b8c386c900c
1 /*
2 * Copyright (c) 2010 Broadcom Corporation
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include <linux/kernel.h>
17 #include <net/mac80211.h>
19 #include <bcmdefs.h>
20 #include <bcmutils.h>
21 #include <siutils.h>
22 #include <wlioctl.h>
23 #include <sbhnddma.h>
24 #include <hnddma.h>
25 #include <d11.h>
27 #include "wlc_types.h"
28 #include "wlc_cfg.h"
29 #include "wlc_rate.h"
30 #include "wlc_scb.h"
31 #include "wlc_pub.h"
32 #include "wlc_key.h"
33 #include "phy/wlc_phy_hal.h"
34 #include "wlc_antsel.h"
35 #include "wl_export.h"
36 #include "wl_dbg.h"
37 #include "wlc_channel.h"
38 #include "wlc_main.h"
39 #include "wlc_ampdu.h"
42 * Disable AMPDU statistics counters for now
44 #define WLCNTINCR(a)
45 #define WLCNTADD(a, b)
47 #define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
48 #define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
49 #define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
50 #define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
51 #define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
52 #define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
53 #define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
54 #define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
55 #define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
56 #define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
57 #define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
58 #define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
59 #define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
61 #define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
62 #define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
63 * without underflows
65 #define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */
66 #define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */
67 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
68 #define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we
69 * accumulate between resets.
72 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
74 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
75 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
76 AMPDU_DELIMITER_LEN + 3\
77 + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
79 #ifdef BCMDBG
80 u32 wl_ampdu_dbg =
81 WL_AMPDU_UPDN_VAL |
82 WL_AMPDU_ERR_VAL |
83 WL_AMPDU_TX_VAL |
84 WL_AMPDU_RX_VAL |
85 WL_AMPDU_CTL_VAL |
86 WL_AMPDU_HW_VAL | WL_AMPDU_HWTXS_VAL | WL_AMPDU_HWDBG_VAL;
87 #endif
89 /* structure to hold tx fifo information and pre-loading state
90 * counters specific to tx underflows of ampdus
91 * some counters might be redundant with the ones in wlc or ampdu structures.
92 * This allows to maintain a specific state independently of
93 * how often and/or when the wlc counters are updated.
95 typedef struct wlc_fifo_info {
96 u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
97 u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
98 u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
99 u32 accum_txfunfl; /* num of underflows since we modified pld params */
100 u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
101 u32 prev_txampdu; /* previous reading of tx ampdu */
102 u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
103 } wlc_fifo_info_t;
105 /* AMPDU module specific state */
106 struct ampdu_info {
107 struct wlc_info *wlc; /* pointer to main wlc structure */
108 int scb_handle; /* scb cubby handle to retrieve data from scb */
109 u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
110 u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
111 u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
112 u8 retry_limit; /* mpdu transmit retry limit */
113 u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
114 u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
115 /* per-tid mpdu transmit retry limit at regular rate */
116 u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
117 u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
118 s8 max_pdu; /* max pdus allowed in ampdu */
119 u8 dur; /* max duration of an ampdu (in msec) */
120 u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
121 u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
122 u32 ffpld_rsvd; /* number of bytes to reserve for preload */
123 u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
124 void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
125 bool mfbr; /* enable multiple fallback rate */
126 u32 tx_max_funl; /* underflows should be kept such that
127 * (tx_max_funfl*underflows) < tx frames
129 wlc_fifo_info_t fifo_tb[NUM_FFPLD_FIFO]; /* table of fifo infos */
133 #define AMPDU_CLEANUPFLAG_RX (0x1)
134 #define AMPDU_CLEANUPFLAG_TX (0x2)
136 #define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
137 #define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
139 static void wlc_ffpld_init(struct ampdu_info *ampdu);
140 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int f);
141 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
143 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
144 scb_ampdu_t *scb_ampdu,
145 u8 tid, bool override);
146 static void ampdu_cleanup_tid_ini(struct ampdu_info *ampdu,
147 scb_ampdu_t *scb_ampdu,
148 u8 tid, bool force);
149 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur);
150 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb);
151 static void scb_ampdu_update_config_all(struct ampdu_info *ampdu);
153 #define wlc_ampdu_txflowcontrol(a, b, c) do {} while (0)
155 static void wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
156 struct scb *scb,
157 struct sk_buff *p, tx_status_t *txs,
158 u32 frmtxstatus, u32 frmtxstatus2);
159 static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
160 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
162 struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
164 struct ampdu_info *ampdu;
165 int i;
167 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
168 if (!ampdu) {
169 wiphy_err(wlc->wiphy, "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 = IEEE80211_HT_MAX_AMPDU_32K;
196 else
197 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_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 kfree(ampdu->ini_free[i]);
229 wlc_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
230 kfree(ampdu);
233 void scb_ampdu_cleanup(struct ampdu_info *ampdu, struct scb *scb)
235 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
236 u8 tid;
238 WL_AMPDU_UPDN("scb_ampdu_cleanup: enter\n");
239 for (tid = 0; tid < AMPDU_MAX_SCB_TID; tid++) {
240 ampdu_cleanup_tid_ini(ampdu, scb_ampdu, tid, false);
244 /* reset the ampdu state machine so that it can gracefully handle packets that were
245 * freed from the dma and tx queues during reinit
247 void wlc_ampdu_reset(struct ampdu_info *ampdu)
251 static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb)
253 scb_ampdu_t *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
254 int i;
256 scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
258 /* go back to legacy size if some preloading is occurring */
259 for (i = 0; i < NUM_FFPLD_FIFO; i++) {
260 if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
261 scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
264 /* apply user override */
265 if (ampdu->max_pdu != AUTO)
266 scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
268 scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
270 if (scb_ampdu->max_rxlen)
271 scb_ampdu->release =
272 min_t(u8, scb_ampdu->release, scb_ampdu->max_rxlen / 1600);
274 scb_ampdu->release = min(scb_ampdu->release,
275 ampdu->fifo_tb[TX_AC_BE_FIFO].
276 mcs2ampdu_table[FFPLD_MAX_MCS]);
279 void scb_ampdu_update_config_all(struct ampdu_info *ampdu)
281 scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
284 static void wlc_ffpld_init(struct ampdu_info *ampdu)
286 int i, j;
287 wlc_fifo_info_t *fifo;
289 for (j = 0; j < NUM_FFPLD_FIFO; j++) {
290 fifo = (ampdu->fifo_tb + j);
291 fifo->ampdu_pld_size = 0;
292 for (i = 0; i <= FFPLD_MAX_MCS; i++)
293 fifo->mcs2ampdu_table[i] = 255;
294 fifo->dmaxferrate = 0;
295 fifo->accum_txampdu = 0;
296 fifo->prev_txfunfl = 0;
297 fifo->accum_txfunfl = 0;
302 /* evaluate the dma transfer rate using the tx underflows as feedback.
303 * If necessary, increase tx fifo preloading. If not enough,
304 * decrease maximum ampdu size for each mcs till underflows stop
305 * Return 1 if pre-loading not active, -1 if not an underflow event,
306 * 0 if pre-loading module took care of the event.
308 static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid)
310 struct ampdu_info *ampdu = wlc->ampdu;
311 u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
312 u32 txunfl_ratio;
313 u8 max_mpdu;
314 u32 current_ampdu_cnt = 0;
315 u16 max_pld_size;
316 u32 new_txunfl;
317 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + fid);
318 uint xmtfifo_sz;
319 u16 cur_txunfl;
321 /* return if we got here for a different reason than underflows */
322 cur_txunfl =
323 wlc_read_shm(wlc,
324 M_UCODE_MACSTAT + offsetof(macstat_t, txfunfl[fid]));
325 new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
326 if (new_txunfl == 0) {
327 WL_FFPLD("check_txunfl : TX status FRAG set but no tx underflows\n");
328 return -1;
330 fifo->prev_txfunfl = cur_txunfl;
332 if (!ampdu->tx_max_funl)
333 return 1;
335 /* check if fifo is big enough */
336 if (wlc_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz)) {
337 WL_FFPLD("check_txunfl : get xmtfifo_sz failed\n");
338 return -1;
341 if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
342 return 1;
344 max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
345 fifo->accum_txfunfl += new_txunfl;
347 /* we need to wait for at least 10 underflows */
348 if (fifo->accum_txfunfl < 10)
349 return 0;
351 WL_FFPLD("ampdu_count %d tx_underflows %d\n",
352 current_ampdu_cnt, fifo->accum_txfunfl);
355 compute the current ratio of tx unfl per ampdu.
356 When the current ampdu count becomes too
357 big while the ratio remains small, we reset
358 the current count in order to not
359 introduce too big of a latency in detecting a
360 large amount of tx underflows later.
363 txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
365 if (txunfl_ratio > ampdu->tx_max_funl) {
366 if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
367 fifo->accum_txfunfl = 0;
369 return 0;
371 max_mpdu =
372 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
374 /* In case max value max_pdu is already lower than
375 the fifo depth, there is nothing more we can do.
378 if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
379 WL_FFPLD(("tx fifo pld : max ampdu fits in fifo\n)"));
380 fifo->accum_txfunfl = 0;
381 return 0;
384 if (fifo->ampdu_pld_size < max_pld_size) {
386 /* increment by TX_FIFO_PLD_INC bytes */
387 fifo->ampdu_pld_size += FFPLD_PLD_INCR;
388 if (fifo->ampdu_pld_size > max_pld_size)
389 fifo->ampdu_pld_size = max_pld_size;
391 /* update scb release size */
392 scb_ampdu_update_config_all(ampdu);
395 compute a new dma xfer rate for max_mpdu @ max mcs.
396 This is the minimum dma rate that
397 can achieve no underflow condition for the current mpdu size.
399 /* note : we divide/multiply by 100 to avoid integer overflows */
400 fifo->dmaxferrate =
401 (((phy_rate / 100) *
402 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
403 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
405 WL_FFPLD("DMA estimated transfer rate %d; pre-load size %d\n",
406 fifo->dmaxferrate, fifo->ampdu_pld_size);
407 } else {
409 /* decrease ampdu size */
410 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
411 if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
412 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
413 AMPDU_NUM_MPDU_LEGACY - 1;
414 else
415 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
417 /* recompute the table */
418 wlc_ffpld_calc_mcs2ampdu_table(ampdu, fid);
420 /* update scb release size */
421 scb_ampdu_update_config_all(ampdu);
424 fifo->accum_txfunfl = 0;
425 return 0;
428 static void wlc_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
430 int i;
431 u32 phy_rate, dma_rate, tmp;
432 u8 max_mpdu;
433 wlc_fifo_info_t *fifo = (ampdu->fifo_tb + f);
435 /* recompute the dma rate */
436 /* note : we divide/multiply by 100 to avoid integer overflows */
437 max_mpdu =
438 min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
439 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
440 dma_rate =
441 (((phy_rate / 100) *
442 (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
443 / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
444 fifo->dmaxferrate = dma_rate;
446 /* fill up the mcs2ampdu table; do not recalc the last mcs */
447 dma_rate = dma_rate >> 7;
448 for (i = 0; i < FFPLD_MAX_MCS; i++) {
449 /* shifting to keep it within integer range */
450 phy_rate = MCS_RATE(i, true, false) >> 7;
451 if (phy_rate > dma_rate) {
452 tmp = ((fifo->ampdu_pld_size * phy_rate) /
453 ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
454 tmp = min_t(u32, tmp, 255);
455 fifo->mcs2ampdu_table[i] = (u8) tmp;
460 static void BCMFASTPATH
461 wlc_ampdu_agg(struct ampdu_info *ampdu, struct scb *scb, struct sk_buff *p,
462 uint prec)
464 scb_ampdu_t *scb_ampdu;
465 scb_ampdu_tid_ini_t *ini;
466 u8 tid = (u8) (p->priority);
468 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
470 /* initialize initiator on first packet; sends addba req */
471 ini = SCB_AMPDU_INI(scb_ampdu, tid);
472 if (ini->magic != INI_MAGIC) {
473 ini = wlc_ampdu_init_tid_ini(ampdu, scb_ampdu, tid, false);
475 return;
478 int BCMFASTPATH
479 wlc_sendampdu(struct ampdu_info *ampdu, struct wlc_txq_info *qi,
480 struct sk_buff **pdu, int prec)
482 struct wlc_info *wlc;
483 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
484 u8 tid, ndelim;
485 int err = 0;
486 u8 preamble_type = WLC_GF_PREAMBLE;
487 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
488 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
489 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
491 bool rr = true, fbr = false;
492 uint i, count = 0, fifo, seg_cnt = 0;
493 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
494 u32 ampdu_len, maxlen = 0;
495 d11txh_t *txh = NULL;
496 u8 *plcp;
497 struct ieee80211_hdr *h;
498 struct scb *scb;
499 scb_ampdu_t *scb_ampdu;
500 scb_ampdu_tid_ini_t *ini;
501 u8 mcs = 0;
502 bool use_rts = false, use_cts = false;
503 ratespec_t rspec = 0, rspec_fallback = 0;
504 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
505 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
506 struct ieee80211_rts *rts;
507 u8 rr_retry_limit;
508 wlc_fifo_info_t *f;
509 bool fbr_iscck;
510 struct ieee80211_tx_info *tx_info;
511 u16 qlen;
512 struct wiphy *wiphy;
514 wlc = ampdu->wlc;
515 wiphy = wlc->wiphy;
516 p = *pdu;
518 tid = (u8) (p->priority);
520 f = ampdu->fifo_tb + prio2fifo[tid];
522 scb = wlc->pub->global_scb;
523 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
524 ini = &scb_ampdu->ini[tid];
526 /* Let pressure continue to build ... */
527 qlen = pktq_plen(&qi->q, prec);
528 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
529 return -EBUSY;
532 wlc_ampdu_agg(ampdu, scb, p, tid);
534 if (wlc->block_datafifo) {
535 wiphy_err(wiphy, "%s: Fifo blocked\n", __func__);
536 return -EBUSY;
538 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
539 ampdu_len = 0;
540 dma_len = 0;
541 while (p) {
542 struct ieee80211_tx_rate *txrate;
544 tx_info = IEEE80211_SKB_CB(p);
545 txrate = tx_info->status.rates;
547 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
548 err = wlc_prep_pdu(wlc, p, &fifo);
549 } else {
550 wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
551 *pdu = NULL;
552 err = 0;
553 break;
556 if (err) {
557 if (err == -EBUSY) {
558 wiphy_err(wiphy, "wl%d: wlc_sendampdu: "
559 "prep_xdu retry; seq 0x%x\n",
560 wlc->pub->unit, seq);
561 WLCNTINCR(ampdu->cnt->sduretry);
562 *pdu = p;
563 break;
566 /* error in the packet; reject it */
567 wiphy_err(wiphy, "wl%d: wlc_sendampdu: prep_xdu "
568 "rejected; seq 0x%x\n", wlc->pub->unit, seq);
569 WLCNTINCR(ampdu->cnt->sdurejected);
571 *pdu = NULL;
572 break;
575 /* pkt is good to be aggregated */
576 txh = (d11txh_t *) p->data;
577 plcp = (u8 *) (txh + 1);
578 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
579 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
580 index = TX_SEQ_TO_INDEX(seq);
582 /* check mcl fields and test whether it can be agg'd */
583 mcl = le16_to_cpu(txh->MacTxControlLow);
584 mcl &= ~TXC_AMPDU_MASK;
585 fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
586 txh->PreloadSize = 0; /* always default to 0 */
588 /* Handle retry limits */
589 if (txrate[0].count <= rr_retry_limit) {
590 txrate[0].count++;
591 rr = true;
592 fbr = false;
593 } else {
594 fbr = true;
595 rr = false;
596 txrate[1].count++;
599 /* extract the length info */
600 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
601 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
603 /* retrieve null delimiter count */
604 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
605 seg_cnt += 1;
607 WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
608 wlc->pub->unit, count, len);
611 * aggregateable mpdu. For ucode/hw agg,
612 * test whether need to break or change the epoch
614 if (count == 0) {
615 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
616 /* refill the bits since might be a retx mpdu */
617 mcl |= TXC_STARTMSDU;
618 rts = (struct ieee80211_rts *)&txh->rts_frame;
620 if (ieee80211_is_rts(rts->frame_control)) {
621 mcl |= TXC_SENDRTS;
622 use_rts = true;
624 if (ieee80211_is_cts(rts->frame_control)) {
625 mcl |= TXC_SENDCTS;
626 use_cts = true;
628 } else {
629 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
630 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
633 len = roundup(len, 4);
634 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
636 dma_len += (u16) pkttotlen(p);
638 WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
639 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
641 txh->MacTxControlLow = cpu_to_le16(mcl);
643 /* this packet is added */
644 pkt[count++] = p;
646 /* patch the first MPDU */
647 if (count == 1) {
648 u8 plcp0, plcp3, is40, sgi;
649 struct ieee80211_sta *sta;
651 sta = tx_info->control.sta;
653 if (rr) {
654 plcp0 = plcp[0];
655 plcp3 = plcp[3];
656 } else {
657 plcp0 = txh->FragPLCPFallback[0];
658 plcp3 = txh->FragPLCPFallback[3];
661 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
662 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
663 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
664 maxlen =
665 min(scb_ampdu->max_rxlen,
666 ampdu->max_txlen[mcs][is40][sgi]);
668 /* XXX Fix me to honor real max_rxlen */
669 /* can fix this as soon as ampdu_action() in mac80211.h
670 * gets extra u8buf_size par */
671 maxlen = 64 * 1024;
673 if (is40)
674 mimo_ctlchbw =
675 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
676 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
678 /* rebuild the rspec and rspec_fallback */
679 rspec = RSPEC_MIMORATE;
680 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
681 if (plcp[0] & MIMO_PLCP_40MHZ)
682 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
684 if (fbr_iscck) /* CCK */
685 rspec_fallback =
686 CCK_RSPEC(CCK_PHY2MAC_RATE
687 (txh->FragPLCPFallback[0]));
688 else { /* MIMO */
689 rspec_fallback = RSPEC_MIMORATE;
690 rspec_fallback |=
691 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
692 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
693 rspec_fallback |=
694 (PHY_TXC1_BW_40MHZ <<
695 RSPEC_BW_SHIFT);
698 if (use_rts || use_cts) {
699 rts_rspec =
700 wlc_rspec_to_rts_rspec(wlc, rspec, false,
701 mimo_ctlchbw);
702 rts_rspec_fallback =
703 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
704 false, mimo_ctlchbw);
708 /* if (first mpdu for host agg) */
709 /* test whether to add more */
710 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
711 (count == f->mcs2ampdu_table[mcs])) {
712 WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
713 wlc->pub->unit, count, mcs);
714 break;
717 if (count == scb_ampdu->max_pdu) {
718 break;
721 /* check to see if the next pkt is a candidate for aggregation */
722 p = pktq_ppeek(&qi->q, prec);
723 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
725 if (p) {
726 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
727 ((u8) (p->priority) == tid)) {
729 plen =
730 pkttotlen(p) + AMPDU_MAX_MPDU_OVERHEAD;
731 plen = max(scb_ampdu->min_len, plen);
733 if ((plen + ampdu_len) > maxlen) {
734 p = NULL;
735 wiphy_err(wiphy, "%s: Bogus plen #1\n",
736 __func__);
737 continue;
740 /* check if there are enough descriptors available */
741 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
742 wiphy_err(wiphy, "%s: No fifo space "
743 "!!\n", __func__);
744 p = NULL;
745 continue;
747 p = pktq_pdeq(&qi->q, prec);
748 } else {
749 p = NULL;
752 } /* end while(p) */
754 ini->tx_in_transit += count;
756 if (count) {
757 WLCNTADD(ampdu->cnt->txmpdu, count);
759 /* patch up the last txh */
760 txh = (d11txh_t *) pkt[count - 1]->data;
761 mcl = le16_to_cpu(txh->MacTxControlLow);
762 mcl &= ~TXC_AMPDU_MASK;
763 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
764 txh->MacTxControlLow = cpu_to_le16(mcl);
766 /* remove the null delimiter after last mpdu */
767 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
768 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
769 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
771 /* remove the pad len from last mpdu */
772 fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
773 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
774 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
775 ampdu_len -= roundup(len, 4) - len;
777 /* patch up the first txh & plcp */
778 txh = (d11txh_t *) pkt[0]->data;
779 plcp = (u8 *) (txh + 1);
781 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
782 /* mark plcp to indicate ampdu */
783 WLC_SET_MIMO_PLCP_AMPDU(plcp);
785 /* reset the mixed mode header durations */
786 if (txh->MModeLen) {
787 u16 mmodelen =
788 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
789 txh->MModeLen = cpu_to_le16(mmodelen);
790 preamble_type = WLC_MM_PREAMBLE;
792 if (txh->MModeFbrLen) {
793 u16 mmfbrlen =
794 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
795 txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
796 fbr_preamble_type = WLC_MM_PREAMBLE;
799 /* set the preload length */
800 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
801 dma_len = min(dma_len, f->ampdu_pld_size);
802 txh->PreloadSize = cpu_to_le16(dma_len);
803 } else
804 txh->PreloadSize = 0;
806 mch = le16_to_cpu(txh->MacTxControlHigh);
808 /* update RTS dur fields */
809 if (use_rts || use_cts) {
810 u16 durid;
811 rts = (struct ieee80211_rts *)&txh->rts_frame;
812 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
813 TXC_PREAMBLE_RTS_MAIN_SHORT)
814 rts_preamble_type = WLC_SHORT_PREAMBLE;
816 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
817 TXC_PREAMBLE_RTS_FB_SHORT)
818 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
820 durid =
821 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
822 rspec, rts_preamble_type,
823 preamble_type, ampdu_len,
824 true);
825 rts->duration = cpu_to_le16(durid);
826 durid = wlc_compute_rtscts_dur(wlc, use_cts,
827 rts_rspec_fallback,
828 rspec_fallback,
829 rts_fbr_preamble_type,
830 fbr_preamble_type,
831 ampdu_len, true);
832 txh->RTSDurFallback = cpu_to_le16(durid);
833 /* set TxFesTimeNormal */
834 txh->TxFesTimeNormal = rts->duration;
835 /* set fallback rate version of TxFesTimeNormal */
836 txh->TxFesTimeFallback = txh->RTSDurFallback;
839 /* set flag and plcp for fallback rate */
840 if (fbr) {
841 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
842 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
843 mch |= TXC_AMPDU_FBR;
844 txh->MacTxControlHigh = cpu_to_le16(mch);
845 WLC_SET_MIMO_PLCP_AMPDU(plcp);
846 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
849 WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
850 wlc->pub->unit, count, ampdu_len);
852 /* inform rate_sel if it this is a rate probe pkt */
853 frameid = le16_to_cpu(txh->TxFrameID);
854 if (frameid & TXFID_RATE_PROBE_MASK) {
855 wiphy_err(wiphy, "%s: XXX what to do with "
856 "TXFID_RATE_PROBE_MASK!?\n", __func__);
858 for (i = 0; i < count; i++)
859 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
860 ampdu->txpkt_weight);
863 /* endif (count) */
864 return err;
867 void BCMFASTPATH
868 wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
869 struct sk_buff *p, tx_status_t *txs)
871 scb_ampdu_t *scb_ampdu;
872 struct wlc_info *wlc = ampdu->wlc;
873 scb_ampdu_tid_ini_t *ini;
874 u32 s1 = 0, s2 = 0;
875 struct ieee80211_tx_info *tx_info;
877 tx_info = IEEE80211_SKB_CB(p);
879 /* BMAC_NOTE: For the split driver, second level txstatus comes later
880 * So if the ACK was received then wait for the second level else just
881 * call the first one
883 if (txs->status & TX_STATUS_ACK_RCV) {
884 u8 status_delay = 0;
886 /* wait till the next 8 bytes of txstatus is available */
887 while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
888 udelay(1);
889 status_delay++;
890 if (status_delay > 10) {
891 return; /* error condition */
895 s2 = R_REG(&wlc->regs->frmtxstatus2);
898 if (likely(scb)) {
899 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
900 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
901 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
902 } else {
903 /* loop through all pkts and free */
904 u8 queue = txs->frameid & TXFID_QUEUE_MASK;
905 d11txh_t *txh;
906 u16 mcl;
907 while (p) {
908 tx_info = IEEE80211_SKB_CB(p);
909 txh = (d11txh_t *) p->data;
910 mcl = le16_to_cpu(txh->MacTxControlLow);
911 pkt_buf_free_skb(p);
912 /* break out if last packet of ampdu */
913 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
914 TXC_AMPDU_LAST)
915 break;
916 p = GETNEXTTXP(wlc, queue);
918 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
920 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
923 void
924 rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
925 tx_status_t *txs, u8 mcs)
927 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
928 int i;
930 /* clear the rest of the rates */
931 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
932 txrate[i].idx = -1;
933 txrate[i].count = 0;
937 #define SHORTNAME "AMPDU status"
939 static void BCMFASTPATH
940 wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
941 struct sk_buff *p, tx_status_t *txs,
942 u32 s1, u32 s2)
944 scb_ampdu_t *scb_ampdu;
945 struct wlc_info *wlc = ampdu->wlc;
946 scb_ampdu_tid_ini_t *ini;
947 u8 bitmap[8], queue, tid;
948 d11txh_t *txh;
949 u8 *plcp;
950 struct ieee80211_hdr *h;
951 u16 seq, start_seq = 0, bindex, index, mcl;
952 u8 mcs = 0;
953 bool ba_recd = false, ack_recd = false;
954 u8 suc_mpdu = 0, tot_mpdu = 0;
955 uint supr_status;
956 bool update_rate = true, retry = true, tx_error = false;
957 u16 mimoantsel = 0;
958 u8 antselid = 0;
959 u8 retry_limit, rr_retry_limit;
960 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
961 struct wiphy *wiphy = wlc->wiphy;
963 #ifdef BCMDBG
964 u8 hole[AMPDU_MAX_MPDU];
965 memset(hole, 0, sizeof(hole));
966 #endif
968 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
969 tid = (u8) (p->priority);
971 ini = SCB_AMPDU_INI(scb_ampdu, tid);
972 retry_limit = ampdu->retry_limit_tid[tid];
973 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
974 memset(bitmap, 0, sizeof(bitmap));
975 queue = txs->frameid & TXFID_QUEUE_MASK;
976 supr_status = txs->status & TX_STATUS_SUPR_MASK;
978 if (txs->status & TX_STATUS_ACK_RCV) {
979 if (TX_STATUS_SUPR_UF == supr_status) {
980 update_rate = false;
983 WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
984 start_seq = txs->sequence >> SEQNUM_SHIFT;
985 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
986 TX_STATUS_BA_BMAP03_SHIFT;
988 WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
989 WARN_ON(!(s1 & TX_STATUS_AMPDU));
991 bitmap[0] |=
992 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
993 TX_STATUS_BA_BMAP47_SHIFT;
994 bitmap[1] = (s1 >> 8) & 0xff;
995 bitmap[2] = (s1 >> 16) & 0xff;
996 bitmap[3] = (s1 >> 24) & 0xff;
998 bitmap[4] = s2 & 0xff;
999 bitmap[5] = (s2 >> 8) & 0xff;
1000 bitmap[6] = (s2 >> 16) & 0xff;
1001 bitmap[7] = (s2 >> 24) & 0xff;
1003 ba_recd = true;
1004 } else {
1005 WLCNTINCR(ampdu->cnt->noba);
1006 if (supr_status) {
1007 update_rate = false;
1008 if (supr_status == TX_STATUS_SUPR_BADCH) {
1009 wiphy_err(wiphy, "%s: Pkt tx suppressed, "
1010 "illegal channel possibly %d\n",
1011 __func__, CHSPEC_CHANNEL(
1012 wlc->default_bss->chanspec));
1013 } else {
1014 if (supr_status != TX_STATUS_SUPR_FRAG)
1015 wiphy_err(wiphy, "%s: wlc_ampdu_dotx"
1016 "status:supr_status 0x%x\n",
1017 __func__, supr_status);
1019 /* no need to retry for badch; will fail again */
1020 if (supr_status == TX_STATUS_SUPR_BADCH ||
1021 supr_status == TX_STATUS_SUPR_EXPTIME) {
1022 retry = false;
1023 wlc->pub->_cnt->txchanrej++;
1024 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1026 wlc->pub->_cnt->txexptime++;
1028 /* TX underflow : try tuning pre-loading or ampdu size */
1029 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1030 /* if there were underflows, but pre-loading is not active,
1031 notify rate adaptation.
1033 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1034 > 0) {
1035 tx_error = true;
1038 } else if (txs->phyerr) {
1039 update_rate = false;
1040 wlc->pub->_cnt->txphyerr++;
1041 wiphy_err(wiphy, "wl%d: wlc_ampdu_dotxstatus: tx phy "
1042 "error (0x%x)\n", wlc->pub->unit,
1043 txs->phyerr);
1045 if (WL_ERROR_ON()) {
1046 prpkt("txpkt (AMPDU)", p);
1047 wlc_print_txdesc((d11txh_t *) p->data);
1049 wlc_print_txstatus(txs);
1053 /* loop through all pkts and retry if not acked */
1054 while (p) {
1055 tx_info = IEEE80211_SKB_CB(p);
1056 txh = (d11txh_t *) p->data;
1057 mcl = le16_to_cpu(txh->MacTxControlLow);
1058 plcp = (u8 *) (txh + 1);
1059 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
1060 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
1062 if (tot_mpdu == 0) {
1063 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
1064 mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
1067 index = TX_SEQ_TO_INDEX(seq);
1068 ack_recd = false;
1069 if (ba_recd) {
1070 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1072 WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
1073 __func__, tid, seq, start_seq, bindex,
1074 isset(bitmap, bindex), index);
1076 /* if acked then clear bit and free packet */
1077 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1078 && isset(bitmap, bindex)) {
1079 ini->tx_in_transit--;
1080 ini->txretry[index] = 0;
1082 /* ampdu_ack_len: number of acked aggregated frames */
1083 /* ampdu_len: number of aggregated frames */
1084 rate_status(wlc, tx_info, txs, mcs);
1085 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1086 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1087 tx_info->status.ampdu_ack_len =
1088 tx_info->status.ampdu_len = 1;
1090 skb_pull(p, D11_PHY_HDR_LEN);
1091 skb_pull(p, D11_TXH_LEN);
1093 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1095 ack_recd = true;
1096 suc_mpdu++;
1099 /* either retransmit or send bar if ack not recd */
1100 if (!ack_recd) {
1101 struct ieee80211_tx_rate *txrate =
1102 tx_info->status.rates;
1103 if (retry && (txrate[0].count < (int)retry_limit)) {
1104 ini->txretry[index]++;
1105 ini->tx_in_transit--;
1106 /* Use high prededence for retransmit to give some punch */
1107 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1108 wlc_txq_enq(wlc, scb, p,
1109 WLC_PRIO_TO_HI_PREC(tid));
1110 } else {
1111 /* Retry timeout */
1112 ini->tx_in_transit--;
1113 ieee80211_tx_info_clear_status(tx_info);
1114 tx_info->status.ampdu_ack_len = 0;
1115 tx_info->status.ampdu_len = 1;
1116 tx_info->flags |=
1117 IEEE80211_TX_STAT_AMPDU_NO_BACK;
1118 skb_pull(p, D11_PHY_HDR_LEN);
1119 skb_pull(p, D11_TXH_LEN);
1120 wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
1121 "transit %d\n", SHORTNAME, seq,
1122 ini->tx_in_transit);
1123 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1127 tot_mpdu++;
1129 /* break out if last packet of ampdu */
1130 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1131 TXC_AMPDU_LAST)
1132 break;
1134 p = GETNEXTTXP(wlc, queue);
1136 wlc_send_q(wlc, wlc->active_queue);
1138 /* update rate state */
1139 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
1141 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1144 static void
1145 ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
1146 bool force)
1148 scb_ampdu_tid_ini_t *ini;
1149 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1150 if (!ini)
1151 return;
1153 WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1154 ampdu->wlc->pub->unit, tid);
1156 if (ini->tx_in_transit && !force)
1157 return;
1159 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1161 /* free all buffered tx packets */
1162 pktq_pflush(&scb_ampdu->txq, ini->tid, true, NULL, 0);
1165 /* initialize the initiator code for tid */
1166 static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
1167 scb_ampdu_t *scb_ampdu,
1168 u8 tid, bool override)
1170 scb_ampdu_tid_ini_t *ini;
1172 /* check for per-tid control of ampdu */
1173 if (!ampdu->ini_enable[tid]) {
1174 wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
1175 __func__, tid);
1176 return NULL;
1179 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1180 ini->tid = tid;
1181 ini->scb = scb_ampdu->scb;
1182 ini->magic = INI_MAGIC;
1183 WLCNTINCR(ampdu->cnt->txaddbareq);
1185 return ini;
1188 static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
1190 struct wlc_info *wlc = ampdu->wlc;
1192 wlc->pub->_ampdu = false;
1194 if (on) {
1195 if (!N_ENAB(wlc->pub)) {
1196 WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
1197 wlc->pub->unit);
1198 return -ENOTSUPP;
1200 if (!wlc_ampdu_cap(ampdu)) {
1201 WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
1202 wlc->pub->unit);
1203 return -ENOTSUPP;
1205 wlc->pub->_ampdu = on;
1208 return 0;
1211 static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
1213 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
1214 return true;
1215 else
1216 return false;
1219 static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
1221 u32 rate, mcs;
1223 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1224 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1225 /* 20MHz, No SGI */
1226 rate = MCS_RATE(mcs, false, false);
1227 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1228 /* 40 MHz, No SGI */
1229 rate = MCS_RATE(mcs, true, false);
1230 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1231 /* 20MHz, SGI */
1232 rate = MCS_RATE(mcs, false, true);
1233 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1234 /* 40 MHz, SGI */
1235 rate = MCS_RATE(mcs, true, true);
1236 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1240 u8 BCMFASTPATH
1241 wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
1242 ratespec_t rspec, int phylen)
1244 scb_ampdu_t *scb_ampdu;
1245 int bytes, cnt, tmp;
1246 u8 tx_density;
1248 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1249 if (scb_ampdu->mpdu_density == 0)
1250 return 0;
1252 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1253 density x is in 2^(x-4) usec
1254 ==> # of bytes needed for req density = rate/2^(17-x)
1255 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1258 tx_density = scb_ampdu->mpdu_density;
1259 tmp = 1 << (17 - tx_density);
1260 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1262 if (bytes > phylen) {
1263 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1264 return (u8) cnt;
1265 } else
1266 return 0;
1269 void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
1271 char template[T_RAM_ACCESS_SZ * 2];
1273 /* driver needs to write the ta in the template; ta is at offset 16 */
1274 memset(template, 0, sizeof(template));
1275 memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
1276 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1277 template);
1280 bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
1282 return wlc->ampdu->ini_enable[tid];
1285 void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
1287 struct wlc_info *wlc = ampdu->wlc;
1289 /* Extend ucode internal watchdog timer to match larger received frames */
1290 if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
1291 IEEE80211_HT_MAX_AMPDU_64K) {
1292 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1293 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1294 } else {
1295 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1296 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
1300 struct cb_del_ampdu_pars {
1301 struct ieee80211_sta *sta;
1302 u16 tid;
1306 * callback function that helps flushing ampdu packets from a priority queue
1308 static bool cb_del_ampdu_pkt(void *p, int arg_a)
1310 struct sk_buff *mpdu = (struct sk_buff *)p;
1311 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
1312 struct cb_del_ampdu_pars *ampdu_pars =
1313 (struct cb_del_ampdu_pars *)arg_a;
1314 bool rc;
1316 rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
1317 rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
1318 tx_info->control.sta == ampdu_pars->sta);
1319 rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
1320 return rc;
1324 * callback function that helps invalidating ampdu packets in a DMA queue
1326 static void dma_cb_fn_ampdu(void *txi, void *arg_a)
1328 struct ieee80211_sta *sta = arg_a;
1329 struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
1331 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
1332 (tx_info->control.sta == sta || sta == NULL))
1333 tx_info->control.sta = NULL;
1337 * When a remote party is no longer available for ampdu communication, any
1338 * pending tx ampdu packets in the driver have to be flushed.
1340 void wlc_ampdu_flush(struct wlc_info *wlc,
1341 struct ieee80211_sta *sta, u16 tid)
1343 struct wlc_txq_info *qi = wlc->active_queue;
1344 struct pktq *pq = &qi->q;
1345 int prec;
1346 struct cb_del_ampdu_pars ampdu_pars;
1348 ampdu_pars.sta = sta;
1349 ampdu_pars.tid = tid;
1350 for (prec = 0; prec < pq->num_prec; prec++) {
1351 pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
1352 (int)&ampdu_pars);
1354 wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);