PageRenderTime 64ms CodeModel.GetById 18ms app.highlight 36ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c

https://bitbucket.org/wisechild/galaxy-nexus
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 *)&ampdu_pars);
1251	}
1252	wlc_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
1253}