cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ampdu.c (33049B)


      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 <net/mac80211.h>
     17
     18#include "rate.h"
     19#include "scb.h"
     20#include "phy/phy_hal.h"
     21#include "antsel.h"
     22#include "main.h"
     23#include "ampdu.h"
     24#include "debug.h"
     25#include "brcms_trace_events.h"
     26
     27/* max number of mpdus in an ampdu */
     28#define AMPDU_MAX_MPDU			32
     29/* max number of mpdus in an ampdu to a legacy */
     30#define AMPDU_NUM_MPDU_LEGACY		16
     31/* max Tx ba window size (in pdu) */
     32#define AMPDU_TX_BA_MAX_WSIZE		64
     33/* default Tx ba window size (in pdu) */
     34#define AMPDU_TX_BA_DEF_WSIZE		64
     35/* default Rx ba window size (in pdu) */
     36#define AMPDU_RX_BA_DEF_WSIZE		64
     37/* max Rx ba window size (in pdu) */
     38#define AMPDU_RX_BA_MAX_WSIZE		64
     39/* max dur of tx ampdu (in msec) */
     40#define	AMPDU_MAX_DUR			5
     41/* default tx retry limit */
     42#define AMPDU_DEF_RETRY_LIMIT		5
     43/* default tx retry limit at reg rate */
     44#define AMPDU_DEF_RR_RETRY_LIMIT	2
     45/* default ffpld reserved bytes */
     46#define AMPDU_DEF_FFPLD_RSVD		2048
     47/* # of inis to be freed on detach */
     48#define AMPDU_INI_FREE			10
     49/* max # of mpdus released at a time */
     50#define	AMPDU_SCB_MAX_RELEASE		20
     51
     52#define NUM_FFPLD_FIFO 4	/* number of fifo concerned by pre-loading */
     53#define FFPLD_TX_MAX_UNFL   200	/* default value of the average number of ampdu
     54				 * without underflows
     55				 */
     56#define FFPLD_MPDU_SIZE 1800	/* estimate of maximum mpdu size */
     57#define FFPLD_MAX_MCS 23	/* we don't deal with mcs 32 */
     58#define FFPLD_PLD_INCR 1000	/* increments in bytes */
     59#define FFPLD_MAX_AMPDU_CNT 5000	/* maximum number of ampdu we
     60					 * accumulate between resets.
     61					 */
     62
     63#define AMPDU_DELIMITER_LEN	4
     64
     65/* max allowed number of mpdus in an ampdu (2 streams) */
     66#define AMPDU_NUM_MPDU		16
     67
     68#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
     69
     70/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
     71#define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
     72	AMPDU_DELIMITER_LEN + 3\
     73	+ DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
     74
     75/* modulo add/sub, bound = 2^k */
     76#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
     77#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
     78
     79/* structure to hold tx fifo information and pre-loading state
     80 * counters specific to tx underflows of ampdus
     81 * some counters might be redundant with the ones in wlc or ampdu structures.
     82 * This allows to maintain a specific state independently of
     83 * how often and/or when the wlc counters are updated.
     84 *
     85 * ampdu_pld_size: number of bytes to be pre-loaded
     86 * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu
     87 * prev_txfunfl: num of underflows last read from the HW macstats counter
     88 * accum_txfunfl: num of underflows since we modified pld params
     89 * accum_txampdu: num of tx ampdu since we modified pld params
     90 * prev_txampdu: previous reading of tx ampdu
     91 * dmaxferrate: estimated dma avg xfer rate in kbits/sec
     92 */
     93struct brcms_fifo_info {
     94	u16 ampdu_pld_size;
     95	u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1];
     96	u16 prev_txfunfl;
     97	u32 accum_txfunfl;
     98	u32 accum_txampdu;
     99	u32 prev_txampdu;
    100	u32 dmaxferrate;
    101};
    102
    103/* AMPDU module specific state
    104 *
    105 * wlc: pointer to main wlc structure
    106 * scb_handle: scb cubby handle to retrieve data from scb
    107 * ini_enable: per-tid initiator enable/disable of ampdu
    108 * ba_tx_wsize: Tx ba window size (in pdu)
    109 * ba_rx_wsize: Rx ba window size (in pdu)
    110 * retry_limit: mpdu transmit retry limit
    111 * rr_retry_limit: mpdu transmit retry limit at regular rate
    112 * retry_limit_tid: per-tid mpdu transmit retry limit
    113 * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate
    114 * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
    115 * max_pdu: max pdus allowed in ampdu
    116 * dur: max duration of an ampdu (in msec)
    117 * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
    118 * ffpld_rsvd: number of bytes to reserve for preload
    119 * max_txlen: max size of ampdu per mcs, bw and sgi
    120 * mfbr: enable multiple fallback rate
    121 * tx_max_funl: underflows should be kept such that
    122 *		(tx_max_funfl*underflows) < tx frames
    123 * fifo_tb: table of fifo infos
    124 */
    125struct ampdu_info {
    126	struct brcms_c_info *wlc;
    127	int scb_handle;
    128	u8 ini_enable[AMPDU_MAX_SCB_TID];
    129	u8 ba_tx_wsize;
    130	u8 ba_rx_wsize;
    131	u8 retry_limit;
    132	u8 rr_retry_limit;
    133	u8 retry_limit_tid[AMPDU_MAX_SCB_TID];
    134	u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
    135	u8 mpdu_density;
    136	s8 max_pdu;
    137	u8 dur;
    138	u8 rx_factor;
    139	u32 ffpld_rsvd;
    140	u32 max_txlen[MCS_TABLE_SIZE][2][2];
    141	bool mfbr;
    142	u32 tx_max_funl;
    143	struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO];
    144};
    145
    146/* used for flushing ampdu packets */
    147struct cb_del_ampdu_pars {
    148	struct ieee80211_sta *sta;
    149	u16 tid;
    150};
    151
    152static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
    153{
    154	u32 rate, mcs;
    155
    156	for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
    157		/* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
    158		/* 20MHz, No SGI */
    159		rate = mcs_2_rate(mcs, false, false);
    160		ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
    161		/* 40 MHz, No SGI */
    162		rate = mcs_2_rate(mcs, true, false);
    163		ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
    164		/* 20MHz, SGI */
    165		rate = mcs_2_rate(mcs, false, true);
    166		ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
    167		/* 40 MHz, SGI */
    168		rate = mcs_2_rate(mcs, true, true);
    169		ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
    170	}
    171}
    172
    173static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
    174{
    175	if (BRCMS_PHY_11N_CAP(ampdu->wlc->band))
    176		return true;
    177	else
    178		return false;
    179}
    180
    181static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
    182{
    183	struct brcms_c_info *wlc = ampdu->wlc;
    184	struct bcma_device *core = wlc->hw->d11core;
    185
    186	wlc->pub->_ampdu = false;
    187
    188	if (on) {
    189		if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
    190			brcms_err(core, "wl%d: driver not nmode enabled\n",
    191				  wlc->pub->unit);
    192			return -ENOTSUPP;
    193		}
    194		if (!brcms_c_ampdu_cap(ampdu)) {
    195			brcms_err(core, "wl%d: device not ampdu capable\n",
    196				  wlc->pub->unit);
    197			return -ENOTSUPP;
    198		}
    199		wlc->pub->_ampdu = on;
    200	}
    201
    202	return 0;
    203}
    204
    205static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
    206{
    207	int i, j;
    208	struct brcms_fifo_info *fifo;
    209
    210	for (j = 0; j < NUM_FFPLD_FIFO; j++) {
    211		fifo = (ampdu->fifo_tb + j);
    212		fifo->ampdu_pld_size = 0;
    213		for (i = 0; i <= FFPLD_MAX_MCS; i++)
    214			fifo->mcs2ampdu_table[i] = 255;
    215		fifo->dmaxferrate = 0;
    216		fifo->accum_txampdu = 0;
    217		fifo->prev_txfunfl = 0;
    218		fifo->accum_txfunfl = 0;
    219
    220	}
    221}
    222
    223struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
    224{
    225	struct ampdu_info *ampdu;
    226	int i;
    227
    228	ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
    229	if (!ampdu)
    230		return NULL;
    231
    232	ampdu->wlc = wlc;
    233
    234	for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
    235		ampdu->ini_enable[i] = true;
    236	/* Disable ampdu for VO by default */
    237	ampdu->ini_enable[PRIO_8021D_VO] = false;
    238	ampdu->ini_enable[PRIO_8021D_NC] = false;
    239
    240	/* Disable ampdu for BK by default since not enough fifo space */
    241	ampdu->ini_enable[PRIO_8021D_NONE] = false;
    242	ampdu->ini_enable[PRIO_8021D_BK] = false;
    243
    244	ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
    245	ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
    246	ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
    247	ampdu->max_pdu = AUTO;
    248	ampdu->dur = AMPDU_MAX_DUR;
    249
    250	ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
    251	/*
    252	 * bump max ampdu rcv size to 64k for all 11n
    253	 * devices except 4321A0 and 4321A1
    254	 */
    255	if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
    256		ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
    257	else
    258		ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
    259	ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
    260	ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
    261
    262	for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
    263		ampdu->retry_limit_tid[i] = ampdu->retry_limit;
    264		ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
    265	}
    266
    267	brcms_c_scb_ampdu_update_max_txlen(ampdu, ampdu->dur);
    268	ampdu->mfbr = false;
    269	/* try to set ampdu to the default value */
    270	brcms_c_ampdu_set(ampdu, wlc->pub->_ampdu);
    271
    272	ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
    273	brcms_c_ffpld_init(ampdu);
    274
    275	return ampdu;
    276}
    277
    278void brcms_c_ampdu_detach(struct ampdu_info *ampdu)
    279{
    280	kfree(ampdu);
    281}
    282
    283static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
    284					    struct scb *scb)
    285{
    286	struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
    287	int i;
    288
    289	scb_ampdu->max_pdu = AMPDU_NUM_MPDU;
    290
    291	/* go back to legacy size if some preloading is occurring */
    292	for (i = 0; i < NUM_FFPLD_FIFO; i++) {
    293		if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
    294			scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
    295	}
    296
    297	/* apply user override */
    298	if (ampdu->max_pdu != AUTO)
    299		scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
    300
    301	scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu,
    302				   AMPDU_SCB_MAX_RELEASE);
    303
    304	if (scb_ampdu->max_rx_ampdu_bytes)
    305		scb_ampdu->release = min_t(u8, scb_ampdu->release,
    306			scb_ampdu->max_rx_ampdu_bytes / 1600);
    307
    308	scb_ampdu->release = min(scb_ampdu->release,
    309				 ampdu->fifo_tb[TX_AC_BE_FIFO].
    310				 mcs2ampdu_table[FFPLD_MAX_MCS]);
    311}
    312
    313static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu)
    314{
    315	brcms_c_scb_ampdu_update_config(ampdu, &ampdu->wlc->pri_scb);
    316}
    317
    318static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
    319{
    320	int i;
    321	u32 phy_rate, dma_rate, tmp;
    322	u8 max_mpdu;
    323	struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f);
    324
    325	/* recompute the dma rate */
    326	/* note : we divide/multiply by 100 to avoid integer overflows */
    327	max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
    328			 AMPDU_NUM_MPDU_LEGACY);
    329	phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
    330	dma_rate =
    331	    (((phy_rate / 100) *
    332	      (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
    333	     / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
    334	fifo->dmaxferrate = dma_rate;
    335
    336	/* fill up the mcs2ampdu table; do not recalc the last mcs */
    337	dma_rate = dma_rate >> 7;
    338	for (i = 0; i < FFPLD_MAX_MCS; i++) {
    339		/* shifting to keep it within integer range */
    340		phy_rate = mcs_2_rate(i, true, false) >> 7;
    341		if (phy_rate > dma_rate) {
    342			tmp = ((fifo->ampdu_pld_size * phy_rate) /
    343			       ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
    344			tmp = min_t(u32, tmp, 255);
    345			fifo->mcs2ampdu_table[i] = (u8) tmp;
    346		}
    347	}
    348}
    349
    350/* evaluate the dma transfer rate using the tx underflows as feedback.
    351 * If necessary, increase tx fifo preloading. If not enough,
    352 * decrease maximum ampdu size for each mcs till underflows stop
    353 * Return 1 if pre-loading not active, -1 if not an underflow event,
    354 * 0 if pre-loading module took care of the event.
    355 */
    356static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
    357{
    358	struct ampdu_info *ampdu = wlc->ampdu;
    359	u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
    360	u32 txunfl_ratio;
    361	u8 max_mpdu;
    362	u32 current_ampdu_cnt = 0;
    363	u16 max_pld_size;
    364	u32 new_txunfl;
    365	struct brcms_fifo_info *fifo = (ampdu->fifo_tb + fid);
    366	uint xmtfifo_sz;
    367	u16 cur_txunfl;
    368
    369	/* return if we got here for a different reason than underflows */
    370	cur_txunfl = brcms_b_read_shm(wlc->hw,
    371				      M_UCODE_MACSTAT +
    372				      offsetof(struct macstat, txfunfl[fid]));
    373	new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
    374	if (new_txunfl == 0) {
    375		brcms_dbg_ht(wlc->hw->d11core,
    376			     "TX status FRAG set but no tx underflows\n");
    377		return -1;
    378	}
    379	fifo->prev_txfunfl = cur_txunfl;
    380
    381	if (!ampdu->tx_max_funl)
    382		return 1;
    383
    384	/* check if fifo is big enough */
    385	if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz))
    386		return -1;
    387
    388	if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
    389		return 1;
    390
    391	max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
    392	fifo->accum_txfunfl += new_txunfl;
    393
    394	/* we need to wait for at least 10 underflows */
    395	if (fifo->accum_txfunfl < 10)
    396		return 0;
    397
    398	brcms_dbg_ht(wlc->hw->d11core, "ampdu_count %d  tx_underflows %d\n",
    399		     current_ampdu_cnt, fifo->accum_txfunfl);
    400
    401	/*
    402	   compute the current ratio of tx unfl per ampdu.
    403	   When the current ampdu count becomes too
    404	   big while the ratio remains small, we reset
    405	   the current count in order to not
    406	   introduce too big of a latency in detecting a
    407	   large amount of tx underflows later.
    408	 */
    409
    410	txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
    411
    412	if (txunfl_ratio > ampdu->tx_max_funl) {
    413		if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT)
    414			fifo->accum_txfunfl = 0;
    415
    416		return 0;
    417	}
    418	max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
    419			 AMPDU_NUM_MPDU_LEGACY);
    420
    421	/* In case max value max_pdu is already lower than
    422	   the fifo depth, there is nothing more we can do.
    423	 */
    424
    425	if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
    426		fifo->accum_txfunfl = 0;
    427		return 0;
    428	}
    429
    430	if (fifo->ampdu_pld_size < max_pld_size) {
    431
    432		/* increment by TX_FIFO_PLD_INC bytes */
    433		fifo->ampdu_pld_size += FFPLD_PLD_INCR;
    434		if (fifo->ampdu_pld_size > max_pld_size)
    435			fifo->ampdu_pld_size = max_pld_size;
    436
    437		/* update scb release size */
    438		brcms_c_scb_ampdu_update_config_all(ampdu);
    439
    440		/*
    441		 * compute a new dma xfer rate for max_mpdu @ max mcs.
    442		 * This is the minimum dma rate that can achieve no
    443		 * underflow condition for the current mpdu size.
    444		 *
    445		 * note : we divide/multiply by 100 to avoid integer overflows
    446		 */
    447		fifo->dmaxferrate =
    448		    (((phy_rate / 100) *
    449		      (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
    450		     / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
    451
    452		brcms_dbg_ht(wlc->hw->d11core,
    453			     "DMA estimated transfer rate %d; "
    454			     "pre-load size %d\n",
    455			     fifo->dmaxferrate, fifo->ampdu_pld_size);
    456	} else {
    457
    458		/* decrease ampdu size */
    459		if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
    460			if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
    461				fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
    462				    AMPDU_NUM_MPDU_LEGACY - 1;
    463			else
    464				fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
    465
    466			/* recompute the table */
    467			brcms_c_ffpld_calc_mcs2ampdu_table(ampdu, fid);
    468
    469			/* update scb release size */
    470			brcms_c_scb_ampdu_update_config_all(ampdu);
    471		}
    472	}
    473	fifo->accum_txfunfl = 0;
    474	return 0;
    475}
    476
    477void
    478brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
    479	u8 ba_wsize,		/* negotiated ba window size (in pdu) */
    480	uint max_rx_ampdu_bytes) /* from ht_cap in beacon */
    481{
    482	struct scb_ampdu *scb_ampdu;
    483	struct scb_ampdu_tid_ini *ini;
    484	struct ampdu_info *ampdu = wlc->ampdu;
    485	struct scb *scb = &wlc->pri_scb;
    486	scb_ampdu = &scb->scb_ampdu;
    487
    488	if (!ampdu->ini_enable[tid]) {
    489		brcms_err(wlc->hw->d11core, "%s: Rejecting tid %d\n",
    490			  __func__, tid);
    491		return;
    492	}
    493
    494	ini = &scb_ampdu->ini[tid];
    495	ini->tid = tid;
    496	ini->scb = scb_ampdu->scb;
    497	ini->ba_wsize = ba_wsize;
    498	scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
    499}
    500
    501void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
    502				 struct brcms_c_info *wlc)
    503{
    504	session->wlc = wlc;
    505	skb_queue_head_init(&session->skb_list);
    506	session->max_ampdu_len = 0;    /* determined from first MPDU */
    507	session->max_ampdu_frames = 0; /* determined from first MPDU */
    508	session->ampdu_len = 0;
    509	session->dma_len = 0;
    510}
    511
    512/*
    513 * Preps the given packet for AMPDU based on the session data. If the
    514 * frame cannot be accomodated in the current session, -ENOSPC is
    515 * returned.
    516 */
    517int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
    518			    struct sk_buff *p)
    519{
    520	struct brcms_c_info *wlc = session->wlc;
    521	struct ampdu_info *ampdu = wlc->ampdu;
    522	struct scb *scb = &wlc->pri_scb;
    523	struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
    524	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
    525	struct ieee80211_tx_rate *txrate = tx_info->status.rates;
    526	struct d11txh *txh = (struct d11txh *)p->data;
    527	unsigned ampdu_frames;
    528	u8 ndelim, tid;
    529	u8 *plcp;
    530	uint len;
    531	u16 mcl;
    532	bool fbr_iscck;
    533	bool rr;
    534
    535	ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
    536	plcp = (u8 *)(txh + 1);
    537	fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
    538	len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
    539			  BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
    540	len = roundup(len, 4) + (ndelim + 1) * AMPDU_DELIMITER_LEN;
    541
    542	ampdu_frames = skb_queue_len(&session->skb_list);
    543	if (ampdu_frames != 0) {
    544		struct sk_buff *first;
    545
    546		if (ampdu_frames + 1 > session->max_ampdu_frames ||
    547		    session->ampdu_len + len > session->max_ampdu_len)
    548			return -ENOSPC;
    549
    550		/*
    551		 * We aren't really out of space if the new frame is of
    552		 * a different priority, but we want the same behaviour
    553		 * so return -ENOSPC anyway.
    554		 *
    555		 * XXX: The old AMPDU code did this, but is it really
    556		 * necessary?
    557		 */
    558		first = skb_peek(&session->skb_list);
    559		if (p->priority != first->priority)
    560			return -ENOSPC;
    561	}
    562
    563	/*
    564	 * Now that we're sure this frame can be accomodated, update the
    565	 * session information.
    566	 */
    567	session->ampdu_len += len;
    568	session->dma_len += p->len;
    569
    570	tid = (u8)p->priority;
    571
    572	/* Handle retry limits */
    573	if (txrate[0].count <= ampdu->rr_retry_limit_tid[tid]) {
    574		txrate[0].count++;
    575		rr = true;
    576	} else {
    577		txrate[1].count++;
    578		rr = false;
    579	}
    580
    581	if (ampdu_frames == 0) {
    582		u8 plcp0, plcp3, is40, sgi, mcs;
    583		uint fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
    584		struct brcms_fifo_info *f = &ampdu->fifo_tb[fifo];
    585
    586		if (rr) {
    587			plcp0 = plcp[0];
    588			plcp3 = plcp[3];
    589		} else {
    590			plcp0 = txh->FragPLCPFallback[0];
    591			plcp3 = txh->FragPLCPFallback[3];
    592
    593		}
    594
    595		/* Limit AMPDU size based on MCS */
    596		is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
    597		sgi = plcp3_issgi(plcp3) ? 1 : 0;
    598		mcs = plcp0 & ~MIMO_PLCP_40MHZ;
    599		session->max_ampdu_len = min(scb_ampdu->max_rx_ampdu_bytes,
    600					     ampdu->max_txlen[mcs][is40][sgi]);
    601
    602		session->max_ampdu_frames = scb_ampdu->max_pdu;
    603		if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
    604			session->max_ampdu_frames =
    605				min_t(u16, f->mcs2ampdu_table[mcs],
    606				      session->max_ampdu_frames);
    607		}
    608	}
    609
    610	/*
    611	 * Treat all frames as "middle" frames of AMPDU here. First and
    612	 * last frames must be fixed up after all MPDUs have been prepped.
    613	 */
    614	mcl = le16_to_cpu(txh->MacTxControlLow);
    615	mcl &= ~TXC_AMPDU_MASK;
    616	mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
    617	mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
    618	txh->MacTxControlLow = cpu_to_le16(mcl);
    619	txh->PreloadSize = 0;	/* always default to 0 */
    620
    621	skb_queue_tail(&session->skb_list, p);
    622
    623	return 0;
    624}
    625
    626void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session)
    627{
    628	struct brcms_c_info *wlc = session->wlc;
    629	struct ampdu_info *ampdu = wlc->ampdu;
    630	struct sk_buff *first, *last;
    631	struct d11txh *txh;
    632	struct ieee80211_tx_info *tx_info;
    633	struct ieee80211_tx_rate *txrate;
    634	u8 ndelim;
    635	u8 *plcp;
    636	uint len;
    637	uint fifo;
    638	struct brcms_fifo_info *f;
    639	u16 mcl;
    640	bool fbr;
    641	bool fbr_iscck;
    642	struct ieee80211_rts *rts;
    643	bool use_rts = false, use_cts = false;
    644	u16 dma_len = session->dma_len;
    645	u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
    646	u32 rspec = 0, rspec_fallback = 0;
    647	u32 rts_rspec = 0, rts_rspec_fallback = 0;
    648	u8 plcp0, is40, mcs;
    649	u16 mch;
    650	u8 preamble_type = BRCMS_GF_PREAMBLE;
    651	u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
    652	u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
    653	u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
    654
    655	if (skb_queue_empty(&session->skb_list))
    656		return;
    657
    658	first = skb_peek(&session->skb_list);
    659	last = skb_peek_tail(&session->skb_list);
    660
    661	/* Need to fix up last MPDU first to adjust AMPDU length */
    662	txh = (struct d11txh *)last->data;
    663	fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
    664	f = &ampdu->fifo_tb[fifo];
    665
    666	mcl = le16_to_cpu(txh->MacTxControlLow);
    667	mcl &= ~TXC_AMPDU_MASK;
    668	mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
    669	txh->MacTxControlLow = cpu_to_le16(mcl);
    670
    671	/* remove the null delimiter after last mpdu */
    672	ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
    673	txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
    674	session->ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
    675
    676	/* remove the pad len from last mpdu */
    677	fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
    678	len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
    679			  BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
    680	session->ampdu_len -= roundup(len, 4) - len;
    681
    682	/* Now fix up the first MPDU */
    683	tx_info = IEEE80211_SKB_CB(first);
    684	txrate = tx_info->status.rates;
    685	txh = (struct d11txh *)first->data;
    686	plcp = (u8 *)(txh + 1);
    687	rts = (struct ieee80211_rts *)&txh->rts_frame;
    688
    689	mcl = le16_to_cpu(txh->MacTxControlLow);
    690	/* If only one MPDU leave it marked as last */
    691	if (first != last) {
    692		mcl &= ~TXC_AMPDU_MASK;
    693		mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
    694	}
    695	mcl |= TXC_STARTMSDU;
    696	if (ieee80211_is_rts(rts->frame_control)) {
    697		mcl |= TXC_SENDRTS;
    698		use_rts = true;
    699	}
    700	if (ieee80211_is_cts(rts->frame_control)) {
    701		mcl |= TXC_SENDCTS;
    702		use_cts = true;
    703	}
    704	txh->MacTxControlLow = cpu_to_le16(mcl);
    705
    706	fbr = txrate[1].count > 0;
    707	if (!fbr)
    708		plcp0 = plcp[0];
    709	else
    710		plcp0 = txh->FragPLCPFallback[0];
    711
    712	is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
    713	mcs = plcp0 & ~MIMO_PLCP_40MHZ;
    714
    715	if (is40) {
    716		if (CHSPEC_SB_UPPER(wlc_phy_chanspec_get(wlc->band->pi)))
    717			mimo_ctlchbw = PHY_TXC1_BW_20MHZ_UP;
    718		else
    719			mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
    720	}
    721
    722	/* rebuild the rspec and rspec_fallback */
    723	rspec = RSPEC_MIMORATE;
    724	rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
    725	if (plcp[0] & MIMO_PLCP_40MHZ)
    726		rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
    727
    728	fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
    729	if (fbr_iscck) {
    730		rspec_fallback =
    731			cck_rspec(cck_phy2mac_rate(txh->FragPLCPFallback[0]));
    732	} else {
    733		rspec_fallback = RSPEC_MIMORATE;
    734		rspec_fallback |= txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
    735		if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
    736			rspec_fallback |= PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT;
    737	}
    738
    739	if (use_rts || use_cts) {
    740		rts_rspec =
    741			brcms_c_rspec_to_rts_rspec(wlc, rspec,
    742						   false, mimo_ctlchbw);
    743		rts_rspec_fallback =
    744			brcms_c_rspec_to_rts_rspec(wlc, rspec_fallback,
    745						   false, mimo_ctlchbw);
    746	}
    747
    748	BRCMS_SET_MIMO_PLCP_LEN(plcp, session->ampdu_len);
    749	/* mark plcp to indicate ampdu */
    750	BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
    751
    752	/* reset the mixed mode header durations */
    753	if (txh->MModeLen) {
    754		u16 mmodelen = brcms_c_calc_lsig_len(wlc, rspec,
    755						     session->ampdu_len);
    756		txh->MModeLen = cpu_to_le16(mmodelen);
    757		preamble_type = BRCMS_MM_PREAMBLE;
    758	}
    759	if (txh->MModeFbrLen) {
    760		u16 mmfbrlen = brcms_c_calc_lsig_len(wlc, rspec_fallback,
    761						     session->ampdu_len);
    762		txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
    763		fbr_preamble_type = BRCMS_MM_PREAMBLE;
    764	}
    765
    766	/* set the preload length */
    767	if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
    768		dma_len = min(dma_len, f->ampdu_pld_size);
    769		txh->PreloadSize = cpu_to_le16(dma_len);
    770	} else {
    771		txh->PreloadSize = 0;
    772	}
    773
    774	mch = le16_to_cpu(txh->MacTxControlHigh);
    775
    776	/* update RTS dur fields */
    777	if (use_rts || use_cts) {
    778		u16 durid;
    779		if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
    780		    TXC_PREAMBLE_RTS_MAIN_SHORT)
    781			rts_preamble_type = BRCMS_SHORT_PREAMBLE;
    782
    783		if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
    784		     TXC_PREAMBLE_RTS_FB_SHORT)
    785			rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
    786
    787		durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
    788						   rspec, rts_preamble_type,
    789						   preamble_type,
    790						   session->ampdu_len, true);
    791		rts->duration = cpu_to_le16(durid);
    792		durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
    793						   rts_rspec_fallback,
    794						   rspec_fallback,
    795						   rts_fbr_preamble_type,
    796						   fbr_preamble_type,
    797						   session->ampdu_len, true);
    798		txh->RTSDurFallback = cpu_to_le16(durid);
    799		/* set TxFesTimeNormal */
    800		txh->TxFesTimeNormal = rts->duration;
    801		/* set fallback rate version of TxFesTimeNormal */
    802		txh->TxFesTimeFallback = txh->RTSDurFallback;
    803	}
    804
    805	/* set flag and plcp for fallback rate */
    806	if (fbr) {
    807		mch |= TXC_AMPDU_FBR;
    808		txh->MacTxControlHigh = cpu_to_le16(mch);
    809		BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
    810		BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
    811	}
    812
    813	brcms_dbg_ht(wlc->hw->d11core, "wl%d: count %d ampdu_len %d\n",
    814		     wlc->pub->unit, skb_queue_len(&session->skb_list),
    815		     session->ampdu_len);
    816}
    817
    818static void
    819brcms_c_ampdu_rate_status(struct brcms_c_info *wlc,
    820			  struct ieee80211_tx_info *tx_info,
    821			  struct tx_status *txs, u8 mcs)
    822{
    823	struct ieee80211_tx_rate *txrate = tx_info->status.rates;
    824	int i;
    825
    826	/* clear the rest of the rates */
    827	for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
    828		txrate[i].idx = -1;
    829		txrate[i].count = 0;
    830	}
    831}
    832
    833static void
    834brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
    835			      struct sk_buff *p, struct tx_status *txs,
    836			      u32 s1, u32 s2)
    837{
    838	struct scb_ampdu *scb_ampdu;
    839	struct brcms_c_info *wlc = ampdu->wlc;
    840	struct scb_ampdu_tid_ini *ini;
    841	u8 bitmap[8], queue, tid;
    842	struct d11txh *txh;
    843	u8 *plcp;
    844	struct ieee80211_hdr *h;
    845	u16 seq, start_seq = 0, bindex, index, mcl;
    846	u8 mcs = 0;
    847	bool ba_recd = false, ack_recd = false;
    848	u8 suc_mpdu = 0, tot_mpdu = 0;
    849	uint supr_status;
    850	bool retry = true;
    851	u16 mimoantsel = 0;
    852	u8 retry_limit;
    853	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
    854
    855#ifdef DEBUG
    856	u8 hole[AMPDU_MAX_MPDU];
    857	memset(hole, 0, sizeof(hole));
    858#endif
    859
    860	scb_ampdu = &scb->scb_ampdu;
    861	tid = (u8) (p->priority);
    862
    863	ini = &scb_ampdu->ini[tid];
    864	retry_limit = ampdu->retry_limit_tid[tid];
    865	memset(bitmap, 0, sizeof(bitmap));
    866	queue = txs->frameid & TXFID_QUEUE_MASK;
    867	supr_status = txs->status & TX_STATUS_SUPR_MASK;
    868
    869	if (txs->status & TX_STATUS_ACK_RCV) {
    870		WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
    871		start_seq = txs->sequence >> SEQNUM_SHIFT;
    872		bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
    873		    TX_STATUS_BA_BMAP03_SHIFT;
    874
    875		WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
    876		WARN_ON(!(s1 & TX_STATUS_AMPDU));
    877
    878		bitmap[0] |=
    879		    (s1 & TX_STATUS_BA_BMAP47_MASK) <<
    880		    TX_STATUS_BA_BMAP47_SHIFT;
    881		bitmap[1] = (s1 >> 8) & 0xff;
    882		bitmap[2] = (s1 >> 16) & 0xff;
    883		bitmap[3] = (s1 >> 24) & 0xff;
    884
    885		bitmap[4] = s2 & 0xff;
    886		bitmap[5] = (s2 >> 8) & 0xff;
    887		bitmap[6] = (s2 >> 16) & 0xff;
    888		bitmap[7] = (s2 >> 24) & 0xff;
    889
    890		ba_recd = true;
    891	} else {
    892		if (supr_status) {
    893			if (supr_status == TX_STATUS_SUPR_BADCH) {
    894				brcms_dbg_ht(wlc->hw->d11core,
    895					  "%s: Pkt tx suppressed, illegal channel possibly %d\n",
    896					  __func__, CHSPEC_CHANNEL(
    897					  wlc->default_bss->chanspec));
    898			} else {
    899				if (supr_status != TX_STATUS_SUPR_FRAG)
    900					brcms_err(wlc->hw->d11core,
    901						  "%s: supr_status 0x%x\n",
    902						  __func__, supr_status);
    903			}
    904			/* no need to retry for badch; will fail again */
    905			if (supr_status == TX_STATUS_SUPR_BADCH ||
    906			    supr_status == TX_STATUS_SUPR_EXPTIME) {
    907				retry = false;
    908			} else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
    909				/* TX underflow:
    910				 *   try tuning pre-loading or ampdu size
    911				 */
    912			} else if (supr_status == TX_STATUS_SUPR_FRAG) {
    913				/*
    914				 * if there were underflows, but pre-loading
    915				 * is not active, notify rate adaptation.
    916				 */
    917				brcms_c_ffpld_check_txfunfl(wlc, queue);
    918			}
    919		} else if (txs->phyerr) {
    920			brcms_dbg_ht(wlc->hw->d11core,
    921				     "%s: ampdu tx phy error (0x%x)\n",
    922				     __func__, txs->phyerr);
    923		}
    924	}
    925
    926	/* loop through all pkts and retry if not acked */
    927	while (p) {
    928		tx_info = IEEE80211_SKB_CB(p);
    929		txh = (struct d11txh *) p->data;
    930		mcl = le16_to_cpu(txh->MacTxControlLow);
    931		plcp = (u8 *) (txh + 1);
    932		h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
    933		seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
    934
    935		trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
    936
    937		if (tot_mpdu == 0) {
    938			mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
    939			mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
    940		}
    941
    942		index = TX_SEQ_TO_INDEX(seq);
    943		ack_recd = false;
    944		if (ba_recd) {
    945			int block_acked;
    946
    947			bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
    948			if (bindex < AMPDU_TX_BA_MAX_WSIZE)
    949				block_acked = isset(bitmap, bindex);
    950			else
    951				block_acked = 0;
    952			brcms_dbg_ht(wlc->hw->d11core,
    953				     "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
    954				     tid, seq, start_seq, bindex,
    955				     block_acked, index);
    956			/* if acked then clear bit and free packet */
    957			if (block_acked) {
    958				ini->txretry[index] = 0;
    959
    960				/*
    961				 * ampdu_ack_len:
    962				 *   number of acked aggregated frames
    963				 */
    964				/* ampdu_len: number of aggregated frames */
    965				brcms_c_ampdu_rate_status(wlc, tx_info, txs,
    966							  mcs);
    967				tx_info->flags |= IEEE80211_TX_STAT_ACK;
    968				tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
    969				tx_info->status.ampdu_ack_len =
    970					tx_info->status.ampdu_len = 1;
    971
    972				skb_pull(p, D11_PHY_HDR_LEN);
    973				skb_pull(p, D11_TXH_LEN);
    974
    975				ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
    976							    p);
    977				ack_recd = true;
    978				suc_mpdu++;
    979			}
    980		}
    981		/* either retransmit or send bar if ack not recd */
    982		if (!ack_recd) {
    983			if (retry && (ini->txretry[index] < (int)retry_limit)) {
    984				int ret;
    985				ini->txretry[index]++;
    986				ret = brcms_c_txfifo(wlc, queue, p);
    987				/*
    988				 * We shouldn't be out of space in the DMA
    989				 * ring here since we're reinserting a frame
    990				 * that was just pulled out.
    991				 */
    992				WARN_ONCE(ret, "queue %d out of txds\n", queue);
    993			} else {
    994				/* Retry timeout */
    995				ieee80211_tx_info_clear_status(tx_info);
    996				tx_info->status.ampdu_ack_len = 0;
    997				tx_info->status.ampdu_len = 1;
    998				tx_info->flags |=
    999				    IEEE80211_TX_STAT_AMPDU_NO_BACK;
   1000				skb_pull(p, D11_PHY_HDR_LEN);
   1001				skb_pull(p, D11_TXH_LEN);
   1002				brcms_dbg_ht(wlc->hw->d11core,
   1003					     "BA Timeout, seq %d\n",
   1004					     seq);
   1005				ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
   1006							    p);
   1007			}
   1008		}
   1009		tot_mpdu++;
   1010
   1011		/* break out if last packet of ampdu */
   1012		if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
   1013		    TXC_AMPDU_LAST)
   1014			break;
   1015
   1016		p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
   1017	}
   1018
   1019	/* update rate state */
   1020	brcms_c_antsel_antsel2id(wlc->asi, mimoantsel);
   1021}
   1022
   1023void
   1024brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
   1025		     struct sk_buff *p, struct tx_status *txs)
   1026{
   1027	struct brcms_c_info *wlc = ampdu->wlc;
   1028	u32 s1 = 0, s2 = 0;
   1029
   1030	/* BMAC_NOTE: For the split driver, second level txstatus comes later
   1031	 * So if the ACK was received then wait for the second level else just
   1032	 * call the first one
   1033	 */
   1034	if (txs->status & TX_STATUS_ACK_RCV) {
   1035		u8 status_delay = 0;
   1036
   1037		/* wait till the next 8 bytes of txstatus is available */
   1038		s1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(frmtxstatus));
   1039		while ((s1 & TXS_V) == 0) {
   1040			udelay(1);
   1041			status_delay++;
   1042			if (status_delay > 10)
   1043				return; /* error condition */
   1044			s1 = bcma_read32(wlc->hw->d11core,
   1045					 D11REGOFFS(frmtxstatus));
   1046		}
   1047
   1048		s2 = bcma_read32(wlc->hw->d11core, D11REGOFFS(frmtxstatus2));
   1049	}
   1050
   1051	if (scb) {
   1052		brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
   1053	} else {
   1054		/* loop through all pkts and free */
   1055		u8 queue = txs->frameid & TXFID_QUEUE_MASK;
   1056		struct d11txh *txh;
   1057		u16 mcl;
   1058		while (p) {
   1059			txh = (struct d11txh *) p->data;
   1060			trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
   1061					   sizeof(*txh));
   1062			mcl = le16_to_cpu(txh->MacTxControlLow);
   1063			brcmu_pkt_buf_free_skb(p);
   1064			/* break out if last packet of ampdu */
   1065			if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
   1066			    TXC_AMPDU_LAST)
   1067				break;
   1068			p = dma_getnexttxp(wlc->hw->di[queue],
   1069					   DMA_RANGE_TRANSMITTED);
   1070		}
   1071	}
   1072}
   1073
   1074void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc)
   1075{
   1076	char template[T_RAM_ACCESS_SZ * 2];
   1077
   1078	/* driver needs to write the ta in the template; ta is at offset 16 */
   1079	memset(template, 0, sizeof(template));
   1080	memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
   1081	brcms_b_write_template_ram(wlc->hw, (T_BA_TPL_BASE + 16),
   1082				  (T_RAM_ACCESS_SZ * 2),
   1083				  template);
   1084}
   1085
   1086bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid)
   1087{
   1088	return wlc->ampdu->ini_enable[tid];
   1089}
   1090
   1091void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu)
   1092{
   1093	struct brcms_c_info *wlc = ampdu->wlc;
   1094
   1095	/*
   1096	 * Extend ucode internal watchdog timer to
   1097	 * match larger received frames
   1098	 */
   1099	if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
   1100	    IEEE80211_HT_MAX_AMPDU_64K) {
   1101		brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
   1102		brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
   1103	} else {
   1104		brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
   1105		brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
   1106	}
   1107}
   1108
   1109/*
   1110 * callback function that helps invalidating ampdu packets in a DMA queue
   1111 */
   1112static void dma_cb_fn_ampdu(void *txi, void *arg_a)
   1113{
   1114	struct ieee80211_sta *sta = arg_a;
   1115	struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi;
   1116
   1117	if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
   1118	    (tx_info->rate_driver_data[0] == sta || sta == NULL))
   1119		tx_info->rate_driver_data[0] = NULL;
   1120}
   1121
   1122/*
   1123 * When a remote party is no longer available for ampdu communication, any
   1124 * pending tx ampdu packets in the driver have to be flushed.
   1125 */
   1126void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
   1127		     struct ieee80211_sta *sta, u16 tid)
   1128{
   1129	brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
   1130}