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