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