]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c
Fix common misspellings
[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>
45575664
AS
17#include <net/mac80211.h>
18
45575664 19#include <bcmdefs.h>
a9533e7e
HP
20#include <bcmutils.h>
21#include <siutils.h>
a9533e7e 22#include <wlioctl.h>
a9533e7e
HP
23#include <sbhnddma.h>
24#include <hnddma.h>
25#include <d11.h>
45575664
AS
26
27#include "wlc_types.h"
28#include "wlc_cfg.h"
29#include "wlc_rate.h"
30#include "wlc_scb.h"
31#include "wlc_pub.h"
32#include "wlc_key.h"
33#include "phy/wlc_phy_hal.h"
34#include "wlc_antsel.h"
35#include "wl_export.h"
36#include "wl_dbg.h"
45575664 37#include "wlc_channel.h"
7ae92624 38#include "wlc_main.h"
45575664 39#include "wlc_ampdu.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.
25985edc 92 * This allows to maintain a specific state independently of
a9533e7e
HP
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);
62b54dca
AS
159static bool wlc_ampdu_cap(struct ampdu_info *ampdu);
160static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on);
a9533e7e 161
1f2fd453 162struct ampdu_info *wlc_ampdu_attach(struct wlc_info *wlc)
a2627bc0 163{
1f2fd453 164 struct ampdu_info *ampdu;
a9533e7e
HP
165 int i;
166
167 /* some code depends on packed structures */
7d4df48e 168 ASSERT(DOT11_MAXNUMFRAGS == NBITS(u16));
a9533e7e
HP
169 ASSERT(ISPOWEROF2(AMPDU_TX_BA_MAX_WSIZE));
170 ASSERT(ISPOWEROF2(AMPDU_RX_BA_MAX_WSIZE));
171 ASSERT(wlc->pub->tunables->ampdunummpdu <= AMPDU_MAX_MPDU);
172 ASSERT(wlc->pub->tunables->ampdunummpdu > 0);
173
1f2fd453 174 ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
ca8c1e59 175 if (!ampdu) {
f4528696
JP
176 WL_ERROR("wl%d: wlc_ampdu_attach: out of mem\n",
177 wlc->pub->unit);
a9533e7e
HP
178 return NULL;
179 }
a9533e7e
HP
180 ampdu->wlc = wlc;
181
182 for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
0f0881b0 183 ampdu->ini_enable[i] = true;
a9533e7e 184 /* Disable ampdu for VO by default */
0965ae88
GKH
185 ampdu->ini_enable[PRIO_8021D_VO] = false;
186 ampdu->ini_enable[PRIO_8021D_NC] = false;
a9533e7e
HP
187
188 /* Disable ampdu for BK by default since not enough fifo space */
0965ae88
GKH
189 ampdu->ini_enable[PRIO_8021D_NONE] = false;
190 ampdu->ini_enable[PRIO_8021D_BK] = false;
a9533e7e
HP
191
192 ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
193 ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
194 ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
195 ampdu->max_pdu = AUTO;
196 ampdu->dur = AMPDU_MAX_DUR;
197 ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
198
199 ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
200 /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
201 if (WLCISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
f4728c38 202 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
a9533e7e 203 else
f4728c38 204 ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
a9533e7e
HP
205 ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
206 ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
207
208 for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
209 ampdu->retry_limit_tid[i] = ampdu->retry_limit;
210 ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
211 }
212
213 ampdu_update_max_txlen(ampdu, ampdu->dur);
0965ae88 214 ampdu->mfbr = false;
a9533e7e
HP
215 /* try to set ampdu to the default value */
216 wlc_ampdu_set(ampdu, wlc->pub->_ampdu);
217
218 ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
219 wlc_ffpld_init(ampdu);
220
221 return ampdu;
222}
223
1f2fd453 224void wlc_ampdu_detach(struct ampdu_info *ampdu)
a2627bc0 225{
a9533e7e
HP
226 int i;
227
228 if (!ampdu)
229 return;
230
231 /* free all ini's which were to be freed on callbacks which were never called */
232 for (i = 0; i < AMPDU_INI_FREE; i++) {
7c0e45d7 233 kfree(ampdu->ini_free[i]);
a9533e7e
HP
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 267
25985edc 268 /* go back to legacy size if some preloading is occurring */
a9533e7e
HP
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
25985edc 409 can achieve no unferflow condition for the current mpdu size.
a9533e7e
HP
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
12bacc1b 491wlc_sendampdu(struct ampdu_info *ampdu, struct wlc_txq_info *qi,
1f2fd453 492 struct sk_buff **pdu, int prec)
a9533e7e 493{
c6a9e1fc 494 struct wlc_info *wlc;
c26b1378 495 struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
41feb5ed 496 u8 tid, ndelim;
a9533e7e 497 int err = 0;
41feb5ed
GKH
498 u8 preamble_type = WLC_GF_PREAMBLE;
499 u8 fbr_preamble_type = WLC_GF_PREAMBLE;
500 u8 rts_preamble_type = WLC_LONG_PREAMBLE;
501 u8 rts_fbr_preamble_type = WLC_LONG_PREAMBLE;
a9533e7e 502
0965ae88 503 bool rr = true, fbr = false;
a9533e7e 504 uint i, count = 0, fifo, seg_cnt = 0;
7d4df48e 505 u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
66cbd3ab 506 u32 ampdu_len, maxlen = 0;
a9533e7e 507 d11txh_t *txh = NULL;
41feb5ed 508 u8 *plcp;
3e9796f9 509 struct ieee80211_hdr *h;
a9533e7e
HP
510 struct scb *scb;
511 scb_ampdu_t *scb_ampdu;
512 scb_ampdu_tid_ini_t *ini;
41feb5ed 513 u8 mcs = 0;
0965ae88 514 bool use_rts = false, use_cts = false;
a9533e7e
HP
515 ratespec_t rspec = 0, rspec_fallback = 0;
516 ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
7d4df48e 517 u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
f3dc3ea4 518 struct ieee80211_rts *rts;
41feb5ed 519 u8 rr_retry_limit;
a9533e7e
HP
520 wlc_fifo_info_t *f;
521 bool fbr_iscck;
522 struct ieee80211_tx_info *tx_info;
7d4df48e 523 u16 qlen;
a9533e7e
HP
524
525 wlc = ampdu->wlc;
a9533e7e
HP
526 p = *pdu;
527
528 ASSERT(p);
529
54991ad6 530 tid = (u8) (p->priority);
a9533e7e
HP
531 ASSERT(tid < AMPDU_MAX_SCB_TID);
532
533 f = ampdu->fifo_tb + prio2fifo[tid];
534
535 scb = wlc->pub->global_scb;
536 ASSERT(scb->magic == SCB_MAGIC);
537
538 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
539 ASSERT(scb_ampdu);
540 ini = &scb_ampdu->ini[tid];
541
542 /* Let pressure continue to build ... */
543 qlen = pktq_plen(&qi->q, prec);
544 if (ini->tx_in_transit > 0 && qlen < scb_ampdu->max_pdu) {
545 return BCME_BUSY;
546 }
547
548 wlc_ampdu_agg(ampdu, scb, p, tid);
549
550 if (wlc->block_datafifo) {
f4528696 551 WL_ERROR("%s: Fifo blocked\n", __func__);
a9533e7e
HP
552 return BCME_BUSY;
553 }
554 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
555 ampdu_len = 0;
556 dma_len = 0;
557 while (p) {
558 struct ieee80211_tx_rate *txrate;
559
560 tx_info = IEEE80211_SKB_CB(p);
561 txrate = tx_info->status.rates;
562
563 if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
564 err = wlc_prep_pdu(wlc, p, &fifo);
565 } else {
f4528696 566 WL_ERROR("%s: AMPDU flag is off!\n", __func__);
a9533e7e
HP
567 *pdu = NULL;
568 err = 0;
569 break;
570 }
571
572 if (err) {
573 if (err == BCME_BUSY) {
f4528696
JP
574 WL_ERROR("wl%d: wlc_sendampdu: prep_xdu retry; seq 0x%x\n",
575 wlc->pub->unit, seq);
a9533e7e
HP
576 WLCNTINCR(ampdu->cnt->sduretry);
577 *pdu = p;
578 break;
579 }
580
581 /* error in the packet; reject it */
f4528696
JP
582 WL_AMPDU_ERR("wl%d: wlc_sendampdu: prep_xdu rejected; seq 0x%x\n",
583 wlc->pub->unit, seq);
a9533e7e
HP
584 WLCNTINCR(ampdu->cnt->sdurejected);
585
586 *pdu = NULL;
587 break;
588 }
589
590 /* pkt is good to be aggregated */
591 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
54991ad6 592 txh = (d11txh_t *) p->data;
41feb5ed 593 plcp = (u8 *) (txh + 1);
3e9796f9 594 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
628f10ba 595 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
a9533e7e
HP
596 index = TX_SEQ_TO_INDEX(seq);
597
598 /* check mcl fields and test whether it can be agg'd */
628f10ba 599 mcl = le16_to_cpu(txh->MacTxControlLow);
a9533e7e 600 mcl &= ~TXC_AMPDU_MASK;
628f10ba 601 fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
a9533e7e
HP
602 ASSERT(!fbr_iscck);
603 txh->PreloadSize = 0; /* always default to 0 */
604
605 /* Handle retry limits */
606 if (txrate[0].count <= rr_retry_limit) {
607 txrate[0].count++;
0f0881b0 608 rr = true;
0965ae88 609 fbr = false;
a9533e7e
HP
610 ASSERT(!fbr);
611 } else {
0f0881b0 612 fbr = true;
0965ae88 613 rr = false;
a9533e7e
HP
614 txrate[1].count++;
615 }
616
617 /* extract the length info */
618 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
619 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
620
621 /* retrieve null delimiter count */
622 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
623 seg_cnt += 1;
624
f4528696
JP
625 WL_AMPDU_TX("wl%d: wlc_sendampdu: mpdu %d plcp_len %d\n",
626 wlc->pub->unit, count, len);
a9533e7e
HP
627
628 /*
629 * aggregateable mpdu. For ucode/hw agg,
630 * test whether need to break or change the epoch
631 */
632 if (count == 0) {
a9533e7e
HP
633 mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
634 /* refill the bits since might be a retx mpdu */
635 mcl |= TXC_STARTMSDU;
f3dc3ea4 636 rts = (struct ieee80211_rts *)&txh->rts_frame;
2fbd6b37
SF
637
638 if (ieee80211_is_rts(rts->frame_control)) {
a9533e7e 639 mcl |= TXC_SENDRTS;
0f0881b0 640 use_rts = true;
a9533e7e 641 }
2fbd6b37 642 if (ieee80211_is_cts(rts->frame_control)) {
a9533e7e 643 mcl |= TXC_SENDCTS;
0f0881b0 644 use_cts = true;
a9533e7e
HP
645 }
646 } else {
647 mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
648 mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
649 }
650
e18d5313 651 len = roundup(len, 4);
a9533e7e
HP
652 ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
653
d6075c9c 654 dma_len += (u16) pkttotlen(p);
a9533e7e 655
f4528696
JP
656 WL_AMPDU_TX("wl%d: wlc_sendampdu: ampdu_len %d seg_cnt %d null delim %d\n",
657 wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
a9533e7e 658
628f10ba 659 txh->MacTxControlLow = cpu_to_le16(mcl);
a9533e7e
HP
660
661 /* this packet is added */
662 pkt[count++] = p;
663
664 /* patch the first MPDU */
665 if (count == 1) {
41feb5ed 666 u8 plcp0, plcp3, is40, sgi;
a9533e7e
HP
667 struct ieee80211_sta *sta;
668
669 sta = tx_info->control.sta;
670
671 if (rr) {
672 plcp0 = plcp[0];
673 plcp3 = plcp[3];
674 } else {
675 plcp0 = txh->FragPLCPFallback[0];
676 plcp3 = txh->FragPLCPFallback[3];
677
678 }
679 is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
680 sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
681 mcs = plcp0 & ~MIMO_PLCP_40MHZ;
682 ASSERT(mcs < MCS_TABLE_SIZE);
683 maxlen =
7068c2f1 684 min(scb_ampdu->max_rxlen,
a9533e7e
HP
685 ampdu->max_txlen[mcs][is40][sgi]);
686
f4528696
JP
687 WL_NONE("sendampdu: sgi %d, is40 %d, mcs %d\n",
688 sgi, is40, mcs);
a9533e7e
HP
689
690 maxlen = 64 * 1024; /* XXX Fix me to honor real max_rxlen */
691
692 if (is40)
693 mimo_ctlchbw =
694 CHSPEC_SB_UPPER(WLC_BAND_PI_RADIO_CHANSPEC)
695 ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
696
697 /* rebuild the rspec and rspec_fallback */
698 rspec = RSPEC_MIMORATE;
699 rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
700 if (plcp[0] & MIMO_PLCP_40MHZ)
701 rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
702
703 if (fbr_iscck) /* CCK */
704 rspec_fallback =
705 CCK_RSPEC(CCK_PHY2MAC_RATE
706 (txh->FragPLCPFallback[0]));
707 else { /* MIMO */
708 rspec_fallback = RSPEC_MIMORATE;
709 rspec_fallback |=
710 txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
711 if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
712 rspec_fallback |=
713 (PHY_TXC1_BW_40MHZ <<
714 RSPEC_BW_SHIFT);
715 }
716
717 if (use_rts || use_cts) {
718 rts_rspec =
0965ae88 719 wlc_rspec_to_rts_rspec(wlc, rspec, false,
a9533e7e
HP
720 mimo_ctlchbw);
721 rts_rspec_fallback =
722 wlc_rspec_to_rts_rspec(wlc, rspec_fallback,
0965ae88 723 false, mimo_ctlchbw);
a9533e7e
HP
724 }
725 }
726
727 /* if (first mpdu for host agg) */
728 /* test whether to add more */
0965ae88 729 if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
a9533e7e 730 (count == f->mcs2ampdu_table[mcs])) {
f4528696
JP
731 WL_AMPDU_ERR("wl%d: PR 37644: stopping ampdu at %d for mcs %d\n",
732 wlc->pub->unit, count, mcs);
a9533e7e
HP
733 break;
734 }
735
736 if (count == scb_ampdu->max_pdu) {
f4528696
JP
737 WL_NONE("Stop taking from q, reached %d deep\n",
738 scb_ampdu->max_pdu);
a9533e7e
HP
739 break;
740 }
741
742 /* check to see if the next pkt is a candidate for aggregation */
743 p = pktq_ppeek(&qi->q, prec);
744 tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
745
746 if (p) {
747 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
54991ad6 748 ((u8) (p->priority) == tid)) {
a9533e7e
HP
749
750 plen =
d6075c9c 751 pkttotlen(p) + AMPDU_MAX_MPDU_OVERHEAD;
3ea2f4d6 752 plen = max(scb_ampdu->min_len, plen);
a9533e7e
HP
753
754 if ((plen + ampdu_len) > maxlen) {
755 p = NULL;
f4528696
JP
756 WL_ERROR("%s: Bogus plen #1\n",
757 __func__);
a9533e7e
HP
758 ASSERT(3 == 4);
759 continue;
760 }
761
762 /* check if there are enough descriptors available */
763 if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
f4528696
JP
764 WL_ERROR("%s: No fifo space !!!!!!\n",
765 __func__);
a9533e7e
HP
766 p = NULL;
767 continue;
768 }
769 p = pktq_pdeq(&qi->q, prec);
770 ASSERT(p);
771 } else {
772 p = NULL;
773 }
774 }
775 } /* end while(p) */
776
777 ini->tx_in_transit += count;
778
779 if (count) {
780 WLCNTADD(ampdu->cnt->txmpdu, count);
781
782 /* patch up the last txh */
54991ad6 783 txh = (d11txh_t *) pkt[count - 1]->data;
628f10ba 784 mcl = le16_to_cpu(txh->MacTxControlLow);
a9533e7e
HP
785 mcl &= ~TXC_AMPDU_MASK;
786 mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
628f10ba 787 txh->MacTxControlLow = cpu_to_le16(mcl);
a9533e7e
HP
788
789 /* remove the null delimiter after last mpdu */
790 ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
791 txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
792 ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
793
794 /* remove the pad len from last mpdu */
628f10ba 795 fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
a9533e7e
HP
796 len = fbr_iscck ? WLC_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
797 : WLC_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
e18d5313 798 ampdu_len -= roundup(len, 4) - len;
a9533e7e
HP
799
800 /* patch up the first txh & plcp */
54991ad6 801 txh = (d11txh_t *) pkt[0]->data;
41feb5ed 802 plcp = (u8 *) (txh + 1);
a9533e7e
HP
803
804 WLC_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
805 /* mark plcp to indicate ampdu */
806 WLC_SET_MIMO_PLCP_AMPDU(plcp);
807
808 /* reset the mixed mode header durations */
809 if (txh->MModeLen) {
7d4df48e 810 u16 mmodelen =
a9533e7e 811 wlc_calc_lsig_len(wlc, rspec, ampdu_len);
628f10ba 812 txh->MModeLen = cpu_to_le16(mmodelen);
a9533e7e
HP
813 preamble_type = WLC_MM_PREAMBLE;
814 }
815 if (txh->MModeFbrLen) {
7d4df48e 816 u16 mmfbrlen =
a9533e7e 817 wlc_calc_lsig_len(wlc, rspec_fallback, ampdu_len);
628f10ba 818 txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
a9533e7e
HP
819 fbr_preamble_type = WLC_MM_PREAMBLE;
820 }
821
822 /* set the preload length */
0965ae88 823 if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
7068c2f1 824 dma_len = min(dma_len, f->ampdu_pld_size);
628f10ba 825 txh->PreloadSize = cpu_to_le16(dma_len);
a9533e7e
HP
826 } else
827 txh->PreloadSize = 0;
828
628f10ba 829 mch = le16_to_cpu(txh->MacTxControlHigh);
a9533e7e
HP
830
831 /* update RTS dur fields */
832 if (use_rts || use_cts) {
7d4df48e 833 u16 durid;
f3dc3ea4 834 rts = (struct ieee80211_rts *)&txh->rts_frame;
a9533e7e
HP
835 if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
836 TXC_PREAMBLE_RTS_MAIN_SHORT)
837 rts_preamble_type = WLC_SHORT_PREAMBLE;
838
839 if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
840 TXC_PREAMBLE_RTS_FB_SHORT)
841 rts_fbr_preamble_type = WLC_SHORT_PREAMBLE;
842
843 durid =
844 wlc_compute_rtscts_dur(wlc, use_cts, rts_rspec,
845 rspec, rts_preamble_type,
846 preamble_type, ampdu_len,
0f0881b0 847 true);
628f10ba 848 rts->duration = cpu_to_le16(durid);
a9533e7e
HP
849 durid = wlc_compute_rtscts_dur(wlc, use_cts,
850 rts_rspec_fallback,
851 rspec_fallback,
852 rts_fbr_preamble_type,
853 fbr_preamble_type,
0f0881b0 854 ampdu_len, true);
628f10ba 855 txh->RTSDurFallback = cpu_to_le16(durid);
a9533e7e 856 /* set TxFesTimeNormal */
f3dc3ea4 857 txh->TxFesTimeNormal = rts->duration;
a9533e7e
HP
858 /* set fallback rate version of TxFesTimeNormal */
859 txh->TxFesTimeFallback = txh->RTSDurFallback;
860 }
861
862 /* set flag and plcp for fallback rate */
863 if (fbr) {
864 WLCNTADD(ampdu->cnt->txfbr_mpdu, count);
865 WLCNTINCR(ampdu->cnt->txfbr_ampdu);
866 mch |= TXC_AMPDU_FBR;
628f10ba 867 txh->MacTxControlHigh = cpu_to_le16(mch);
a9533e7e
HP
868 WLC_SET_MIMO_PLCP_AMPDU(plcp);
869 WLC_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
870 }
871
f4528696
JP
872 WL_AMPDU_TX("wl%d: wlc_sendampdu: count %d ampdu_len %d\n",
873 wlc->pub->unit, count, ampdu_len);
a9533e7e
HP
874
875 /* inform rate_sel if it this is a rate probe pkt */
628f10ba 876 frameid = le16_to_cpu(txh->TxFrameID);
a9533e7e 877 if (frameid & TXFID_RATE_PROBE_MASK) {
f4528696
JP
878 WL_ERROR("%s: XXX what to do with TXFID_RATE_PROBE_MASK!?\n",
879 __func__);
a9533e7e 880 }
a9533e7e
HP
881 for (i = 0; i < count; i++)
882 wlc_txfifo(wlc, fifo, pkt[i], i == (count - 1),
883 ampdu->txpkt_weight);
a9533e7e
HP
884
885 }
886 /* endif (count) */
887 return err;
888}
889
890void BCMFASTPATH
1f2fd453
RV
891wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
892 struct sk_buff *p, tx_status_t *txs)
a9533e7e
HP
893{
894 scb_ampdu_t *scb_ampdu;
c6a9e1fc 895 struct wlc_info *wlc = ampdu->wlc;
a9533e7e 896 scb_ampdu_tid_ini_t *ini;
66cbd3ab 897 u32 s1 = 0, s2 = 0;
a9533e7e
HP
898 struct ieee80211_tx_info *tx_info;
899
900 tx_info = IEEE80211_SKB_CB(p);
901 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
a9533e7e 902 ASSERT(txs->status & TX_STATUS_AMPDU);
a9533e7e
HP
903
904 /* BMAC_NOTE: For the split driver, second level txstatus comes later
905 * So if the ACK was received then wait for the second level else just
906 * call the first one
907 */
908 if (txs->status & TX_STATUS_ACK_RCV) {
41feb5ed 909 u8 status_delay = 0;
a9533e7e
HP
910
911 /* wait till the next 8 bytes of txstatus is available */
ff31c54c 912 while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
7383141b 913 udelay(1);
a9533e7e
HP
914 status_delay++;
915 if (status_delay > 10) {
916 ASSERT(status_delay <= 10);
917 return;
918 }
919 }
920
921 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
922 ASSERT(s1 & TX_STATUS_AMPDU);
ff31c54c 923 s2 = R_REG(&wlc->regs->frmtxstatus2);
a9533e7e
HP
924 }
925
0bf97bb1
RV
926 if (likely(scb)) {
927 ASSERT(scb->magic == SCB_MAGIC);
928 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
929 ASSERT(scb_ampdu);
930 ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
931 ASSERT(ini->scb == scb);
932 wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
933 } else {
934 /* loop through all pkts and free */
935 u8 queue = txs->frameid & TXFID_QUEUE_MASK;
936 d11txh_t *txh;
937 u16 mcl;
938 while (p) {
939 tx_info = IEEE80211_SKB_CB(p);
940 txh = (d11txh_t *) p->data;
941 mcl = le16_to_cpu(txh->MacTxControlLow);
942 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
943 pkt_buf_free_skb(p);
944 /* break out if last packet of ampdu */
945 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
946 TXC_AMPDU_LAST)
947 break;
948 p = GETNEXTTXP(wlc, queue);
949 ASSERT(p != NULL);
950 }
951 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
952 }
a9533e7e
HP
953 wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
954}
955
a9533e7e 956void
c6a9e1fc 957rate_status(struct wlc_info *wlc, struct ieee80211_tx_info *tx_info,
41feb5ed 958 tx_status_t *txs, u8 mcs)
a9533e7e
HP
959{
960 struct ieee80211_tx_rate *txrate = tx_info->status.rates;
961 int i;
962
963 /* clear the rest of the rates */
964 for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
965 txrate[i].idx = -1;
966 txrate[i].count = 0;
967 }
968}
969
a9533e7e
HP
970#define SHORTNAME "AMPDU status"
971
972static void BCMFASTPATH
1f2fd453 973wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
c26b1378
AS
974 struct sk_buff *p, tx_status_t *txs,
975 u32 s1, u32 s2)
a9533e7e
HP
976{
977 scb_ampdu_t *scb_ampdu;
c6a9e1fc 978 struct wlc_info *wlc = ampdu->wlc;
a9533e7e 979 scb_ampdu_tid_ini_t *ini;
41feb5ed 980 u8 bitmap[8], queue, tid;
a9533e7e 981 d11txh_t *txh;
41feb5ed 982 u8 *plcp;
3e9796f9 983 struct ieee80211_hdr *h;
7d4df48e 984 u16 seq, start_seq = 0, bindex, index, mcl;
41feb5ed 985 u8 mcs = 0;
0965ae88 986 bool ba_recd = false, ack_recd = false;
41feb5ed 987 u8 suc_mpdu = 0, tot_mpdu = 0;
a9533e7e 988 uint supr_status;
0965ae88 989 bool update_rate = true, retry = true, tx_error = false;
7d4df48e 990 u16 mimoantsel = 0;
41feb5ed
GKH
991 u8 antselid = 0;
992 u8 retry_limit, rr_retry_limit;
a9533e7e
HP
993 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
994
995#ifdef BCMDBG
41feb5ed 996 u8 hole[AMPDU_MAX_MPDU];
9249ede9 997 memset(hole, 0, sizeof(hole));
a9533e7e
HP
998#endif
999
1000 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
1001 ASSERT(txs->status & TX_STATUS_AMPDU);
1002
1003 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1004 ASSERT(scb_ampdu);
1005
54991ad6 1006 tid = (u8) (p->priority);
a9533e7e
HP
1007
1008 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1009 retry_limit = ampdu->retry_limit_tid[tid];
1010 rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
1011
1012 ASSERT(ini->scb == scb);
1013
9249ede9 1014 memset(bitmap, 0, sizeof(bitmap));
a9533e7e
HP
1015 queue = txs->frameid & TXFID_QUEUE_MASK;
1016 ASSERT(queue < AC_COUNT);
1017
1018 supr_status = txs->status & TX_STATUS_SUPR_MASK;
1019
1020 if (txs->status & TX_STATUS_ACK_RCV) {
1021 if (TX_STATUS_SUPR_UF == supr_status) {
0965ae88 1022 update_rate = false;
a9533e7e
HP
1023 }
1024
1025 ASSERT(txs->status & TX_STATUS_INTERMEDIATE);
1026 start_seq = txs->sequence >> SEQNUM_SHIFT;
1027 bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
1028 TX_STATUS_BA_BMAP03_SHIFT;
1029
1030 ASSERT(!(s1 & TX_STATUS_INTERMEDIATE));
1031 ASSERT(s1 & TX_STATUS_AMPDU);
1032
1033 bitmap[0] |=
1034 (s1 & TX_STATUS_BA_BMAP47_MASK) <<
1035 TX_STATUS_BA_BMAP47_SHIFT;
1036 bitmap[1] = (s1 >> 8) & 0xff;
1037 bitmap[2] = (s1 >> 16) & 0xff;
1038 bitmap[3] = (s1 >> 24) & 0xff;
1039
1040 bitmap[4] = s2 & 0xff;
1041 bitmap[5] = (s2 >> 8) & 0xff;
1042 bitmap[6] = (s2 >> 16) & 0xff;
1043 bitmap[7] = (s2 >> 24) & 0xff;
1044
0f0881b0 1045 ba_recd = true;
a9533e7e
HP
1046 } else {
1047 WLCNTINCR(ampdu->cnt->noba);
1048 if (supr_status) {
0965ae88 1049 update_rate = false;
a9533e7e 1050 if (supr_status == TX_STATUS_SUPR_BADCH) {
f4528696
JP
1051 WL_ERROR("%s: Pkt tx suppressed, illegal channel possibly %d\n",
1052 __func__,
1053 CHSPEC_CHANNEL(wlc->default_bss->chanspec));
a9533e7e
HP
1054 } else {
1055 if (supr_status == TX_STATUS_SUPR_FRAG)
f4528696
JP
1056 WL_NONE("%s: AMPDU frag err\n",
1057 __func__);
a9533e7e 1058 else
f4528696
JP
1059 WL_ERROR("%s: wlc_ampdu_dotxstatus: supr_status 0x%x\n",
1060 __func__, supr_status);
a9533e7e
HP
1061 }
1062 /* no need to retry for badch; will fail again */
1063 if (supr_status == TX_STATUS_SUPR_BADCH ||
1064 supr_status == TX_STATUS_SUPR_EXPTIME) {
0965ae88 1065 retry = false;
e4cf544e 1066 wlc->pub->_cnt->txchanrej++;
a9533e7e
HP
1067 } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
1068
e4cf544e 1069 wlc->pub->_cnt->txexptime++;
a9533e7e
HP
1070
1071 /* TX underflow : try tuning pre-loading or ampdu size */
1072 } else if (supr_status == TX_STATUS_SUPR_FRAG) {
1073 /* if there were underflows, but pre-loading is not active,
1074 notify rate adaptation.
1075 */
1076 if (wlc_ffpld_check_txfunfl(wlc, prio2fifo[tid])
1077 > 0) {
0f0881b0 1078 tx_error = true;
a9533e7e
HP
1079 }
1080 }
1081 } else if (txs->phyerr) {
0965ae88 1082 update_rate = false;
e4cf544e 1083 wlc->pub->_cnt->txphyerr++;
f4528696
JP
1084 WL_ERROR("wl%d: wlc_ampdu_dotxstatus: tx phy error (0x%x)\n",
1085 wlc->pub->unit, txs->phyerr);
a9533e7e 1086
a9533e7e 1087 if (WL_ERROR_ON()) {
26bcc181 1088 prpkt("txpkt (AMPDU)", p);
54991ad6 1089 wlc_print_txdesc((d11txh_t *) p->data);
a9533e7e 1090 }
bc042b67 1091 wlc_print_txstatus(txs);
a9533e7e
HP
1092 }
1093 }
1094
1095 /* loop through all pkts and retry if not acked */
1096 while (p) {
1097 tx_info = IEEE80211_SKB_CB(p);
1098 ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
54991ad6 1099 txh = (d11txh_t *) p->data;
628f10ba 1100 mcl = le16_to_cpu(txh->MacTxControlLow);
41feb5ed 1101 plcp = (u8 *) (txh + 1);
3e9796f9 1102 h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
628f10ba 1103 seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
a9533e7e
HP
1104
1105 if (tot_mpdu == 0) {
1106 mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
628f10ba 1107 mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
a9533e7e
HP
1108 }
1109
1110 index = TX_SEQ_TO_INDEX(seq);
0965ae88 1111 ack_recd = false;
a9533e7e
HP
1112 if (ba_recd) {
1113 bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
1114
f4528696
JP
1115 WL_AMPDU_TX("%s: tid %d seq is %d, start_seq is %d, bindex is %d set %d, index %d\n",
1116 __func__, tid, seq, start_seq, bindex,
1117 isset(bitmap, bindex), index);
a9533e7e
HP
1118
1119 /* if acked then clear bit and free packet */
1120 if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
1121 && isset(bitmap, bindex)) {
1122 ini->tx_in_transit--;
1123 ini->txretry[index] = 0;
1124
1125 /* ampdu_ack_len: number of acked aggregated frames */
1126 /* ampdu_ack_map: block ack bit map for the aggregation */
1127 /* ampdu_len: number of aggregated frames */
1128 rate_status(wlc, tx_info, txs, mcs);
1129 tx_info->flags |= IEEE80211_TX_STAT_ACK;
1130 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
1131
1132 /* XXX TODO: Make these accurate. */
1133 tx_info->status.ampdu_ack_len =
1134 (txs->
1135 status & TX_STATUS_FRM_RTX_MASK) >>
1136 TX_STATUS_FRM_RTX_SHIFT;
1137 tx_info->status.ampdu_len =
1138 (txs->
1139 status & TX_STATUS_FRM_RTX_MASK) >>
1140 TX_STATUS_FRM_RTX_SHIFT;
1141
c303ecbd
AS
1142 skb_pull(p, D11_PHY_HDR_LEN);
1143 skb_pull(p, D11_TXH_LEN);
a9533e7e
HP
1144
1145 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1146 p);
0f0881b0 1147 ack_recd = true;
a9533e7e
HP
1148 suc_mpdu++;
1149 }
1150 }
1151 /* either retransmit or send bar if ack not recd */
1152 if (!ack_recd) {
1153 struct ieee80211_tx_rate *txrate =
1154 tx_info->status.rates;
1155 if (retry && (txrate[0].count < (int)retry_limit)) {
1156 ini->txretry[index]++;
1157 ini->tx_in_transit--;
1158 /* Use high prededence for retransmit to give some punch */
1159 /* wlc_txq_enq(wlc, scb, p, WLC_PRIO_TO_PREC(tid)); */
1160 wlc_txq_enq(wlc, scb, p,
1161 WLC_PRIO_TO_HI_PREC(tid));
1162 } else {
1163 /* Retry timeout */
1164 ini->tx_in_transit--;
1165 ieee80211_tx_info_clear_status(tx_info);
1166 tx_info->flags |=
1167 IEEE80211_TX_STAT_AMPDU_NO_BACK;
c303ecbd
AS
1168 skb_pull(p, D11_PHY_HDR_LEN);
1169 skb_pull(p, D11_TXH_LEN);
f4528696
JP
1170 WL_ERROR("%s: BA Timeout, seq %d, in_transit %d\n",
1171 SHORTNAME, seq, ini->tx_in_transit);
a9533e7e
HP
1172 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
1173 p);
1174 }
1175 }
1176 tot_mpdu++;
1177
1178 /* break out if last packet of ampdu */
1179 if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
1180 TXC_AMPDU_LAST)
1181 break;
1182
1183 p = GETNEXTTXP(wlc, queue);
1184 if (p == NULL) {
1185 ASSERT(p);
1186 break;
1187 }
1188 }
1189 wlc_send_q(wlc, wlc->active_queue);
1190
1191 /* update rate state */
61044c4c 1192 antselid = wlc_antsel_antsel2id(wlc->asi, mimoantsel);
a9533e7e
HP
1193
1194 wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
1195}
1196
1197static void
1f2fd453 1198ampdu_cleanup_tid_ini(struct ampdu_info *ampdu, scb_ampdu_t *scb_ampdu, u8 tid,
a9533e7e
HP
1199 bool force)
1200{
1201 scb_ampdu_tid_ini_t *ini;
ca8c1e59
JC
1202 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1203 if (!ini)
a9533e7e
HP
1204 return;
1205
f4528696
JP
1206 WL_AMPDU_CTL("wl%d: ampdu_cleanup_tid_ini: tid %d\n",
1207 ampdu->wlc->pub->unit, tid);
a9533e7e
HP
1208
1209 if (ini->tx_in_transit && !force)
1210 return;
1211
1212 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, ini->scb);
1213 ASSERT(ini == &scb_ampdu->ini[ini->tid]);
1214
1215 /* free all buffered tx packets */
537ebbbe 1216 pktq_pflush(&scb_ampdu->txq, ini->tid, true, NULL, 0);
a9533e7e
HP
1217}
1218
1219/* initialize the initiator code for tid */
1f2fd453 1220static scb_ampdu_tid_ini_t *wlc_ampdu_init_tid_ini(struct ampdu_info *ampdu,
7cc4a4c0 1221 scb_ampdu_t *scb_ampdu,
41feb5ed 1222 u8 tid, bool override)
a9533e7e
HP
1223{
1224 scb_ampdu_tid_ini_t *ini;
1225
1226 ASSERT(scb_ampdu);
1227 ASSERT(scb_ampdu->scb);
1228 ASSERT(SCB_AMPDU(scb_ampdu->scb));
1229 ASSERT(tid < AMPDU_MAX_SCB_TID);
1230
1231 /* check for per-tid control of ampdu */
1232 if (!ampdu->ini_enable[tid]) {
f4528696 1233 WL_ERROR("%s: Rejecting tid %d\n", __func__, tid);
a9533e7e
HP
1234 return NULL;
1235 }
1236
1237 ini = SCB_AMPDU_INI(scb_ampdu, tid);
1238 ini->tid = tid;
1239 ini->scb = scb_ampdu->scb;
1240 ini->magic = INI_MAGIC;
1241 WLCNTINCR(ampdu->cnt->txaddbareq);
1242
1243 return ini;
1244}
1245
62b54dca 1246static int wlc_ampdu_set(struct ampdu_info *ampdu, bool on)
a9533e7e 1247{
c6a9e1fc 1248 struct wlc_info *wlc = ampdu->wlc;
a9533e7e 1249
0965ae88 1250 wlc->pub->_ampdu = false;
a9533e7e
HP
1251
1252 if (on) {
1253 if (!N_ENAB(wlc->pub)) {
f4528696
JP
1254 WL_AMPDU_ERR("wl%d: driver not nmode enabled\n",
1255 wlc->pub->unit);
a9533e7e
HP
1256 return BCME_UNSUPPORTED;
1257 }
1258 if (!wlc_ampdu_cap(ampdu)) {
f4528696
JP
1259 WL_AMPDU_ERR("wl%d: device not ampdu capable\n",
1260 wlc->pub->unit);
a9533e7e
HP
1261 return BCME_UNSUPPORTED;
1262 }
1263 wlc->pub->_ampdu = on;
1264 }
1265
1266 return 0;
1267}
1268
62b54dca 1269static bool wlc_ampdu_cap(struct ampdu_info *ampdu)
a9533e7e
HP
1270{
1271 if (WLC_PHY_11N_CAP(ampdu->wlc->band))
0f0881b0 1272 return true;
a9533e7e 1273 else
0965ae88 1274 return false;
a9533e7e
HP
1275}
1276
1f2fd453 1277static void ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
a9533e7e 1278{
66cbd3ab 1279 u32 rate, mcs;
a9533e7e
HP
1280
1281 for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
1282 /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
1283 /* 20MHz, No SGI */
0965ae88 1284 rate = MCS_RATE(mcs, false, false);
a9533e7e
HP
1285 ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
1286 /* 40 MHz, No SGI */
0965ae88 1287 rate = MCS_RATE(mcs, true, false);
a9533e7e
HP
1288 ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
1289 /* 20MHz, SGI */
0965ae88 1290 rate = MCS_RATE(mcs, false, true);
a9533e7e
HP
1291 ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
1292 /* 40 MHz, SGI */
0f0881b0 1293 rate = MCS_RATE(mcs, true, true);
a9533e7e
HP
1294 ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
1295 }
1296}
1297
41feb5ed 1298u8 BCMFASTPATH
1f2fd453 1299wlc_ampdu_null_delim_cnt(struct ampdu_info *ampdu, struct scb *scb,
a9533e7e
HP
1300 ratespec_t rspec, int phylen)
1301{
1302 scb_ampdu_t *scb_ampdu;
1303 int bytes, cnt, tmp;
41feb5ed 1304 u8 tx_density;
a9533e7e
HP
1305
1306 ASSERT(scb);
1307 ASSERT(SCB_AMPDU(scb));
1308
1309 scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
1310 ASSERT(scb_ampdu);
1311
1312 if (scb_ampdu->mpdu_density == 0)
1313 return 0;
1314
1315 /* RSPEC2RATE is in kbps units ==> ~RSPEC2RATE/2^13 is in bytes/usec
1316 density x is in 2^(x-4) usec
1317 ==> # of bytes needed for req density = rate/2^(17-x)
1318 ==> # of null delimiters = ceil(ceil(rate/2^(17-x)) - phylen)/4)
1319 */
1320
1321 tx_density = scb_ampdu->mpdu_density;
1322
1323 ASSERT(tx_density <= AMPDU_MAX_MPDU_DENSITY);
1324 tmp = 1 << (17 - tx_density);
1325 bytes = CEIL(RSPEC2RATE(rspec), tmp);
1326
1327 if (bytes > phylen) {
1328 cnt = CEIL(bytes - phylen, AMPDU_DELIMITER_LEN);
1329 ASSERT(cnt <= 255);
41feb5ed 1330 return (u8) cnt;
a9533e7e
HP
1331 } else
1332 return 0;
1333}
1334
c6a9e1fc 1335void wlc_ampdu_macaddr_upd(struct wlc_info *wlc)
a9533e7e
HP
1336{
1337 char template[T_RAM_ACCESS_SZ * 2];
1338
1339 /* driver needs to write the ta in the template; ta is at offset 16 */
9249ede9 1340 memset(template, 0, sizeof(template));
02160695 1341 memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
a9533e7e
HP
1342 wlc_write_template_ram(wlc, (T_BA_TPL_BASE + 16), (T_RAM_ACCESS_SZ * 2),
1343 template);
1344}
1345
c6a9e1fc 1346bool wlc_aggregatable(struct wlc_info *wlc, u8 tid)
a9533e7e 1347{
90ea2296 1348 return wlc->ampdu->ini_enable[tid];
a9533e7e
HP
1349}
1350
1f2fd453 1351void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
a9533e7e 1352{
c6a9e1fc 1353 struct wlc_info *wlc = ampdu->wlc;
a9533e7e
HP
1354
1355 /* Extend ucode internal watchdog timer to match larger received frames */
f4728c38
SF
1356 if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
1357 IEEE80211_HT_MAX_AMPDU_64K) {
a9533e7e
HP
1358 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
1359 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
1360 } else {
1361 wlc_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
1362 wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
1363 }
1364}
61f44205
RV
1365
1366struct cb_del_ampdu_pars {
1367 struct ieee80211_sta *sta;
1368 u16 tid;
1369};
1370
1371/*
1372 * callback function that helps flushing ampdu packets from a priority queue
1373 */
1374static bool cb_del_ampdu_pkt(void *p, int arg_a)
1375{
1376 struct sk_buff *mpdu = (struct sk_buff *)p;
1377 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
1378 struct cb_del_ampdu_pars *ampdu_pars =
1379 (struct cb_del_ampdu_pars *)arg_a;
1380 bool rc;
1381
1382 rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
1383 rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
1384 tx_info->control.sta == ampdu_pars->sta);
1385 rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
1386 return rc;
1387}
1388
9ee63c6a
RV
1389/*
1390 * callback function that helps invalidating ampdu packets in a DMA queue
1391 */
1392static void dma_cb_fn_ampdu(void *txi, void *arg_a)
1393{
1394 struct ieee80211_sta *sta = arg_a;
1395 struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
1396
1397 if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
1398 (tx_info->control.sta == sta || sta == NULL))
1399 tx_info->control.sta = NULL;
1400}
1401
61f44205
RV
1402/*
1403 * When a remote party is no longer available for ampdu communication, any
1404 * pending tx ampdu packets in the driver have to be flushed.
1405 */
1406void wlc_ampdu_flush(struct wlc_info *wlc,
1407 struct ieee80211_sta *sta, u16 tid)
1408{
1409 struct wlc_txq_info *qi = wlc->active_queue;
1410 struct pktq *pq = &qi->q;
1411 int prec;
1412 struct cb_del_ampdu_pars ampdu_pars;
1413
1414 ampdu_pars.sta = sta;
1415 ampdu_pars.tid = tid;
1416 for (prec = 0; prec < pq->num_prec; prec++) {
1417 pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
1418 (int)&ampdu_pars);
1419 }
9ee63c6a 1420 wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
61f44205 1421}