]> git.karo-electronics.de Git - linux-beck.git/commitdiff
staging: brcm80211: remove static function prototypes from main.c
authorArend van Spriel <arend@broadcom.com>
Thu, 1 Sep 2011 09:17:00 +0000 (11:17 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 6 Sep 2011 23:38:49 +0000 (16:38 -0700)
Function prototypes for static functions are not strictly needed and
considered unwanted by linux community. This patch reorders the
functions in brcmsmac/main.c and gets rid of the prototypes.

Reported-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Roland Vossen <rvossen@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/brcm80211/brcmsmac/main.c

index 3aa03090b0189dbe183ee458a31dba504a59ed87..2825b1e755b1bab4c157ba6e5342104ae74593af 100644 (file)
@@ -285,181 +285,6 @@ struct brcms_b_state {
        u32 preamble_ovr;       /* preamble override */
 };
 
-/* local prototypes */
-static void brcms_b_clkctl_clk(struct brcms_hardware *wlc, uint mode);
-
-/* used by wlc_wakeucode_init() */
-static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
-                           const struct d11init *inits);
-static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
-                           const uint nbytes);
-static void brcms_ucode_download(struct brcms_hardware *wlc);
-static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw);
-
-/* used by brcms_c_down() */
-static void brcms_c_flushqueues(struct brcms_c_info *wlc);
-
-static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs);
-static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw);
-static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw);
-static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
-                                      uint tx_fifo);
-static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
-                                  uint tx_fifo);
-
-/* Low Level Prototypes */
-
-struct brcms_b_state;
-
-static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device,
-                         uint unit, bool piomode, void *regsva,
-                         struct pci_dev *btparam);
-
-/* up/down, reset, clk */
-static void brcms_b_reset(struct brcms_hardware *wlc_hw);
-static int brcms_b_state_get(struct brcms_hardware *wlc_hw,
-                             struct brcms_b_state *state);
-static void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf,
-                                  uint *len);
-
-static void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw,
-                                 u8 *ea);
-
-static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw);
-static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw);
-
-static void brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw,
-                                  int match_reg_offset,
-                                  const u8 *addr);
-static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin);
-static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax);
-
-static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, u16 SRL,
-                                   u16 LRL);
-
-static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw);
-
-static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set,
-                          u32 req_bit);
-static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw,
-                              u32 antsel_avail);
-static int brcms_b_bandtype(struct brcms_hardware *wlc_hw);
-static void brcms_b_info_init(struct brcms_hardware *wlc_hw);
-static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want);
-static u16 brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset,
-                                  u32 sel);
-static void brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset,
-                                 u16 v, u32 sel);
-static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk);
-static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme);
-static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw);
-static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw);
-static bool brcms_c_validboardtype(struct brcms_hardware *wlc);
-static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw);
-static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw);
-static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw);
-static void brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init);
-static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw);
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool want, u32 flags);
-static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw);
-static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw);
-static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc);
-static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask);
-static void brcms_c_gpio_init(struct brcms_c_info *wlc);
-static void brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw,
-                                         u16 bcn[], int len);
-static void brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw,
-                                         u16 bcn[], int len);
-static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec);
-static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit);
-static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
-                            u16 chanspec);
-static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
-                                       bool shortslot);
-static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw);
-static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
-                                            u8 rate);
-
-static u16 brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc,
-                                              struct ieee80211_hw *hw,
-                                              struct sk_buff *p,
-                                              struct scb *scb, uint frag,
-                                              uint nfrags, uint queue,
-                                              uint next_frag_len,
-                                              struct wsec_key *key,
-                                              u32 rspec_override);
-static void brcms_c_bss_default_init(struct brcms_c_info *wlc);
-static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc);
-static u32 mac80211_wlc_set_nrate(struct brcms_c_info *wlc,
-                                        struct brcms_band *cur_band,
-                                        u32 int_val);
-static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc);
-static void brcms_c_watchdog(void *arg);
-static void brcms_c_watchdog_by_timer(void *arg);
-static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate);
-static int brcms_c_set_rateset(struct brcms_c_info *wlc,
-                              struct brcms_c_rateset *rs_arg);
-static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc);
-
-/* send and receive */
-static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc);
-static void brcms_c_txq_free(struct brcms_c_info *wlc,
-                        struct brcms_txq_info *qi);
-static void brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
-                                    struct brcms_txq_info *qi,
-                                    bool on, int prio);
-static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc);
-static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rate,
-                                uint length, u8 *plcp);
-static void brcms_c_compute_ofdm_plcp(u32 rate, uint length, u8 *plcp);
-static void brcms_c_compute_mimo_plcp(u32 rate, uint length, u8 *plcp);
-static u16 brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
-                                   u8 preamble_type, uint next_frag_len);
-static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
-                            struct brcms_d11rxhdr *rxh);
-static void brcms_c_recvctl(struct brcms_c_info *wlc,
-                       struct d11rxhdr *rxh, struct sk_buff *p);
-static uint brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 rate,
-                              u8 preamble_type, uint dur);
-static uint brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rate,
-                             u8 preamble_type);
-static uint brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rate,
-                             u8 preamble_type);
-/* interrupt, up/down, band */
-static void brcms_c_setband(struct brcms_c_info *wlc, uint bandunit);
-static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc);
-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
-                                    u16 chanspec);
-static void brcms_c_bsinit(struct brcms_c_info *wlc);
-static int brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle,
-                             bool isOFDM, bool writeToShm);
-static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc);
-static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc);
-static void brcms_c_radio_timer(void *arg);
-static void brcms_c_radio_enable(struct brcms_c_info *wlc);
-static void brcms_c_radio_upd(struct brcms_c_info *wlc);
-
-/* scan, association, BSS */
-static uint brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rate,
-                            u8 preamble_type);
-static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap);
-static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val);
-static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val);
-static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx);
-
-static void brcms_c_wme_retries_write(struct brcms_c_info *wlc);
-static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc);
-static uint brcms_c_attach_module(struct brcms_c_info *wlc);
-static void brcms_c_detach_module(struct brcms_c_info *wlc);
-static void brcms_c_timers_deinit(struct brcms_c_info *wlc);
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc);
-static uint brcms_c_down_del_timer(struct brcms_c_info *wlc);
-static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc);
-static int _brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
-                     struct brcms_c_if *wlcif);
-static void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, u16 bcn[],
-                                         int len, bool both);
-
 const u8 prio2fifo[NUMPRIO] = {
        TX_AC_BE_FIFO,          /* 0    BE      AC_BE   Best Effort */
        TX_AC_BK_FIFO,          /* 1    BK      AC_BK   Background */
@@ -554,6 +379,44 @@ static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
        }
 }
 
+static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
+                               const struct d11init *inits)
+{
+       int i;
+       u8 *base;
+       u8 *addr;
+       u16 size;
+       u32 value;
+
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+       base = (u8 *)wlc_hw->regs;
+
+       for (i = 0; inits[i].addr != 0xffff; i++) {
+               size = le16_to_cpu(inits[i].size);
+               addr = base + le16_to_cpu(inits[i].addr);
+               value = le32_to_cpu(inits[i].value);
+               if (size == 2)
+                       W_REG((u16 *)addr, value);
+               else if (size == 4)
+                       W_REG((u32 *)addr, value);
+               else
+                       break;
+       }
+}
+
+static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
+{
+       u8 idx;
+       u16 addr[] = {
+               M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
+               M_HOST_FLAGS5
+       };
+
+       for (idx = 0; idx < MHFMAX; idx++)
+               brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
+}
+
 static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
 {
        struct wiphy *wiphy = wlc_hw->wlc->wiphy;
@@ -585,6 +448,30 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
        }
 }
 
+static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
+{
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
+
+       wlc_hw->phyclk = clk;
+
+       if (OFF == clk) {       /* clear gmode bit, put phy into reset */
+
+               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
+                              (SICF_PRST | SICF_FGC));
+               udelay(1);
+               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
+               udelay(1);
+
+       } else {                /* take phy out of reset */
+
+               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
+               udelay(1);
+               ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
+               udelay(1);
+
+       }
+}
+
 /* switch to new band but leave it inactive */
 static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
 {
@@ -734,6 +621,36 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
        return morepending;
 }
 
+/* brcms_b_tx_fifo_suspended:
+ * Check the MAC's tx suspend status for a tx fifo.
+ *
+ * When the MAC acknowledges a tx suspend, it indicates that no more
+ * packets will be transmitted out the radio. This is independent of
+ * DMA channel suspension---the DMA may have finished suspending, or may still
+ * be pulling data into a tx fifo, by the time the MAC acks the suspend
+ * request.
+ */
+static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
+                                     uint tx_fifo)
+{
+       /* check that a suspend has been requested and is no longer pending */
+
+       /*
+        * for DMA mode, the suspend request is set in xmtcontrol of the DMA
+        * engine, and the tx fifo suspend at the lower end of the MAC is
+        * acknowledged in the chnstatus register.
+        *
+        * The tx fifo suspend completion is independent of the DMA suspend
+        * completion and may be acked before or after the DMA is suspended.
+        */
+       if (dma_txsuspended(wlc_hw->di[tx_fifo]) &&
+           (R_REG(&wlc_hw->regs->chnstatus) &
+            (1 << tx_fifo)) == 0)
+               return true;
+
+       return false;
+}
+
 /* second-level interrupt processing
  *   Return true if another dpc needs to be re-scheduled. false otherwise.
  *   Param 'bounded' indicates if applicable loops should be bounded.
@@ -845,6 +762,26 @@ int brcms_b_state_get(struct brcms_hardware *wlc_hw,
        return 0;
 }
 
+/* set initial host flags value */
+static void
+brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
+{
+       struct brcms_hardware *wlc_hw = wlc->hw;
+
+       memset(mhfs, 0, MHFMAX * sizeof(u16));
+
+       mhfs[MHF2] |= mhf2_init;
+
+       /* prohibit use of slowclock on multifunction boards */
+       if (wlc_hw->boardflags & BFL_NOPLLDOWN)
+               mhfs[MHF1] |= MHF1_FORCEFASTCLK;
+
+       if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
+               mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
+               mhfs[MHF1] |= MHF1_IQSWAP_WAR;
+       }
+}
+
 static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
 {
        uint i;
@@ -1058,26 +995,6 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
        }
 }
 
-/* set initial host flags value */
-static void
-brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
-{
-       struct brcms_hardware *wlc_hw = wlc->hw;
-
-       memset(mhfs, 0, MHFMAX * sizeof(u16));
-
-       mhfs[MHF2] |= mhf2_init;
-
-       /* prohibit use of slowclock on multifunction boards */
-       if (wlc_hw->boardflags & BFL_NOPLLDOWN)
-               mhfs[MHF1] |= MHF1_FORCEFASTCLK;
-
-       if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
-               mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
-               mhfs[MHF1] |= MHF1_IQSWAP_WAR;
-       }
-}
-
 /* set or clear ucode host flag bits
  * it has an optimization for no-change write
  * it only writes through shared memory when the core has clock;
@@ -1142,18 +1059,6 @@ brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
        }
 }
 
-static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
-{
-       u8 idx;
-       u16 addr[] = {
-               M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
-               M_HOST_FLAGS5
-       };
-
-       for (idx = 0; idx < MHFMAX; idx++)
-               brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
-}
-
 /* set the maccontrol register to desired reset state and
  * initialize the sw cache of the register
  */
@@ -1167,6 +1072,27 @@ static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
        brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
 }
 
+/*
+ * write the software state of maccontrol and
+ * overrides to the maccontrol register
+ */
+static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
+{
+       u32 maccontrol = wlc_hw->maccontrol;
+
+       /* OR in the wake bit if overridden */
+       if (wlc_hw->wake_override)
+               maccontrol |= MCTL_WAKE;
+
+       /* set AP and INFRA bits for mute if needed */
+       if (wlc_hw->mute_override) {
+               maccontrol &= ~(MCTL_AP);
+               maccontrol |= MCTL_INFRA;
+       }
+
+       W_REG(&wlc_hw->regs->maccontrol, maccontrol);
+}
+
 /* set or clear maccontrol bits */
 void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
 {
@@ -1189,27 +1115,6 @@ void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
        brcms_c_mctrl_write(wlc_hw);
 }
 
-/*
- * write the software state of maccontrol and
- * overrides to the maccontrol register
- */
-static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
-{
-       u32 maccontrol = wlc_hw->maccontrol;
-
-       /* OR in the wake bit if overridden */
-       if (wlc_hw->wake_override)
-               maccontrol |= MCTL_WAKE;
-
-       /* set AP and INFRA bits for mute if needed */
-       if (wlc_hw->mute_override) {
-               maccontrol &= ~(MCTL_AP);
-               maccontrol |= MCTL_INFRA;
-       }
-
-       W_REG(&wlc_hw->regs->maccontrol, maccontrol);
-}
-
 void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
                                 u32 override_bit)
 {
@@ -1420,28 +1325,113 @@ static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
        brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
 }
 
-/* band-specific init */
-static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
+static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
 {
-       struct brcms_hardware *wlc_hw = wlc->hw;
+       u16 phyctl;
+       u16 phytxant = wlc_hw->bmac_phytxant;
+       u16 mask = PHY_TXC_ANT_MASK;
 
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               wlc_hw->band->bandunit);
+       /* set the Probe Response frame phy control word */
+       phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
+       phyctl = (phyctl & ~mask) | phytxant;
+       brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
 
-       brcms_c_ucode_bsinit(wlc_hw);
+       /* set the Response (ACK/CTS) frame phy control word */
+       phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
+       phyctl = (phyctl & ~mask) | phytxant;
+       brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
+}
 
-       wlc_phy_init(wlc_hw->band->pi, chanspec);
+static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
+                                        u8 rate)
+{
+       uint i;
+       u8 plcp_rate = 0;
+       struct plcp_signal_rate_lookup {
+               u8 rate;
+               u8 signal_rate;
+       };
+       /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
+       const struct plcp_signal_rate_lookup rate_lookup[] = {
+               {BRCM_RATE_6M, 0xB},
+               {BRCM_RATE_9M, 0xF},
+               {BRCM_RATE_12M, 0xA},
+               {BRCM_RATE_18M, 0xE},
+               {BRCM_RATE_24M, 0x9},
+               {BRCM_RATE_36M, 0xD},
+               {BRCM_RATE_48M, 0x8},
+               {BRCM_RATE_54M, 0xC}
+       };
 
-       brcms_c_ucode_txant_set(wlc_hw);
+       for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
+               if (rate == rate_lookup[i].rate) {
+                       plcp_rate = rate_lookup[i].signal_rate;
+                       break;
+               }
+       }
 
-       /*
-        * cwmin is band-specific, update hardware
-        * with value for current band
+       /* Find the SHM pointer to the rate table entry by looking in the
+        * Direct-map Table
         */
-       brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
-       brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
+       return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
+}
 
-       brcms_b_update_slot_timing(wlc_hw,
+static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
+{
+       u8 rate;
+       u8 rates[8] = {
+               BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
+               BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
+       };
+       u16 entry_ptr;
+       u16 pctl1;
+       uint i;
+
+       if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
+               return;
+
+       /* walk the phy rate table and update the entries */
+       for (i = 0; i < ARRAY_SIZE(rates); i++) {
+               rate = rates[i];
+
+               entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
+
+               /* read the SHM Rate Table entry OFDM PCTL1 values */
+               pctl1 =
+                   brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
+
+               /* modify the value */
+               pctl1 &= ~PHY_TXC1_MODE_MASK;
+               pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
+
+               /* Update the SHM Rate Table entry OFDM PCTL1 values */
+               brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
+                                  pctl1);
+       }
+}
+
+/* band-specific init */
+static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
+{
+       struct brcms_hardware *wlc_hw = wlc->hw;
+
+       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+               wlc_hw->band->bandunit);
+
+       brcms_c_ucode_bsinit(wlc_hw);
+
+       wlc_phy_init(wlc_hw->band->pi, chanspec);
+
+       brcms_c_ucode_txant_set(wlc_hw);
+
+       /*
+        * cwmin is band-specific, update hardware
+        * with value for current band
+        */
+       brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
+       brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
+
+       brcms_b_update_slot_timing(wlc_hw,
                                    BAND_5G(wlc_hw->band->
                                            bandtype) ? true : wlc_hw->
                                    shortslot);
@@ -1459,30 +1449,6 @@ static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
        brcms_b_upd_synthpu(wlc_hw);
 }
 
-static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
-{
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
-
-       wlc_hw->phyclk = clk;
-
-       if (OFF == clk) {       /* clear gmode bit, put phy into reset */
-
-               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
-                              (SICF_PRST | SICF_FGC));
-               udelay(1);
-               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
-               udelay(1);
-
-       } else {                /* take phy out of reset */
-
-               ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
-               udelay(1);
-               ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
-               udelay(1);
-
-       }
-}
-
 /* Perform a soft reset of the PHY PLL */
 void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
 {
@@ -1689,6 +1655,29 @@ static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
        return macaddr;
 }
 
+/* power both the pll and external oscillator on/off */
+static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
+{
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
+
+       /*
+        * dont power down if plldown is false or
+        * we must poll hw radio disable
+        */
+       if (!want && wlc_hw->pllreq)
+               return;
+
+       if (wlc_hw->sih)
+               ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
+
+       wlc_hw->sbclk = want;
+       if (!wlc_hw->sbclk) {
+               wlc_hw->clk = false;
+               if (wlc_hw->band && wlc_hw->band->pi)
+                       wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+       }
+}
+
 /*
  * Return true if radio is disabled, otherwise false.
  * hw radio disable signal is an external pin, users activate it asynchronously
@@ -1990,6 +1979,23 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
        ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
 }
 
+static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
+                             const uint nbytes) {
+       struct d11regs *regs = wlc_hw->regs;
+       uint i;
+       uint count;
+
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+       count = (nbytes / sizeof(u32));
+
+       W_REG(&regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
+       (void)R_REG(&regs->objaddr);
+       for (i = 0; i < count; i++)
+               W_REG(&regs->objdata, le32_to_cpu(ucode[i]));
+
+}
+
 static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
 {
        struct brcms_c_info *wlc;
@@ -2020,66 +2026,6 @@ static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
        }
 }
 
-static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
-                             const uint nbytes) {
-       struct d11regs *regs = wlc_hw->regs;
-       uint i;
-       uint count;
-
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
-       count = (nbytes / sizeof(u32));
-
-       W_REG(&regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
-       (void)R_REG(&regs->objaddr);
-       for (i = 0; i < count; i++)
-               W_REG(&regs->objdata, le32_to_cpu(ucode[i]));
-
-}
-
-static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
-                           const struct d11init *inits)
-{
-       int i;
-       u8 *base;
-       u8 *addr;
-       u16 size;
-       u32 value;
-
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
-       base = (u8 *)wlc_hw->regs;
-
-       for (i = 0; inits[i].addr != 0xffff; i++) {
-               size = le16_to_cpu(inits[i].size);
-               addr = base + le16_to_cpu(inits[i].addr);
-               value = le32_to_cpu(inits[i].value);
-               if (size == 2)
-                       W_REG((u16 *)addr, value);
-               else if (size == 4)
-                       W_REG((u32 *)addr, value);
-               else
-                       break;
-       }
-}
-
-static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
-{
-       u16 phyctl;
-       u16 phytxant = wlc_hw->bmac_phytxant;
-       u16 mask = PHY_TXC_ANT_MASK;
-
-       /* set the Probe Response frame phy control word */
-       phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
-       phyctl = (phyctl & ~mask) | phytxant;
-       brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
-
-       /* set the Response (ACK/CTS) frame phy control word */
-       phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
-       phyctl = (phyctl & ~mask) | phytxant;
-       brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
-}
-
 void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
 {
        /* update sw state */
@@ -2259,6 +2205,28 @@ static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
        }
 }
 
+static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
+                                  uint tx_fifo)
+{
+       /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
+        * but need to be done here for PIO otherwise the watchdog will catch
+        * the inconsistency and fire
+        */
+       /* Two clients of this code, 11h Quiet period and scanning. */
+       if (wlc_hw->di[tx_fifo])
+               dma_txresume(wlc_hw->di[tx_fifo]);
+
+       /* allow core to sleep again */
+       if (wlc_hw->suspended_fifos == 0)
+               return;
+       else {
+               wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
+               if (wlc_hw->suspended_fifos == 0)
+                       brcms_c_ucode_wake_override_clear(wlc_hw,
+                                               BRCMS_WAKE_OVERRIDE_TXFIFO);
+       }
+}
+
 static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
 {
        u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
@@ -2295,58 +2263,6 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
                brcms_c_ucode_mute_override_clear(wlc_hw);
 }
 
-/* brcms_b_tx_fifo_suspended:
- * Check the MAC's tx suspend status for a tx fifo.
- *
- * When the MAC acknowledges a tx suspend, it indicates that no more
- * packets will be transmitted out the radio. This is independent of
- * DMA channel suspension---the DMA may have finished suspending, or may still
- * be pulling data into a tx fifo, by the time the MAC acks the suspend
- * request.
- */
-static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
-                                     uint tx_fifo)
-{
-       /* check that a suspend has been requested and is no longer pending */
-
-       /*
-        * for DMA mode, the suspend request is set in xmtcontrol of the DMA
-        * engine, and the tx fifo suspend at the lower end of the MAC is
-        * acknowledged in the chnstatus register.
-        *
-        * The tx fifo suspend completion is independent of the DMA suspend
-        * completion and may be acked before or after the DMA is suspended.
-        */
-       if (dma_txsuspended(wlc_hw->di[tx_fifo]) &&
-           (R_REG(&wlc_hw->regs->chnstatus) &
-            (1 << tx_fifo)) == 0)
-               return true;
-
-       return false;
-}
-
-static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
-                                  uint tx_fifo)
-{
-       /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
-        * but need to be done here for PIO otherwise the watchdog will catch
-        * the inconsistency and fire
-        */
-       /* Two clients of this code, 11h Quiet period and scanning. */
-       if (wlc_hw->di[tx_fifo])
-               dma_txresume(wlc_hw->di[tx_fifo]);
-
-       /* allow core to sleep again */
-       if (wlc_hw->suspended_fifos == 0)
-               return;
-       else {
-               wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
-               if (wlc_hw->suspended_fifos == 0)
-                       brcms_c_ucode_wake_override_clear(wlc_hw,
-                                               BRCMS_WAKE_OVERRIDE_TXFIFO);
-       }
-}
-
 /*
  * Read and clear macintmask and macintstatus and intstatus registers.
  * This routine should be called with interrupts off
@@ -2569,75 +2485,7 @@ void brcms_c_enable_mac(struct brcms_c_info *wlc)
                                          BRCMS_WAKE_OVERRIDE_MACSUSPEND);
 }
 
-static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
-{
-       u8 rate;
-       u8 rates[8] = {
-               BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
-               BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
-       };
-       u16 entry_ptr;
-       u16 pctl1;
-       uint i;
-
-       if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
-               return;
-
-       /* walk the phy rate table and update the entries */
-       for (i = 0; i < ARRAY_SIZE(rates); i++) {
-               rate = rates[i];
-
-               entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
-
-               /* read the SHM Rate Table entry OFDM PCTL1 values */
-               pctl1 =
-                   brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
-
-               /* modify the value */
-               pctl1 &= ~PHY_TXC1_MODE_MASK;
-               pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
-
-               /* Update the SHM Rate Table entry OFDM PCTL1 values */
-               brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
-                                  pctl1);
-       }
-}
-
-static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
-                                        u8 rate)
-{
-       uint i;
-       u8 plcp_rate = 0;
-       struct plcp_signal_rate_lookup {
-               u8 rate;
-               u8 signal_rate;
-       };
-       /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
-       const struct plcp_signal_rate_lookup rate_lookup[] = {
-               {BRCM_RATE_6M, 0xB},
-               {BRCM_RATE_9M, 0xF},
-               {BRCM_RATE_12M, 0xA},
-               {BRCM_RATE_18M, 0xE},
-               {BRCM_RATE_24M, 0x9},
-               {BRCM_RATE_36M, 0xD},
-               {BRCM_RATE_48M, 0x8},
-               {BRCM_RATE_54M, 0xC}
-       };
-
-       for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
-               if (rate == rate_lookup[i].rate) {
-                       plcp_rate = rate_lookup[i].signal_rate;
-                       break;
-               }
-       }
-
-       /* Find the SHM pointer to the rate table entry by looking in the
-        * Direct-map Table
-        */
-       return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
-}
-
-void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
+void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
 {
        wlc_hw->hw_stf_ss_opmode = stf_mode;
 
@@ -2799,29 +2647,6 @@ void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
        wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
 }
 
-/* power both the pll and external oscillator on/off */
-static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
-{
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
-
-       /*
-        * dont power down if plldown is false or
-        * we must poll hw radio disable
-        */
-       if (!want && wlc_hw->pllreq)
-               return;
-
-       if (wlc_hw->sih)
-               ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
-
-       wlc_hw->sbclk = want;
-       if (!wlc_hw->sbclk) {
-               wlc_hw->clk = false;
-               if (wlc_hw->band && wlc_hw->band->pi)
-                       wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
-       }
-}
-
 static void brcms_c_flushqueues(struct brcms_c_info *wlc)
 {
        struct brcms_hardware *wlc_hw = wlc->hw;
@@ -2841,16 +2666,6 @@ static void brcms_c_flushqueues(struct brcms_c_info *wlc)
        dma_rxreclaim(wlc_hw->di[RX_FIFO]);
 }
 
-u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
-{
-       return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
-}
-
-void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
-{
-       brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
-}
-
 static u16
 brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
 {
@@ -2885,6 +2700,16 @@ brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
                W_REG(objdata_lo, v);
 }
 
+u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
+{
+       return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
+}
+
+void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
+{
+       brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
+}
+
 /* Copy a buffer to shared memory of specified type .
  * SHM 'offset' needs to be an even address and
  * Buffer length 'len' must be an even number of bytes
@@ -3319,101 +3144,315 @@ brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
                brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
 }
 
-void brcms_c_init(struct brcms_c_info *wlc)
+static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc)
 {
-       struct d11regs *regs;
-       u16 chanspec;
-       int i;
-       struct brcms_bss_cfg *bsscfg;
-       bool mute = false;
+       u8 local;
+       s16 local_max;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       local = BRCMS_TXPWR_MAX;
+       if (wlc->pub->associated &&
+           (brcmu_chspec_ctlchan(wlc->chanspec) ==
+            brcmu_chspec_ctlchan(wlc->home_chanspec))) {
 
-       regs = wlc->regs;
+               /* get the local power constraint if we are on the AP's
+                * channel [802.11h, 7.3.2.13]
+                */
+               /* Clamp the value between 0 and BRCMS_TXPWR_MAX w/o
+                * overflowing the target */
+               local_max =
+                   (wlc->txpwr_local_max -
+                    wlc->txpwr_local_constraint) * BRCMS_TXPWR_DB_FACTOR;
+               if (local_max > 0 && local_max < BRCMS_TXPWR_MAX)
+                       return (u8) local_max;
+               if (local_max < 0)
+                       return 0;
+       }
 
-       /*
-        * This will happen if a big-hammer was executed. In
-        * that case, we want to go back to the channel that
-        * we were on and not new channel
-        */
-       if (wlc->pub->associated)
-               chanspec = wlc->home_chanspec;
-       else
-               chanspec = brcms_c_init_chanspec(wlc);
+       return local;
+}
 
-       brcms_b_init(wlc->hw, chanspec, mute);
+static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
+                                    u16 chanspec)
+{
+       /* Save our copy of the chanspec */
+       wlc->chanspec = chanspec;
 
-       /* update beacon listen interval */
-       brcms_c_bcn_li_upd(wlc);
+       /* Set the chanspec and power limits for this locale after computing
+        * any 11h local tx power constraints.
+        */
+       brcms_c_channel_set_chanspec(wlc->cmi, chanspec,
+                                brcms_c_local_constraint_qdbm(wlc));
 
-       /* the world is new again, so is our reported rate */
-       brcms_c_reprate_init(wlc);
+       if (wlc->stf->ss_algosel_auto)
+               brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
+                                           chanspec);
 
-       /* write ethernet address to core */
-       FOREACH_BSS(wlc, i, bsscfg)
-               brcms_c_set_mac(bsscfg);
-               brcms_c_set_bssid(bsscfg);
-       END_FOREACH_BSS()
+       brcms_c_stf_ss_update(wlc, wlc->band);
 
-       /* Update tsf_cfprep if associated and up */
-       if (wlc->pub->associated) {
-               FOREACH_BSS(wlc, i, bsscfg)
-                       if (bsscfg->up) {
-                               u32 bi;
+}
 
-                               /* get beacon period and convert to uS */
-                               bi = bsscfg->current_bss->beacon_period << 10;
-                               /*
-                                * update since init path would reset
-                                * to default value
-                                */
-                               W_REG(&regs->tsf_cfprep,
-                                     (bi << CFPREP_CBI_SHIFT));
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
+                                    u16 chanspec)
+{
+       struct brcms_c_rateset default_rateset;
+       uint parkband;
+       uint i, band_order[2];
 
-                               /* Update maccontrol PM related bits */
-                               brcms_c_set_ps_ctrl(wlc);
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       /*
+        * We might have been bandlocked during down and the chip
+        * power-cycled (hibernate). Figure out the right band to park on
+        */
+       if (wlc->bandlocked || NBANDS(wlc) == 1) {
+               /* updated in brcms_c_bandlock() */
+               parkband = wlc->band->bandunit;
+               band_order[0] = band_order[1] = parkband;
+       } else {
+               /* park on the band of the specified chanspec */
+               parkband = CHSPEC_BANDUNIT(chanspec);
 
-                               break;
-                       }
-               END_FOREACH_BSS()
+               /* order so that parkband initialize last */
+               band_order[0] = parkband ^ 1;
+               band_order[1] = parkband;
        }
 
-       brcms_c_bandinit_ordered(wlc, chanspec);
-
-       brcms_c_init_scb(wlc, &global_scb);
-
-       /* init probe response timeout */
-       brcms_c_write_shm(wlc, M_PRS_MAXTIME, wlc->prb_resp_timeout);
-
-       /* init max burst txop (framebursting) */
-       brcms_c_write_shm(wlc, M_MBURST_TXOP,
-                     (wlc->
-                      _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
+       /* make each band operational, software state init */
+       for (i = 0; i < NBANDS(wlc); i++) {
+               uint j = band_order[i];
 
-       /* initialize maximum allowed duty cycle */
-       brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
-       brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
+               wlc->band = wlc->bandstate[j];
 
-       /*
-        * Update some shared memory locations related to
-        * max AMPDU size allowed to received
-        */
-       brcms_c_ampdu_shm_upd(wlc->ampdu);
+               brcms_default_rateset(wlc, &default_rateset);
 
-       /* band-specific inits */
-       brcms_c_bsinit(wlc);
+               /* fill in hw_rate */
+               brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
+                                  false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+                                  (bool) N_ENAB(wlc->pub));
 
-       /* Enable EDCF mode (while the MAC is suspended) */
-       if (EDCF_ENAB(wlc->pub)) {
-               OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
-               brcms_c_edcf_setparams(wlc, false);
+               /* init basic rate lookup */
+               brcms_c_rate_lookup_init(wlc, &default_rateset);
        }
 
-       /* Init precedence maps for empty FIFOs */
-       brcms_c_tx_prec_map_init(wlc);
+       /* sync up phy/radio chanspec */
+       brcms_c_set_phy_chanspec(wlc, chanspec);
+}
 
-       /* read the ucode version if we have not yet done so */
-       if (wlc->ucode_rev == 0) {
+/*
+ * ucode, hwmac update
+ *    Channel dependent updates for ucode and hw
+ */
+static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
+{
+       /* enable or disable any active IBSSs depending on whether or not
+        * we are on the home channel
+        */
+       if (wlc->home_chanspec == BRCMS_BAND_PI_RADIO_CHANSPEC) {
+               if (wlc->pub->associated) {
+                       /*
+                        * BMAC_NOTE: This is something that should be fixed
+                        * in ucode inits. I think that the ucode inits set
+                        * up the bcn templates and shm values with a bogus
+                        * beacon. This should not be done in the inits. If
+                        * ucode needs to set up a beacon for testing, the
+                        * test routines should write it down, not expect the
+                        * inits to populate a bogus beacon.
+                        */
+                       if (BRCMS_PHY_11N_CAP(wlc->band))
+                               brcms_c_write_shm(wlc, M_BCN_TXTSF_OFFSET,
+                                             wlc->band->bcntsfoff);
+               }
+       } else {
+               /* disable an active IBSS if we are not on the home channel */
+       }
+
+       /* update the various promisc bits */
+       brcms_c_mac_bcn_promisc(wlc);
+       brcms_c_mac_promisc(wlc);
+}
+
+/* band-specific init */
+static void brcms_c_bsinit(struct brcms_c_info *wlc)
+{
+       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
+                wlc->pub->unit, wlc->band->bandunit);
+
+       /* write ucode ACK/CTS rate table */
+       brcms_c_set_ratetable(wlc);
+
+       /* update some band specific mac configuration */
+       brcms_c_ucode_mac_upd(wlc);
+
+       /* init antenna selection */
+       brcms_c_antsel_init(wlc->asi);
+
+}
+
+/* formula:  IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
+static int
+brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
+                  bool writeToShm)
+{
+       int idle_busy_ratio_x_16 = 0;
+       uint offset =
+           isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
+           M_TX_IDLE_BUSY_RATIO_X_16_CCK;
+       if (duty_cycle > 100 || duty_cycle < 0) {
+               wiphy_err(wlc->wiphy, "wl%d:  duty cycle value off limit\n",
+                         wlc->pub->unit);
+               return -EINVAL;
+       }
+       if (duty_cycle)
+               idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
+       /* Only write to shared memory  when wl is up */
+       if (writeToShm)
+               brcms_c_write_shm(wlc, offset, (u16) idle_busy_ratio_x_16);
+
+       if (isOFDM)
+               wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
+       else
+               wlc->tx_duty_cycle_cck = (u16) duty_cycle;
+
+       return 0;
+}
+
+/*
+ * Initialize the base precedence map for dequeueing
+ * from txq based on WME settings
+ */
+static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
+{
+       wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
+       memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
+
+       /*
+        * For non-WME, both fifos have overlapping MAXPRIO. So just
+        * disable all precedences if either is full.
+        */
+       if (!EDCF_ENAB(wlc->pub)) {
+               wlc->fifo2prec_map[TX_DATA_FIFO] = BRCMS_PREC_BMP_ALL;
+               wlc->fifo2prec_map[TX_CTL_FIFO] = BRCMS_PREC_BMP_ALL;
+       } else {
+               wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
+               wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
+               wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
+               wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
+       }
+}
+
+static void
+brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
+                            struct brcms_txq_info *qi, bool on, int prio)
+{
+       /* transmit flowcontrol is not yet implemented */
+}
+
+static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
+{
+       struct brcms_txq_info *qi;
+
+       for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
+               if (qi->stopped) {
+                       brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
+                       qi->stopped = 0;
+               }
+       }
+}
+
+void brcms_c_init(struct brcms_c_info *wlc)
+{
+       struct d11regs *regs;
+       u16 chanspec;
+       int i;
+       struct brcms_bss_cfg *bsscfg;
+       bool mute = false;
+
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+       regs = wlc->regs;
+
+       /*
+        * This will happen if a big-hammer was executed. In
+        * that case, we want to go back to the channel that
+        * we were on and not new channel
+        */
+       if (wlc->pub->associated)
+               chanspec = wlc->home_chanspec;
+       else
+               chanspec = brcms_c_init_chanspec(wlc);
+
+       brcms_b_init(wlc->hw, chanspec, mute);
+
+       /* update beacon listen interval */
+       brcms_c_bcn_li_upd(wlc);
+
+       /* the world is new again, so is our reported rate */
+       brcms_c_reprate_init(wlc);
+
+       /* write ethernet address to core */
+       FOREACH_BSS(wlc, i, bsscfg)
+               brcms_c_set_mac(bsscfg);
+               brcms_c_set_bssid(bsscfg);
+       END_FOREACH_BSS()
+
+       /* Update tsf_cfprep if associated and up */
+       if (wlc->pub->associated) {
+               FOREACH_BSS(wlc, i, bsscfg)
+                       if (bsscfg->up) {
+                               u32 bi;
+
+                               /* get beacon period and convert to uS */
+                               bi = bsscfg->current_bss->beacon_period << 10;
+                               /*
+                                * update since init path would reset
+                                * to default value
+                                */
+                               W_REG(&regs->tsf_cfprep,
+                                     (bi << CFPREP_CBI_SHIFT));
+
+                               /* Update maccontrol PM related bits */
+                               brcms_c_set_ps_ctrl(wlc);
+
+                               break;
+                       }
+               END_FOREACH_BSS()
+       }
+
+       brcms_c_bandinit_ordered(wlc, chanspec);
+
+       brcms_c_init_scb(wlc, &global_scb);
+
+       /* init probe response timeout */
+       brcms_c_write_shm(wlc, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+
+       /* init max burst txop (framebursting) */
+       brcms_c_write_shm(wlc, M_MBURST_TXOP,
+                     (wlc->
+                      _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
+
+       /* initialize maximum allowed duty cycle */
+       brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
+       brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
+
+       /*
+        * Update some shared memory locations related to
+        * max AMPDU size allowed to received
+        */
+       brcms_c_ampdu_shm_upd(wlc->ampdu);
+
+       /* band-specific inits */
+       brcms_c_bsinit(wlc);
+
+       /* Enable EDCF mode (while the MAC is suspended) */
+       if (EDCF_ENAB(wlc->pub)) {
+               OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
+               brcms_c_edcf_setparams(wlc, false);
+       }
+
+       /* Init precedence maps for empty FIFOs */
+       brcms_c_tx_prec_map_init(wlc);
+
+       /* read the ucode version if we have not yet done so */
+       if (wlc->ucode_rev == 0) {
                wlc->ucode_rev =
                    brcms_c_read_shm(wlc, M_BOM_REV_MAJOR) << NBITS(u16);
                wlc->ucode_rev |= brcms_c_read_shm(wlc, M_BOM_REV_MINOR);
@@ -3585,33 +3624,6 @@ void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
        brcms_b_set_shortslot(wlc->hw, shortslot);
 }
 
-static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc)
-{
-       u8 local;
-       s16 local_max;
-
-       local = BRCMS_TXPWR_MAX;
-       if (wlc->pub->associated &&
-           (brcmu_chspec_ctlchan(wlc->chanspec) ==
-            brcmu_chspec_ctlchan(wlc->home_chanspec))) {
-
-               /* get the local power constraint if we are on the AP's
-                * channel [802.11h, 7.3.2.13]
-                */
-               /* Clamp the value between 0 and BRCMS_TXPWR_MAX w/o
-                * overflowing the target */
-               local_max =
-                   (wlc->txpwr_local_max -
-                    wlc->txpwr_local_constraint) * BRCMS_TXPWR_DB_FACTOR;
-               if (local_max > 0 && local_max < BRCMS_TXPWR_MAX)
-                       return (u8) local_max;
-               if (local_max < 0)
-                       return 0;
-       }
-
-       return local;
-}
-
 /*
  * propagate home chanspec to all bsscfgs in
  * case bsscfg->current_bss->chanspec is referenced
@@ -3635,33 +3647,13 @@ void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
        }
 }
 
-static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
-                                    u16 chanspec)
+void
+brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
+                     bool mute, struct txpwr_limits *txpwr)
 {
-       /* Save our copy of the chanspec */
-       wlc->chanspec = chanspec;
+       uint bandunit;
 
-       /* Set the chanspec and power limits for this locale after computing
-        * any 11h local tx power constraints.
-        */
-       brcms_c_channel_set_chanspec(wlc->cmi, chanspec,
-                                brcms_c_local_constraint_qdbm(wlc));
-
-       if (wlc->stf->ss_algosel_auto)
-               brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
-                                           chanspec);
-
-       brcms_c_stf_ss_update(wlc, wlc->band);
-
-}
-
-void
-brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
-                     bool mute, struct txpwr_limits *txpwr)
-{
-       uint bandunit;
-
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
 
        wlc_hw->chanspec = chanspec;
 
@@ -3699,6 +3691,30 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
        }
 }
 
+/* switch to and initialize new band */
+static void brcms_c_setband(struct brcms_c_info *wlc,
+                                          uint bandunit)
+{
+       int idx;
+       struct brcms_bss_cfg *cfg;
+
+       wlc->band = wlc->bandstate[bandunit];
+
+       if (!wlc->pub->up)
+               return;
+
+       /* wait for at least one beacon before entering sleeping state */
+       for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) {
+               cfg = wlc->bsscfg[idx];
+               if (cfg && BSSCFG_STA(cfg) && cfg->associated)
+                       cfg->PMawakebcn = true;
+       }
+       brcms_c_set_ps_ctrl(wlc);
+
+       /* band-specific initializations */
+       brcms_c_bsinit(wlc);
+}
+
 void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 {
        uint bandunit;
@@ -3882,126 +3898,6 @@ static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
        }
 }
 
-/*
- * ucode, hwmac update
- *    Channel dependent updates for ucode and hw
- */
-static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
-{
-       /* enable or disable any active IBSSs depending on whether or not
-        * we are on the home channel
-        */
-       if (wlc->home_chanspec == BRCMS_BAND_PI_RADIO_CHANSPEC) {
-               if (wlc->pub->associated) {
-                       /*
-                        * BMAC_NOTE: This is something that should be fixed
-                        * in ucode inits. I think that the ucode inits set
-                        * up the bcn templates and shm values with a bogus
-                        * beacon. This should not be done in the inits. If
-                        * ucode needs to set up a beacon for testing, the
-                        * test routines should write it down, not expect the
-                        * inits to populate a bogus beacon.
-                        */
-                       if (BRCMS_PHY_11N_CAP(wlc->band))
-                               brcms_c_write_shm(wlc, M_BCN_TXTSF_OFFSET,
-                                             wlc->band->bcntsfoff);
-               }
-       } else {
-               /* disable an active IBSS if we are not on the home channel */
-       }
-
-       /* update the various promisc bits */
-       brcms_c_mac_bcn_promisc(wlc);
-       brcms_c_mac_promisc(wlc);
-}
-
-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
-                                    u16 chanspec)
-{
-       struct brcms_c_rateset default_rateset;
-       uint parkband;
-       uint i, band_order[2];
-
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-       /*
-        * We might have been bandlocked during down and the chip
-        * power-cycled (hibernate). Figure out the right band to park on
-        */
-       if (wlc->bandlocked || NBANDS(wlc) == 1) {
-               /* updated in brcms_c_bandlock() */
-               parkband = wlc->band->bandunit;
-               band_order[0] = band_order[1] = parkband;
-       } else {
-               /* park on the band of the specified chanspec */
-               parkband = CHSPEC_BANDUNIT(chanspec);
-
-               /* order so that parkband initialize last */
-               band_order[0] = parkband ^ 1;
-               band_order[1] = parkband;
-       }
-
-       /* make each band operational, software state init */
-       for (i = 0; i < NBANDS(wlc); i++) {
-               uint j = band_order[i];
-
-               wlc->band = wlc->bandstate[j];
-
-               brcms_default_rateset(wlc, &default_rateset);
-
-               /* fill in hw_rate */
-               brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
-                                  false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
-                                  (bool) N_ENAB(wlc->pub));
-
-               /* init basic rate lookup */
-               brcms_c_rate_lookup_init(wlc, &default_rateset);
-       }
-
-       /* sync up phy/radio chanspec */
-       brcms_c_set_phy_chanspec(wlc, chanspec);
-}
-
-/* band-specific init */
-static void brcms_c_bsinit(struct brcms_c_info *wlc)
-{
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
-                wlc->pub->unit, wlc->band->bandunit);
-
-       /* write ucode ACK/CTS rate table */
-       brcms_c_set_ratetable(wlc);
-
-       /* update some band specific mac configuration */
-       brcms_c_ucode_mac_upd(wlc);
-
-       /* init antenna selection */
-       brcms_c_antsel_init(wlc->asi);
-
-}
-
-/* switch to and initialize new band */
-static void brcms_c_setband(struct brcms_c_info *wlc,
-                                          uint bandunit)
-{
-       int idx;
-       struct brcms_bss_cfg *cfg;
-
-       wlc->band = wlc->bandstate[bandunit];
-
-       if (!wlc->pub->up)
-               return;
-
-       /* wait for at least one beacon before entering sleeping state */
-       for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) {
-               cfg = wlc->bsscfg[idx];
-               if (cfg && BSSCFG_STA(cfg) && cfg->associated)
-                       cfg->PMawakebcn = true;
-       }
-       brcms_c_set_ps_ctrl(wlc);
-
-       /* band-specific initializations */
-       brcms_c_bsinit(wlc);
-}
-
 /*
  * Initialize a WME Parameter Info Element with default
  * STA parameters from WMM Spec, Table 12
@@ -4142,68 +4038,275 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
 
 }
 
-bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
+/* maintain LED behavior in down state */
+static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
 {
-       wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
-               wlc, "watchdog");
-       if (!wlc->wdtimer) {
-               wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for wdtimer "
-                         "failed\n", unit);
-               goto fail;
-       }
+       /*
+        * maintain LEDs while in down state, turn on sbclk if
+        * not available yet. Turn on sbclk if necessary
+        */
+       if (!AP_ENAB(wlc->pub)) {
+               brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_FLIP);
 
-       wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
-               wlc, "radio");
-       if (!wlc->radio_timer) {
-               wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for radio_timer "
-                         "failed\n", unit);
-               goto fail;
+               brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_FLIP);
        }
+}
 
-       return true;
+static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
+{
+       /* Don't start the timer if HWRADIO feature is disabled */
+       if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO))
+               return true;
 
- fail:
-       return false;
+       wlc->radio_monitor = true;
+       brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_RADIO_MON);
+       brcms_add_timer(wlc->wl, wlc->radio_timer, TIMER_INTERVAL_RADIOCHK,
+                       true);
+       return true;
 }
 
-/*
- * Initialize brcms_c_info default values ...
- * may get overrides later in this function
- */
-void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
+void brcms_c_radio_disable(struct brcms_c_info *wlc)
 {
-       int i;
-       /* Assume the device is there until proven otherwise */
-       wlc->device_present = true;
-
-       /* Save our copy of the chanspec */
-       wlc->chanspec = CH20MHZ_CHSPEC(1);
+       if (!wlc->pub->up) {
+               brcms_c_down_led_upd(wlc);
+               return;
+       }
 
-       /* various 802.11g modes */
-       wlc->shortslot = false;
-       wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
+       brcms_c_radio_monitor_start(wlc);
+       brcms_down(wlc->wl);
+}
 
-       brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
-       brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
+static void brcms_c_radio_enable(struct brcms_c_info *wlc)
+{
+       if (wlc->pub->up)
+               return;
 
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
-                              BRCMS_PROTECTION_AUTO);
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
-                              BRCMS_PROTECTION_AUTO);
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
+       if (DEVICEREMOVED(wlc))
+               return;
 
-       brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
-                              BRCMS_PROTECTION_CTL_OVERLAP);
+       brcms_up(wlc->wl);
+}
 
-       /* 802.11g draft 4.0 NonERP elt advertisement */
-       wlc->include_legacy_erp = true;
+bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
+{
+       if (!wlc->radio_monitor)
+               return true;
 
-       wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
-       wlc->stf->txant = ANT_TX_DEF;
+       wlc->radio_monitor = false;
+       brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON);
+       return brcms_del_timer(wlc->wl, wlc->radio_timer);
+}
 
-       wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
+/* read hwdisable state and propagate to wlc flag */
+static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
+{
+       if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off)
+               return;
+
+       if (brcms_b_radio_read_hwdisabled(wlc->hw))
+               mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+       else
+               mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+}
+
+/*
+ * centralized radio disable/enable function,
+ * invoke radio enable/disable after updating hwradio status
+ */
+static void brcms_c_radio_upd(struct brcms_c_info *wlc)
+{
+       if (wlc->pub->radio_disabled)
+               brcms_c_radio_disable(wlc);
+       else
+               brcms_c_radio_enable(wlc);
+}
+
+/* update hwradio status and return it */
+bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
+{
+       brcms_c_radio_hwdisable_upd(wlc);
+
+       return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
+                       true : false;
+}
+
+/* periodical query hw radio button while driver is "down" */
+static void brcms_c_radio_timer(void *arg)
+{
+       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+
+       if (DEVICEREMOVED(wlc)) {
+               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+                       __func__);
+               brcms_down(wlc->wl);
+               return;
+       }
+
+       /* cap mpc off count */
+       if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
+               wlc->mpc_offcnt++;
+
+       brcms_c_radio_hwdisable_upd(wlc);
+       brcms_c_radio_upd(wlc);
+}
+
+/* common low-level watchdog code */
+void brcms_b_watchdog(void *arg)
+{
+       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+       struct brcms_hardware *wlc_hw = wlc->hw;
+
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+       if (!wlc_hw->up)
+               return;
+
+       /* increment second count */
+       wlc_hw->now++;
+
+       /* Check for FIFO error interrupts */
+       brcms_b_fifoerrors(wlc_hw);
+
+       /* make sure RX dma has buffers */
+       dma_rxfill(wlc->hw->di[RX_FIFO]);
+
+       wlc_phy_watchdog(wlc_hw->band->pi);
+}
+
+/* common watchdog code */
+static void brcms_c_watchdog(void *arg)
+{
+       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+       int i;
+       struct brcms_bss_cfg *cfg;
+
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+       if (!wlc->pub->up)
+               return;
+
+       if (DEVICEREMOVED(wlc)) {
+               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+                         __func__);
+               brcms_down(wlc->wl);
+               return;
+       }
+
+       /* increment second count */
+       wlc->pub->now++;
+
+       /* delay radio disable */
+       if (wlc->mpc_delay_off) {
+               if (--wlc->mpc_delay_off == 0) {
+                       mboolset(wlc->pub->radio_disabled,
+                                WL_RADIO_MPC_DISABLE);
+                       if (wlc->mpc && brcms_c_ismpc(wlc))
+                               wlc->mpc_offcnt = 0;
+                       wlc->mpc_laston_ts = OSL_SYSUPTIME();
+               }
+       }
+
+       /* mpc sync */
+       brcms_c_radio_mpc_upd(wlc);
+       /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
+       brcms_c_radio_hwdisable_upd(wlc);
+       brcms_c_radio_upd(wlc);
+       /* if radio is disable, driver may be down, quit here */
+       if (wlc->pub->radio_disabled)
+               return;
+
+       brcms_b_watchdog(wlc);
+
+       /*
+        * occasionally sample mac stat counters to
+        * detect 16-bit counter wrap
+        */
+       if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
+               brcms_c_statsupd(wlc);
+
+       /* Manage TKIP countermeasures timers */
+       FOREACH_BSS(wlc, i, cfg)
+               if (cfg->tk_cm_dt)
+                       cfg->tk_cm_dt--;
+               if (cfg->tk_cm_bt)
+                       cfg->tk_cm_bt--;
+       END_FOREACH_BSS()
+
+       if (BRCMS_ISNPHY(wlc->band) && !wlc->pub->tempsense_disable &&
+           ((wlc->pub->now - wlc->tempsense_lasttime) >=
+            BRCMS_TEMPSENSE_PERIOD)) {
+               wlc->tempsense_lasttime = wlc->pub->now;
+               brcms_c_tempsense_upd(wlc);
+       }
+}
+
+static void brcms_c_watchdog_by_timer(void *arg)
+{
+       brcms_c_watchdog(arg);
+}
+
+bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
+{
+       wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
+               wlc, "watchdog");
+       if (!wlc->wdtimer) {
+               wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for wdtimer "
+                         "failed\n", unit);
+               goto fail;
+       }
+
+       wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
+               wlc, "radio");
+       if (!wlc->radio_timer) {
+               wiphy_err(wlc->wiphy, "wl%d:  wl_init_timer for radio_timer "
+                         "failed\n", unit);
+               goto fail;
+       }
+
+       return true;
+
+ fail:
+       return false;
+}
+
+/*
+ * Initialize brcms_c_info default values ...
+ * may get overrides later in this function
+ */
+void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
+{
+       int i;
+       /* Assume the device is there until proven otherwise */
+       wlc->device_present = true;
+
+       /* Save our copy of the chanspec */
+       wlc->chanspec = CH20MHZ_CHSPEC(1);
+
+       /* various 802.11g modes */
+       wlc->shortslot = false;
+       wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
+
+       brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
+       brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
+
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
+                              BRCMS_PROTECTION_AUTO);
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
+                              BRCMS_PROTECTION_AUTO);
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
+
+       brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
+                              BRCMS_PROTECTION_CTL_OVERLAP);
+
+       /* 802.11g draft 4.0 NonERP elt advertisement */
+       wlc->include_legacy_erp = true;
+
+       wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
+       wlc->stf->txant = ANT_TX_DEF;
+
+       wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
 
        wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
        for (i = 0; i < NFIFO; i++)
@@ -4637,28 +4740,210 @@ int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, uint unit,
        return err;
 }
 
-/*
- * The common driver entry routine. Error codes should be unique
- */
-struct brcms_c_info *
-brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
-              bool piomode, void *regsva, struct pci_dev *btparam, uint *perr)
+static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
 {
-       struct brcms_c_info *wlc;
-       uint err = 0;
-       uint j;
-       struct brcms_pub *pub;
-       uint n_disabled;
+       uint unit;
+       unit = wlc->pub->unit;
 
-       /* allocate struct brcms_c_info state and its substructures */
-       wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device);
-       if (wlc == NULL)
-               goto fail;
-       wlc->wiphy = wl->wiphy;
-       pub = wlc->pub;
+       if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
+               /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
+               wlc->band->antgain = 8;
+       } else if (wlc->band->antgain == -1) {
+               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
+                         " srom, using 2dB\n", unit, __func__);
+               wlc->band->antgain = 8;
+       } else {
+               s8 gain, fract;
+               /* Older sroms specified gain in whole dbm only.  In order
+                * be able to specify qdbm granularity and remain backward
+                * compatible the whole dbms are now encoded in only
+                * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
+                * 6 bit signed number ranges from -32 - 31.
+                *
+                * Examples:
+                * 0x1 = 1 db,
+                * 0xc1 = 1.75 db (1 + 3 quarters),
+                * 0x3f = -1 (-1 + 0 quarters),
+                * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
+                * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
+                */
+               gain = wlc->band->antgain & 0x3f;
+               gain <<= 2;     /* Sign extend */
+               gain >>= 2;
+               fract = (wlc->band->antgain & 0xc0) >> 6;
+               wlc->band->antgain = 4 * gain + fract;
+       }
+}
 
-#if defined(BCMDBG)
-       wlc_info_dbg = wlc;
+static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
+{
+       int aa;
+       uint unit;
+       char *vars;
+       int bandtype;
+
+       unit = wlc->pub->unit;
+       vars = wlc->pub->vars;
+       bandtype = wlc->band->bandtype;
+
+       /* get antennas available */
+       aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa5g" : "aa2g"));
+       if (aa == 0)
+               aa = (s8) getintvar(vars,
+                                     (BAND_5G(bandtype) ? "aa1" : "aa0"));
+       if ((aa < 1) || (aa > 15)) {
+               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
+                         " srom (0x%x), using 3\n", unit, __func__, aa);
+               aa = 3;
+       }
+
+       /* reset the defaults if we have a single antenna */
+       if (aa == 1) {
+               wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
+               wlc->stf->txant = ANT_TX_FORCE_0;
+       } else if (aa == 2) {
+               wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
+               wlc->stf->txant = ANT_TX_FORCE_1;
+       } else {
+       }
+
+       /* Compute Antenna Gain */
+       wlc->band->antgain =
+           (s8) getintvar(vars, (BAND_5G(bandtype) ? "ag1" : "ag0"));
+       brcms_c_attach_antgain_init(wlc);
+
+       return true;
+}
+
+static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
+{
+       u16 chanspec;
+       struct brcms_band *band;
+       struct brcms_bss_info *bi = wlc->default_bss;
+
+       /* init default and target BSS with some sane initial values */
+       memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
+       bi->beacon_period = BEACON_INTERVAL_DEFAULT;
+       bi->dtim_period = DTIM_INTERVAL_DEFAULT;
+
+       /* fill the default channel as the first valid channel
+        * starting from the 2G channels
+        */
+       chanspec = CH20MHZ_CHSPEC(1);
+       wlc->home_chanspec = bi->chanspec = chanspec;
+
+       /* find the band of our default channel */
+       band = wlc->band;
+       if (NBANDS(wlc) > 1 && band->bandunit != CHSPEC_BANDUNIT(chanspec))
+               band = wlc->bandstate[OTHERBANDUNIT(wlc)];
+
+       /* init bss rates to the band specific default rate set */
+       brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
+               band->bandtype, false, BRCMS_RATE_MASK_FULL,
+               (bool) N_ENAB(wlc->pub), CHSPEC_WLC_BW(chanspec),
+               wlc->stf->txstreams);
+
+       if (N_ENAB(wlc->pub))
+               bi->flags |= BRCMS_BSS_HT;
+}
+
+static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
+{
+       struct brcms_txq_info *qi, *p;
+
+       qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
+       if (qi != NULL) {
+               /*
+                * Have enough room for control packets along with HI watermark
+                * Also, add room to txq for total psq packets if all the SCBs
+                * leave PS mode. The watermark for flowcontrol to OS packets
+                * will remain the same
+                */
+               brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
+                         (2 * wlc->pub->tunables->datahiwat) + PKTQ_LEN_DEFAULT
+                         + wlc->pub->psq_pkts_total);
+
+               /* add this queue to the the global list */
+               p = wlc->tx_queues;
+               if (p == NULL) {
+                       wlc->tx_queues = qi;
+               } else {
+                       while (p->next != NULL)
+                               p = p->next;
+                       p->next = qi;
+               }
+       }
+       return qi;
+}
+
+static void brcms_c_txq_free(struct brcms_c_info *wlc,
+                            struct brcms_txq_info *qi)
+{
+       struct brcms_txq_info *p;
+
+       if (qi == NULL)
+               return;
+
+       /* remove the queue from the linked list */
+       p = wlc->tx_queues;
+       if (p == qi)
+               wlc->tx_queues = p->next;
+       else {
+               while (p != NULL && p->next != qi)
+                       p = p->next;
+               if (p != NULL)
+                       p->next = p->next->next;
+       }
+
+       kfree(qi);
+}
+
+static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
+{
+       uint i;
+       struct brcms_band *band;
+
+       for (i = 0; i < NBANDS(wlc); i++) {
+               if (IS_SINGLEBAND_5G(wlc->deviceid))
+                       i = BAND_5G_INDEX;
+               band = wlc->bandstate[i];
+               if (band->bandtype == BRCM_BAND_5G) {
+                       if ((bwcap == BRCMS_N_BW_40ALL)
+                           || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
+                               band->mimo_cap_40 = true;
+                       else
+                               band->mimo_cap_40 = false;
+               } else {
+                       if (bwcap == BRCMS_N_BW_40ALL)
+                               band->mimo_cap_40 = true;
+                       else
+                               band->mimo_cap_40 = false;
+               }
+       }
+}
+
+/*
+ * The common driver entry routine. Error codes should be unique
+ */
+struct brcms_c_info *
+brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
+              bool piomode, void *regsva, struct pci_dev *btparam, uint *perr)
+{
+       struct brcms_c_info *wlc;
+       uint err = 0;
+       uint j;
+       struct brcms_pub *pub;
+       uint n_disabled;
+
+       /* allocate struct brcms_c_info state and its substructures */
+       wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device);
+       if (wlc == NULL)
+               goto fail;
+       wlc->wiphy = wl->wiphy;
+       pub = wlc->pub;
+
+#if defined(BCMDBG)
+       wlc_info_dbg = wlc;
 #endif
 
        wlc->band = wlc->bandstate[0];
@@ -4893,82 +5178,6 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
        return NULL;
 }
 
-static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
-{
-       uint unit;
-       unit = wlc->pub->unit;
-
-       if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) {
-               /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */
-               wlc->band->antgain = 8;
-       } else if (wlc->band->antgain == -1) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
-                         " srom, using 2dB\n", unit, __func__);
-               wlc->band->antgain = 8;
-       } else {
-               s8 gain, fract;
-               /* Older sroms specified gain in whole dbm only.  In order
-                * be able to specify qdbm granularity and remain backward
-                * compatible the whole dbms are now encoded in only
-                * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
-                * 6 bit signed number ranges from -32 - 31.
-                *
-                * Examples:
-                * 0x1 = 1 db,
-                * 0xc1 = 1.75 db (1 + 3 quarters),
-                * 0x3f = -1 (-1 + 0 quarters),
-                * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
-                * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
-                */
-               gain = wlc->band->antgain & 0x3f;
-               gain <<= 2;     /* Sign extend */
-               gain >>= 2;
-               fract = (wlc->band->antgain & 0xc0) >> 6;
-               wlc->band->antgain = 4 * gain + fract;
-       }
-}
-
-static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
-{
-       int aa;
-       uint unit;
-       char *vars;
-       int bandtype;
-
-       unit = wlc->pub->unit;
-       vars = wlc->pub->vars;
-       bandtype = wlc->band->bandtype;
-
-       /* get antennas available */
-       aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa5g" : "aa2g"));
-       if (aa == 0)
-               aa = (s8) getintvar(vars,
-                                     (BAND_5G(bandtype) ? "aa1" : "aa0"));
-       if ((aa < 1) || (aa > 15)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
-                         " srom (0x%x), using 3\n", unit, __func__, aa);
-               aa = 3;
-       }
-
-       /* reset the defaults if we have a single antenna */
-       if (aa == 1) {
-               wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;
-               wlc->stf->txant = ANT_TX_FORCE_0;
-       } else if (aa == 2) {
-               wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;
-               wlc->stf->txant = ANT_TX_FORCE_1;
-       } else {
-       }
-
-       /* Compute Antenna Gain */
-       wlc->band->antgain =
-           (s8) getintvar(vars, (BAND_5G(bandtype) ? "ag1" : "ag0"));
-       brcms_c_attach_antgain_init(wlc);
-
-       return true;
-}
-
-
 static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
 {
        /* free timer state */
@@ -5102,26 +5311,14 @@ void brcms_c_ap_upd(struct brcms_c_info *wlc)
        wlc->mpc = true;
 }
 
-/* read hwdisable state and propagate to wlc flag */
-static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
+/*
+ * return true if Minimum Power Consumption should
+ * be entered, false otherwise
+ */
+bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
 {
-       if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off)
-               return;
-
-       if (brcms_b_radio_read_hwdisabled(wlc->hw))
-               mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
-       else
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
-}
-
-/*
- * return true if Minimum Power Consumption should
- * be entered, false otherwise
- */
-bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
-{
-       return false;
-}
+       return false;
+}
 
 bool brcms_c_ismpc(struct brcms_c_info *wlc)
 {
@@ -5182,202 +5379,6 @@ void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
 
        wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
 }
-
-/*
- * centralized radio disable/enable function,
- * invoke radio enable/disable after updating hwradio status
- */
-static void brcms_c_radio_upd(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->radio_disabled)
-               brcms_c_radio_disable(wlc);
-       else
-               brcms_c_radio_enable(wlc);
-}
-
-/* maintain LED behavior in down state */
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
-{
-       /*
-        * maintain LEDs while in down state, turn on sbclk if
-        * not available yet. Turn on sbclk if necessary
-        */
-       if (!AP_ENAB(wlc->pub)) {
-               brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_FLIP);
-
-               brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_FLIP);
-       }
-}
-
-/* update hwradio status and return it */
-bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
-{
-       brcms_c_radio_hwdisable_upd(wlc);
-
-       return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
-                       true : false;
-}
-
-void brcms_c_radio_disable(struct brcms_c_info *wlc)
-{
-       if (!wlc->pub->up) {
-               brcms_c_down_led_upd(wlc);
-               return;
-       }
-
-       brcms_c_radio_monitor_start(wlc);
-       brcms_down(wlc->wl);
-}
-
-static void brcms_c_radio_enable(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->up)
-               return;
-
-       if (DEVICEREMOVED(wlc))
-               return;
-
-       brcms_up(wlc->wl);
-}
-
-/* periodical query hw radio button while driver is "down" */
-static void brcms_c_radio_timer(void *arg)
-{
-       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
-
-       if (DEVICEREMOVED(wlc)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
-                       __func__);
-               brcms_down(wlc->wl);
-               return;
-       }
-
-       /* cap mpc off count */
-       if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
-               wlc->mpc_offcnt++;
-
-       brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
-}
-
-static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
-{
-       /* Don't start the timer if HWRADIO feature is disabled */
-       if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO))
-               return true;
-
-       wlc->radio_monitor = true;
-       brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_RADIO_MON);
-       brcms_add_timer(wlc->wl, wlc->radio_timer, TIMER_INTERVAL_RADIOCHK,
-                       true);
-       return true;
-}
-
-bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
-{
-       if (!wlc->radio_monitor)
-               return true;
-
-       wlc->radio_monitor = false;
-       brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON);
-       return brcms_del_timer(wlc->wl, wlc->radio_timer);
-}
-
-/* common low-level watchdog code */
-void brcms_b_watchdog(void *arg)
-{
-       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
-       struct brcms_hardware *wlc_hw = wlc->hw;
-
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
-       if (!wlc_hw->up)
-               return;
-
-       /* increment second count */
-       wlc_hw->now++;
-
-       /* Check for FIFO error interrupts */
-       brcms_b_fifoerrors(wlc_hw);
-
-       /* make sure RX dma has buffers */
-       dma_rxfill(wlc->hw->di[RX_FIFO]);
-
-       wlc_phy_watchdog(wlc_hw->band->pi);
-}
-
-static void brcms_c_watchdog_by_timer(void *arg)
-{
-       brcms_c_watchdog(arg);
-}
-
-/* common watchdog code */
-static void brcms_c_watchdog(void *arg)
-{
-       struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
-       int i;
-       struct brcms_bss_cfg *cfg;
-
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
-       if (!wlc->pub->up)
-               return;
-
-       if (DEVICEREMOVED(wlc)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
-                         __func__);
-               brcms_down(wlc->wl);
-               return;
-       }
-
-       /* increment second count */
-       wlc->pub->now++;
-
-       /* delay radio disable */
-       if (wlc->mpc_delay_off) {
-               if (--wlc->mpc_delay_off == 0) {
-                       mboolset(wlc->pub->radio_disabled,
-                                WL_RADIO_MPC_DISABLE);
-                       if (wlc->mpc && brcms_c_ismpc(wlc))
-                               wlc->mpc_offcnt = 0;
-                       wlc->mpc_laston_ts = OSL_SYSUPTIME();
-               }
-       }
-
-       /* mpc sync */
-       brcms_c_radio_mpc_upd(wlc);
-       /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
-       brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
-       /* if radio is disable, driver may be down, quit here */
-       if (wlc->pub->radio_disabled)
-               return;
-
-       brcms_b_watchdog(wlc);
-
-       /*
-        * occasionally sample mac stat counters to
-        * detect 16-bit counter wrap
-        */
-       if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
-               brcms_c_statsupd(wlc);
-
-       /* Manage TKIP countermeasures timers */
-       FOREACH_BSS(wlc, i, cfg)
-               if (cfg->tk_cm_dt)
-                       cfg->tk_cm_dt--;
-               if (cfg->tk_cm_bt)
-                       cfg->tk_cm_bt--;
-       END_FOREACH_BSS()
-
-       if (BRCMS_ISNPHY(wlc->band) && !wlc->pub->tempsense_disable &&
-           ((wlc->pub->now - wlc->tempsense_lasttime) >=
-            BRCMS_TEMPSENSE_PERIOD)) {
-               wlc->tempsense_lasttime = wlc->pub->now;
-               brcms_c_tempsense_upd(wlc);
-       }
-}
-
 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
 void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
 {
@@ -5478,6 +5479,23 @@ int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
        return 0;
 }
 
+/*
+ * Write WME tunable parameters for retransmit/max rate
+ * from wlc struct to ucode
+ */
+static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
+{
+       int ac;
+
+       /* Need clock to do this */
+       if (!wlc->clk)
+               return;
+
+       for (ac = 0; ac < AC_COUNT; ac++)
+               brcms_c_write_shm(wlc, M_AC_TXLMT_ADDR(ac),
+                                 wlc->wme_retries[ac]);
+}
+
 /* make interface operational */
 int brcms_c_up(struct brcms_c_info *wlc)
 {
@@ -5586,30 +5604,6 @@ int brcms_c_up(struct brcms_c_info *wlc)
        return 0;
 }
 
-/*
- * Initialize the base precedence map for dequeueing
- * from txq based on WME settings
- */
-static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
-{
-       wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
-       memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
-
-       /*
-        * For non-WME, both fifos have overlapping MAXPRIO. So just
-        * disable all precedences if either is full.
-        */
-       if (!EDCF_ENAB(wlc->pub)) {
-               wlc->fifo2prec_map[TX_DATA_FIFO] = BRCMS_PREC_BMP_ALL;
-               wlc->fifo2prec_map[TX_CTL_FIFO] = BRCMS_PREC_BMP_ALL;
-       } else {
-               wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
-               wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
-               wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
-               wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
-       }
-}
-
 static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
 {
        uint callbacks = 0;
@@ -6057,13 +6051,6 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
        return;
 }
 
-int
-brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
-             struct brcms_c_if *wlcif)
-{
-       return _brcms_c_ioctl(wlc, cmd, arg, len, wlcif);
-}
-
 /* common ioctl handler. return: 0=ok, -1=error, positive=particular error */
 static int
 _brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
@@ -6314,6 +6301,13 @@ _brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
        return bcmerror;
 }
 
+int
+brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
+             struct brcms_c_if *wlcif)
+{
+       return _brcms_c_ioctl(wlc, cmd, arg, len, wlcif);
+}
+
 /*
  * register watchdog and down handlers.
  */
@@ -6360,23 +6354,6 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
        return -ENODATA;
 }
 
-/*
- * Write WME tunable parameters for retransmit/max rate
- * from wlc struct to ucode
- */
-static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
-{
-       int ac;
-
-       /* Need clock to do this */
-       if (!wlc->clk)
-               return;
-
-       for (ac = 0; ac < AC_COUNT; ac++)
-               brcms_c_write_shm(wlc, M_AC_TXLMT_ADDR(ac),
-                                 wlc->wme_retries[ac]);
-}
-
 #ifdef BCMDBG
 static const char * const supr_reason[] = {
        "None", "PMQ Entry", "Flush request",
@@ -6759,100 +6736,6 @@ void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
        }
 }
 
-bool
-brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
-                    struct ieee80211_hw *hw)
-{
-       u8 prio;
-       uint fifo;
-       struct scb *scb = &global_scb;
-       struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
-
-       /*
-        * 802.11 standard requires management traffic
-        * to go at highest priority
-        */
-       prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
-               MAXPRIO;
-       fifo = prio2fifo[prio];
-       if (unlikely
-           (brcms_c_d11hdrs_mac80211(
-               wlc, hw, sdu, scb, 0, 1, fifo, 0, NULL, 0)))
-               return -EINVAL;
-       brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
-       brcms_c_send_q(wlc);
-       return 0;
-}
-
-void brcms_c_send_q(struct brcms_c_info *wlc)
-{
-       struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
-       int prec;
-       u16 prec_map;
-       int err = 0, i, count;
-       uint fifo;
-       struct brcms_txq_info *qi = wlc->pkt_queue;
-       struct pktq *q = &qi->q;
-       struct ieee80211_tx_info *tx_info;
-
-       if (in_send_q)
-               return;
-       else
-               in_send_q = true;
-
-       prec_map = wlc->tx_prec_map;
-
-       /* Send all the enq'd pkts that we can.
-        * Dequeue packets with precedence with empty HW fifo only
-        */
-       while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
-               tx_info = IEEE80211_SKB_CB(pkt[0]);
-               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
-               } else {
-                       count = 1;
-                       err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
-                       if (!err) {
-                               for (i = 0; i < count; i++)
-                                       brcms_c_txfifo(wlc, fifo, pkt[i], true,
-                                                      1);
-                       }
-               }
-
-               if (err == -EBUSY) {
-                       brcmu_pktq_penq_head(q, prec, pkt[0]);
-                       /*
-                        * If send failed due to any other reason than a
-                        * change in HW FIFO condition, quit. Otherwise,
-                        * read the new prec_map!
-                        */
-                       if (prec_map == wlc->tx_prec_map)
-                               break;
-                       prec_map = wlc->tx_prec_map;
-               }
-       }
-
-       /*
-        * Check if flow control needs to be turned off after
-        * sending the packet
-        */
-       if (!EDCF_ENAB(wlc->pub)
-           || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
-               if (brcms_c_txflowcontrol_prio_isset(wlc, qi, ALLPRIO)
-                   && (pktq_len(q) < wlc->pub->tunables->datahiwat / 2))
-                       brcms_c_txflowcontrol(wlc, qi, OFF, ALLPRIO);
-       } else if (wlc->pub->_priofc) {
-               int prio;
-               for (prio = MAXPRIO; prio >= 0; prio--) {
-                       if (brcms_c_txflowcontrol_prio_isset(wlc, qi, prio) &&
-                           (pktq_plen(q, wlc_prio2prec_map[prio]) <
-                           wlc->pub->tunables->datahiwat / 2))
-                               brcms_c_txflowcontrol(wlc, qi, OFF, prio);
-               }
-       }
-       in_send_q = false;
-}
-
 /*
  * bcmc_fid_generate:
  * Generate frame ID for a BCMC packet.  The frag field is not used
@@ -6874,347 +6757,264 @@ bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,
        return frameid;
 }
 
-void
-brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
-              bool commit, s8 txpktpend)
+static uint
+brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
+                     u8 preamble_type)
 {
-       u16 frameid = INVALIDFID;
-       struct d11txh *txh;
-
-       txh = (struct d11txh *) (p->data);
-
-       /* When a BC/MC frame is being committed to the BCMC fifo
-        * via DMA (NOT PIO), update ucode or BSS info as appropriate.
-        */
-       if (fifo == TX_BCMC_FIFO)
-               frameid = le16_to_cpu(txh->TxFrameID);
-
-       if (BRCMS_WAR16165(wlc))
-               brcms_c_war16165(wlc, true);
-
+       uint dur = 0;
 
+       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
+               wlc->pub->unit, rspec, preamble_type);
        /*
-        * Bump up pending count for if not using rpc. If rpc is
-        * used, this will be handled in brcms_b_txfifo()
+        * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+        * is less than or equal to the rate of the immediately previous
+        * frame in the FES
         */
-       if (commit) {
-               TXPKTPENDINC(wlc, fifo, txpktpend);
-               BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
-                        txpktpend, TXPKTPENDGET(wlc, fifo));
-       }
-
-       /* Commit BCMC sequence number in the SHM frame ID location */
-       if (frameid != INVALIDFID)
-               BCMCFID(wlc, frameid);
-
-       if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
-               wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+       rspec = BRCMS_BASIC_RATE(wlc, rspec);
+       /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
+       dur =
+           brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+                               (DOT11_ACK_LEN + FCS_LEN));
+       return dur;
 }
 
-void
-brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
-                    uint length, u8 *plcp)
+static uint
+brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
+                     u8 preamble_type)
 {
-       if (IS_MCS(rspec))
-               brcms_c_compute_mimo_plcp(rspec, length, plcp);
-       else if (IS_OFDM(rspec))
-               brcms_c_compute_ofdm_plcp(rspec, length, plcp);
-       else
-               brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
-       return;
+       BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
+               wlc->pub->unit, rspec, preamble_type);
+       return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
 }
 
-/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
+static uint
+brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
+                    u8 preamble_type)
 {
-       u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
-       plcp[0] = mcs;
-       if (RSPEC_IS40MHZ(rspec) || (mcs == 32))
-               plcp[0] |= MIMO_PLCP_40MHZ;
-       BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
-       plcp[3] = RSPEC_MIMOPLCP3(rspec); /* rspec already holds this byte */
-       plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
-       plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
-       plcp[5] = 0;
+       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
+                "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
+       /*
+        * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+        * is less than or equal to the rate of the immediately previous
+        * frame in the FES
+        */
+       rspec = BRCMS_BASIC_RATE(wlc, rspec);
+       /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
+       return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+                                  (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
+                                   FCS_LEN));
 }
 
-/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void
-brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
+/* brcms_c_compute_frame_dur()
+ *
+ * Calculate the 802.11 MAC header DUR field for MPDU
+ * DUR for a single frame = 1 SIFS + 1 ACK
+ * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
+ *
+ * rate                        MPDU rate in unit of 500kbps
+ * next_frag_len       next MPDU length in bytes
+ * preamble_type       use short/GF or long/MM PLCP header
+ */
+static u16
+brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
+                     u8 preamble_type, uint next_frag_len)
 {
-       u8 rate_signal;
-       u32 tmp = 0;
-       int rate = RSPEC2RATE(rspec);
+       u16 dur, sifs;
 
-       /*
-        * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
-        * transmitted first
-        */
-       rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
-       memset(plcp, 0, D11_PHY_HDR_LEN);
-       D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
+       sifs = SIFS(wlc->band);
 
-       tmp = (length & 0xfff) << 5;
-       plcp[2] |= (tmp >> 16) & 0xff;
-       plcp[1] |= (tmp >> 8) & 0xff;
-       plcp[0] |= tmp & 0xff;
+       dur = sifs;
+       dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
 
-       return;
+       if (next_frag_len) {
+               /* Double the current DUR to get 2 SIFS + 2 ACKs */
+               dur *= 2;
+               /* add another SIFS and the frag time */
+               dur += sifs;
+               dur +=
+                   (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
+                                                next_frag_len);
+       }
+       return dur;
 }
 
-/*
- * Compute PLCP, but only requires actual rate and length of pkt.
- * Rate is given in the driver standard multiple of 500 kbps.
- * le is set for 11 Mbps rate if necessary.
- * Broken out for PRQ.
- */
-
-static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
-                            uint length, u8 *plcp)
+/* The opposite of brcms_c_calc_frame_time */
+static uint
+brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
+                  u8 preamble_type, uint dur)
 {
-       u16 usec = 0;
-       u8 le = 0;
+       uint nsyms, mac_len, Ndps, kNdps;
+       uint rate = RSPEC2RATE(ratespec);
 
-       switch (rate_500) {
-       case BRCM_RATE_1M:
-               usec = length << 3;
-               break;
-       case BRCM_RATE_2M:
-               usec = length << 2;
-               break;
-       case BRCM_RATE_5M5:
-               usec = (length << 4) / 11;
-               if ((length << 4) - (usec * 11) > 0)
-                       usec++;
-               break;
-       case BRCM_RATE_11M:
-               usec = (length << 3) / 11;
-               if ((length << 3) - (usec * 11) > 0) {
-                       usec++;
-                       if ((usec * 11) - (length << 3) >= 8)
-                               le = D11B_PLCP_SIGNAL_LE;
-               }
-               break;
+       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
+                wlc->pub->unit, ratespec, preamble_type, dur);
 
-       default:
-               wiphy_err(wlc->wiphy,
-                         "brcms_c_cck_plcp_set: unsupported rate %d\n",
-                         rate_500);
-               rate_500 = BRCM_RATE_1M;
-               usec = length << 3;
-               break;
+       if (IS_MCS(ratespec)) {
+               uint mcs = ratespec & RSPEC_RATE_MASK;
+               int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
+               dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+               /* payload calculation matches that of regular ofdm */
+               if (BAND_2G(wlc->band->bandtype))
+                       dur -= DOT11_OFDM_SIGNAL_EXTENSION;
+               /* kNdbps = kbps * 4 */
+               kNdps =
+                   MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
+                            RSPEC_ISSGI(ratespec)) * 4;
+               nsyms = dur / APHY_SYMBOL_TIME;
+               mac_len =
+                   ((nsyms * kNdps) -
+                    ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
+       } else if (IS_OFDM(ratespec)) {
+               dur -= APHY_PREAMBLE_TIME;
+               dur -= APHY_SIGNAL_TIME;
+               /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+               Ndps = rate * 2;
+               nsyms = dur / APHY_SYMBOL_TIME;
+               mac_len =
+                   ((nsyms * Ndps) -
+                    (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
+       } else {
+               if (preamble_type & BRCMS_SHORT_PREAMBLE)
+                       dur -= BPHY_PLCP_SHORT_TIME;
+               else
+                       dur -= BPHY_PLCP_TIME;
+               mac_len = dur * rate;
+               /* divide out factor of 2 in rate (1/2 mbps) */
+               mac_len = mac_len / 8 / 2;
        }
-       /* PLCP signal byte */
-       plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */
-       /* PLCP service byte */
-       plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
-       /* PLCP length u16, little endian */
-       plcp[2] = usec & 0xff;
-       plcp[3] = (usec >> 8) & 0xff;
-       /* PLCP CRC16 */
-       plcp[4] = 0;
-       plcp[5] = 0;
+       return mac_len;
 }
 
-/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
-                                uint length, u8 *plcp)
+static u32
+mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
+                      u32 int_val)
 {
-       int rate = RSPEC2RATE(rspec);
-
-       brcms_c_cck_plcp_set(wlc, rate, length, plcp);
-}
+       u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
+       u8 rate = int_val & NRATE_RATE_MASK;
+       u32 rspec;
+       bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
+       bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
+       bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
+                                 == NRATE_OVERRIDE_MCS_ONLY);
+       int bcmerror = 0;
 
-/* brcms_c_compute_frame_dur()
- *
- * Calculate the 802.11 MAC header DUR field for MPDU
- * DUR for a single frame = 1 SIFS + 1 ACK
- * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
- *
- * rate                        MPDU rate in unit of 500kbps
- * next_frag_len       next MPDU length in bytes
- * preamble_type       use short/GF or long/MM PLCP header
- */
-static u16
-brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
-                     u8 preamble_type, uint next_frag_len)
-{
-       u16 dur, sifs;
+       if (!ismcs)
+               return (u32) rate;
 
-       sifs = SIFS(wlc->band);
+       /* validate the combination of rate/mcs/stf is allowed */
+       if (N_ENAB(wlc->pub) && ismcs) {
+               /* mcs only allowed when nmode */
+               if (stf > PHY_TXC1_MODE_SDM) {
+                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
+                                BRCMS_UNIT(wlc), __func__);
+                       bcmerror = -EINVAL;
+                       goto done;
+               }
 
-       dur = sifs;
-       dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
+               /* mcs 32 is a special case, DUP mode 40 only */
+               if (rate == 32) {
+                       if (!CHSPEC_IS40(wlc->home_chanspec) ||
+                           ((stf != PHY_TXC1_MODE_SISO)
+                            && (stf != PHY_TXC1_MODE_CDD))) {
+                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
+                                         "32\n", BRCMS_UNIT(wlc), __func__);
+                               bcmerror = -EINVAL;
+                               goto done;
+                       }
+                       /* mcs > 7 must use stf SDM */
+               } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
+                       /* mcs > 7 must use stf SDM */
+                       if (stf != PHY_TXC1_MODE_SDM) {
+                               BCMMSG(wlc->wiphy, "wl%d: enabling "
+                                        "SDM mode for mcs %d\n",
+                                        BRCMS_UNIT(wlc), rate);
+                               stf = PHY_TXC1_MODE_SDM;
+                       }
+               } else {
+                       /*
+                        * MCS 0-7 may use SISO, CDD, and for
+                        * phy_rev >= 3 STBC
+                        */
+                       if ((stf > PHY_TXC1_MODE_STBC) ||
+                           (!BRCMS_STBC_CAP_PHY(wlc)
+                            && (stf == PHY_TXC1_MODE_STBC))) {
+                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
+                                         "\n", BRCMS_UNIT(wlc), __func__);
+                               bcmerror = -EINVAL;
+                               goto done;
+                       }
+               }
+       } else if (IS_OFDM(rate)) {
+               if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
+                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
+                                 BRCMS_UNIT(wlc), __func__);
+                       bcmerror = -EINVAL;
+                       goto done;
+               }
+       } else if (IS_CCK(rate)) {
+               if ((cur_band->bandtype != BRCM_BAND_2G)
+                   || (stf != PHY_TXC1_MODE_SISO)) {
+                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
+                                 BRCMS_UNIT(wlc), __func__);
+                       bcmerror = -EINVAL;
+                       goto done;
+               }
+       } else {
+               wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
+                         BRCMS_UNIT(wlc), __func__);
+               bcmerror = -EINVAL;
+               goto done;
+       }
+       /* make sure multiple antennae are available for non-siso rates */
+       if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
+               wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
+                         "request\n", BRCMS_UNIT(wlc), __func__);
+               bcmerror = -EINVAL;
+               goto done;
+       }
 
-       if (next_frag_len) {
-               /* Double the current DUR to get 2 SIFS + 2 ACKs */
-               dur *= 2;
-               /* add another SIFS and the frag time */
-               dur += sifs;
-               dur +=
-                   (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
-                                                next_frag_len);
+       rspec = rate;
+       if (ismcs) {
+               rspec |= RSPEC_MIMORATE;
+               /* For STBC populate the STC field of the ratespec */
+               if (stf == PHY_TXC1_MODE_STBC) {
+                       u8 stc;
+                       stc = 1;        /* Nss for single stream is always 1 */
+                       rspec |= (stc << RSPEC_STC_SHIFT);
+               }
        }
-       return dur;
+
+       rspec |= (stf << RSPEC_STF_SHIFT);
+
+       if (override_mcs_only)
+               rspec |= RSPEC_OVERRIDE_MCS_ONLY;
+
+       if (issgi)
+               rspec |= RSPEC_SHORT_GI;
+
+       if ((rate != 0)
+           && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
+               return rate;
+
+       return rspec;
+done:
+       return rate;
 }
 
-/* brcms_c_compute_rtscts_dur()
+/*
+ * Add struct d11txh, struct cck_phy_hdr.
  *
- * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
- * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
- * DUR for CTS-TO-SELF w/ frame    = 2 SIFS         + next frame time + 1 ACK
+ * 'p' data must start with 802.11 MAC header
+ * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
+ *
+ * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
  *
- * cts                 cts-to-self or rts/cts
- * rts_rate            rts or cts rate in unit of 500kbps
- * rate                        next MPDU rate in unit of 500kbps
- * frame_len           next MPDU frame length in bytes
  */
-u16
-brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
-                          u32 rts_rate,
-                          u32 frame_rate, u8 rts_preamble_type,
-                          u8 frame_preamble_type, uint frame_len, bool ba)
-{
-       u16 dur, sifs;
-
-       sifs = SIFS(wlc->band);
-
-       if (!cts_only) {
-               /* RTS/CTS */
-               dur = 3 * sifs;
-               dur +=
-                   (u16) brcms_c_calc_cts_time(wlc, rts_rate,
-                                              rts_preamble_type);
-       } else {
-               /* CTS-TO-SELF */
-               dur = 2 * sifs;
-       }
-
-       dur +=
-           (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,
-                                        frame_len);
-       if (ba)
-               dur +=
-                   (u16) brcms_c_calc_ba_time(wlc, frame_rate,
-                                             BRCMS_SHORT_PREAMBLE);
-       else
-               dur +=
-                   (u16) brcms_c_calc_ack_time(wlc, frame_rate,
-                                              frame_preamble_type);
-       return dur;
-}
-
-u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
-{
-       u16 phyctl1 = 0;
-       u16 bw;
-
-       if (BRCMS_ISLCNPHY(wlc->band)) {
-               bw = PHY_TXC1_BW_20MHZ;
-       } else {
-               bw = RSPEC_GET_BW(rspec);
-               /* 10Mhz is not supported yet */
-               if (bw < PHY_TXC1_BW_20MHZ) {
-                       wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
-                                 "not supported yet, set to 20L\n", bw);
-                       bw = PHY_TXC1_BW_20MHZ;
-               }
-       }
-
-       if (IS_MCS(rspec)) {
-               uint mcs = rspec & RSPEC_RATE_MASK;
-
-               /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */
-               phyctl1 = RSPEC_PHYTXBYTE2(rspec);
-               /* set the upper byte of phyctl1 */
-               phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
-       } else if (IS_CCK(rspec) && !BRCMS_ISLCNPHY(wlc->band)
-                  && !BRCMS_ISSSLPNPHY(wlc->band)) {
-               /*
-                * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
-                * Data Rate. Eventually MIMOPHY would also be converted to
-                * this format
-                */
-               /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
-               phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
-       } else {                /* legacy OFDM/CCK */
-               s16 phycfg;
-               /* get the phyctl byte from rate phycfg table */
-               phycfg = brcms_c_rate_legacy_phyctl(RSPEC2RATE(rspec));
-               if (phycfg == -1) {
-                       wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
-                                 "legacy OFDM/CCK rate\n");
-                       phycfg = 0;
-               }
-               /* set the upper byte of phyctl1 */
-               phyctl1 =
-                   (bw | (phycfg << 8) |
-                    (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
-       }
-       return phyctl1;
-}
-
-u32
-brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
-                          bool use_rspec, u16 mimo_ctlchbw)
-{
-       u32 rts_rspec = 0;
-
-       if (use_rspec)
-               /* use frame rate as rts rate */
-               rts_rspec = rspec;
-       else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec))
-               /* Use 11Mbps as the g protection RTS target rate and fallback.
-                * Use the BRCMS_BASIC_RATE() lookup to find the best basic rate
-                * under the target in case 11 Mbps is not Basic.
-                * 6 and 9 Mbps are not usually selected by rate selection, but
-                * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
-                * is more robust.
-                */
-               rts_rspec = BRCMS_BASIC_RATE(wlc, BRCM_RATE_11M);
-       else
-               /* calculate RTS rate and fallback rate based on the frame rate
-                * RTS must be sent at a basic rate since it is a
-                * control frame, sec 9.6 of 802.11 spec
-                */
-               rts_rspec = BRCMS_BASIC_RATE(wlc, rspec);
-
-       if (BRCMS_PHY_11N_CAP(wlc->band)) {
-               /* set rts txbw to correct side band */
-               rts_rspec &= ~RSPEC_BW_MASK;
-
-               /*
-                * if rspec/rspec_fallback is 40MHz, then send RTS on both
-                * 20MHz channel (DUP), otherwise send RTS on control channel
-                */
-               if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec))
-                       rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
-               else
-                       rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
-
-               /* pick siso/cdd as default for ofdm */
-               if (IS_OFDM(rts_rspec)) {
-                       rts_rspec &= ~RSPEC_STF_MASK;
-                       rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
-               }
-       }
-       return rts_rspec;
-}
-
-/*
- * Add struct d11txh, struct cck_phy_hdr.
- *
- * 'p' data must start with 802.11 MAC header
- * 'p' must allow enough bytes of local headers to be "pushed" onto the packet
- *
- * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)
- *
- */
-static u16
-brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
-                    struct sk_buff *p, struct scb *scb, uint frag,
-                    uint nfrags, uint queue, uint next_frag_len,
-                    struct wsec_key *key, u32 rspec_override)
+static u16
+brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
+                    struct sk_buff *p, struct scb *scb, uint frag,
+                    uint nfrags, uint queue, uint next_frag_len,
+                    struct wsec_key *key, u32 rspec_override)
 {
        struct ieee80211_hdr *h;
        struct d11txh *txh;
@@ -7249,621 +7049,1022 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        u16 mimo_txbw;
        u8 mimo_preamble_type;
 
-       /* locate 802.11 MAC header */
-       h = (struct ieee80211_hdr *)(p->data);
-       qos = ieee80211_is_data_qos(h->frame_control);
+       /* locate 802.11 MAC header */
+       h = (struct ieee80211_hdr *)(p->data);
+       qos = ieee80211_is_data_qos(h->frame_control);
+
+       /* compute length of frame in bytes for use in PLCP computations */
+       len = brcmu_pkttotlen(p);
+       phylen = len + FCS_LEN;
+
+       /* If WEP enabled, add room in phylen for the additional bytes of
+        * ICV which MAC generates.  We do NOT add the additional bytes to
+        * the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN
+        * in this case
+        */
+       if (key)
+               phylen += key->icv_len;
+
+       /* Get tx_info */
+       tx_info = IEEE80211_SKB_CB(p);
+
+       /* add PLCP */
+       plcp = skb_push(p, D11_PHY_HDR_LEN);
+
+       /* add Broadcom tx descriptor header */
+       txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
+       memset(txh, 0, D11_TXH_LEN);
+
+       /* setup frameid */
+       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               /* non-AP STA should never use BCMC queue */
+               if (queue == TX_BCMC_FIFO) {
+                       wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
+                                 "TX_BCMC!\n", BRCMS_UNIT(wlc), __func__);
+                       frameid = bcmc_fid_generate(wlc, NULL, txh);
+               } else {
+                       /* Increment the counter for first fragment */
+                       if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                               SCB_SEQNUM(scb, p->priority)++;
+
+                       /* extract fragment number from frame first */
+                       seq = le16_to_cpu(seq) & FRAGNUM_MASK;
+                       seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT);
+                       h->seq_ctrl = cpu_to_le16(seq);
+
+                       frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
+                           (queue & TXFID_QUEUE_MASK);
+               }
+       }
+       frameid |= queue & TXFID_QUEUE_MASK;
+
+       /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
+       if (SCB_PS(scb) || ieee80211_is_beacon(h->frame_control))
+               mcl |= TXC_IGNOREPMQ;
+
+       txrate[0] = tx_info->control.rates;
+       txrate[1] = txrate[0] + 1;
+
+       /*
+        * if rate control algorithm didn't give us a fallback
+        * rate, use the primary rate
+        */
+       if (txrate[1]->idx < 0)
+               txrate[1] = txrate[0];
+
+       for (k = 0; k < hw->max_rates; k++) {
+               is_mcs[k] =
+                   txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
+               if (!is_mcs[k]) {
+                       if ((txrate[k]->idx >= 0)
+                           && (txrate[k]->idx <
+                               hw->wiphy->bands[tx_info->band]->n_bitrates)) {
+                               rate_val[k] =
+                                   hw->wiphy->bands[tx_info->band]->
+                                   bitrates[txrate[k]->idx].hw_value;
+                               short_preamble[k] =
+                                   txrate[k]->
+                                   flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
+                                   true : false;
+                       } else {
+                               rate_val[k] = BRCM_RATE_1M;
+                       }
+               } else {
+                       rate_val[k] = txrate[k]->idx;
+               }
+
+               /*
+                * Currently only support same setting for primay and
+                * fallback rates. Unify flags for each rate into a
+                * single value for the frame
+                */
+               use_rts |=
+                   txrate[k]->
+                   flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
+               use_cts |=
+                   txrate[k]->
+                   flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
+
+               if (is_mcs[k])
+                       rate_val[k] |= NRATE_MCS_INUSE;
+
+               rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]);
+
+               /*
+                * (1) RATE:
+                *   determine and validate primary rate
+                *   and fallback rates
+                */
+               if (!RSPEC_ACTIVE(rspec[k])) {
+                       rspec[k] = BRCM_RATE_1M;
+               } else {
+                       if (!is_multicast_ether_addr(h->addr1)) {
+                               /* set tx antenna config */
+                               brcms_c_antsel_antcfg_get(wlc->asi, false,
+                                       false, 0, 0, &antcfg, &fbantcfg);
+                       }
+               }
+       }
+
+       phyctl1_stf = wlc->stf->ss_opmode;
+
+       if (N_ENAB(wlc->pub)) {
+               for (k = 0; k < hw->max_rates; k++) {
+                       /*
+                        * apply siso/cdd to single stream mcs's or ofdm
+                        * if rspec is auto selected
+                        */
+                       if (((IS_MCS(rspec[k]) &&
+                             IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
+                            IS_OFDM(rspec[k]))
+                           && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
+                               || !(rspec[k] & RSPEC_OVERRIDE))) {
+                               rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
+
+                               /* For SISO MCS use STBC if possible */
+                               if (IS_MCS(rspec[k])
+                                   && BRCMS_STF_SS_STBC_TX(wlc, scb)) {
+                                       u8 stc;
+
+                                       /* Nss for single stream is always 1 */
+                                       stc = 1;
+                                       rspec[k] |= (PHY_TXC1_MODE_STBC <<
+                                                       RSPEC_STF_SHIFT) |
+                                                   (stc << RSPEC_STC_SHIFT);
+                               } else
+                                       rspec[k] |=
+                                           (phyctl1_stf << RSPEC_STF_SHIFT);
+                       }
+
+                       /*
+                        * Is the phy configured to use 40MHZ frames? If
+                        * so then pick the desired txbw
+                        */
+                       if (CHSPEC_WLC_BW(wlc->chanspec) == BRCMS_40_MHZ) {
+                               /* default txbw is 20in40 SB */
+                               mimo_ctlchbw = mimo_txbw =
+                                  CHSPEC_SB_UPPER(BRCMS_BAND_PI_RADIO_CHANSPEC)
+                                  ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
+
+                               if (IS_MCS(rspec[k])) {
+                                       /* mcs 32 must be 40b/w DUP */
+                                       if ((rspec[k] & RSPEC_RATE_MASK)
+                                           == 32) {
+                                               mimo_txbw =
+                                                   PHY_TXC1_BW_40MHZ_DUP;
+                                               /* use override */
+                                       } else if (wlc->mimo_40txbw != AUTO)
+                                               mimo_txbw = wlc->mimo_40txbw;
+                                       /* else check if dst is using 40 Mhz */
+                                       else if (scb->flags & SCB_IS40)
+                                               mimo_txbw = PHY_TXC1_BW_40MHZ;
+                               } else if (IS_OFDM(rspec[k])) {
+                                       if (wlc->ofdm_40txbw != AUTO)
+                                               mimo_txbw = wlc->ofdm_40txbw;
+                               } else if (wlc->cck_40txbw != AUTO) {
+                                       mimo_txbw = wlc->cck_40txbw;
+                               }
+                       } else {
+                               /*
+                                * mcs32 is 40 b/w only.
+                                * This is possible for probe packets on
+                                * a STA during SCAN
+                                */
+                               if ((rspec[k] & RSPEC_RATE_MASK) == 32)
+                                       /* mcs 0 */
+                                       rspec[k] = RSPEC_MIMORATE;
+
+                               mimo_txbw = PHY_TXC1_BW_20MHZ;
+                       }
+
+                       /* Set channel width */
+                       rspec[k] &= ~RSPEC_BW_MASK;
+                       if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
+                               rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
+                       else
+                               rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
+
+                       /* Disable short GI, not supported yet */
+                       rspec[k] &= ~RSPEC_SHORT_GI;
+
+                       mimo_preamble_type = BRCMS_MM_PREAMBLE;
+                       if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
+                               mimo_preamble_type = BRCMS_GF_PREAMBLE;
+
+                       if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
+                           && (!IS_MCS(rspec[k]))) {
+                               wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
+                                         "RC_MCS != IS_MCS(rspec)\n",
+                                         BRCMS_UNIT(wlc), __func__);
+                       }
+
+                       if (IS_MCS(rspec[k])) {
+                               preamble_type[k] = mimo_preamble_type;
+
+                               /*
+                                * if SGI is selected, then forced mm
+                                * for single stream
+                                */
+                               if ((rspec[k] & RSPEC_SHORT_GI)
+                                   && IS_SINGLE_STREAM(rspec[k] &
+                                                       RSPEC_RATE_MASK))
+                                       preamble_type[k] = BRCMS_MM_PREAMBLE;
+                       }
+
+                       /* should be better conditionalized */
+                       if (!IS_MCS(rspec[0])
+                           && (tx_info->control.rates[0].
+                               flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
+                               preamble_type[k] = BRCMS_SHORT_PREAMBLE;
+               }
+       } else {
+               for (k = 0; k < hw->max_rates; k++) {
+                       /* Set ctrlchbw as 20Mhz */
+                       rspec[k] &= ~RSPEC_BW_MASK;
+                       rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
+
+                       /* for nphy, stf of ofdm frames must follow policies */
+                       if (BRCMS_ISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
+                               rspec[k] &= ~RSPEC_STF_MASK;
+                               rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
+                       }
+               }
+       }
+
+       /* Reset these for use with AMPDU's */
+       txrate[0]->count = 0;
+       txrate[1]->count = 0;
+
+       /* (2) PROTECTION, may change rspec */
+       if ((ieee80211_is_data(h->frame_control) ||
+           ieee80211_is_mgmt(h->frame_control)) &&
+           (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))
+               use_rts = true;
+
+       /* (3) PLCP: determine PLCP header and MAC duration,
+        * fill struct d11txh */
+       brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);
+       brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
+       memcpy(&txh->FragPLCPFallback,
+              plcp_fallback, sizeof(txh->FragPLCPFallback));
+
+       /* Length field now put in CCK FBR CRC field */
+       if (IS_CCK(rspec[1])) {
+               txh->FragPLCPFallback[4] = phylen & 0xff;
+               txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
+       }
+
+       /* MIMO-RATE: need validation ?? */
+       mainrates = IS_OFDM(rspec[0]) ?
+                       D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
+                       plcp[0];
+
+       /* DUR field for main rate */
+       if (!ieee80211_is_pspoll(h->frame_control) &&
+           !is_multicast_ether_addr(h->addr1) && !use_rifs) {
+               durid =
+                   brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],
+                                         next_frag_len);
+               h->duration_id = cpu_to_le16(durid);
+       } else if (use_rifs) {
+               /* NAV protect to end of next max packet size */
+               durid =
+                   (u16) brcms_c_calc_frame_time(wlc, rspec[0],
+                                                preamble_type[0],
+                                                DOT11_MAX_FRAG_LEN);
+               durid += RIFS_11N_TIME;
+               h->duration_id = cpu_to_le16(durid);
+       }
+
+       /* DUR field for fallback rate */
+       if (ieee80211_is_pspoll(h->frame_control))
+               txh->FragDurFallback = h->duration_id;
+       else if (is_multicast_ether_addr(h->addr1) || use_rifs)
+               txh->FragDurFallback = 0;
+       else {
+               durid = brcms_c_compute_frame_dur(wlc, rspec[1],
+                                             preamble_type[1], next_frag_len);
+               txh->FragDurFallback = cpu_to_le16(durid);
+       }
 
-       /* compute length of frame in bytes for use in PLCP computations */
-       len = brcmu_pkttotlen(p);
-       phylen = len + FCS_LEN;
+       /* (4) MAC-HDR: MacTxControlLow */
+       if (frag == 0)
+               mcl |= TXC_STARTMSDU;
 
-       /* If WEP enabled, add room in phylen for the additional bytes of
-        * ICV which MAC generates.  We do NOT add the additional bytes to
-        * the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN
-        * in this case
-        */
-       if (key)
-               phylen += key->icv_len;
+       if (!is_multicast_ether_addr(h->addr1))
+               mcl |= TXC_IMMEDACK;
 
-       /* Get tx_info */
-       tx_info = IEEE80211_SKB_CB(p);
+       if (BAND_5G(wlc->band->bandtype))
+               mcl |= TXC_FREQBAND_5G;
 
-       /* add PLCP */
-       plcp = skb_push(p, D11_PHY_HDR_LEN);
+       if (CHSPEC_IS40(BRCMS_BAND_PI_RADIO_CHANSPEC))
+               mcl |= TXC_BW_40;
 
-       /* add Broadcom tx descriptor header */
-       txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
-       memset(txh, 0, D11_TXH_LEN);
+       /* set AMIC bit if using hardware TKIP MIC */
+       if (hwtkmic)
+               mcl |= TXC_AMIC;
 
-       /* setup frameid */
-       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               /* non-AP STA should never use BCMC queue */
-               if (queue == TX_BCMC_FIFO) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
-                                 "TX_BCMC!\n", BRCMS_UNIT(wlc), __func__);
-                       frameid = bcmc_fid_generate(wlc, NULL, txh);
-               } else {
-                       /* Increment the counter for first fragment */
-                       if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-                               SCB_SEQNUM(scb, p->priority)++;
+       txh->MacTxControlLow = cpu_to_le16(mcl);
 
-                       /* extract fragment number from frame first */
-                       seq = le16_to_cpu(seq) & FRAGNUM_MASK;
-                       seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT);
-                       h->seq_ctrl = cpu_to_le16(seq);
+       /* MacTxControlHigh */
+       mch = 0;
 
-                       frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
-                           (queue & TXFID_QUEUE_MASK);
-               }
+       /* Set fallback rate preamble type */
+       if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
+           (preamble_type[1] == BRCMS_GF_PREAMBLE)) {
+               if (RSPEC2RATE(rspec[1]) != BRCM_RATE_1M)
+                       mch |= TXC_PREAMBLE_DATA_FB_SHORT;
        }
-       frameid |= queue & TXFID_QUEUE_MASK;
 
-       /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
-       if (SCB_PS(scb) || ieee80211_is_beacon(h->frame_control))
-               mcl |= TXC_IGNOREPMQ;
+       /* MacFrameControl */
+       memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));
+       txh->TxFesTimeNormal = cpu_to_le16(0);
 
-       txrate[0] = tx_info->control.rates;
-       txrate[1] = txrate[0] + 1;
+       txh->TxFesTimeFallback = cpu_to_le16(0);
+
+       /* TxFrameRA */
+       memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);
+
+       /* TxFrameID */
+       txh->TxFrameID = cpu_to_le16(frameid);
 
        /*
-        * if rate control algorithm didn't give us a fallback
-        * rate, use the primary rate
+        * TxStatus, Note the case of recreating the first frag of a suppressed
+        * frame then we may need to reset the retry cnt's via the status reg
         */
-       if (txrate[1]->idx < 0)
-               txrate[1] = txrate[0];
+       txh->TxStatus = cpu_to_le16(status);
 
-       for (k = 0; k < hw->max_rates; k++) {
-               is_mcs[k] =
-                   txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
-               if (!is_mcs[k]) {
-                       if ((txrate[k]->idx >= 0)
-                           && (txrate[k]->idx <
-                               hw->wiphy->bands[tx_info->band]->n_bitrates)) {
-                               rate_val[k] =
-                                   hw->wiphy->bands[tx_info->band]->
-                                   bitrates[txrate[k]->idx].hw_value;
-                               short_preamble[k] =
-                                   txrate[k]->
-                                   flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
-                                   true : false;
-                       } else {
-                               rate_val[k] = BRCM_RATE_1M;
-                       }
-               } else {
-                       rate_val[k] = txrate[k]->idx;
-               }
+       /*
+        * extra fields for ucode AMPDU aggregation, the new fields are added to
+        * the END of previous structure so that it's compatible in driver.
+        */
+       txh->MaxNMpdus = cpu_to_le16(0);
+       txh->MaxABytes_MRT = cpu_to_le16(0);
+       txh->MaxABytes_FBR = cpu_to_le16(0);
+       txh->MinMBytes = cpu_to_le16(0);
 
-               /*
-                * Currently only support same setting for primay and
-                * fallback rates. Unify flags for each rate into a
-                * single value for the frame
-                */
-               use_rts |=
-                   txrate[k]->
-                   flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;
-               use_cts |=
-                   txrate[k]->
-                   flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
+       /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,
+        * furnish struct d11txh */
+       /* RTS PLCP header and RTS frame */
+       if (use_rts || use_cts) {
+               if (use_rts && use_cts)
+                       use_cts = false;
 
-               if (is_mcs[k])
-                       rate_val[k] |= NRATE_MCS_INUSE;
+               for (k = 0; k < 2; k++) {
+                       rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],
+                                                             false,
+                                                             mimo_ctlchbw);
+               }
 
-               rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]);
+               if (!IS_OFDM(rts_rspec[0]) &&
+                   !((RSPEC2RATE(rts_rspec[0]) == BRCM_RATE_1M) ||
+                     (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
+                       rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
+                       mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
+               }
 
-               /*
-                * (1) RATE:
-                *   determine and validate primary rate
-                *   and fallback rates
-                */
-               if (!RSPEC_ACTIVE(rspec[k])) {
-                       rspec[k] = BRCM_RATE_1M;
+               if (!IS_OFDM(rts_rspec[1]) &&
+                   !((RSPEC2RATE(rts_rspec[1]) == BRCM_RATE_1M) ||
+                     (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
+                       rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
+                       mch |= TXC_PREAMBLE_RTS_FB_SHORT;
+               }
+
+               /* RTS/CTS additions to MacTxControlLow */
+               if (use_cts) {
+                       txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);
                } else {
-                       if (!is_multicast_ether_addr(h->addr1)) {
-                               /* set tx antenna config */
-                               brcms_c_antsel_antcfg_get(wlc->asi, false,
-                                       false, 0, 0, &antcfg, &fbantcfg);
-                       }
+                       txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);
+                       txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);
                }
-       }
 
-       phyctl1_stf = wlc->stf->ss_opmode;
+               /* RTS PLCP header */
+               rts_plcp = txh->RTSPhyHeader;
+               if (use_cts)
+                       rts_phylen = DOT11_CTS_LEN + FCS_LEN;
+               else
+                       rts_phylen = DOT11_RTS_LEN + FCS_LEN;
 
-       if (N_ENAB(wlc->pub)) {
-               for (k = 0; k < hw->max_rates; k++) {
-                       /*
-                        * apply siso/cdd to single stream mcs's or ofdm
-                        * if rspec is auto selected
-                        */
-                       if (((IS_MCS(rspec[k]) &&
-                             IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
-                            IS_OFDM(rspec[k]))
-                           && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
-                               || !(rspec[k] & RSPEC_OVERRIDE))) {
-                               rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
+               brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
 
-                               /* For SISO MCS use STBC if possible */
-                               if (IS_MCS(rspec[k])
-                                   && BRCMS_STF_SS_STBC_TX(wlc, scb)) {
-                                       u8 stc;
+               /* fallback rate version of RTS PLCP header */
+               brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,
+                                rts_plcp_fallback);
+               memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,
+                      sizeof(txh->RTSPLCPFallback));
 
-                                       /* Nss for single stream is always 1 */
-                                       stc = 1;
-                                       rspec[k] |= (PHY_TXC1_MODE_STBC <<
-                                                       RSPEC_STF_SHIFT) |
-                                                   (stc << RSPEC_STC_SHIFT);
-                               } else
-                                       rspec[k] |=
-                                           (phyctl1_stf << RSPEC_STF_SHIFT);
-                       }
+               /* RTS frame fields... */
+               rts = (struct ieee80211_rts *)&txh->rts_frame;
+
+               durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
+                                              rspec[0], rts_preamble_type[0],
+                                              preamble_type[0], phylen, false);
+               rts->duration = cpu_to_le16(durid);
+               /* fallback rate version of RTS DUR field */
+               durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
+                                              rts_rspec[1], rspec[1],
+                                              rts_preamble_type[1],
+                                              preamble_type[1], phylen, false);
+               txh->RTSDurFallback = cpu_to_le16(durid);
+
+               if (use_cts) {
+                       rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                                        IEEE80211_STYPE_CTS);
+
+                       memcpy(&rts->ra, &h->addr2, ETH_ALEN);
+               } else {
+                       rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                                        IEEE80211_STYPE_RTS);
+
+                       memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN);
+               }
+
+               /* mainrate
+                *    low 8 bits: main frag rate/mcs,
+                *    high 8 bits: rts/cts rate/mcs
+                */
+               mainrates |= (IS_OFDM(rts_rspec[0]) ?
+                               D11A_PHY_HDR_GRATE(
+                                       (struct ofdm_phy_hdr *) rts_plcp) :
+                               rts_plcp[0]) << 8;
+       } else {
+               memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
+               memset((char *)&txh->rts_frame, 0,
+                       sizeof(struct ieee80211_rts));
+               memset((char *)txh->RTSPLCPFallback, 0,
+                     sizeof(txh->RTSPLCPFallback));
+               txh->RTSDurFallback = 0;
+       }
 
-                       /*
-                        * Is the phy configured to use 40MHZ frames? If
-                        * so then pick the desired txbw
-                        */
-                       if (CHSPEC_WLC_BW(wlc->chanspec) == BRCMS_40_MHZ) {
-                               /* default txbw is 20in40 SB */
-                               mimo_ctlchbw = mimo_txbw =
-                                  CHSPEC_SB_UPPER(BRCMS_BAND_PI_RADIO_CHANSPEC)
-                                  ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
+#ifdef SUPPORT_40MHZ
+       /* add null delimiter count */
+       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec))
+               txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
+                  brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
 
-                               if (IS_MCS(rspec[k])) {
-                                       /* mcs 32 must be 40b/w DUP */
-                                       if ((rspec[k] & RSPEC_RATE_MASK)
-                                           == 32) {
-                                               mimo_txbw =
-                                                   PHY_TXC1_BW_40MHZ_DUP;
-                                               /* use override */
-                                       } else if (wlc->mimo_40txbw != AUTO)
-                                               mimo_txbw = wlc->mimo_40txbw;
-                                       /* else check if dst is using 40 Mhz */
-                                       else if (scb->flags & SCB_IS40)
-                                               mimo_txbw = PHY_TXC1_BW_40MHZ;
-                               } else if (IS_OFDM(rspec[k])) {
-                                       if (wlc->ofdm_40txbw != AUTO)
-                                               mimo_txbw = wlc->ofdm_40txbw;
-                               } else if (wlc->cck_40txbw != AUTO) {
-                                       mimo_txbw = wlc->cck_40txbw;
-                               }
-                       } else {
-                               /*
-                                * mcs32 is 40 b/w only.
-                                * This is possible for probe packets on
-                                * a STA during SCAN
-                                */
-                               if ((rspec[k] & RSPEC_RATE_MASK) == 32)
-                                       /* mcs 0 */
-                                       rspec[k] = RSPEC_MIMORATE;
+#endif
 
-                               mimo_txbw = PHY_TXC1_BW_20MHZ;
-                       }
+       /*
+        * Now that RTS/RTS FB preamble types are updated, write
+        * the final value
+        */
+       txh->MacTxControlHigh = cpu_to_le16(mch);
 
-                       /* Set channel width */
-                       rspec[k] &= ~RSPEC_BW_MASK;
-                       if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
-                               rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
-                       else
-                               rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
+       /*
+        * MainRates (both the rts and frag plcp rates have
+        * been calculated now)
+        */
+       txh->MainRates = cpu_to_le16(mainrates);
 
-                       /* Disable short GI, not supported yet */
-                       rspec[k] &= ~RSPEC_SHORT_GI;
+       /* XtraFrameTypes */
+       xfts = FRAMETYPE(rspec[1], wlc->mimoft);
+       xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
+       xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
+       xfts |=
+           CHSPEC_CHANNEL(BRCMS_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT;
+       txh->XtraFrameTypes = cpu_to_le16(xfts);
 
-                       mimo_preamble_type = BRCMS_MM_PREAMBLE;
-                       if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
-                               mimo_preamble_type = BRCMS_GF_PREAMBLE;
+       /* PhyTxControlWord */
+       phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
+       if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
+           (preamble_type[0] == BRCMS_GF_PREAMBLE)) {
+               if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M)
+                       phyctl |= PHY_TXC_SHORT_HDR;
+       }
 
-                       if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
-                           && (!IS_MCS(rspec[k]))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
-                                         "RC_MCS != IS_MCS(rspec)\n",
-                                         BRCMS_UNIT(wlc), __func__);
-                       }
+       /* phytxant is properly bit shifted */
+       phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
+       txh->PhyTxControlWord = cpu_to_le16(phyctl);
 
-                       if (IS_MCS(rspec[k])) {
-                               preamble_type[k] = mimo_preamble_type;
+       /* PhyTxControlWord_1 */
+       if (BRCMS_PHY_11N_CAP(wlc->band)) {
+               u16 phyctl1 = 0;
 
-                               /*
-                                * if SGI is selected, then forced mm
-                                * for single stream
-                                */
-                               if ((rspec[k] & RSPEC_SHORT_GI)
-                                   && IS_SINGLE_STREAM(rspec[k] &
-                                                       RSPEC_RATE_MASK))
-                                       preamble_type[k] = BRCMS_MM_PREAMBLE;
-                       }
+               phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);
+               txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);
+               phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);
+               txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);
 
-                       /* should be better conditionalized */
-                       if (!IS_MCS(rspec[0])
-                           && (tx_info->control.rates[0].
-                               flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
-                               preamble_type[k] = BRCMS_SHORT_PREAMBLE;
+               if (use_rts || use_cts) {
+                       phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);
+                       txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);
+                       phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);
+                       txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);
                }
-       } else {
-               for (k = 0; k < hw->max_rates; k++) {
-                       /* Set ctrlchbw as 20Mhz */
-                       rspec[k] &= ~RSPEC_BW_MASK;
-                       rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
 
-                       /* for nphy, stf of ofdm frames must follow policies */
-                       if (BRCMS_ISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
-                               rspec[k] &= ~RSPEC_STF_MASK;
-                               rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
-                       }
+               /*
+                * For mcs frames, if mixedmode(overloaded with long preamble)
+                * is going to be set, fill in non-zero MModeLen and/or
+                * MModeFbrLen it will be unnecessary if they are separated
+                */
+               if (IS_MCS(rspec[0]) &&
+                   (preamble_type[0] == BRCMS_MM_PREAMBLE)) {
+                       u16 mmodelen =
+                           brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
+                       txh->MModeLen = cpu_to_le16(mmodelen);
+               }
+
+               if (IS_MCS(rspec[1]) &&
+                   (preamble_type[1] == BRCMS_MM_PREAMBLE)) {
+                       u16 mmodefbrlen =
+                           brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
+                       txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);
                }
        }
 
-       /* Reset these for use with AMPDU's */
-       txrate[0]->count = 0;
-       txrate[1]->count = 0;
+       ac = skb_get_queue_mapping(p);
+       if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
+               uint frag_dur, dur, dur_fallback;
 
-       /* (2) PROTECTION, may change rspec */
-       if ((ieee80211_is_data(h->frame_control) ||
-           ieee80211_is_mgmt(h->frame_control)) &&
-           (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))
-               use_rts = true;
+               /* WME: Update TXOP threshold */
+               if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
+                       frag_dur =
+                           brcms_c_calc_frame_time(wlc, rspec[0],
+                                       preamble_type[0], phylen);
 
-       /* (3) PLCP: determine PLCP header and MAC duration,
-        * fill struct d11txh */
-       brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);
-       brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);
-       memcpy(&txh->FragPLCPFallback,
-              plcp_fallback, sizeof(txh->FragPLCPFallback));
+                       if (rts) {
+                               /* 1 RTS or CTS-to-self frame */
+                               dur =
+                                   brcms_c_calc_cts_time(wlc, rts_rspec[0],
+                                                     rts_preamble_type[0]);
+                               dur_fallback =
+                                   brcms_c_calc_cts_time(wlc, rts_rspec[1],
+                                                     rts_preamble_type[1]);
+                               /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
+                               dur += le16_to_cpu(rts->duration);
+                               dur_fallback +=
+                                       le16_to_cpu(txh->RTSDurFallback);
+                       } else if (use_rifs) {
+                               dur = frag_dur;
+                               dur_fallback = 0;
+                       } else {
+                               /* frame + SIFS + ACK */
+                               dur = frag_dur;
+                               dur +=
+                                   brcms_c_compute_frame_dur(wlc, rspec[0],
+                                                         preamble_type[0], 0);
 
-       /* Length field now put in CCK FBR CRC field */
-       if (IS_CCK(rspec[1])) {
-               txh->FragPLCPFallback[4] = phylen & 0xff;
-               txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
-       }
+                               dur_fallback =
+                                   brcms_c_calc_frame_time(wlc, rspec[1],
+                                                       preamble_type[1],
+                                                       phylen);
+                               dur_fallback +=
+                                   brcms_c_compute_frame_dur(wlc, rspec[1],
+                                                         preamble_type[1], 0);
+                       }
+                       /* NEED to set TxFesTimeNormal (hard) */
+                       txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
+                       /*
+                        * NEED to set fallback rate version of
+                        * TxFesTimeNormal (hard)
+                        */
+                       txh->TxFesTimeFallback =
+                               cpu_to_le16((u16) dur_fallback);
 
-       /* MIMO-RATE: need validation ?? */
-       mainrates = IS_OFDM(rspec[0]) ?
-                       D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
-                       plcp[0];
+                       /*
+                        * update txop byte threshold (txop minus intraframe
+                        * overhead)
+                        */
+                       if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
+                               uint newfragthresh;
 
-       /* DUR field for main rate */
-       if (!ieee80211_is_pspoll(h->frame_control) &&
-           !is_multicast_ether_addr(h->addr1) && !use_rifs) {
-               durid =
-                   brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],
-                                         next_frag_len);
-               h->duration_id = cpu_to_le16(durid);
-       } else if (use_rifs) {
-               /* NAV protect to end of next max packet size */
-               durid =
-                   (u16) brcms_c_calc_frame_time(wlc, rspec[0],
-                                                preamble_type[0],
-                                                DOT11_MAX_FRAG_LEN);
-               durid += RIFS_11N_TIME;
-               h->duration_id = cpu_to_le16(durid);
-       }
+                               newfragthresh =
+                                   brcms_c_calc_frame_len(wlc,
+                                       rspec[0], preamble_type[0],
+                                       (wlc->edcf_txop[ac] -
+                                               (dur - frag_dur)));
+                               /* range bound the fragthreshold */
+                               if (newfragthresh < DOT11_MIN_FRAG_LEN)
+                                       newfragthresh =
+                                           DOT11_MIN_FRAG_LEN;
+                               else if (newfragthresh >
+                                        wlc->usr_fragthresh)
+                                       newfragthresh =
+                                           wlc->usr_fragthresh;
+                               /* update the fragthresh and do txc update */
+                               if (wlc->fragthresh[queue] !=
+                                   (u16) newfragthresh)
+                                       wlc->fragthresh[queue] =
+                                           (u16) newfragthresh;
+                       } else {
+                               wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
+                                         "for rate %d\n",
+                                         wlc->pub->unit, fifo_names[queue],
+                                         RSPEC2RATE(rspec[0]));
+                       }
 
-       /* DUR field for fallback rate */
-       if (ieee80211_is_pspoll(h->frame_control))
-               txh->FragDurFallback = h->duration_id;
-       else if (is_multicast_ether_addr(h->addr1) || use_rifs)
-               txh->FragDurFallback = 0;
-       else {
-               durid = brcms_c_compute_frame_dur(wlc, rspec[1],
-                                             preamble_type[1], next_frag_len);
-               txh->FragDurFallback = cpu_to_le16(durid);
+                       if (dur > wlc->edcf_txop[ac])
+                               wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
+                                         "exceeded phylen %d/%d dur %d/%d\n",
+                                         wlc->pub->unit, __func__,
+                                         fifo_names[queue],
+                                         phylen, wlc->fragthresh[queue],
+                                         dur, wlc->edcf_txop[ac]);
+               }
        }
 
-       /* (4) MAC-HDR: MacTxControlLow */
-       if (frag == 0)
-               mcl |= TXC_STARTMSDU;
+       return 0;
+}
 
-       if (!is_multicast_ether_addr(h->addr1))
-               mcl |= TXC_IMMEDACK;
+bool
+brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
+                    struct ieee80211_hw *hw)
+{
+       u8 prio;
+       uint fifo;
+       struct scb *scb = &global_scb;
+       struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
 
-       if (BAND_5G(wlc->band->bandtype))
-               mcl |= TXC_FREQBAND_5G;
+       /*
+        * 802.11 standard requires management traffic
+        * to go at highest priority
+        */
+       prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
+               MAXPRIO;
+       fifo = prio2fifo[prio];
+       if (unlikely
+           (brcms_c_d11hdrs_mac80211(
+               wlc, hw, sdu, scb, 0, 1, fifo, 0, NULL, 0)))
+               return -EINVAL;
+       brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
+       brcms_c_send_q(wlc);
+       return 0;
+}
 
-       if (CHSPEC_IS40(BRCMS_BAND_PI_RADIO_CHANSPEC))
-               mcl |= TXC_BW_40;
+void brcms_c_send_q(struct brcms_c_info *wlc)
+{
+       struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
+       int prec;
+       u16 prec_map;
+       int err = 0, i, count;
+       uint fifo;
+       struct brcms_txq_info *qi = wlc->pkt_queue;
+       struct pktq *q = &qi->q;
+       struct ieee80211_tx_info *tx_info;
 
-       /* set AMIC bit if using hardware TKIP MIC */
-       if (hwtkmic)
-               mcl |= TXC_AMIC;
+       if (in_send_q)
+               return;
+       else
+               in_send_q = true;
 
-       txh->MacTxControlLow = cpu_to_le16(mcl);
+       prec_map = wlc->tx_prec_map;
 
-       /* MacTxControlHigh */
-       mch = 0;
+       /* Send all the enq'd pkts that we can.
+        * Dequeue packets with precedence with empty HW fifo only
+        */
+       while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
+               tx_info = IEEE80211_SKB_CB(pkt[0]);
+               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
+               } else {
+                       count = 1;
+                       err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
+                       if (!err) {
+                               for (i = 0; i < count; i++)
+                                       brcms_c_txfifo(wlc, fifo, pkt[i], true,
+                                                      1);
+                       }
+               }
 
-       /* Set fallback rate preamble type */
-       if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
-           (preamble_type[1] == BRCMS_GF_PREAMBLE)) {
-               if (RSPEC2RATE(rspec[1]) != BRCM_RATE_1M)
-                       mch |= TXC_PREAMBLE_DATA_FB_SHORT;
+               if (err == -EBUSY) {
+                       brcmu_pktq_penq_head(q, prec, pkt[0]);
+                       /*
+                        * If send failed due to any other reason than a
+                        * change in HW FIFO condition, quit. Otherwise,
+                        * read the new prec_map!
+                        */
+                       if (prec_map == wlc->tx_prec_map)
+                               break;
+                       prec_map = wlc->tx_prec_map;
+               }
        }
 
-       /* MacFrameControl */
-       memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));
-       txh->TxFesTimeNormal = cpu_to_le16(0);
-
-       txh->TxFesTimeFallback = cpu_to_le16(0);
-
-       /* TxFrameRA */
-       memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);
-
-       /* TxFrameID */
-       txh->TxFrameID = cpu_to_le16(frameid);
-
-       /*
-        * TxStatus, Note the case of recreating the first frag of a suppressed
-        * frame then we may need to reset the retry cnt's via the status reg
-        */
-       txh->TxStatus = cpu_to_le16(status);
-
        /*
-        * extra fields for ucode AMPDU aggregation, the new fields are added to
-        * the END of previous structure so that it's compatible in driver.
+        * Check if flow control needs to be turned off after
+        * sending the packet
         */
-       txh->MaxNMpdus = cpu_to_le16(0);
-       txh->MaxABytes_MRT = cpu_to_le16(0);
-       txh->MaxABytes_FBR = cpu_to_le16(0);
-       txh->MinMBytes = cpu_to_le16(0);
-
-       /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,
-        * furnish struct d11txh */
-       /* RTS PLCP header and RTS frame */
-       if (use_rts || use_cts) {
-               if (use_rts && use_cts)
-                       use_cts = false;
-
-               for (k = 0; k < 2; k++) {
-                       rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],
-                                                             false,
-                                                             mimo_ctlchbw);
+       if (!EDCF_ENAB(wlc->pub)
+           || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
+               if (brcms_c_txflowcontrol_prio_isset(wlc, qi, ALLPRIO)
+                   && (pktq_len(q) < wlc->pub->tunables->datahiwat / 2))
+                       brcms_c_txflowcontrol(wlc, qi, OFF, ALLPRIO);
+       } else if (wlc->pub->_priofc) {
+               int prio;
+               for (prio = MAXPRIO; prio >= 0; prio--) {
+                       if (brcms_c_txflowcontrol_prio_isset(wlc, qi, prio) &&
+                           (pktq_plen(q, wlc_prio2prec_map[prio]) <
+                           wlc->pub->tunables->datahiwat / 2))
+                               brcms_c_txflowcontrol(wlc, qi, OFF, prio);
                }
+       }
+       in_send_q = false;
+}
 
-               if (!IS_OFDM(rts_rspec[0]) &&
-                   !((RSPEC2RATE(rts_rspec[0]) == BRCM_RATE_1M) ||
-                     (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
-                       rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
-                       mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
-               }
+static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx)
+{
+       if (tx) {
+               /* the post-increment is used in STAY_AWAKE macro */
+               if (wlc->txpend16165war++ == 0)
+                       brcms_c_set_ps_ctrl(wlc);
+       } else {
+               wlc->txpend16165war--;
+               if (wlc->txpend16165war == 0)
+                       brcms_c_set_ps_ctrl(wlc);
+       }
+}
 
-               if (!IS_OFDM(rts_rspec[1]) &&
-                   !((RSPEC2RATE(rts_rspec[1]) == BRCM_RATE_1M) ||
-                     (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
-                       rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
-                       mch |= TXC_PREAMBLE_RTS_FB_SHORT;
-               }
+void
+brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
+              bool commit, s8 txpktpend)
+{
+       u16 frameid = INVALIDFID;
+       struct d11txh *txh;
 
-               /* RTS/CTS additions to MacTxControlLow */
-               if (use_cts) {
-                       txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);
-               } else {
-                       txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);
-                       txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);
-               }
+       txh = (struct d11txh *) (p->data);
 
-               /* RTS PLCP header */
-               rts_plcp = txh->RTSPhyHeader;
-               if (use_cts)
-                       rts_phylen = DOT11_CTS_LEN + FCS_LEN;
-               else
-                       rts_phylen = DOT11_RTS_LEN + FCS_LEN;
+       /* When a BC/MC frame is being committed to the BCMC fifo
+        * via DMA (NOT PIO), update ucode or BSS info as appropriate.
+        */
+       if (fifo == TX_BCMC_FIFO)
+               frameid = le16_to_cpu(txh->TxFrameID);
 
-               brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);
+       if (BRCMS_WAR16165(wlc))
+               brcms_c_war16165(wlc, true);
 
-               /* fallback rate version of RTS PLCP header */
-               brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,
-                                rts_plcp_fallback);
-               memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,
-                      sizeof(txh->RTSPLCPFallback));
 
-               /* RTS frame fields... */
-               rts = (struct ieee80211_rts *)&txh->rts_frame;
+       /*
+        * Bump up pending count for if not using rpc. If rpc is
+        * used, this will be handled in brcms_b_txfifo()
+        */
+       if (commit) {
+               TXPKTPENDINC(wlc, fifo, txpktpend);
+               BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
+                        txpktpend, TXPKTPENDGET(wlc, fifo));
+       }
 
-               durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],
-                                              rspec[0], rts_preamble_type[0],
-                                              preamble_type[0], phylen, false);
-               rts->duration = cpu_to_le16(durid);
-               /* fallback rate version of RTS DUR field */
-               durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
-                                              rts_rspec[1], rspec[1],
-                                              rts_preamble_type[1],
-                                              preamble_type[1], phylen, false);
-               txh->RTSDurFallback = cpu_to_le16(durid);
+       /* Commit BCMC sequence number in the SHM frame ID location */
+       if (frameid != INVALIDFID)
+               BCMCFID(wlc, frameid);
 
-               if (use_cts) {
-                       rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
-                                                        IEEE80211_STYPE_CTS);
+       if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
+               wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+}
 
-                       memcpy(&rts->ra, &h->addr2, ETH_ALEN);
-               } else {
-                       rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
-                                                        IEEE80211_STYPE_RTS);
+/*
+ * Compute PLCP, but only requires actual rate and length of pkt.
+ * Rate is given in the driver standard multiple of 500 kbps.
+ * le is set for 11 Mbps rate if necessary.
+ * Broken out for PRQ.
+ */
+
+static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
+                            uint length, u8 *plcp)
+{
+       u16 usec = 0;
+       u8 le = 0;
 
-                       memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN);
+       switch (rate_500) {
+       case BRCM_RATE_1M:
+               usec = length << 3;
+               break;
+       case BRCM_RATE_2M:
+               usec = length << 2;
+               break;
+       case BRCM_RATE_5M5:
+               usec = (length << 4) / 11;
+               if ((length << 4) - (usec * 11) > 0)
+                       usec++;
+               break;
+       case BRCM_RATE_11M:
+               usec = (length << 3) / 11;
+               if ((length << 3) - (usec * 11) > 0) {
+                       usec++;
+                       if ((usec * 11) - (length << 3) >= 8)
+                               le = D11B_PLCP_SIGNAL_LE;
                }
+               break;
 
-               /* mainrate
-                *    low 8 bits: main frag rate/mcs,
-                *    high 8 bits: rts/cts rate/mcs
-                */
-               mainrates |= (IS_OFDM(rts_rspec[0]) ?
-                               D11A_PHY_HDR_GRATE(
-                                       (struct ofdm_phy_hdr *) rts_plcp) :
-                               rts_plcp[0]) << 8;
-       } else {
-               memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
-               memset((char *)&txh->rts_frame, 0,
-                       sizeof(struct ieee80211_rts));
-               memset((char *)txh->RTSPLCPFallback, 0,
-                     sizeof(txh->RTSPLCPFallback));
-               txh->RTSDurFallback = 0;
+       default:
+               wiphy_err(wlc->wiphy,
+                         "brcms_c_cck_plcp_set: unsupported rate %d\n",
+                         rate_500);
+               rate_500 = BRCM_RATE_1M;
+               usec = length << 3;
+               break;
        }
+       /* PLCP signal byte */
+       plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */
+       /* PLCP service byte */
+       plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);
+       /* PLCP length u16, little endian */
+       plcp[2] = usec & 0xff;
+       plcp[3] = (usec >> 8) & 0xff;
+       /* PLCP CRC16 */
+       plcp[4] = 0;
+       plcp[5] = 0;
+}
 
-#ifdef SUPPORT_40MHZ
-       /* add null delimiter count */
-       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec))
-               txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
-                  brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
+{
+       u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
+       plcp[0] = mcs;
+       if (RSPEC_IS40MHZ(rspec) || (mcs == 32))
+               plcp[0] |= MIMO_PLCP_40MHZ;
+       BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
+       plcp[3] = RSPEC_MIMOPLCP3(rspec); /* rspec already holds this byte */
+       plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
+       plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
+       plcp[5] = 0;
+}
 
-#endif
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void
+brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
+{
+       u8 rate_signal;
+       u32 tmp = 0;
+       int rate = RSPEC2RATE(rspec);
 
        /*
-        * Now that RTS/RTS FB preamble types are updated, write
-        * the final value
+        * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
+        * transmitted first
         */
-       txh->MacTxControlHigh = cpu_to_le16(mch);
+       rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
+       memset(plcp, 0, D11_PHY_HDR_LEN);
+       D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
 
-       /*
-        * MainRates (both the rts and frag plcp rates have
-        * been calculated now)
-        */
-       txh->MainRates = cpu_to_le16(mainrates);
+       tmp = (length & 0xfff) << 5;
+       plcp[2] |= (tmp >> 16) & 0xff;
+       plcp[1] |= (tmp >> 8) & 0xff;
+       plcp[0] |= tmp & 0xff;
 
-       /* XtraFrameTypes */
-       xfts = FRAMETYPE(rspec[1], wlc->mimoft);
-       xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
-       xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
-       xfts |=
-           CHSPEC_CHANNEL(BRCMS_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT;
-       txh->XtraFrameTypes = cpu_to_le16(xfts);
+       return;
+}
 
-       /* PhyTxControlWord */
-       phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
-       if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
-           (preamble_type[0] == BRCMS_GF_PREAMBLE)) {
-               if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M)
-                       phyctl |= PHY_TXC_SHORT_HDR;
-       }
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
+                                uint length, u8 *plcp)
+{
+       int rate = RSPEC2RATE(rspec);
 
-       /* phytxant is properly bit shifted */
-       phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);
-       txh->PhyTxControlWord = cpu_to_le16(phyctl);
+       brcms_c_cck_plcp_set(wlc, rate, length, plcp);
+}
 
-       /* PhyTxControlWord_1 */
-       if (BRCMS_PHY_11N_CAP(wlc->band)) {
-               u16 phyctl1 = 0;
+void
+brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
+                    uint length, u8 *plcp)
+{
+       if (IS_MCS(rspec))
+               brcms_c_compute_mimo_plcp(rspec, length, plcp);
+       else if (IS_OFDM(rspec))
+               brcms_c_compute_ofdm_plcp(rspec, length, plcp);
+       else
+               brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
+       return;
+}
 
-               phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);
-               txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);
-               phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);
-               txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);
+/* brcms_c_compute_rtscts_dur()
+ *
+ * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame
+ * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK
+ * DUR for CTS-TO-SELF w/ frame    = 2 SIFS         + next frame time + 1 ACK
+ *
+ * cts                 cts-to-self or rts/cts
+ * rts_rate            rts or cts rate in unit of 500kbps
+ * rate                        next MPDU rate in unit of 500kbps
+ * frame_len           next MPDU frame length in bytes
+ */
+u16
+brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
+                          u32 rts_rate,
+                          u32 frame_rate, u8 rts_preamble_type,
+                          u8 frame_preamble_type, uint frame_len, bool ba)
+{
+       u16 dur, sifs;
 
-               if (use_rts || use_cts) {
-                       phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);
-                       txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);
-                       phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);
-                       txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);
-               }
+       sifs = SIFS(wlc->band);
 
-               /*
-                * For mcs frames, if mixedmode(overloaded with long preamble)
-                * is going to be set, fill in non-zero MModeLen and/or
-                * MModeFbrLen it will be unnecessary if they are separated
-                */
-               if (IS_MCS(rspec[0]) &&
-                   (preamble_type[0] == BRCMS_MM_PREAMBLE)) {
-                       u16 mmodelen =
-                           brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
-                       txh->MModeLen = cpu_to_le16(mmodelen);
-               }
+       if (!cts_only) {
+               /* RTS/CTS */
+               dur = 3 * sifs;
+               dur +=
+                   (u16) brcms_c_calc_cts_time(wlc, rts_rate,
+                                              rts_preamble_type);
+       } else {
+               /* CTS-TO-SELF */
+               dur = 2 * sifs;
+       }
 
-               if (IS_MCS(rspec[1]) &&
-                   (preamble_type[1] == BRCMS_MM_PREAMBLE)) {
-                       u16 mmodefbrlen =
-                           brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
-                       txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);
+       dur +=
+           (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,
+                                        frame_len);
+       if (ba)
+               dur +=
+                   (u16) brcms_c_calc_ba_time(wlc, frame_rate,
+                                             BRCMS_SHORT_PREAMBLE);
+       else
+               dur +=
+                   (u16) brcms_c_calc_ack_time(wlc, frame_rate,
+                                              frame_preamble_type);
+       return dur;
+}
+
+u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
+{
+       u16 phyctl1 = 0;
+       u16 bw;
+
+       if (BRCMS_ISLCNPHY(wlc->band)) {
+               bw = PHY_TXC1_BW_20MHZ;
+       } else {
+               bw = RSPEC_GET_BW(rspec);
+               /* 10Mhz is not supported yet */
+               if (bw < PHY_TXC1_BW_20MHZ) {
+                       wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
+                                 "not supported yet, set to 20L\n", bw);
+                       bw = PHY_TXC1_BW_20MHZ;
                }
        }
 
-       ac = skb_get_queue_mapping(p);
-       if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
-               uint frag_dur, dur, dur_fallback;
+       if (IS_MCS(rspec)) {
+               uint mcs = rspec & RSPEC_RATE_MASK;
 
-               /* WME: Update TXOP threshold */
-               if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
-                       frag_dur =
-                           brcms_c_calc_frame_time(wlc, rspec[0],
-                                       preamble_type[0], phylen);
+               /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */
+               phyctl1 = RSPEC_PHYTXBYTE2(rspec);
+               /* set the upper byte of phyctl1 */
+               phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
+       } else if (IS_CCK(rspec) && !BRCMS_ISLCNPHY(wlc->band)
+                  && !BRCMS_ISSSLPNPHY(wlc->band)) {
+               /*
+                * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
+                * Data Rate. Eventually MIMOPHY would also be converted to
+                * this format
+                */
+               /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
+               phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+       } else {                /* legacy OFDM/CCK */
+               s16 phycfg;
+               /* get the phyctl byte from rate phycfg table */
+               phycfg = brcms_c_rate_legacy_phyctl(RSPEC2RATE(rspec));
+               if (phycfg == -1) {
+                       wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
+                                 "legacy OFDM/CCK rate\n");
+                       phycfg = 0;
+               }
+               /* set the upper byte of phyctl1 */
+               phyctl1 =
+                   (bw | (phycfg << 8) |
+                    (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+       }
+       return phyctl1;
+}
 
-                       if (rts) {
-                               /* 1 RTS or CTS-to-self frame */
-                               dur =
-                                   brcms_c_calc_cts_time(wlc, rts_rspec[0],
-                                                     rts_preamble_type[0]);
-                               dur_fallback =
-                                   brcms_c_calc_cts_time(wlc, rts_rspec[1],
-                                                     rts_preamble_type[1]);
-                               /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */
-                               dur += le16_to_cpu(rts->duration);
-                               dur_fallback +=
-                                       le16_to_cpu(txh->RTSDurFallback);
-                       } else if (use_rifs) {
-                               dur = frag_dur;
-                               dur_fallback = 0;
-                       } else {
-                               /* frame + SIFS + ACK */
-                               dur = frag_dur;
-                               dur +=
-                                   brcms_c_compute_frame_dur(wlc, rspec[0],
-                                                         preamble_type[0], 0);
+u32
+brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
+                          bool use_rspec, u16 mimo_ctlchbw)
+{
+       u32 rts_rspec = 0;
 
-                               dur_fallback =
-                                   brcms_c_calc_frame_time(wlc, rspec[1],
-                                                       preamble_type[1],
-                                                       phylen);
-                               dur_fallback +=
-                                   brcms_c_compute_frame_dur(wlc, rspec[1],
-                                                         preamble_type[1], 0);
-                       }
-                       /* NEED to set TxFesTimeNormal (hard) */
-                       txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
-                       /*
-                        * NEED to set fallback rate version of
-                        * TxFesTimeNormal (hard)
-                        */
-                       txh->TxFesTimeFallback =
-                               cpu_to_le16((u16) dur_fallback);
+       if (use_rspec)
+               /* use frame rate as rts rate */
+               rts_rspec = rspec;
+       else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec))
+               /* Use 11Mbps as the g protection RTS target rate and fallback.
+                * Use the BRCMS_BASIC_RATE() lookup to find the best basic rate
+                * under the target in case 11 Mbps is not Basic.
+                * 6 and 9 Mbps are not usually selected by rate selection, but
+                * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
+                * is more robust.
+                */
+               rts_rspec = BRCMS_BASIC_RATE(wlc, BRCM_RATE_11M);
+       else
+               /* calculate RTS rate and fallback rate based on the frame rate
+                * RTS must be sent at a basic rate since it is a
+                * control frame, sec 9.6 of 802.11 spec
+                */
+               rts_rspec = BRCMS_BASIC_RATE(wlc, rspec);
 
-                       /*
-                        * update txop byte threshold (txop minus intraframe
-                        * overhead)
-                        */
-                       if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
-                               uint newfragthresh;
+       if (BRCMS_PHY_11N_CAP(wlc->band)) {
+               /* set rts txbw to correct side band */
+               rts_rspec &= ~RSPEC_BW_MASK;
 
-                               newfragthresh =
-                                   brcms_c_calc_frame_len(wlc,
-                                       rspec[0], preamble_type[0],
-                                       (wlc->edcf_txop[ac] -
-                                               (dur - frag_dur)));
-                               /* range bound the fragthreshold */
-                               if (newfragthresh < DOT11_MIN_FRAG_LEN)
-                                       newfragthresh =
-                                           DOT11_MIN_FRAG_LEN;
-                               else if (newfragthresh >
-                                        wlc->usr_fragthresh)
-                                       newfragthresh =
-                                           wlc->usr_fragthresh;
-                               /* update the fragthresh and do txc update */
-                               if (wlc->fragthresh[queue] !=
-                                   (u16) newfragthresh)
-                                       wlc->fragthresh[queue] =
-                                           (u16) newfragthresh;
-                       } else {
-                               wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
-                                         "for rate %d\n",
-                                         wlc->pub->unit, fifo_names[queue],
-                                         RSPEC2RATE(rspec[0]));
-                       }
+               /*
+                * if rspec/rspec_fallback is 40MHz, then send RTS on both
+                * 20MHz channel (DUP), otherwise send RTS on control channel
+                */
+               if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec))
+                       rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
+               else
+                       rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
 
-                       if (dur > wlc->edcf_txop[ac])
-                               wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
-                                         "exceeded phylen %d/%d dur %d/%d\n",
-                                         wlc->pub->unit, __func__,
-                                         fifo_names[queue],
-                                         phylen, wlc->fragthresh[queue],
-                                         dur, wlc->edcf_txop[ac]);
+               /* pick siso/cdd as default for ofdm */
+               if (IS_OFDM(rts_rspec)) {
+                       rts_rspec &= ~RSPEC_STF_MASK;
+                       rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
                }
        }
-
-       return 0;
+       return rts_rspec;
 }
 
 void brcms_c_tbtt(struct brcms_c_info *wlc)
@@ -7878,19 +8079,6 @@ void brcms_c_tbtt(struct brcms_c_info *wlc)
                wlc->qvalid |= MCMD_DIRFRMQVAL;
 }
 
-static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx)
-{
-       if (tx) {
-               /* the post-increment is used in STAY_AWAKE macro */
-               if (wlc->txpend16165war++ == 0)
-                       brcms_c_set_ps_ctrl(wlc);
-       } else {
-               wlc->txpend16165war--;
-               if (wlc->txpend16165war == 0)
-                       brcms_c_set_ps_ctrl(wlc);
-       }
-}
-
 /* process an individual struct tx_status */
 bool
 brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2)
@@ -8507,101 +8695,6 @@ brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
        return dur;
 }
 
-/* The opposite of brcms_c_calc_frame_time */
-static uint
-brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
-                  u8 preamble_type, uint dur)
-{
-       uint nsyms, mac_len, Ndps, kNdps;
-       uint rate = RSPEC2RATE(ratespec);
-
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
-                wlc->pub->unit, ratespec, preamble_type, dur);
-
-       if (IS_MCS(ratespec)) {
-               uint mcs = ratespec & RSPEC_RATE_MASK;
-               int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
-               dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
-               /* payload calculation matches that of regular ofdm */
-               if (BAND_2G(wlc->band->bandtype))
-                       dur -= DOT11_OFDM_SIGNAL_EXTENSION;
-               /* kNdbps = kbps * 4 */
-               kNdps =
-                   MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
-                            RSPEC_ISSGI(ratespec)) * 4;
-               nsyms = dur / APHY_SYMBOL_TIME;
-               mac_len =
-                   ((nsyms * kNdps) -
-                    ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
-       } else if (IS_OFDM(ratespec)) {
-               dur -= APHY_PREAMBLE_TIME;
-               dur -= APHY_SIGNAL_TIME;
-               /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
-               Ndps = rate * 2;
-               nsyms = dur / APHY_SYMBOL_TIME;
-               mac_len =
-                   ((nsyms * Ndps) -
-                    (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
-       } else {
-               if (preamble_type & BRCMS_SHORT_PREAMBLE)
-                       dur -= BPHY_PLCP_SHORT_TIME;
-               else
-                       dur -= BPHY_PLCP_TIME;
-               mac_len = dur * rate;
-               /* divide out factor of 2 in rate (1/2 mbps) */
-               mac_len = mac_len / 8 / 2;
-       }
-       return mac_len;
-}
-
-static uint
-brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
-                    u8 preamble_type)
-{
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
-                "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
-       /*
-        * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
-        * is less than or equal to the rate of the immediately previous
-        * frame in the FES
-        */
-       rspec = BRCMS_BASIC_RATE(wlc, rspec);
-       /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
-       return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
-                                  (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
-                                   FCS_LEN));
-}
-
-static uint
-brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
-                     u8 preamble_type)
-{
-       uint dur = 0;
-
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
-               wlc->pub->unit, rspec, preamble_type);
-       /*
-        * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
-        * is less than or equal to the rate of the immediately previous
-        * frame in the FES
-        */
-       rspec = BRCMS_BASIC_RATE(wlc, rspec);
-       /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
-       dur =
-           brcms_c_calc_frame_time(wlc, rspec, preamble_type,
-                               (DOT11_ACK_LEN + FCS_LEN));
-       return dur;
-}
-
-static uint
-brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
-                     u8 preamble_type)
-{
-       BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
-               wlc->pub->unit, rspec, preamble_type);
-       return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
-}
-
 /* derive wlc->band->basic_rate[] table from 'rateset' */
 void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
                              struct brcms_c_rateset *rateset)
@@ -8816,30 +8909,6 @@ bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
        return false;
 }
 
-static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
-{
-       uint i;
-       struct brcms_band *band;
-
-       for (i = 0; i < NBANDS(wlc); i++) {
-               if (IS_SINGLEBAND_5G(wlc->deviceid))
-                       i = BAND_5G_INDEX;
-               band = wlc->bandstate[i];
-               if (band->bandtype == BRCM_BAND_5G) {
-                       if ((bwcap == BRCMS_N_BW_40ALL)
-                           || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
-                               band->mimo_cap_40 = true;
-                       else
-                               band->mimo_cap_40 = false;
-               } else {
-                       if (bwcap == BRCMS_N_BW_40ALL)
-                               band->mimo_cap_40 = true;
-                       else
-                               band->mimo_cap_40 = false;
-               }
-       }
-}
-
 void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
 {
        const struct brcms_c_rateset *rs_dflt;
@@ -8984,6 +9053,12 @@ brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, u16 bcn[],
        }
 }
 
+void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, u16 bcn[], int len,
+                                  bool both)
+{
+       brcms_b_write_hw_bcntemplates(wlc->hw, bcn, len, both);
+}
+
 /*
  * Update a beacon for a particular BSS
  * For MBSS, this updates the software template and sets "latest" to
@@ -9180,182 +9255,6 @@ void brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
                wlc->stf->txstreams);
 }
 
-static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
-{
-       u16 chanspec;
-       struct brcms_band *band;
-       struct brcms_bss_info *bi = wlc->default_bss;
-
-       /* init default and target BSS with some sane initial values */
-       memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
-       bi->beacon_period = BEACON_INTERVAL_DEFAULT;
-       bi->dtim_period = DTIM_INTERVAL_DEFAULT;
-
-       /* fill the default channel as the first valid channel
-        * starting from the 2G channels
-        */
-       chanspec = CH20MHZ_CHSPEC(1);
-       wlc->home_chanspec = bi->chanspec = chanspec;
-
-       /* find the band of our default channel */
-       band = wlc->band;
-       if (NBANDS(wlc) > 1 && band->bandunit != CHSPEC_BANDUNIT(chanspec))
-               band = wlc->bandstate[OTHERBANDUNIT(wlc)];
-
-       /* init bss rates to the band specific default rate set */
-       brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
-               band->bandtype, false, BRCMS_RATE_MASK_FULL,
-               (bool) N_ENAB(wlc->pub), CHSPEC_WLC_BW(chanspec),
-               wlc->stf->txstreams);
-
-       if (N_ENAB(wlc->pub))
-               bi->flags |= BRCMS_BSS_HT;
-}
-
-static u32
-mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
-                      u32 int_val)
-{
-       u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
-       u8 rate = int_val & NRATE_RATE_MASK;
-       u32 rspec;
-       bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
-       bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
-       bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
-                                 == NRATE_OVERRIDE_MCS_ONLY);
-       int bcmerror = 0;
-
-       if (!ismcs)
-               return (u32) rate;
-
-       /* validate the combination of rate/mcs/stf is allowed */
-       if (N_ENAB(wlc->pub) && ismcs) {
-               /* mcs only allowed when nmode */
-               if (stf > PHY_TXC1_MODE_SDM) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
-                                BRCMS_UNIT(wlc), __func__);
-                       bcmerror = -EINVAL;
-                       goto done;
-               }
-
-               /* mcs 32 is a special case, DUP mode 40 only */
-               if (rate == 32) {
-                       if (!CHSPEC_IS40(wlc->home_chanspec) ||
-                           ((stf != PHY_TXC1_MODE_SISO)
-                            && (stf != PHY_TXC1_MODE_CDD))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
-                                         "32\n", BRCMS_UNIT(wlc), __func__);
-                               bcmerror = -EINVAL;
-                               goto done;
-                       }
-                       /* mcs > 7 must use stf SDM */
-               } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
-                       /* mcs > 7 must use stf SDM */
-                       if (stf != PHY_TXC1_MODE_SDM) {
-                               BCMMSG(wlc->wiphy, "wl%d: enabling "
-                                        "SDM mode for mcs %d\n",
-                                        BRCMS_UNIT(wlc), rate);
-                               stf = PHY_TXC1_MODE_SDM;
-                       }
-               } else {
-                       /*
-                        * MCS 0-7 may use SISO, CDD, and for
-                        * phy_rev >= 3 STBC
-                        */
-                       if ((stf > PHY_TXC1_MODE_STBC) ||
-                           (!BRCMS_STBC_CAP_PHY(wlc)
-                            && (stf == PHY_TXC1_MODE_STBC))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
-                                         "\n", BRCMS_UNIT(wlc), __func__);
-                               bcmerror = -EINVAL;
-                               goto done;
-                       }
-               }
-       } else if (IS_OFDM(rate)) {
-               if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
-                                 BRCMS_UNIT(wlc), __func__);
-                       bcmerror = -EINVAL;
-                       goto done;
-               }
-       } else if (IS_CCK(rate)) {
-               if ((cur_band->bandtype != BRCM_BAND_2G)
-                   || (stf != PHY_TXC1_MODE_SISO)) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
-                                 BRCMS_UNIT(wlc), __func__);
-                       bcmerror = -EINVAL;
-                       goto done;
-               }
-       } else {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
-                         BRCMS_UNIT(wlc), __func__);
-               bcmerror = -EINVAL;
-               goto done;
-       }
-       /* make sure multiple antennae are available for non-siso rates */
-       if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
-                         "request\n", BRCMS_UNIT(wlc), __func__);
-               bcmerror = -EINVAL;
-               goto done;
-       }
-
-       rspec = rate;
-       if (ismcs) {
-               rspec |= RSPEC_MIMORATE;
-               /* For STBC populate the STC field of the ratespec */
-               if (stf == PHY_TXC1_MODE_STBC) {
-                       u8 stc;
-                       stc = 1;        /* Nss for single stream is always 1 */
-                       rspec |= (stc << RSPEC_STC_SHIFT);
-               }
-       }
-
-       rspec |= (stf << RSPEC_STF_SHIFT);
-
-       if (override_mcs_only)
-               rspec |= RSPEC_OVERRIDE_MCS_ONLY;
-
-       if (issgi)
-               rspec |= RSPEC_SHORT_GI;
-
-       if ((rate != 0)
-           && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
-               return rate;
-
-       return rspec;
-done:
-       return rate;
-}
-
-/* formula:  IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
-static int
-brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
-                  bool writeToShm)
-{
-       int idle_busy_ratio_x_16 = 0;
-       uint offset =
-           isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
-           M_TX_IDLE_BUSY_RATIO_X_16_CCK;
-       if (duty_cycle > 100 || duty_cycle < 0) {
-               wiphy_err(wlc->wiphy, "wl%d:  duty cycle value off limit\n",
-                         wlc->pub->unit);
-               return -EINVAL;
-       }
-       if (duty_cycle)
-               idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
-       /* Only write to shared memory  when wl is up */
-       if (writeToShm)
-               brcms_c_write_shm(wlc, offset, (u16) idle_busy_ratio_x_16);
-
-       if (isOFDM)
-               wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
-       else
-               wlc->tx_duty_cycle_cck = (u16) duty_cycle;
-
-       return 0;
-}
-
 /* Read a single u16 from shared memory.
  * SHM 'offset' needs to be an even address
  */
@@ -9420,12 +9319,6 @@ void brcms_c_write_template_ram(struct brcms_c_info *wlc, int offset, int len,
        brcms_b_write_template_ram(wlc->hw, offset, len, buf);
 }
 
-void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, u16 bcn[], int len,
-                                  bool both)
-{
-       brcms_b_write_hw_bcntemplates(wlc->hw, bcn, len, both);
-}
-
 void
 brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
                  const u8 *addr)
@@ -9545,76 +9438,6 @@ brcms_c_txflowcontrol_override(struct brcms_c_info *wlc,
        }
 }
 
-static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
-{
-       struct brcms_txq_info *qi;
-
-       for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
-               if (qi->stopped) {
-                       brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
-                       qi->stopped = 0;
-               }
-       }
-}
-
-static void
-brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
-                            struct brcms_txq_info *qi, bool on, int prio)
-{
-       /* wlcif_list is never filled so this function is not functional yet */
-}
-
-static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
-{
-       struct brcms_txq_info *qi, *p;
-
-       qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
-       if (qi != NULL) {
-               /*
-                * Have enough room for control packets along with HI watermark
-                * Also, add room to txq for total psq packets if all the SCBs
-                * leave PS mode. The watermark for flowcontrol to OS packets
-                * will remain the same
-                */
-               brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
-                         (2 * wlc->pub->tunables->datahiwat) + PKTQ_LEN_DEFAULT
-                         + wlc->pub->psq_pkts_total);
-
-               /* add this queue to the the global list */
-               p = wlc->tx_queues;
-               if (p == NULL) {
-                       wlc->tx_queues = qi;
-               } else {
-                       while (p->next != NULL)
-                               p = p->next;
-                       p->next = qi;
-               }
-       }
-       return qi;
-}
-
-static void brcms_c_txq_free(struct brcms_c_info *wlc,
-                            struct brcms_txq_info *qi)
-{
-       struct brcms_txq_info *p;
-
-       if (qi == NULL)
-               return;
-
-       /* remove the queue from the linked list */
-       p = wlc->tx_queues;
-       if (p == qi)
-               wlc->tx_queues = p->next;
-       else {
-               while (p != NULL && p->next != qi)
-                       p = p->next;
-               if (p != NULL)
-                       p->next = p->next->next;
-       }
-
-       kfree(qi);
-}
-
 /*
  * Flag 'scan in progress' to withhold dynamic phy calibration
  */