Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010 Broadcom Corporation
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0011  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0013  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0014  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 #include <net/mac80211.h>
0017 
0018 #include "rate.h"
0019 #include "scb.h"
0020 #include "phy/phy_hal.h"
0021 #include "antsel.h"
0022 #include "main.h"
0023 #include "ampdu.h"
0024 #include "debug.h"
0025 #include "brcms_trace_events.h"
0026 
0027 /* max number of mpdus in an ampdu */
0028 #define AMPDU_MAX_MPDU          32
0029 /* max number of mpdus in an ampdu to a legacy */
0030 #define AMPDU_NUM_MPDU_LEGACY       16
0031 /* max Tx ba window size (in pdu) */
0032 #define AMPDU_TX_BA_MAX_WSIZE       64
0033 /* default Tx ba window size (in pdu) */
0034 #define AMPDU_TX_BA_DEF_WSIZE       64
0035 /* default Rx ba window size (in pdu) */
0036 #define AMPDU_RX_BA_DEF_WSIZE       64
0037 /* max Rx ba window size (in pdu) */
0038 #define AMPDU_RX_BA_MAX_WSIZE       64
0039 /* max dur of tx ampdu (in msec) */
0040 #define AMPDU_MAX_DUR           5
0041 /* default tx retry limit */
0042 #define AMPDU_DEF_RETRY_LIMIT       5
0043 /* default tx retry limit at reg rate */
0044 #define AMPDU_DEF_RR_RETRY_LIMIT    2
0045 /* default ffpld reserved bytes */
0046 #define AMPDU_DEF_FFPLD_RSVD        2048
0047 /* # of inis to be freed on detach */
0048 #define AMPDU_INI_FREE          10
0049 /* max # of mpdus released at a time */
0050 #define AMPDU_SCB_MAX_RELEASE       20
0051 
0052 #define NUM_FFPLD_FIFO 4    /* number of fifo concerned by pre-loading */
0053 #define FFPLD_TX_MAX_UNFL   200 /* default value of the average number of ampdu
0054                  * without underflows
0055                  */
0056 #define FFPLD_MPDU_SIZE 1800    /* estimate of maximum mpdu size */
0057 #define FFPLD_MAX_MCS 23    /* we don't deal with mcs 32 */
0058 #define FFPLD_PLD_INCR 1000 /* increments in bytes */
0059 #define FFPLD_MAX_AMPDU_CNT 5000    /* maximum number of ampdu we
0060                      * accumulate between resets.
0061                      */
0062 
0063 #define AMPDU_DELIMITER_LEN 4
0064 
0065 /* max allowed number of mpdus in an ampdu (2 streams) */
0066 #define AMPDU_NUM_MPDU      16
0067 
0068 #define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
0069 
0070 /* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
0071 #define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\
0072     AMPDU_DELIMITER_LEN + 3\
0073     + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
0074 
0075 /* modulo add/sub, bound = 2^k */
0076 #define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
0077 #define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
0078 
0079 /* structure to hold tx fifo information and pre-loading state
0080  * counters specific to tx underflows of ampdus
0081  * some counters might be redundant with the ones in wlc or ampdu structures.
0082  * This allows to maintain a specific state independently of
0083  * how often and/or when the wlc counters are updated.
0084  *
0085  * ampdu_pld_size: number of bytes to be pre-loaded
0086  * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu
0087  * prev_txfunfl: num of underflows last read from the HW macstats counter
0088  * accum_txfunfl: num of underflows since we modified pld params
0089  * accum_txampdu: num of tx ampdu since we modified pld params
0090  * prev_txampdu: previous reading of tx ampdu
0091  * dmaxferrate: estimated dma avg xfer rate in kbits/sec
0092  */
0093 struct brcms_fifo_info {
0094     u16 ampdu_pld_size;
0095     u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1];
0096     u16 prev_txfunfl;
0097     u32 accum_txfunfl;
0098     u32 accum_txampdu;
0099     u32 prev_txampdu;
0100     u32 dmaxferrate;
0101 };
0102 
0103 /* AMPDU module specific state
0104  *
0105  * wlc: pointer to main wlc structure
0106  * scb_handle: scb cubby handle to retrieve data from scb
0107  * ini_enable: per-tid initiator enable/disable of ampdu
0108  * ba_tx_wsize: Tx ba window size (in pdu)
0109  * ba_rx_wsize: Rx ba window size (in pdu)
0110  * retry_limit: mpdu transmit retry limit
0111  * rr_retry_limit: mpdu transmit retry limit at regular rate
0112  * retry_limit_tid: per-tid mpdu transmit retry limit
0113  * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate
0114  * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
0115  * max_pdu: max pdus allowed in ampdu
0116  * dur: max duration of an ampdu (in msec)
0117  * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
0118  * ffpld_rsvd: number of bytes to reserve for preload
0119  * max_txlen: max size of ampdu per mcs, bw and sgi
0120  * mfbr: enable multiple fallback rate
0121  * tx_max_funl: underflows should be kept such that
0122  *      (tx_max_funfl*underflows) < tx frames
0123  * fifo_tb: table of fifo infos
0124  */
0125 struct ampdu_info {
0126     struct brcms_c_info *wlc;
0127     int scb_handle;
0128     u8 ini_enable[AMPDU_MAX_SCB_TID];
0129     u8 ba_tx_wsize;
0130     u8 ba_rx_wsize;
0131     u8 retry_limit;
0132     u8 rr_retry_limit;
0133     u8 retry_limit_tid[AMPDU_MAX_SCB_TID];
0134     u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
0135     u8 mpdu_density;
0136     s8 max_pdu;
0137     u8 dur;
0138     u8 rx_factor;
0139     u32 ffpld_rsvd;
0140     u32 max_txlen[MCS_TABLE_SIZE][2][2];
0141     bool mfbr;
0142     u32 tx_max_funl;
0143     struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO];
0144 };
0145 
0146 /* used for flushing ampdu packets */
0147 struct cb_del_ampdu_pars {
0148     struct ieee80211_sta *sta;
0149     u16 tid;
0150 };
0151 
0152 static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
0153 {
0154     u32 rate, mcs;
0155 
0156     for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
0157         /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
0158         /* 20MHz, No SGI */
0159         rate = mcs_2_rate(mcs, false, false);
0160         ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
0161         /* 40 MHz, No SGI */
0162         rate = mcs_2_rate(mcs, true, false);
0163         ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
0164         /* 20MHz, SGI */
0165         rate = mcs_2_rate(mcs, false, true);
0166         ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
0167         /* 40 MHz, SGI */
0168         rate = mcs_2_rate(mcs, true, true);
0169         ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
0170     }
0171 }
0172 
0173 static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
0174 {
0175     if (BRCMS_PHY_11N_CAP(ampdu->wlc->band))
0176         return true;
0177     else
0178         return false;
0179 }
0180 
0181 static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
0182 {
0183     struct brcms_c_info *wlc = ampdu->wlc;
0184     struct bcma_device *core = wlc->hw->d11core;
0185 
0186     wlc->pub->_ampdu = false;
0187 
0188     if (on) {
0189         if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
0190             brcms_err(core, "wl%d: driver not nmode enabled\n",
0191                   wlc->pub->unit);
0192             return -ENOTSUPP;
0193         }
0194         if (!brcms_c_ampdu_cap(ampdu)) {
0195             brcms_err(core, "wl%d: device not ampdu capable\n",
0196                   wlc->pub->unit);
0197             return -ENOTSUPP;
0198         }
0199         wlc->pub->_ampdu = on;
0200     }
0201 
0202     return 0;
0203 }
0204 
0205 static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
0206 {
0207     int i, j;
0208     struct brcms_fifo_info *fifo;
0209 
0210     for (j = 0; j < NUM_FFPLD_FIFO; j++) {
0211         fifo = (ampdu->fifo_tb + j);
0212         fifo->ampdu_pld_size = 0;
0213         for (i = 0; i <= FFPLD_MAX_MCS; i++)
0214             fifo->mcs2ampdu_table[i] = 255;
0215         fifo->dmaxferrate = 0;
0216         fifo->accum_txampdu = 0;
0217         fifo->prev_txfunfl = 0;
0218         fifo->accum_txfunfl = 0;
0219 
0220     }
0221 }
0222 
0223 struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
0224 {
0225     struct ampdu_info *ampdu;
0226     int i;
0227 
0228     ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
0229     if (!ampdu)
0230         return NULL;
0231 
0232     ampdu->wlc = wlc;
0233 
0234     for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
0235         ampdu->ini_enable[i] = true;
0236     /* Disable ampdu for VO by default */
0237     ampdu->ini_enable[PRIO_8021D_VO] = false;
0238     ampdu->ini_enable[PRIO_8021D_NC] = false;
0239 
0240     /* Disable ampdu for BK by default since not enough fifo space */
0241     ampdu->ini_enable[PRIO_8021D_NONE] = false;
0242     ampdu->ini_enable[PRIO_8021D_BK] = false;
0243 
0244     ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE;
0245     ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE;
0246     ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
0247     ampdu->max_pdu = AUTO;
0248     ampdu->dur = AMPDU_MAX_DUR;
0249 
0250     ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
0251     /*
0252      * bump max ampdu rcv size to 64k for all 11n
0253      * devices except 4321A0 and 4321A1
0254      */
0255     if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
0256         ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
0257     else
0258         ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K;
0259     ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT;
0260     ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT;
0261 
0262     for (i = 0; i < AMPDU_MAX_SCB_TID; i++) {
0263         ampdu->retry_limit_tid[i] = ampdu->retry_limit;
0264         ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit;
0265     }
0266 
0267     brcms_c_scb_ampdu_update_max_txlen(ampdu, ampdu->dur);
0268     ampdu->mfbr = false;
0269     /* try to set ampdu to the default value */
0270     brcms_c_ampdu_set(ampdu, wlc->pub->_ampdu);
0271 
0272     ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL;
0273     brcms_c_ffpld_init(ampdu);
0274 
0275     return ampdu;
0276 }
0277 
0278 void brcms_c_ampdu_detach(struct ampdu_info *ampdu)
0279 {
0280     kfree(ampdu);
0281 }
0282 
0283 static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
0284                         struct scb *scb)
0285 {
0286     struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
0287     int i;
0288 
0289     scb_ampdu->max_pdu = AMPDU_NUM_MPDU;
0290 
0291     /* go back to legacy size if some preloading is occurring */
0292     for (i = 0; i < NUM_FFPLD_FIFO; i++) {
0293         if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR)
0294             scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY;
0295     }
0296 
0297     /* apply user override */
0298     if (ampdu->max_pdu != AUTO)
0299         scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
0300 
0301     scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu,
0302                    AMPDU_SCB_MAX_RELEASE);
0303 
0304     if (scb_ampdu->max_rx_ampdu_bytes)
0305         scb_ampdu->release = min_t(u8, scb_ampdu->release,
0306             scb_ampdu->max_rx_ampdu_bytes / 1600);
0307 
0308     scb_ampdu->release = min(scb_ampdu->release,
0309                  ampdu->fifo_tb[TX_AC_BE_FIFO].
0310                  mcs2ampdu_table[FFPLD_MAX_MCS]);
0311 }
0312 
0313 static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu)
0314 {
0315     brcms_c_scb_ampdu_update_config(ampdu, &ampdu->wlc->pri_scb);
0316 }
0317 
0318 static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
0319 {
0320     int i;
0321     u32 phy_rate, dma_rate, tmp;
0322     u8 max_mpdu;
0323     struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f);
0324 
0325     /* recompute the dma rate */
0326     /* note : we divide/multiply by 100 to avoid integer overflows */
0327     max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
0328              AMPDU_NUM_MPDU_LEGACY);
0329     phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
0330     dma_rate =
0331         (((phy_rate / 100) *
0332           (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
0333          / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
0334     fifo->dmaxferrate = dma_rate;
0335 
0336     /* fill up the mcs2ampdu table; do not recalc the last mcs */
0337     dma_rate = dma_rate >> 7;
0338     for (i = 0; i < FFPLD_MAX_MCS; i++) {
0339         /* shifting to keep it within integer range */
0340         phy_rate = mcs_2_rate(i, true, false) >> 7;
0341         if (phy_rate > dma_rate) {
0342             tmp = ((fifo->ampdu_pld_size * phy_rate) /
0343                    ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
0344             tmp = min_t(u32, tmp, 255);
0345             fifo->mcs2ampdu_table[i] = (u8) tmp;
0346         }
0347     }
0348 }
0349 
0350 /* evaluate the dma transfer rate using the tx underflows as feedback.
0351  * If necessary, increase tx fifo preloading. If not enough,
0352  * decrease maximum ampdu size for each mcs till underflows stop
0353  * Return 1 if pre-loading not active, -1 if not an underflow event,
0354  * 0 if pre-loading module took care of the event.
0355  */
0356 static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
0357 {
0358     struct ampdu_info *ampdu = wlc->ampdu;
0359     u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
0360     u32 txunfl_ratio;
0361     u8 max_mpdu;
0362     u32 current_ampdu_cnt = 0;
0363     u16 max_pld_size;
0364     u32 new_txunfl;
0365     struct brcms_fifo_info *fifo = (ampdu->fifo_tb + fid);
0366     uint xmtfifo_sz;
0367     u16 cur_txunfl;
0368 
0369     /* return if we got here for a different reason than underflows */
0370     cur_txunfl = brcms_b_read_shm(wlc->hw,
0371                       M_UCODE_MACSTAT +
0372                       offsetof(struct macstat, txfunfl[fid]));
0373     new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
0374     if (new_txunfl == 0) {
0375         brcms_dbg_ht(wlc->hw->d11core,
0376                  "TX status FRAG set but no tx underflows\n");
0377         return -1;
0378     }
0379     fifo->prev_txfunfl = cur_txunfl;
0380 
0381     if (!ampdu->tx_max_funl)
0382         return 1;
0383 
0384     /* check if fifo is big enough */
0385     if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz))
0386         return -1;
0387 
0388     if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
0389         return 1;
0390 
0391     max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd;
0392     fifo->accum_txfunfl += new_txunfl;
0393 
0394     /* we need to wait for at least 10 underflows */
0395     if (fifo->accum_txfunfl < 10)
0396         return 0;
0397 
0398     brcms_dbg_ht(wlc->hw->d11core, "ampdu_count %d  tx_underflows %d\n",
0399              current_ampdu_cnt, fifo->accum_txfunfl);
0400 
0401     /*
0402        compute the current ratio of tx unfl per ampdu.
0403        When the current ampdu count becomes too
0404        big while the ratio remains small, we reset
0405        the current count in order to not
0406        introduce too big of a latency in detecting a
0407        large amount of tx underflows later.
0408      */
0409 
0410     txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
0411 
0412     if (txunfl_ratio > ampdu->tx_max_funl) {
0413         if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT)
0414             fifo->accum_txfunfl = 0;
0415 
0416         return 0;
0417     }
0418     max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
0419              AMPDU_NUM_MPDU_LEGACY);
0420 
0421     /* In case max value max_pdu is already lower than
0422        the fifo depth, there is nothing more we can do.
0423      */
0424 
0425     if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) {
0426         fifo->accum_txfunfl = 0;
0427         return 0;
0428     }
0429 
0430     if (fifo->ampdu_pld_size < max_pld_size) {
0431 
0432         /* increment by TX_FIFO_PLD_INC bytes */
0433         fifo->ampdu_pld_size += FFPLD_PLD_INCR;
0434         if (fifo->ampdu_pld_size > max_pld_size)
0435             fifo->ampdu_pld_size = max_pld_size;
0436 
0437         /* update scb release size */
0438         brcms_c_scb_ampdu_update_config_all(ampdu);
0439 
0440         /*
0441          * compute a new dma xfer rate for max_mpdu @ max mcs.
0442          * This is the minimum dma rate that can achieve no
0443          * underflow condition for the current mpdu size.
0444          *
0445          * note : we divide/multiply by 100 to avoid integer overflows
0446          */
0447         fifo->dmaxferrate =
0448             (((phy_rate / 100) *
0449               (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
0450              / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
0451 
0452         brcms_dbg_ht(wlc->hw->d11core,
0453                  "DMA estimated transfer rate %d; "
0454                  "pre-load size %d\n",
0455                  fifo->dmaxferrate, fifo->ampdu_pld_size);
0456     } else {
0457 
0458         /* decrease ampdu size */
0459         if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) {
0460             if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255)
0461                 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] =
0462                     AMPDU_NUM_MPDU_LEGACY - 1;
0463             else
0464                 fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1;
0465 
0466             /* recompute the table */
0467             brcms_c_ffpld_calc_mcs2ampdu_table(ampdu, fid);
0468 
0469             /* update scb release size */
0470             brcms_c_scb_ampdu_update_config_all(ampdu);
0471         }
0472     }
0473     fifo->accum_txfunfl = 0;
0474     return 0;
0475 }
0476 
0477 void
0478 brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
0479     u8 ba_wsize,        /* negotiated ba window size (in pdu) */
0480     uint max_rx_ampdu_bytes) /* from ht_cap in beacon */
0481 {
0482     struct scb_ampdu *scb_ampdu;
0483     struct scb_ampdu_tid_ini *ini;
0484     struct ampdu_info *ampdu = wlc->ampdu;
0485     struct scb *scb = &wlc->pri_scb;
0486     scb_ampdu = &scb->scb_ampdu;
0487 
0488     if (!ampdu->ini_enable[tid]) {
0489         brcms_err(wlc->hw->d11core, "%s: Rejecting tid %d\n",
0490               __func__, tid);
0491         return;
0492     }
0493 
0494     ini = &scb_ampdu->ini[tid];
0495     ini->tid = tid;
0496     ini->scb = scb_ampdu->scb;
0497     ini->ba_wsize = ba_wsize;
0498     scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
0499 }
0500 
0501 void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
0502                  struct brcms_c_info *wlc)
0503 {
0504     session->wlc = wlc;
0505     skb_queue_head_init(&session->skb_list);
0506     session->max_ampdu_len = 0;    /* determined from first MPDU */
0507     session->max_ampdu_frames = 0; /* determined from first MPDU */
0508     session->ampdu_len = 0;
0509     session->dma_len = 0;
0510 }
0511 
0512 /*
0513  * Preps the given packet for AMPDU based on the session data. If the
0514  * frame cannot be accomodated in the current session, -ENOSPC is
0515  * returned.
0516  */
0517 int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
0518                 struct sk_buff *p)
0519 {
0520     struct brcms_c_info *wlc = session->wlc;
0521     struct ampdu_info *ampdu = wlc->ampdu;
0522     struct scb *scb = &wlc->pri_scb;
0523     struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
0524     struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
0525     struct ieee80211_tx_rate *txrate = tx_info->status.rates;
0526     struct d11txh *txh = (struct d11txh *)p->data;
0527     unsigned ampdu_frames;
0528     u8 ndelim, tid;
0529     u8 *plcp;
0530     uint len;
0531     u16 mcl;
0532     bool fbr_iscck;
0533     bool rr;
0534 
0535     ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
0536     plcp = (u8 *)(txh + 1);
0537     fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
0538     len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
0539               BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
0540     len = roundup(len, 4) + (ndelim + 1) * AMPDU_DELIMITER_LEN;
0541 
0542     ampdu_frames = skb_queue_len(&session->skb_list);
0543     if (ampdu_frames != 0) {
0544         struct sk_buff *first;
0545 
0546         if (ampdu_frames + 1 > session->max_ampdu_frames ||
0547             session->ampdu_len + len > session->max_ampdu_len)
0548             return -ENOSPC;
0549 
0550         /*
0551          * We aren't really out of space if the new frame is of
0552          * a different priority, but we want the same behaviour
0553          * so return -ENOSPC anyway.
0554          *
0555          * XXX: The old AMPDU code did this, but is it really
0556          * necessary?
0557          */
0558         first = skb_peek(&session->skb_list);
0559         if (p->priority != first->priority)
0560             return -ENOSPC;
0561     }
0562 
0563     /*
0564      * Now that we're sure this frame can be accomodated, update the
0565      * session information.
0566      */
0567     session->ampdu_len += len;
0568     session->dma_len += p->len;
0569 
0570     tid = (u8)p->priority;
0571 
0572     /* Handle retry limits */
0573     if (txrate[0].count <= ampdu->rr_retry_limit_tid[tid]) {
0574         txrate[0].count++;
0575         rr = true;
0576     } else {
0577         txrate[1].count++;
0578         rr = false;
0579     }
0580 
0581     if (ampdu_frames == 0) {
0582         u8 plcp0, plcp3, is40, sgi, mcs;
0583         uint fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
0584         struct brcms_fifo_info *f = &ampdu->fifo_tb[fifo];
0585 
0586         if (rr) {
0587             plcp0 = plcp[0];
0588             plcp3 = plcp[3];
0589         } else {
0590             plcp0 = txh->FragPLCPFallback[0];
0591             plcp3 = txh->FragPLCPFallback[3];
0592 
0593         }
0594 
0595         /* Limit AMPDU size based on MCS */
0596         is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
0597         sgi = plcp3_issgi(plcp3) ? 1 : 0;
0598         mcs = plcp0 & ~MIMO_PLCP_40MHZ;
0599         session->max_ampdu_len = min(scb_ampdu->max_rx_ampdu_bytes,
0600                          ampdu->max_txlen[mcs][is40][sgi]);
0601 
0602         session->max_ampdu_frames = scb_ampdu->max_pdu;
0603         if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
0604             session->max_ampdu_frames =
0605                 min_t(u16, f->mcs2ampdu_table[mcs],
0606                       session->max_ampdu_frames);
0607         }
0608     }
0609 
0610     /*
0611      * Treat all frames as "middle" frames of AMPDU here. First and
0612      * last frames must be fixed up after all MPDUs have been prepped.
0613      */
0614     mcl = le16_to_cpu(txh->MacTxControlLow);
0615     mcl &= ~TXC_AMPDU_MASK;
0616     mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
0617     mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
0618     txh->MacTxControlLow = cpu_to_le16(mcl);
0619     txh->PreloadSize = 0;   /* always default to 0 */
0620 
0621     skb_queue_tail(&session->skb_list, p);
0622 
0623     return 0;
0624 }
0625 
0626 void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session)
0627 {
0628     struct brcms_c_info *wlc = session->wlc;
0629     struct ampdu_info *ampdu = wlc->ampdu;
0630     struct sk_buff *first, *last;
0631     struct d11txh *txh;
0632     struct ieee80211_tx_info *tx_info;
0633     struct ieee80211_tx_rate *txrate;
0634     u8 ndelim;
0635     u8 *plcp;
0636     uint len;
0637     uint fifo;
0638     struct brcms_fifo_info *f;
0639     u16 mcl;
0640     bool fbr;
0641     bool fbr_iscck;
0642     struct ieee80211_rts *rts;
0643     bool use_rts = false, use_cts = false;
0644     u16 dma_len = session->dma_len;
0645     u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
0646     u32 rspec = 0, rspec_fallback = 0;
0647     u32 rts_rspec = 0, rts_rspec_fallback = 0;
0648     u8 plcp0, is40, mcs;
0649     u16 mch;
0650     u8 preamble_type = BRCMS_GF_PREAMBLE;
0651     u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
0652     u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
0653     u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
0654 
0655     if (skb_queue_empty(&session->skb_list))
0656         return;
0657 
0658     first = skb_peek(&session->skb_list);
0659     last = skb_peek_tail(&session->skb_list);
0660 
0661     /* Need to fix up last MPDU first to adjust AMPDU length */
0662     txh = (struct d11txh *)last->data;
0663     fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
0664     f = &ampdu->fifo_tb[fifo];
0665 
0666     mcl = le16_to_cpu(txh->MacTxControlLow);
0667     mcl &= ~TXC_AMPDU_MASK;
0668     mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
0669     txh->MacTxControlLow = cpu_to_le16(mcl);
0670 
0671     /* remove the null delimiter after last mpdu */
0672     ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
0673     txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
0674     session->ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
0675 
0676     /* remove the pad len from last mpdu */
0677     fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
0678     len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
0679               BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
0680     session->ampdu_len -= roundup(len, 4) - len;
0681 
0682     /* Now fix up the first MPDU */
0683     tx_info = IEEE80211_SKB_CB(first);
0684     txrate = tx_info->status.rates;
0685     txh = (struct d11txh *)first->data;
0686     plcp = (u8 *)(txh + 1);
0687     rts = (struct ieee80211_rts *)&txh->rts_frame;
0688 
0689     mcl = le16_to_cpu(txh->MacTxControlLow);
0690     /* If only one MPDU leave it marked as last */
0691     if (first != last) {
0692         mcl &= ~TXC_AMPDU_MASK;
0693         mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
0694     }
0695     mcl |= TXC_STARTMSDU;
0696     if (ieee80211_is_rts(rts->frame_control)) {
0697         mcl |= TXC_SENDRTS;
0698         use_rts = true;
0699     }
0700     if (ieee80211_is_cts(rts->frame_control)) {
0701         mcl |= TXC_SENDCTS;
0702         use_cts = true;
0703     }
0704     txh->MacTxControlLow = cpu_to_le16(mcl);
0705 
0706     fbr = txrate[1].count > 0;
0707     if (!fbr)
0708         plcp0 = plcp[0];
0709     else
0710         plcp0 = txh->FragPLCPFallback[0];
0711 
0712     is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
0713     mcs = plcp0 & ~MIMO_PLCP_40MHZ;
0714 
0715     if (is40) {
0716         if (CHSPEC_SB_UPPER(wlc_phy_chanspec_get(wlc->band->pi)))
0717             mimo_ctlchbw = PHY_TXC1_BW_20MHZ_UP;
0718         else
0719             mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
0720     }
0721 
0722     /* rebuild the rspec and rspec_fallback */
0723     rspec = RSPEC_MIMORATE;
0724     rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
0725     if (plcp[0] & MIMO_PLCP_40MHZ)
0726         rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
0727 
0728     fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
0729     if (fbr_iscck) {
0730         rspec_fallback =
0731             cck_rspec(cck_phy2mac_rate(txh->FragPLCPFallback[0]));
0732     } else {
0733         rspec_fallback = RSPEC_MIMORATE;
0734         rspec_fallback |= txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
0735         if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
0736             rspec_fallback |= PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT;
0737     }
0738 
0739     if (use_rts || use_cts) {
0740         rts_rspec =
0741             brcms_c_rspec_to_rts_rspec(wlc, rspec,
0742                            false, mimo_ctlchbw);
0743         rts_rspec_fallback =
0744             brcms_c_rspec_to_rts_rspec(wlc, rspec_fallback,
0745                            false, mimo_ctlchbw);
0746     }
0747 
0748     BRCMS_SET_MIMO_PLCP_LEN(plcp, session->ampdu_len);
0749     /* mark plcp to indicate ampdu */
0750     BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
0751 
0752     /* reset the mixed mode header durations */
0753     if (txh->MModeLen) {
0754         u16 mmodelen = brcms_c_calc_lsig_len(wlc, rspec,
0755                              session->ampdu_len);
0756         txh->MModeLen = cpu_to_le16(mmodelen);
0757         preamble_type = BRCMS_MM_PREAMBLE;
0758     }
0759     if (txh->MModeFbrLen) {
0760         u16 mmfbrlen = brcms_c_calc_lsig_len(wlc, rspec_fallback,
0761                              session->ampdu_len);
0762         txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
0763         fbr_preamble_type = BRCMS_MM_PREAMBLE;
0764     }
0765 
0766     /* set the preload length */
0767     if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
0768         dma_len = min(dma_len, f->ampdu_pld_size);
0769         txh->PreloadSize = cpu_to_le16(dma_len);
0770     } else {
0771         txh->PreloadSize = 0;
0772     }
0773 
0774     mch = le16_to_cpu(txh->MacTxControlHigh);
0775 
0776     /* update RTS dur fields */
0777     if (use_rts || use_cts) {
0778         u16 durid;
0779         if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
0780             TXC_PREAMBLE_RTS_MAIN_SHORT)
0781             rts_preamble_type = BRCMS_SHORT_PREAMBLE;
0782 
0783         if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
0784              TXC_PREAMBLE_RTS_FB_SHORT)
0785             rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
0786 
0787         durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
0788                            rspec, rts_preamble_type,
0789                            preamble_type,
0790                            session->ampdu_len, true);
0791         rts->duration = cpu_to_le16(durid);
0792         durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
0793                            rts_rspec_fallback,
0794                            rspec_fallback,
0795                            rts_fbr_preamble_type,
0796                            fbr_preamble_type,
0797                            session->ampdu_len, true);
0798         txh->RTSDurFallback = cpu_to_le16(durid);
0799         /* set TxFesTimeNormal */
0800         txh->TxFesTimeNormal = rts->duration;
0801         /* set fallback rate version of TxFesTimeNormal */
0802         txh->TxFesTimeFallback = txh->RTSDurFallback;
0803     }
0804 
0805     /* set flag and plcp for fallback rate */
0806     if (fbr) {
0807         mch |= TXC_AMPDU_FBR;
0808         txh->MacTxControlHigh = cpu_to_le16(mch);
0809         BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
0810         BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
0811     }
0812 
0813     brcms_dbg_ht(wlc->hw->d11core, "wl%d: count %d ampdu_len %d\n",
0814              wlc->pub->unit, skb_queue_len(&session->skb_list),
0815              session->ampdu_len);
0816 }
0817 
0818 static void
0819 brcms_c_ampdu_rate_status(struct brcms_c_info *wlc,
0820               struct ieee80211_tx_info *tx_info,
0821               struct tx_status *txs, u8 mcs)
0822 {
0823     struct ieee80211_tx_rate *txrate = tx_info->status.rates;
0824     int i;
0825 
0826     /* clear the rest of the rates */
0827     for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
0828         txrate[i].idx = -1;
0829         txrate[i].count = 0;
0830     }
0831 }
0832 
0833 static void
0834 brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
0835                   struct sk_buff *p, struct tx_status *txs,
0836                   u32 s1, u32 s2)
0837 {
0838     struct scb_ampdu *scb_ampdu;
0839     struct brcms_c_info *wlc = ampdu->wlc;
0840     struct scb_ampdu_tid_ini *ini;
0841     u8 bitmap[8], queue, tid;
0842     struct d11txh *txh;
0843     u8 *plcp;
0844     struct ieee80211_hdr *h;
0845     u16 seq, start_seq = 0, bindex, index, mcl;
0846     u8 mcs = 0;
0847     bool ba_recd = false, ack_recd = false;
0848     u8 suc_mpdu = 0, tot_mpdu = 0;
0849     uint supr_status;
0850     bool retry = true;
0851     u16 mimoantsel = 0;
0852     u8 retry_limit;
0853     struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
0854 
0855 #ifdef DEBUG
0856     u8 hole[AMPDU_MAX_MPDU];
0857     memset(hole, 0, sizeof(hole));
0858 #endif
0859 
0860     scb_ampdu = &scb->scb_ampdu;
0861     tid = (u8) (p->priority);
0862 
0863     ini = &scb_ampdu->ini[tid];
0864     retry_limit = ampdu->retry_limit_tid[tid];
0865     memset(bitmap, 0, sizeof(bitmap));
0866     queue = txs->frameid & TXFID_QUEUE_MASK;
0867     supr_status = txs->status & TX_STATUS_SUPR_MASK;
0868 
0869     if (txs->status & TX_STATUS_ACK_RCV) {
0870         WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
0871         start_seq = txs->sequence >> SEQNUM_SHIFT;
0872         bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >>
0873             TX_STATUS_BA_BMAP03_SHIFT;
0874 
0875         WARN_ON(s1 & TX_STATUS_INTERMEDIATE);
0876         WARN_ON(!(s1 & TX_STATUS_AMPDU));
0877 
0878         bitmap[0] |=
0879             (s1 & TX_STATUS_BA_BMAP47_MASK) <<
0880             TX_STATUS_BA_BMAP47_SHIFT;
0881         bitmap[1] = (s1 >> 8) & 0xff;
0882         bitmap[2] = (s1 >> 16) & 0xff;
0883         bitmap[3] = (s1 >> 24) & 0xff;
0884 
0885         bitmap[4] = s2 & 0xff;
0886         bitmap[5] = (s2 >> 8) & 0xff;
0887         bitmap[6] = (s2 >> 16) & 0xff;
0888         bitmap[7] = (s2 >> 24) & 0xff;
0889 
0890         ba_recd = true;
0891     } else {
0892         if (supr_status) {
0893             if (supr_status == TX_STATUS_SUPR_BADCH) {
0894                 brcms_dbg_ht(wlc->hw->d11core,
0895                       "%s: Pkt tx suppressed, illegal channel possibly %d\n",
0896                       __func__, CHSPEC_CHANNEL(
0897                       wlc->default_bss->chanspec));
0898             } else {
0899                 if (supr_status != TX_STATUS_SUPR_FRAG)
0900                     brcms_err(wlc->hw->d11core,
0901                           "%s: supr_status 0x%x\n",
0902                           __func__, supr_status);
0903             }
0904             /* no need to retry for badch; will fail again */
0905             if (supr_status == TX_STATUS_SUPR_BADCH ||
0906                 supr_status == TX_STATUS_SUPR_EXPTIME) {
0907                 retry = false;
0908             } else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
0909                 /* TX underflow:
0910                  *   try tuning pre-loading or ampdu size
0911                  */
0912             } else if (supr_status == TX_STATUS_SUPR_FRAG) {
0913                 /*
0914                  * if there were underflows, but pre-loading
0915                  * is not active, notify rate adaptation.
0916                  */
0917                 brcms_c_ffpld_check_txfunfl(wlc, queue);
0918             }
0919         } else if (txs->phyerr) {
0920             brcms_dbg_ht(wlc->hw->d11core,
0921                      "%s: ampdu tx phy error (0x%x)\n",
0922                      __func__, txs->phyerr);
0923         }
0924     }
0925 
0926     /* loop through all pkts and retry if not acked */
0927     while (p) {
0928         tx_info = IEEE80211_SKB_CB(p);
0929         txh = (struct d11txh *) p->data;
0930         mcl = le16_to_cpu(txh->MacTxControlLow);
0931         plcp = (u8 *) (txh + 1);
0932         h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
0933         seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
0934 
0935         trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
0936 
0937         if (tot_mpdu == 0) {
0938             mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
0939             mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
0940         }
0941 
0942         index = TX_SEQ_TO_INDEX(seq);
0943         ack_recd = false;
0944         if (ba_recd) {
0945             int block_acked;
0946 
0947             bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
0948             if (bindex < AMPDU_TX_BA_MAX_WSIZE)
0949                 block_acked = isset(bitmap, bindex);
0950             else
0951                 block_acked = 0;
0952             brcms_dbg_ht(wlc->hw->d11core,
0953                      "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
0954                      tid, seq, start_seq, bindex,
0955                      block_acked, index);
0956             /* if acked then clear bit and free packet */
0957             if (block_acked) {
0958                 ini->txretry[index] = 0;
0959 
0960                 /*
0961                  * ampdu_ack_len:
0962                  *   number of acked aggregated frames
0963                  */
0964                 /* ampdu_len: number of aggregated frames */
0965                 brcms_c_ampdu_rate_status(wlc, tx_info, txs,
0966                               mcs);
0967                 tx_info->flags |= IEEE80211_TX_STAT_ACK;
0968                 tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
0969                 tx_info->status.ampdu_ack_len =
0970                     tx_info->status.ampdu_len = 1;
0971 
0972                 skb_pull(p, D11_PHY_HDR_LEN);
0973                 skb_pull(p, D11_TXH_LEN);
0974 
0975                 ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
0976                                 p);
0977                 ack_recd = true;
0978                 suc_mpdu++;
0979             }
0980         }
0981         /* either retransmit or send bar if ack not recd */
0982         if (!ack_recd) {
0983             if (retry && (ini->txretry[index] < (int)retry_limit)) {
0984                 int ret;
0985                 ini->txretry[index]++;
0986                 ret = brcms_c_txfifo(wlc, queue, p);
0987                 /*
0988                  * We shouldn't be out of space in the DMA
0989                  * ring here since we're reinserting a frame
0990                  * that was just pulled out.
0991                  */
0992                 WARN_ONCE(ret, "queue %d out of txds\n", queue);
0993             } else {
0994                 /* Retry timeout */
0995                 ieee80211_tx_info_clear_status(tx_info);
0996                 tx_info->status.ampdu_ack_len = 0;
0997                 tx_info->status.ampdu_len = 1;
0998                 tx_info->flags |=
0999                     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 
1023 void
1024 brcms_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 
1074 void 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 
1086 bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid)
1087 {
1088     return wlc->ampdu->ini_enable[tid];
1089 }
1090 
1091 void 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  */
1112 static 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  */
1126 void 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 }