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