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