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