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