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