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