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