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