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