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