brcm80211: cleanup function prototypes
authorAlwin Beukers <alwin@broadcom.com>
Wed, 12 Oct 2011 18:51:13 +0000 (20:51 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 14 Oct 2011 18:48:16 +0000 (14:48 -0400)
- removed unneeded fn prototypes from include files.
- explicitly marked fn prototypes as extern in include files.
- reordered functions to account for removed forward declarations
  in include files.
- removed unused functions: brcms_c_txflowcontrol_override,
  brcms_c_txflowcontrol_prio_isset, brcms_c_txflowcontrol.

Reviewed-by: Roland Vossen <rvossen@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/pub.h

index 665bf8011cb6ae1295f0721f476f59edd4a1a8ef..cce6228c0c036421dc6d1b14ed16180d2dc4a02c 100644 (file)
@@ -343,53 +343,6 @@ struct d11init {
        __le32 value;
 };
 
-/* currently the best mechanism for determining SIFS is the band in use */
-static u16 get_sifs(struct brcms_band *band)
-{
-       return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
-                                BPHY_SIFS_TIME;
-}
-
-
-/*
- * Detect Card removed.
- * Even checking an sbconfig register read will not false trigger when the core
- * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
- * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
- * reg with fixed 0/1 pattern (some platforms return all 0).
- * If clocks are present, call the sb routine which will figure out if the
- * device is removed.
- */
-static bool brcms_deviceremoved(struct brcms_c_info *wlc)
-{
-       if (!wlc->hw->clk)
-               return ai_deviceremoved(wlc->hw->sih);
-       return (R_REG(&wlc->hw->regs->maccontrol) &
-               (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
-}
-
-/* sum the individual fifo tx pending packet counts */
-static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
-{
-       return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
-              wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
-}
-
-static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
-{
-       return wlc->pub->_nbands > 1 && !wlc->bandlocked;
-}
-
-static int brcms_chspec_bw(u16 chanspec)
-{
-       if (CHSPEC_IS40(chanspec))
-               return BRCMS_40_MHZ;
-       if (CHSPEC_IS20(chanspec))
-               return BRCMS_20_MHZ;
-
-       return BRCMS_10_MHZ;
-}
-
 struct edcf_acparam {
        u8 ACI;
        u8 ECW;
@@ -465,6 +418,66 @@ static const char fifo_names[6][0];
 static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
 #endif
 
+/* currently the best mechanism for determining SIFS is the band in use */
+static u16 get_sifs(struct brcms_band *band)
+{
+       return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
+                                BPHY_SIFS_TIME;
+}
+
+/*
+ * Detect Card removed.
+ * Even checking an sbconfig register read will not false trigger when the core
+ * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
+ * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
+ * reg with fixed 0/1 pattern (some platforms return all 0).
+ * If clocks are present, call the sb routine which will figure out if the
+ * device is removed.
+ */
+static bool brcms_deviceremoved(struct brcms_c_info *wlc)
+{
+       if (!wlc->hw->clk)
+               return ai_deviceremoved(wlc->hw->sih);
+       return (R_REG(&wlc->hw->regs->maccontrol) &
+               (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
+}
+
+/* sum the individual fifo tx pending packet counts */
+static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
+{
+       return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
+              wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
+}
+
+static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
+{
+       return wlc->pub->_nbands > 1 && !wlc->bandlocked;
+}
+
+static int brcms_chspec_bw(u16 chanspec)
+{
+       if (CHSPEC_IS40(chanspec))
+               return BRCMS_40_MHZ;
+       if (CHSPEC_IS20(chanspec))
+               return BRCMS_20_MHZ;
+
+       return BRCMS_10_MHZ;
+}
+
+/*
+ * return true if Minimum Power Consumption should
+ * be entered, false otherwise
+ */
+static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
+{
+       return false;
+}
+
+static bool brcms_c_ismpc(struct brcms_c_info *wlc)
+{
+       return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
+}
+
 static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
 {
        if (cfg == NULL)
@@ -646,6 +659,79 @@ static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
        }
 }
 
+/*
+ * calculate frame duration of a given rate and length, return
+ * time in usec unit
+ */
+uint
+brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+                       u8 preamble_type, uint mac_len)
+{
+       uint nsyms, dur = 0, Ndps, kNdps;
+       uint rate = rspec2rate(ratespec);
+
+       if (rate == 0) {
+               wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
+                         wlc->pub->unit);
+               rate = BRCM_RATE_1M;
+       }
+
+       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
+                wlc->pub->unit, ratespec, preamble_type, mac_len);
+
+       if (is_mcs_rate(ratespec)) {
+               uint mcs = ratespec & RSPEC_RATE_MASK;
+               int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+
+               dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+               if (preamble_type == BRCMS_MM_PREAMBLE)
+                       dur += PREN_MM_EXT;
+               /* 1000Ndbps = kbps * 4 */
+               kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+                                  rspec_issgi(ratespec)) * 4;
+
+               if (rspec_stc(ratespec) == 0)
+                       nsyms =
+                           CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+                                 APHY_TAIL_NBITS) * 1000, kNdps);
+               else
+                       /* STBC needs to have even number of symbols */
+                       nsyms =
+                           2 *
+                           CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+                                 APHY_TAIL_NBITS) * 1000, 2 * kNdps);
+
+               dur += APHY_SYMBOL_TIME * nsyms;
+               if (wlc->band->bandtype == BRCM_BAND_2G)
+                       dur += DOT11_OFDM_SIGNAL_EXTENSION;
+       } else if (is_ofdm_rate(rate)) {
+               dur = APHY_PREAMBLE_TIME;
+               dur += APHY_SIGNAL_TIME;
+               /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+               Ndps = rate * 2;
+               /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
+               nsyms =
+                   CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
+                        Ndps);
+               dur += APHY_SYMBOL_TIME * nsyms;
+               if (wlc->band->bandtype == BRCM_BAND_2G)
+                       dur += DOT11_OFDM_SIGNAL_EXTENSION;
+       } else {
+               /*
+                * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
+                * will divide out
+                */
+               mac_len = mac_len * 8 * 2;
+               /* calc ceiling of bits/rate = microseconds of air time */
+               dur = (mac_len + rate - 1) / rate;
+               if (preamble_type & BRCMS_SHORT_PREAMBLE)
+                       dur += BPHY_PLCP_SHORT_TIME;
+               else
+                       dur += BPHY_PLCP_TIME;
+       }
+       return dur;
+}
+
 static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
                                const struct d11init *inits)
 {
@@ -740,6 +826,26 @@ static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
        }
 }
 
+/* low-level band switch utility routine */
+static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
+{
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+               bandunit);
+
+       wlc_hw->band = wlc_hw->bandstate[bandunit];
+
+       /*
+        * BMAC_NOTE:
+        *   until we eliminate need for wlc->band refs in low level code
+        */
+       wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
+
+       /* set gmode core flag */
+       if (wlc_hw->sbclk && !wlc_hw->noreset)
+               ai_core_cflags(wlc_hw->sih, SICF_GMODE,
+                              ((bandunit == 0) ? SICF_GMODE : 0));
+}
+
 /* switch to new band but leave it inactive */
 static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
 {
@@ -763,107 +869,45 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
        return macintmask;
 }
 
-/* Process received frames */
-/*
- * Return true if more frames need to be processed. false otherwise.
- * Param 'bound' indicates max. # frames to process before break out.
- */
+/* process an individual struct tx_status */
 static bool
-brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
+brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 {
        struct sk_buff *p;
-       struct sk_buff *head = NULL;
-       struct sk_buff *tail = NULL;
-       uint n = 0;
-       uint bound_limit = bound ? RXBND : -1;
-
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-       /* gather received frames */
-       while ((p = dma_rx(wlc_hw->di[fifo]))) {
+       uint queue;
+       struct d11txh *txh;
+       struct scb *scb = NULL;
+       bool free_pdu;
+       int tx_rts, tx_frame_count, tx_rts_count;
+       uint totlen, supr_status;
+       bool lastframe;
+       struct ieee80211_hdr *h;
+       u16 mcl;
+       struct ieee80211_tx_info *tx_info;
+       struct ieee80211_tx_rate *txrate;
+       int i;
 
-               if (!tail)
-                       head = tail = p;
-               else {
-                       tail->prev = p;
-                       tail = p;
-               }
+       /* discard intermediate indications for ucode with one legitimate case:
+        *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
+        *   but the subsequent tx of DATA failed. so it will start rts/cts
+        *   from the beginning (resetting the rts transmission count)
+        */
+       if (!(txs->status & TX_STATUS_AMPDU)
+           && (txs->status & TX_STATUS_INTERMEDIATE)) {
+               wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
+                         __func__);
+               return false;
+       }
 
-               /* !give others some time to run! */
-               if (++n >= bound_limit)
-                       break;
+       queue = txs->frameid & TXFID_QUEUE_MASK;
+       if (queue >= NFIFO) {
+               p = NULL;
+               goto fatal;
        }
 
-       /* post more rbufs */
-       dma_rxfill(wlc_hw->di[fifo]);
-
-       /* process each frame */
-       while ((p = head) != NULL) {
-               struct d11rxhdr_le *rxh_le;
-               struct d11rxhdr *rxh;
-               head = head->prev;
-               p->prev = NULL;
-
-               rxh_le = (struct d11rxhdr_le *)p->data;
-               rxh = (struct d11rxhdr *)p->data;
-
-               /* fixup rx header endianness */
-               rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
-               rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
-               rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
-               rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
-               rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
-               rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
-               rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
-               rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
-               rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
-               rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
-               rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
-
-               brcms_c_recv(wlc_hw->wlc, p);
-       }
-
-       return n >= bound_limit;
-}
-
-/* process an individual struct tx_status */
-static bool
-brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
-{
-       struct sk_buff *p;
-       uint queue;
-       struct d11txh *txh;
-       struct scb *scb = NULL;
-       bool free_pdu;
-       int tx_rts, tx_frame_count, tx_rts_count;
-       uint totlen, supr_status;
-       bool lastframe;
-       struct ieee80211_hdr *h;
-       u16 mcl;
-       struct ieee80211_tx_info *tx_info;
-       struct ieee80211_tx_rate *txrate;
-       int i;
-
-       /* discard intermediate indications for ucode with one legitimate case:
-        *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
-        *   but the subsequent tx of DATA failed. so it will start rts/cts
-        *   from the beginning (resetting the rts transmission count)
-        */
-       if (!(txs->status & TX_STATUS_AMPDU)
-           && (txs->status & TX_STATUS_INTERMEDIATE)) {
-               wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
-                         __func__);
-               return false;
-       }
-
-       queue = txs->frameid & TXFID_QUEUE_MASK;
-       if (queue >= NFIFO) {
-               p = NULL;
-               goto fatal;
-       }
-
-       p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
-       if (p == NULL)
-               goto fatal;
+       p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
+       if (p == NULL)
+               goto fatal;
 
        txh = (struct d11txh *) (p->data);
        mcl = le16_to_cpu(txh->MacTxControlLow);
@@ -1054,97 +1098,14 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
        return morepending;
 }
 
-/* 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.
- */
-bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
+static void brcms_c_tbtt(struct brcms_c_info *wlc)
 {
-       u32 macintstatus;
-       struct brcms_hardware *wlc_hw = wlc->hw;
-       struct d11regs __iomem *regs = wlc_hw->regs;
-       struct wiphy *wiphy = wlc->wiphy;
-
-       if (brcms_deviceremoved(wlc)) {
-               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
-                         __func__);
-               brcms_down(wlc->wl);
-               return false;
-       }
-
-       /* grab and clear the saved software intstatus bits */
-       macintstatus = wlc->macintstatus;
-       wlc->macintstatus = 0;
-
-       BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
-              wlc_hw->unit, macintstatus);
-
-       WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
-
-       /* tx status */
-       if (macintstatus & MI_TFS) {
-               bool fatal;
-               if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
-                       wlc->macintstatus |= MI_TFS;
-               if (fatal) {
-                       wiphy_err(wiphy, "MI_TFS: fatal\n");
-                       goto fatal;
-               }
-       }
-
-       if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
-               brcms_c_tbtt(wlc);
-
-       /* ATIM window end */
-       if (macintstatus & MI_ATIMWINEND) {
-               BCMMSG(wlc->wiphy, "end of ATIM window\n");
-               OR_REG(&regs->maccommand, wlc->qvalid);
-               wlc->qvalid = 0;
-       }
-
-       /*
-        * received data or control frame, MI_DMAINT is
-        * indication of RX_FIFO interrupt
-        */
-       if (macintstatus & MI_DMAINT)
-               if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
-                       wlc->macintstatus |= MI_DMAINT;
-
-       /* noise sample collected */
-       if (macintstatus & MI_BG_NOISE)
-               wlc_phy_noise_sample_intr(wlc_hw->band->pi);
-
-       if (macintstatus & MI_GP0) {
-               wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
-                       "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
-
-               printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
-                                       __func__, wlc_hw->sih->chip,
-                                       wlc_hw->sih->chiprev);
-               /* big hammer */
-               brcms_init(wlc->wl);
-       }
-
-       /* gptimer timeout */
-       if (macintstatus & MI_TO)
-               W_REG(&regs->gptimer, 0);
-
-       if (macintstatus & MI_RFDISABLE) {
-               BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
-                      " RF Disable Input\n", wlc_hw->unit);
-               brcms_rfkill_set_hw_state(wlc->wl);
-       }
-
-       /* send any enq'd tx packets. Just makes sure to jump start tx */
-       if (!pktq_empty(&wlc->pkt_queue->q))
-               brcms_c_send_q(wlc);
-
-       /* it isn't done and needs to be resched if macintstatus is non-zero */
-       return wlc->macintstatus != 0;
-
- fatal:
-       brcms_init(wlc->wl);
-       return wlc->macintstatus != 0;
+       if (!wlc->bsscfg->BSS)
+               /*
+                * DirFrmQ is now valid...defer setting until end
+                * of ATIM window
+                */
+               wlc->qvalid |= MCMD_DIRFRMQVAL;
 }
 
 /* set initial host flags value */
@@ -1922,26 +1883,6 @@ static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
        WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
 }
 
-/* low-level band switch utility routine */
-void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
-{
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               bandunit);
-
-       wlc_hw->band = wlc_hw->bandstate[bandunit];
-
-       /*
-        * BMAC_NOTE:
-        *   until we eliminate need for wlc->band refs in low level code
-        */
-       wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
-
-       /* set gmode core flag */
-       if (wlc_hw->sbclk && !wlc_hw->noreset)
-               ai_core_cflags(wlc_hw->sih, SICF_GMODE,
-                              ((bandunit == 0) ? SICF_GMODE : 0));
-}
-
 static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
 {
 
@@ -2405,6 +2346,13 @@ void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
        wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
 }
 
+static void brcms_c_fatal_error(struct brcms_c_info *wlc)
+{
+       wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+                 wlc->pub->unit);
+       brcms_init(wlc->wl);
+}
+
 static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
 {
        bool fatal = false;
@@ -2962,7 +2910,7 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
        }
 }
 
-void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
+static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
 {
        bool dev_gone;
 
@@ -3106,6 +3054,16 @@ brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
        }
 }
 
+/* Copy a buffer to shared memory.
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ */
+static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
+                       const void *buf, int len)
+{
+       brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
+}
+
 static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,
                                   u16 SRL, u16 LRL)
 {
@@ -3159,7 +3117,7 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
  * conditions under which the PM bit should be set in outgoing frames
  * and STAY_AWAKE is meaningful
  */
-bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
 {
        struct brcms_bss_cfg *cfg = wlc->bsscfg;
 
@@ -3185,6 +3143,58 @@ bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
        return true;
 }
 
+static void brcms_c_statsupd(struct brcms_c_info *wlc)
+{
+       int i;
+       struct macstat macstats;
+#ifdef BCMDBG
+       u16 delta;
+       u16 rxf0ovfl;
+       u16 txfunfl[NFIFO];
+#endif                         /* BCMDBG */
+
+       /* if driver down, make no sense to update stats */
+       if (!wlc->pub->up)
+               return;
+
+#ifdef BCMDBG
+       /* save last rx fifo 0 overflow count */
+       rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
+
+       /* save last tx fifo  underflow count */
+       for (i = 0; i < NFIFO; i++)
+               txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
+#endif                         /* BCMDBG */
+
+       /* Read mac stats from contiguous shared memory */
+       brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
+                               sizeof(struct macstat), OBJADDR_SHM_SEL);
+
+#ifdef BCMDBG
+       /* check for rx fifo 0 overflow */
+       delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
+       if (delta)
+               wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
+                         wlc->pub->unit, delta);
+
+       /* check for tx fifo underflows */
+       for (i = 0; i < NFIFO; i++) {
+               delta =
+                   (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
+                             txfunfl[i]);
+               if (delta)
+                       wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
+                                 "\n", wlc->pub->unit, delta, i);
+       }
+#endif                         /* BCMDBG */
+
+       /* merge counters from dma module */
+       for (i = 0; i < NFIFO; i++) {
+               if (wlc->hw->di[i])
+                       dma_counterreset(wlc->hw->di[i]);
+       }
+}
+
 static void brcms_b_reset(struct brcms_hardware *wlc_hw)
 {
        BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
@@ -3211,13 +3221,6 @@ void brcms_c_reset(struct brcms_c_info *wlc)
        brcms_b_reset(wlc->hw);
 }
 
-void brcms_c_fatal_error(struct brcms_c_info *wlc)
-{
-       wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
-                 wlc->pub->unit);
-       brcms_init(wlc->wl);
-}
-
 /* Return the channel the driver should initialize during brcms_c_init.
  * the channel may have to be changed from the currently configured channel
  * if other configurations are in conflict (bandlocked, 11n mode disabled,
@@ -3494,11 +3497,115 @@ static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
                                            chanspec);
 
        brcms_c_stf_ss_update(wlc, wlc->band);
-
 }
 
-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
-                                    u16 chanspec)
+static void
+brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
+{
+       brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
+               wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
+               (bool) (wlc->pub->_n_enab & SUPPORT_11N),
+               brcms_chspec_bw(wlc->default_bss->chanspec),
+               wlc->stf->txstreams);
+}
+
+/* derive wlc->band->basic_rate[] table from 'rateset' */
+static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
+                             struct brcms_c_rateset *rateset)
+{
+       u8 rate;
+       u8 mandatory;
+       u8 cck_basic = 0;
+       u8 ofdm_basic = 0;
+       u8 *br = wlc->band->basic_rate;
+       uint i;
+
+       /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
+       memset(br, 0, BRCM_MAXRATE + 1);
+
+       /* For each basic rate in the rates list, make an entry in the
+        * best basic lookup.
+        */
+       for (i = 0; i < rateset->count; i++) {
+               /* only make an entry for a basic rate */
+               if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
+                       continue;
+
+               /* mask off basic bit */
+               rate = (rateset->rates[i] & BRCMS_RATE_MASK);
+
+               if (rate > BRCM_MAXRATE) {
+                       wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
+                                 "invalid rate 0x%X in rate set\n",
+                                 rateset->rates[i]);
+                       continue;
+               }
+
+               br[rate] = rate;
+       }
+
+       /* The rate lookup table now has non-zero entries for each
+        * basic rate, equal to the basic rate: br[basicN] = basicN
+        *
+        * To look up the best basic rate corresponding to any
+        * particular rate, code can use the basic_rate table
+        * like this
+        *
+        * basic_rate = wlc->band->basic_rate[tx_rate]
+        *
+        * Make sure there is a best basic rate entry for
+        * every rate by walking up the table from low rates
+        * to high, filling in holes in the lookup table
+        */
+
+       for (i = 0; i < wlc->band->hw_rateset.count; i++) {
+               rate = wlc->band->hw_rateset.rates[i];
+
+               if (br[rate] != 0) {
+                       /* This rate is a basic rate.
+                        * Keep track of the best basic rate so far by
+                        * modulation type.
+                        */
+                       if (is_ofdm_rate(rate))
+                               ofdm_basic = rate;
+                       else
+                               cck_basic = rate;
+
+                       continue;
+               }
+
+               /* This rate is not a basic rate so figure out the
+                * best basic rate less than this rate and fill in
+                * the hole in the table
+                */
+
+               br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
+
+               if (br[rate] != 0)
+                       continue;
+
+               if (is_ofdm_rate(rate)) {
+                       /*
+                        * In 11g and 11a, the OFDM mandatory rates
+                        * are 6, 12, and 24 Mbps
+                        */
+                       if (rate >= BRCM_RATE_24M)
+                               mandatory = BRCM_RATE_24M;
+                       else if (rate >= BRCM_RATE_12M)
+                               mandatory = BRCM_RATE_12M;
+                       else
+                               mandatory = BRCM_RATE_6M;
+               } else {
+                       /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
+                       mandatory = rate;
+               }
+
+               br[rate] = mandatory;
+       }
+}
+
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
+                                    u16 chanspec)
 {
        struct brcms_c_rateset default_rateset;
        uint parkband;
@@ -3543,6 +3650,44 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
        brcms_c_set_phy_chanspec(wlc, chanspec);
 }
 
+static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
+{
+       if (wlc->bcnmisc_monitor)
+               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
+       else
+               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+       wlc->bcnmisc_monitor = promisc;
+       brcms_c_mac_bcn_promisc(wlc);
+}
+
+/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
+static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
+{
+       u32 promisc_bits = 0;
+
+       /*
+        * promiscuous mode just sets MCTL_PROMISC
+        * Note: APs get all BSS traffic without the need to set
+        * the MCTL_PROMISC bit since all BSS data traffic is
+        * directed at the AP
+        */
+       if (wlc->pub->promisc)
+               promisc_bits |= MCTL_PROMISC;
+
+       /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
+        * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
+        * handled in brcms_c_mac_bcn_promisc()
+        */
+       if (wlc->monitor)
+               promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
+
+       brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+}
+
 /*
  * ucode, hwmac update
  *    Channel dependent updates for ucode and hw
@@ -3576,6 +3721,88 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
        brcms_c_mac_promisc(wlc);
 }
 
+static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
+                                  u8 basic_rate)
+{
+       u8 phy_rate, index;
+       u8 basic_phy_rate, basic_index;
+       u16 dir_table, basic_table;
+       u16 basic_ptr;
+
+       /* Shared memory address for the table we are reading */
+       dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
+
+       /* Shared memory address for the table we are writing */
+       basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
+
+       /*
+        * for a given rate, the LS-nibble of the PLCP SIGNAL field is
+        * the index into the rate table.
+        */
+       phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
+       basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
+       index = phy_rate & 0xf;
+       basic_index = basic_phy_rate & 0xf;
+
+       /* Find the SHM pointer to the ACK rate entry by looking in the
+        * Direct-map Table
+        */
+       basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
+
+       /* Update the SHM BSS-basic-rate-set mapping table with the pointer
+        * to the correct basic rate for the given incoming rate
+        */
+       brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
+}
+
+static const struct brcms_c_rateset *
+brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
+{
+       const struct brcms_c_rateset *rs_dflt;
+
+       if (BRCMS_PHY_11N_CAP(wlc->band)) {
+               if (wlc->band->bandtype == BRCM_BAND_5G)
+                       rs_dflt = &ofdm_mimo_rates;
+               else
+                       rs_dflt = &cck_ofdm_mimo_rates;
+       } else if (wlc->band->gmode)
+               rs_dflt = &cck_ofdm_rates;
+       else
+               rs_dflt = &cck_rates;
+
+       return rs_dflt;
+}
+
+static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
+{
+       const struct brcms_c_rateset *rs_dflt;
+       struct brcms_c_rateset rs;
+       u8 rate, basic_rate;
+       uint i;
+
+       rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+
+       brcms_c_rateset_copy(rs_dflt, &rs);
+       brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+
+       /* walk the phy rate table and update SHM basic rate lookup table */
+       for (i = 0; i < rs.count; i++) {
+               rate = rs.rates[i] & BRCMS_RATE_MASK;
+
+               /* for a given rate brcms_basic_rate returns the rate at
+                * which a response ACK/CTS should be sent.
+                */
+               basic_rate = brcms_basic_rate(wlc, rate);
+               if (basic_rate == 0)
+                       /* This should only happen if we are using a
+                        * restricted rateset.
+                        */
+                       basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
+
+               brcms_c_write_rate_shm(wlc, rate, basic_rate);
+       }
+}
+
 /* band-specific init */
 static void brcms_c_bsinit(struct brcms_c_info *wlc)
 {
@@ -3655,183 +3882,35 @@ static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
        }
 }
 
-void brcms_c_init(struct brcms_c_info *wlc)
+/* push sw hps and wake state through hardware */
+static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
 {
-       struct d11regs __iomem *regs;
-       u16 chanspec;
-       bool mute = false;
-
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       u32 v1, v2;
+       bool hps;
+       bool awake_before;
 
-       regs = wlc->regs;
+       hps = brcms_c_ps_allowed(wlc);
 
-       /*
-        * 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);
+       BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
 
-       brcms_b_init(wlc->hw, chanspec, mute);
+       v1 = R_REG(&wlc->regs->maccontrol);
+       v2 = MCTL_WAKE;
+       if (hps)
+               v2 |= MCTL_HPS;
 
-       /* update beacon listen interval */
-       brcms_c_bcn_li_upd(wlc);
+       brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
 
-       /* write ethernet address to core */
-       brcms_c_set_mac(wlc->bsscfg);
-       brcms_c_set_bssid(wlc->bsscfg);
-
-       /* Update tsf_cfprep if associated and up */
-       if (wlc->pub->associated && wlc->bsscfg->up) {
-               u32 bi;
-
-               /* get beacon period and convert to uS */
-               bi = wlc->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);
-       }
-
-       brcms_c_bandinit_ordered(wlc, chanspec);
-
-       /* init probe response timeout */
-       brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
-
-       /* init max burst txop (framebursting) */
-       brcms_b_write_shm(wlc->hw, 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) */
-       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_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
-               wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
-       }
-
-       /* ..now really unleash hell (allow the MAC out of suspend) */
-       brcms_c_enable_mac(wlc);
-
-       /* clear tx flow control */
-       brcms_c_txflowcontrol_reset(wlc);
-
-       /* enable the RF Disable Delay timer */
-       W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
-
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-
-       /*
-        * Initialize WME parameters; if they haven't been set by some other
-        * mechanism (IOVar, etc) then read them from the hardware.
-        */
-       if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
-               /* Uninitialized; read from HW */
-               int ac;
-
-               for (ac = 0; ac < AC_COUNT; ac++)
-                       wlc->wme_retries[ac] =
-                           brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
-       }
-}
-
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
-{
-       wlc->bcnmisc_monitor = promisc;
-       brcms_c_mac_bcn_promisc(wlc);
-}
-
-void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
-{
-       if (wlc->bcnmisc_monitor)
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
-       else
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
-}
-
-/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
-void brcms_c_mac_promisc(struct brcms_c_info *wlc)
-{
-       u32 promisc_bits = 0;
-
-       /*
-        * promiscuous mode just sets MCTL_PROMISC
-        * Note: APs get all BSS traffic without the need to set
-        * the MCTL_PROMISC bit since all BSS data traffic is
-        * directed at the AP
-        */
-       if (wlc->pub->promisc)
-               promisc_bits |= MCTL_PROMISC;
-
-       /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
-        * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
-        * handled in brcms_c_mac_bcn_promisc()
-        */
-       if (wlc->monitor)
-               promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
-
-       brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
-}
-
-/* push sw hps and wake state through hardware */
-void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
-{
-       u32 v1, v2;
-       bool hps;
-       bool awake_before;
-
-       hps = brcms_c_ps_allowed(wlc);
-
-       BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
-
-       v1 = R_REG(&wlc->regs->maccontrol);
-       v2 = MCTL_WAKE;
-       if (hps)
-               v2 |= MCTL_HPS;
-
-       brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
-
-       awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
+       awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
 
        if (!awake_before)
                brcms_b_wait_for_wake(wlc->hw);
-
 }
 
 /*
  * Write this BSS config's MAC address to core.
  * Updates RXE match engine.
  */
-int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
+static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
 {
        int err = 0;
        struct brcms_c_info *wlc = bsscfg->wlc;
@@ -3847,7 +3926,7 @@ int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
 /* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
  * Updates RXE match engine.
  */
-void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
+static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
 {
        /* we need to update BSSID in RXE match registers */
        brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
@@ -3868,7 +3947,7 @@ static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
  * Suspend the the MAC and update the slot timing
  * for standard 11b/g (20us slots) or shortslot 11g (9us slots).
  */
-void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
+static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
 {
        /* use the override if it is set */
        if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)
@@ -3882,7 +3961,7 @@ void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
        brcms_b_set_shortslot(wlc->hw, shortslot);
 }
 
-void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
+static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 {
        if (wlc->home_chanspec != chanspec) {
                wlc->home_chanspec = chanspec;
@@ -3952,7 +4031,7 @@ static void brcms_c_setband(struct brcms_c_info *wlc,
        brcms_c_bsinit(wlc);
 }
 
-void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
+static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 {
        uint bandunit;
        bool switchband = false;
@@ -4006,31 +4085,6 @@ void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
        brcms_c_ucode_mac_upd(wlc);
 }
 
-u32 brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc,
-                                     struct brcms_c_rateset *rs)
-{
-       u32 lowest_basic_rspec;
-       uint i;
-
-       /* Use the lowest basic rate */
-       lowest_basic_rspec = rs->rates[0] & BRCMS_RATE_MASK;
-       for (i = 0; i < rs->count; i++) {
-               if (rs->rates[i] & BRCMS_RATE_FLAG) {
-                       lowest_basic_rspec = rs->rates[i] & BRCMS_RATE_MASK;
-                       break;
-               }
-       }
-
-       /*
-        * pick siso/cdd as default for OFDM (note no basic
-        * rate MCSs are supported yet)
-        */
-       if (is_ofdm_rate(lowest_basic_rspec))
-               lowest_basic_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
-
-       return lowest_basic_rspec;
-}
-
 /*
  * This function changes the phytxctl for beacon based on current
  * beacon ratespec AND txant setting as per this table:
@@ -4239,7 +4293,7 @@ static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
        brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
 }
 
-void brcms_c_radio_disable(struct brcms_c_info *wlc)
+static void brcms_c_radio_disable(struct brcms_c_info *wlc)
 {
        if (!wlc->pub->up) {
                brcms_c_down_led_upd(wlc);
@@ -4261,7 +4315,7 @@ static void brcms_c_radio_enable(struct brcms_c_info *wlc)
        brcms_up(wlc->wl);
 }
 
-bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
+static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
 {
        if (!wlc->radio_monitor)
                return true;
@@ -4347,6 +4401,60 @@ static void brcms_b_watchdog(void *arg)
        wlc_phy_watchdog(wlc_hw->band->pi);
 }
 
+static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
+{
+       bool mpc_radio, radio_state;
+
+       /*
+        * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
+        * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
+        * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
+        * the radio is going down.
+        */
+       if (!wlc->mpc) {
+               if (!wlc->pub->radio_disabled)
+                       return;
+               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+               brcms_c_radio_upd(wlc);
+               if (!wlc->pub->radio_disabled)
+                       brcms_c_radio_monitor_stop(wlc);
+               return;
+       }
+
+       /*
+        * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
+        * wlc->pub->radio_disabled to go ON, always call radio_upd
+        * synchronously to go OFF, postpone radio_upd to later when
+        * context is safe(e.g. watchdog)
+        */
+       radio_state =
+           (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
+            ON);
+       mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
+
+       if (radio_state == ON && mpc_radio == OFF)
+               wlc->mpc_delay_off = wlc->mpc_dlycnt;
+       else if (radio_state == OFF && mpc_radio == ON) {
+               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+               brcms_c_radio_upd(wlc);
+               if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
+                       wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
+               else
+                       wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+       }
+       /*
+        * Below logic is meant to capture the transition from mpc off
+        * to mpc on for reasons other than wlc->mpc_delay_off keeping
+        * the mpc off. In that case reset wlc->mpc_delay_off to
+        * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
+        */
+       if ((wlc->prev_non_delay_mpc == false) &&
+           (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
+               wlc->mpc_delay_off = wlc->mpc_dlycnt;
+
+       wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
+}
+
 /* common watchdog code */
 static void brcms_c_watchdog(void *arg)
 {
@@ -4408,7 +4516,7 @@ 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)
+static 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");
@@ -4436,7 +4544,7 @@ bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
  * 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)
+static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
 {
        int i;
 
@@ -5025,224 +5133,33 @@ static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
        }
 }
 
-/*
- * 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 __iomem *regsva, struct pci_dev *btparam,
-              uint *perr)
+static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
 {
-       struct brcms_c_info *wlc;
-       uint err = 0;
-       uint i, j;
-       struct brcms_pub *pub;
-
-       /* 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
+       /* free timer state */
+       if (wlc->wdtimer) {
+               brcms_free_timer(wlc->wdtimer);
+               wlc->wdtimer = NULL;
+       }
+       if (wlc->radio_timer) {
+               brcms_free_timer(wlc->radio_timer);
+               wlc->radio_timer = NULL;
+       }
+}
 
-       wlc->band = wlc->bandstate[0];
-       wlc->core = wlc->corestate;
-       wlc->wl = wl;
-       pub->unit = unit;
-       pub->_piomode = piomode;
-       wlc->bandinit_pending = false;
+static void brcms_c_detach_module(struct brcms_c_info *wlc)
+{
+       if (wlc->asi) {
+               brcms_c_antsel_detach(wlc->asi);
+               wlc->asi = NULL;
+       }
 
-       /* populate struct brcms_c_info with default values  */
-       brcms_c_info_init(wlc, unit);
+       if (wlc->ampdu) {
+               brcms_c_ampdu_detach(wlc->ampdu);
+               wlc->ampdu = NULL;
+       }
 
-       /* update sta/ap related parameters */
-       brcms_c_ap_upd(wlc);
-
-       /*
-        * low level attach steps(all hw accesses go
-        * inside, no more in rest of the attach)
-        */
-       err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva,
-                            btparam);
-       if (err)
-               goto fail;
-
-       brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
-
-       pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
-
-       /* disable allowed duty cycle */
-       wlc->tx_duty_cycle_ofdm = 0;
-       wlc->tx_duty_cycle_cck = 0;
-
-       brcms_c_stf_phy_chain_calc(wlc);
-
-       /* txchain 1: txant 0, txchain 2: txant 1 */
-       if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
-               wlc->stf->txant = wlc->stf->hw_txchain - 1;
-
-       /* push to BMAC driver */
-       wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
-                              wlc->stf->hw_rxchain);
-
-       /* pull up some info resulting from the low attach */
-       for (i = 0; i < NFIFO; i++)
-               wlc->core->txavail[i] = wlc->hw->txavail[i];
-
-       memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
-       memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
-
-       for (j = 0; j < wlc->pub->_nbands; j++) {
-               wlc->band = wlc->bandstate[j];
-
-               if (!brcms_c_attach_stf_ant_init(wlc)) {
-                       err = 24;
-                       goto fail;
-               }
-
-               /* default contention windows size limits */
-               wlc->band->CWmin = APHY_CWMIN;
-               wlc->band->CWmax = PHY_CWMAX;
-
-               /* init gmode value */
-               if (wlc->band->bandtype == BRCM_BAND_2G) {
-                       wlc->band->gmode = GMODE_AUTO;
-                       brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
-                                          wlc->band->gmode);
-               }
-
-               /* init _n_enab supported mode */
-               if (BRCMS_PHY_11N_CAP(wlc->band)) {
-                       pub->_n_enab = SUPPORT_11N;
-                       brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
-                                                  ((pub->_n_enab ==
-                                                    SUPPORT_11N) ? WL_11N_2x2 :
-                                                   WL_11N_3x3));
-               }
-
-               /* init per-band default rateset, depend on band->gmode */
-               brcms_default_rateset(wlc, &wlc->band->defrateset);
-
-               /* fill in hw_rateset */
-               brcms_c_rateset_filter(&wlc->band->defrateset,
-                                  &wlc->band->hw_rateset, false,
-                                  BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
-                                  (bool) (wlc->pub->_n_enab & SUPPORT_11N));
-       }
-
-       /*
-        * update antenna config due to
-        * wlc->stf->txant/txchain/ant_rx_ovr change
-        */
-       brcms_c_stf_phy_txant_upd(wlc);
-
-       /* attach each modules */
-       err = brcms_c_attach_module(wlc);
-       if (err != 0)
-               goto fail;
-
-       if (!brcms_c_timers_init(wlc, unit)) {
-               wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
-                         __func__);
-               err = 32;
-               goto fail;
-       }
-
-       /* depend on rateset, gmode */
-       wlc->cmi = brcms_c_channel_mgr_attach(wlc);
-       if (!wlc->cmi) {
-               wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
-                         "\n", unit, __func__);
-               err = 33;
-               goto fail;
-       }
-
-       /* init default when all parameters are ready, i.e. ->rateset */
-       brcms_c_bss_default_init(wlc);
-
-       /*
-        * Complete the wlc default state initializations..
-        */
-
-       /* allocate our initial queue */
-       wlc->pkt_queue = brcms_c_txq_alloc(wlc);
-       if (wlc->pkt_queue == NULL) {
-               wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
-                         unit, __func__);
-               err = 100;
-               goto fail;
-       }
-
-       wlc->bsscfg->wlc = wlc;
-
-       wlc->mimoft = FT_HT;
-       wlc->mimo_40txbw = AUTO;
-       wlc->ofdm_40txbw = AUTO;
-       wlc->cck_40txbw = AUTO;
-       brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
-
-       /* Set default values of SGI */
-       if (BRCMS_SGI_CAP_PHY(wlc)) {
-               brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
-                                              BRCMS_N_SGI_40));
-       } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
-               brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
-                                              BRCMS_N_SGI_40));
-       } else {
-               brcms_c_ht_update_sgi_rx(wlc, 0);
-       }
-
-       /* initialize radio_mpc_disable according to wlc->mpc */
-       brcms_c_radio_mpc_upd(wlc);
-       brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
-
-       if (perr)
-               *perr = 0;
-
-       return wlc;
-
- fail:
-       wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
-                 unit, __func__, err);
-       if (wlc)
-               brcms_c_detach(wlc);
-
-       if (perr)
-               *perr = err;
-       return NULL;
-}
-
-static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
-{
-       /* free timer state */
-       if (wlc->wdtimer) {
-               brcms_free_timer(wlc->wdtimer);
-               wlc->wdtimer = NULL;
-       }
-       if (wlc->radio_timer) {
-               brcms_free_timer(wlc->radio_timer);
-               wlc->radio_timer = NULL;
-       }
-}
-
-static void brcms_c_detach_module(struct brcms_c_info *wlc)
-{
-       if (wlc->asi) {
-               brcms_c_antsel_detach(wlc->asi);
-               wlc->asi = NULL;
-       }
-
-       if (wlc->ampdu) {
-               brcms_c_ampdu_detach(wlc->ampdu);
-               wlc->ampdu = NULL;
-       }
-
-       brcms_c_stf_detach(wlc);
-}
+       brcms_c_stf_detach(wlc);
+}
 
 /*
  * low level detach
@@ -5332,7 +5249,7 @@ uint brcms_c_detach(struct brcms_c_info *wlc)
 }
 
 /* update state that depends on the current value of "ap" */
-void brcms_c_ap_upd(struct brcms_c_info *wlc)
+static void brcms_c_ap_upd(struct brcms_c_info *wlc)
 {
        /* STA-BSS; short capable */
        wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
@@ -5341,73 +5258,6 @@ void brcms_c_ap_upd(struct brcms_c_info *wlc)
        wlc->mpc = true;
 }
 
-/*
- * 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;
-}
-
-bool brcms_c_ismpc(struct brcms_c_info *wlc)
-{
-       return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
-}
-
-void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
-{
-       bool mpc_radio, radio_state;
-
-       /*
-        * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
-        * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
-        * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
-        * the radio is going down.
-        */
-       if (!wlc->mpc) {
-               if (!wlc->pub->radio_disabled)
-                       return;
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (!wlc->pub->radio_disabled)
-                       brcms_c_radio_monitor_stop(wlc);
-               return;
-       }
-
-       /*
-        * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
-        * wlc->pub->radio_disabled to go ON, always call radio_upd
-        * synchronously to go OFF, postpone radio_upd to later when
-        * context is safe(e.g. watchdog)
-        */
-       radio_state =
-           (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
-            ON);
-       mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
-
-       if (radio_state == ON && mpc_radio == OFF)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-       else if (radio_state == OFF && mpc_radio == ON) {
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
-                       wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
-               else
-                       wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-       }
-       /*
-        * Below logic is meant to capture the transition from mpc off
-        * to mpc on for reasons other than wlc->mpc_delay_off keeping
-        * the mpc off. In that case reset wlc->mpc_delay_off to
-        * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
-        */
-       if ((wlc->prev_non_delay_mpc == false) &&
-           (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-
-       wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
-}
 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
 static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
 {
@@ -6195,59 +6045,7 @@ void brcms_c_print_txstatus(struct tx_status *txs)
 #endif                         /* defined(BCMDBG) */
 }
 
-void brcms_c_statsupd(struct brcms_c_info *wlc)
-{
-       int i;
-       struct macstat macstats;
-#ifdef BCMDBG
-       u16 delta;
-       u16 rxf0ovfl;
-       u16 txfunfl[NFIFO];
-#endif                         /* BCMDBG */
-
-       /* if driver down, make no sense to update stats */
-       if (!wlc->pub->up)
-               return;
-
-#ifdef BCMDBG
-       /* save last rx fifo 0 overflow count */
-       rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
-
-       /* save last tx fifo  underflow count */
-       for (i = 0; i < NFIFO; i++)
-               txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
-#endif                         /* BCMDBG */
-
-       /* Read mac stats from contiguous shared memory */
-       brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
-                               sizeof(struct macstat), OBJADDR_SHM_SEL);
-
-#ifdef BCMDBG
-       /* check for rx fifo 0 overflow */
-       delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
-       if (delta)
-               wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
-                         wlc->pub->unit, delta);
-
-       /* check for tx fifo underflows */
-       for (i = 0; i < NFIFO; i++) {
-               delta =
-                   (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
-                             txfunfl[i]);
-               if (delta)
-                       wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
-                                 "\n", wlc->pub->unit, delta, i);
-       }
-#endif                         /* BCMDBG */
-
-       /* merge counters from dma module */
-       for (i = 0; i < NFIFO; i++) {
-               if (wlc->hw->di[i])
-                       dma_counterreset(wlc->hw->di[i]);
-       }
-}
-
-bool brcms_c_chipmatch(u16 vendor, u16 device)
+bool brcms_c_chipmatch(u16 vendor, u16 device)
 {
        if (vendor != PCI_VENDOR_ID_BROADCOM) {
                pr_err("chipmatch: unknown vendor id %04x\n", vendor);
@@ -6417,24 +6215,7 @@ u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
        return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
 }
 
-/* Callback for device removed */
-
-/*
- * Attempts to queue a packet onto a multiple-precedence queue,
- * if necessary evicting a lower precedence packet from the queue.
- *
- * 'prec' is the precedence number that has already been mapped
- * from the packet priority.
- *
- * Returns true if packet consumed (queued), false if not.
- */
-static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
-                     struct sk_buff *pkt, int prec)
-{
-       return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
-}
-
-bool
+static bool
 brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
                      struct sk_buff *pkt, int prec, bool head)
 {
@@ -6481,6 +6262,21 @@ brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
        return true;
 }
 
+/*
+ * Attempts to queue a packet onto a multiple-precedence queue,
+ * if necessary evicting a lower precedence packet from the queue.
+ *
+ * 'prec' is the precedence number that has already been mapped
+ * from the packet priority.
+ *
+ * Returns true if packet consumed (queued), false if not.
+ */
+static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
+                     struct sk_buff *pkt, int prec)
+{
+       return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
+}
+
 void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
                     struct sk_buff *sdu, uint prec)
 {
@@ -6647,6 +6443,43 @@ brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
        return mac_len;
 }
 
+/*
+ * Return true if the specified rate is supported by the specified band.
+ * BRCM_BAND_AUTO indicates the current band.
+ */
+static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
+                   bool verbose)
+{
+       struct brcms_c_rateset *hw_rateset;
+       uint i;
+
+       if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
+               hw_rateset = &wlc->band->hw_rateset;
+       else if (wlc->pub->_nbands > 1)
+               hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
+       else
+               /* other band specified and we are a single band device */
+               return false;
+
+       /* check if this is a mimo rate */
+       if (is_mcs_rate(rspec)) {
+               if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
+                       goto error;
+
+               return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
+       }
+
+       for (i = 0; i < hw_rateset->count; i++)
+               if (hw_rateset->rates[i] == rspec2rate(rspec))
+                       return true;
+ error:
+       if (verbose)
+               wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
+                         "not in hw_rateset\n", wlc->pub->unit, rspec);
+
+       return false;
+}
+
 static u32
 mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
                       u32 int_val)
@@ -6764,84 +6597,291 @@ done:
 }
 
 /*
- * 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)
- *
+ * 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 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 ieee80211_hdr *h;
-       struct d11txh *txh;
-       u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
-       int len, phylen, rts_phylen;
-       u16 mch, phyctl, xfts, mainrates;
-       u16 seq = 0, mcl = 0, status = 0, frameid = 0;
-       u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
-       u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
-       bool use_rts = false;
-       bool use_cts = false;
-       bool use_rifs = false;
-       bool short_preamble[2] = { false, false };
-       u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
-       u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
-       u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
-       struct ieee80211_rts *rts = NULL;
-       bool qos;
-       uint ac;
-       bool hwtkmic = false;
-       u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
-#define ANTCFG_NONE 0xFF
-       u8 antcfg = ANTCFG_NONE;
-       u8 fbantcfg = ANTCFG_NONE;
-       uint phyctl1_stf = 0;
-       u16 durid = 0;
-       struct ieee80211_tx_rate *txrate[2];
-       int k;
-       struct ieee80211_tx_info *tx_info;
-       bool is_mcs;
-       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);
+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;
 
-       /* compute length of frame in bytes for use in PLCP computations */
-       len = brcmu_pkttotlen(p);
-       phylen = len + FCS_LEN;
+       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;
 
-       /* Get tx_info */
-       tx_info = IEEE80211_SKB_CB(p);
+       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;
+}
 
-       /* add PLCP */
-       plcp = skb_push(p, D11_PHY_HDR_LEN);
+/* 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;
+}
 
-       /* add Broadcom tx descriptor header */
-       txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);
-       memset(txh, 0, D11_TXH_LEN);
+/* 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);
 
-       /* 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", wlc->pub->unit, __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[p->priority]++;
+       /*
+        * 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);
 
-                       /* extract fragment number from frame first */
-                       seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
-                       seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
+       tmp = (length & 0xfff) << 5;
+       plcp[2] |= (tmp >> 16) & 0xff;
+       plcp[1] |= (tmp >> 8) & 0xff;
+       plcp[0] |= tmp & 0xff;
+}
+
+/* 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);
+
+       brcms_c_cck_plcp_set(wlc, rate, length, plcp);
+}
+
+static void
+brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
+                    uint length, u8 *plcp)
+{
+       if (is_mcs_rate(rspec))
+               brcms_c_compute_mimo_plcp(rspec, length, plcp);
+       else if (is_ofdm_rate(rspec))
+               brcms_c_compute_ofdm_plcp(rspec, length, plcp);
+       else
+               brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
+}
+
+/* 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;
+
+       sifs = get_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;
+}
+
+static 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_rate(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_rate(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;
+}
+
+/*
+ * 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 ieee80211_hdr *h;
+       struct d11txh *txh;
+       u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];
+       int len, phylen, rts_phylen;
+       u16 mch, phyctl, xfts, mainrates;
+       u16 seq = 0, mcl = 0, status = 0, frameid = 0;
+       u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
+       u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
+       bool use_rts = false;
+       bool use_cts = false;
+       bool use_rifs = false;
+       bool short_preamble[2] = { false, false };
+       u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
+       u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };
+       u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];
+       struct ieee80211_rts *rts = NULL;
+       bool qos;
+       uint ac;
+       bool hwtkmic = false;
+       u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
+#define ANTCFG_NONE 0xFF
+       u8 antcfg = ANTCFG_NONE;
+       u8 fbantcfg = ANTCFG_NONE;
+       uint phyctl1_stf = 0;
+       u16 durid = 0;
+       struct ieee80211_tx_rate *txrate[2];
+       int k;
+       struct ieee80211_tx_info *tx_info;
+       bool is_mcs;
+       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);
+
+       /* compute length of frame in bytes for use in PLCP computations */
+       len = brcmu_pkttotlen(p);
+       phylen = len + FCS_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", wlc->pub->unit, __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[p->priority]++;
+
+                       /* extract fragment number from frame first */
+                       seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
+                       seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
                        h->seq_ctrl = cpu_to_le16(seq);
 
                        frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
@@ -7518,237 +7558,30 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
                wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
 }
 
-/*
- * 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)
+u32
+brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
+                          bool use_rspec, u16 mimo_ctlchbw)
 {
-       u16 usec = 0;
-       u8 le = 0;
+       u32 rts_rspec = 0;
 
-       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;
-
-       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;
-}
-
-/* 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;
-}
-
-/* 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);
-
-       /*
-        * 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);
-
-       tmp = (length & 0xfff) << 5;
-       plcp[2] |= (tmp >> 16) & 0xff;
-       plcp[1] |= (tmp >> 8) & 0xff;
-       plcp[0] |= tmp & 0xff;
-}
-
-/* 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);
-
-       brcms_c_cck_plcp_set(wlc, rate, length, plcp);
-}
-
-void
-brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
-                    uint length, u8 *plcp)
-{
-       if (is_mcs_rate(rspec))
-               brcms_c_compute_mimo_plcp(rspec, length, plcp);
-       else if (is_ofdm_rate(rspec))
-               brcms_c_compute_ofdm_plcp(rspec, length, plcp);
-       else
-               brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
-}
-
-/* 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;
-
-       sifs = get_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_rate(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_rate(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_rate(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 (use_rspec)
+               /* use frame rate as rts rate */
+               rts_rspec = rspec;
+       else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(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 */
@@ -7772,16 +7605,6 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
        return rts_rspec;
 }
 
-void brcms_c_tbtt(struct brcms_c_info *wlc)
-{
-       if (!wlc->bsscfg->BSS)
-               /*
-                * DirFrmQ is now valid...defer setting until end
-                * of ATIM window
-                */
-               wlc->qvalid |= MCMD_DIRFRMQVAL;
-}
-
 void
 brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
 {
@@ -7796,7 +7619,7 @@ brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
 }
 
 /* Update beacon listen interval in shared memory */
-void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
+static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
 {
        /* wake up every DTIM is the default */
        if (wlc->bcn_li_dtim == 1)
@@ -7993,93 +7816,33 @@ brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
        ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
 }
 
-/* Process received frames */
-/*
- * Return true if more frames need to be processed. false otherwise.
- * Param 'bound' indicates max. # frames to process before break out.
+/* calculate frame duration for Mixed-mode L-SIG spoofing, return
+ * number of bytes goes in the length field
+ *
+ * Formula given by HT PHY Spec v 1.13
+ *   len = 3(nsyms + nstream + 3) - 3
  */
-void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
+u16
+brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
+                     uint mac_len)
 {
-       struct d11rxhdr *rxh;
-       struct ieee80211_hdr *h;
-       uint len;
-       bool is_amsdu;
-
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
-       /* frame starts with rxhdr */
-       rxh = (struct d11rxhdr *) (p->data);
+       uint nsyms, len = 0, kNdps;
 
-       /* strip off rxhdr */
-       skb_pull(p, BRCMS_HWRXOFF);
+       BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
+                wlc->pub->unit, rspec2rate(ratespec), mac_len);
 
-       /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
-       if (rxh->RxStatus1 & RXS_PBPRES) {
-               if (p->len < 2) {
-                       wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
-                                 "len %d\n", wlc->pub->unit, p->len);
-                       goto toss;
-               }
-               skb_pull(p, 2);
-       }
+       if (is_mcs_rate(ratespec)) {
+               uint mcs = ratespec & RSPEC_RATE_MASK;
+               int tot_streams = (mcs_2_txstreams(mcs) + 1) +
+                                 rspec_stc(ratespec);
 
-       h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
-       len = p->len;
-
-       if (rxh->RxStatus1 & RXS_FCSERR) {
-               if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
-                       wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
-                                 " tossing\n");
-                       goto toss;
-               } else {
-                       wiphy_err(wlc->wiphy, "RCSERR!!!\n");
-                       goto toss;
-               }
-       }
-
-       /* check received pkt has at least frame control field */
-       if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
-               goto toss;
-
-       /* not supporting A-MSDU */
-       is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
-       if (is_amsdu)
-               goto toss;
-
-       brcms_c_recvctl(wlc, rxh, p);
-       return;
-
- toss:
-       brcmu_pkt_buf_free_skb(p);
-}
-
-/* calculate frame duration for Mixed-mode L-SIG spoofing, return
- * number of bytes goes in the length field
- *
- * Formula given by HT PHY Spec v 1.13
- *   len = 3(nsyms + nstream + 3) - 3
- */
-u16
-brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
-                     uint mac_len)
-{
-       uint nsyms, len = 0, kNdps;
-
-       BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
-                wlc->pub->unit, rspec2rate(ratespec), mac_len);
-
-       if (is_mcs_rate(ratespec)) {
-               uint mcs = ratespec & RSPEC_RATE_MASK;
-               int tot_streams = (mcs_2_txstreams(mcs) + 1) +
-                                 rspec_stc(ratespec);
-
-               /*
-                * the payload duration calculation matches that
-                * of regular ofdm
-                */
-               /* 1000Ndbps = kbps * 4 */
-               kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
-                                  rspec_issgi(ratespec)) * 4;
+               /*
+                * the payload duration calculation matches that
+                * of regular ofdm
+                */
+               /* 1000Ndbps = kbps * 4 */
+               kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+                                  rspec_issgi(ratespec)) * 4;
 
                if (rspec_stc(ratespec) == 0)
                        nsyms =
@@ -8104,737 +7867,847 @@ brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
        return (u16) len;
 }
 
-/*
- * calculate frame duration of a given rate and length, return
- * time in usec unit
- */
-uint
-brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
-                       u8 preamble_type, uint mac_len)
+static void
+brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
 {
-       uint nsyms, dur = 0, Ndps, kNdps;
-       uint rate = rspec2rate(ratespec);
+       const struct brcms_c_rateset *rs_dflt;
+       struct brcms_c_rateset rs;
+       u8 rate;
+       u16 entry_ptr;
+       u8 plcp[D11_PHY_HDR_LEN];
+       u16 dur, sifs;
+       uint i;
 
-       if (rate == 0) {
-               wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
-                         wlc->pub->unit);
-               rate = BRCM_RATE_1M;
-       }
+       sifs = get_sifs(wlc->band);
 
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
-                wlc->pub->unit, ratespec, preamble_type, mac_len);
+       rs_dflt = brcms_c_rateset_get_hwrs(wlc);
 
-       if (is_mcs_rate(ratespec)) {
-               uint mcs = ratespec & RSPEC_RATE_MASK;
-               int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+       brcms_c_rateset_copy(rs_dflt, &rs);
+       brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
 
-               dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
-               if (preamble_type == BRCMS_MM_PREAMBLE)
-                       dur += PREN_MM_EXT;
-               /* 1000Ndbps = kbps * 4 */
-               kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
-                                  rspec_issgi(ratespec)) * 4;
+       /*
+        * walk the phy rate table and update MAC core SHM
+        * basic rate table entries
+        */
+       for (i = 0; i < rs.count; i++) {
+               rate = rs.rates[i] & BRCMS_RATE_MASK;
 
-               if (rspec_stc(ratespec) == 0)
-                       nsyms =
-                           CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
-                                 APHY_TAIL_NBITS) * 1000, kNdps);
-               else
-                       /* STBC needs to have even number of symbols */
-                       nsyms =
-                           2 *
-                           CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
-                                 APHY_TAIL_NBITS) * 1000, 2 * kNdps);
+               entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
+
+               /* Calculate the Probe Response PLCP for the given rate */
+               brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
 
-               dur += APHY_SYMBOL_TIME * nsyms;
-               if (wlc->band->bandtype == BRCM_BAND_2G)
-                       dur += DOT11_OFDM_SIGNAL_EXTENSION;
-       } else if (is_ofdm_rate(rate)) {
-               dur = APHY_PREAMBLE_TIME;
-               dur += APHY_SIGNAL_TIME;
-               /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
-               Ndps = rate * 2;
-               /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
-               nsyms =
-                   CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
-                        Ndps);
-               dur += APHY_SYMBOL_TIME * nsyms;
-               if (wlc->band->bandtype == BRCM_BAND_2G)
-                       dur += DOT11_OFDM_SIGNAL_EXTENSION;
-       } else {
                /*
-                * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
-                * will divide out
+                * Calculate the duration of the Probe Response
+                * frame plus SIFS for the MAC
                 */
-               mac_len = mac_len * 8 * 2;
-               /* calc ceiling of bits/rate = microseconds of air time */
-               dur = (mac_len + rate - 1) / rate;
-               if (preamble_type & BRCMS_SHORT_PREAMBLE)
-                       dur += BPHY_PLCP_SHORT_TIME;
-               else
-                       dur += BPHY_PLCP_TIME;
+               dur = (u16) brcms_c_calc_frame_time(wlc, rate,
+                                               BRCMS_LONG_PREAMBLE, frame_len);
+               dur += sifs;
+
+               /* Update the SHM Rate Table entry Probe Response values */
+               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
+                             (u16) (plcp[0] + (plcp[1] << 8)));
+               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
+                             (u16) (plcp[2] + (plcp[3] << 8)));
+               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
        }
-       return dur;
 }
 
-/* derive wlc->band->basic_rate[] table from 'rateset' */
-void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
-                             struct brcms_c_rateset *rateset)
+/*     Max buffering needed for beacon template/prb resp template is 142 bytes.
+ *
+ *     PLCP header is 6 bytes.
+ *     802.11 A3 header is 24 bytes.
+ *     Max beacon frame body template length is 112 bytes.
+ *     Max probe resp frame body template length is 110 bytes.
+ *
+ *      *len on input contains the max length of the packet available.
+ *
+ *     The *len value is set to the number of bytes in buf used, and starts
+ *     with the PLCP and included up to, but not including, the 4 byte FCS.
+ */
+static void
+brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
+                        u32 bcn_rspec,
+                        struct brcms_bss_cfg *cfg, u16 *buf, int *len)
 {
-       u8 rate;
-       u8 mandatory;
-       u8 cck_basic = 0;
-       u8 ofdm_basic = 0;
-       u8 *br = wlc->band->basic_rate;
-       uint i;
-
-       /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
-       memset(br, 0, BRCM_MAXRATE + 1);
+       static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
+       struct cck_phy_hdr *plcp;
+       struct ieee80211_mgmt *h;
+       int hdr_len, body_len;
 
-       /* For each basic rate in the rates list, make an entry in the
-        * best basic lookup.
-        */
-       for (i = 0; i < rateset->count; i++) {
-               /* only make an entry for a basic rate */
-               if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
-                       continue;
+       hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
 
-               /* mask off basic bit */
-               rate = (rateset->rates[i] & BRCMS_RATE_MASK);
+       /* calc buffer size provided for frame body */
+       body_len = *len - hdr_len;
+       /* return actual size */
+       *len = hdr_len + body_len;
 
-               if (rate > BRCM_MAXRATE) {
-                       wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
-                                 "invalid rate 0x%X in rate set\n",
-                                 rateset->rates[i]);
-                       continue;
-               }
+       /* format PHY and MAC headers */
+       memset((char *)buf, 0, hdr_len);
 
-               br[rate] = rate;
-       }
+       plcp = (struct cck_phy_hdr *) buf;
 
-       /* The rate lookup table now has non-zero entries for each
-        * basic rate, equal to the basic rate: br[basicN] = basicN
-        *
-        * To look up the best basic rate corresponding to any
-        * particular rate, code can use the basic_rate table
-        * like this
-        *
-        * basic_rate = wlc->band->basic_rate[tx_rate]
-        *
-        * Make sure there is a best basic rate entry for
-        * every rate by walking up the table from low rates
-        * to high, filling in holes in the lookup table
+       /*
+        * PLCP for Probe Response frames are filled in from
+        * core's rate table
         */
+       if (type == IEEE80211_STYPE_BEACON)
+               /* fill in PLCP */
+               brcms_c_compute_plcp(wlc, bcn_rspec,
+                                (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
+                                (u8 *) plcp);
 
-       for (i = 0; i < wlc->band->hw_rateset.count; i++) {
-               rate = wlc->band->hw_rateset.rates[i];
+       /* "Regular" and 16 MBSS but not for 4 MBSS */
+       /* Update the phytxctl for the beacon based on the rspec */
+       brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
 
-               if (br[rate] != 0) {
-                       /* This rate is a basic rate.
-                        * Keep track of the best basic rate so far by
-                        * modulation type.
-                        */
-                       if (is_ofdm_rate(rate))
-                               ofdm_basic = rate;
-                       else
-                               cck_basic = rate;
+       h = (struct ieee80211_mgmt *)&plcp[1];
 
-                       continue;
-               }
+       /* fill in 802.11 header */
+       h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
 
-               /* This rate is not a basic rate so figure out the
-                * best basic rate less than this rate and fill in
-                * the hole in the table
-                */
+       /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
+       /* A1 filled in by MAC for prb resp, broadcast for bcn */
+       if (type == IEEE80211_STYPE_BEACON)
+               memcpy(&h->da, &ether_bcast, ETH_ALEN);
+       memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
+       memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
 
-               br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
+       /* SEQ filled in by MAC */
+}
 
-               if (br[rate] != 0)
-                       continue;
+int brcms_c_get_header_len(void)
+{
+       return TXOFF;
+}
 
-               if (is_ofdm_rate(rate)) {
-                       /*
-                        * In 11g and 11a, the OFDM mandatory rates
-                        * are 6, 12, and 24 Mbps
-                        */
-                       if (rate >= BRCM_RATE_24M)
-                               mandatory = BRCM_RATE_24M;
-                       else if (rate >= BRCM_RATE_12M)
-                               mandatory = BRCM_RATE_12M;
-                       else
-                               mandatory = BRCM_RATE_6M;
-               } else {
-                       /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
-                       mandatory = rate;
-               }
+/*
+ * Update all beacons for the system.
+ */
+void brcms_c_update_beacon(struct brcms_c_info *wlc)
+{
+       struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
 
-               br[rate] = mandatory;
-       }
+       if (bsscfg->up && !bsscfg->BSS)
+               /* Clear the soft intmask */
+               wlc->defmacintmask &= ~MI_BCNTPL;
 }
 
-static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
-                                  u8 basic_rate)
+/* Write ssid into shared memory */
+static void
+brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
 {
-       u8 phy_rate, index;
-       u8 basic_phy_rate, basic_index;
-       u16 dir_table, basic_table;
-       u16 basic_ptr;
+       u8 *ssidptr = cfg->SSID;
+       u16 base = M_SSID;
+       u8 ssidbuf[IEEE80211_MAX_SSID_LEN];
 
-       /* Shared memory address for the table we are reading */
-       dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
+       /* padding the ssid with zero and copy it into shm */
+       memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);
+       memcpy(ssidbuf, ssidptr, cfg->SSID_len);
 
-       /* Shared memory address for the table we are writing */
-       basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
+       brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
+       brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
+}
+
+static void
+brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
+                             struct brcms_bss_cfg *cfg,
+                             bool suspend)
+{
+       u16 prb_resp[BCN_TMPL_LEN / 2];
+       int len = BCN_TMPL_LEN;
 
        /*
-        * for a given rate, the LS-nibble of the PLCP SIGNAL field is
-        * the index into the rate table.
+        * write the probe response to hardware, or save in
+        * the config structure
         */
-       phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
-       basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
-       index = phy_rate & 0xf;
-       basic_index = basic_phy_rate & 0xf;
 
-       /* Find the SHM pointer to the ACK rate entry by looking in the
-        * Direct-map Table
-        */
-       basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
+       /* create the probe response template */
+       brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
+                                cfg, prb_resp, &len);
 
-       /* Update the SHM BSS-basic-rate-set mapping table with the pointer
-        * to the correct basic rate for the given incoming rate
+       if (suspend)
+               brcms_c_suspend_mac_and_wait(wlc);
+
+       /* write the probe response into the template region */
+       brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
+                                   (len + 3) & ~3, prb_resp);
+
+       /* write the length of the probe response frame (+PLCP/-FCS) */
+       brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
+
+       /* write the SSID and SSID length */
+       brcms_c_shm_ssid_upd(wlc, cfg);
+
+       /*
+        * Write PLCP headers and durations for probe response frames
+        * at all rates. Use the actual frame length covered by the
+        * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
+        * by subtracting the PLCP len and adding the FCS.
         */
-       brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
+       len += (-D11_PHY_HDR_LEN + FCS_LEN);
+       brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+
+       if (suspend)
+               brcms_c_enable_mac(wlc);
 }
 
-static const struct brcms_c_rateset *
-brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
+void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
 {
-       const struct brcms_c_rateset *rs_dflt;
-
-       if (BRCMS_PHY_11N_CAP(wlc->band)) {
-               if (wlc->band->bandtype == BRCM_BAND_5G)
-                       rs_dflt = &ofdm_mimo_rates;
-               else
-                       rs_dflt = &cck_ofdm_mimo_rates;
-       } else if (wlc->band->gmode)
-               rs_dflt = &cck_ofdm_rates;
-       else
-               rs_dflt = &cck_rates;
+       struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
 
-       return rs_dflt;
+       /* update AP or IBSS probe responses */
+       if (bsscfg->up && !bsscfg->BSS)
+               brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
 }
 
-void brcms_c_set_ratetable(struct brcms_c_info *wlc)
+/* prepares pdu for transmission. returns BCM error codes */
+int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
 {
-       const struct brcms_c_rateset *rs_dflt;
-       struct brcms_c_rateset rs;
-       u8 rate, basic_rate;
-       uint i;
+       uint fifo;
+       struct d11txh *txh;
+       struct ieee80211_hdr *h;
+       struct scb *scb;
 
-       rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+       txh = (struct d11txh *) (pdu->data);
+       h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
 
-       brcms_c_rateset_copy(rs_dflt, &rs);
-       brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+       /* get the pkt queue info. This was put at brcms_c_sendctl or
+        * brcms_c_send for PDU */
+       fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
 
-       /* walk the phy rate table and update SHM basic rate lookup table */
-       for (i = 0; i < rs.count; i++) {
-               rate = rs.rates[i] & BRCMS_RATE_MASK;
+       scb = NULL;
 
-               /* for a given rate brcms_basic_rate returns the rate at
-                * which a response ACK/CTS should be sent.
-                */
-               basic_rate = brcms_basic_rate(wlc, rate);
-               if (basic_rate == 0)
-                       /* This should only happen if we are using a
-                        * restricted rateset.
-                        */
-                       basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
+       *fifop = fifo;
 
-               brcms_c_write_rate_shm(wlc, rate, basic_rate);
+       /* return if insufficient dma resources */
+       if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
+               /* Mark precedences related to this FIFO, unsendable */
+               /* A fifo is full. Clear precedences related to that FIFO */
+               wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
+               return -EBUSY;
        }
+       return 0;
 }
 
-/*
- * Return true if the specified rate is supported by the specified band.
- * BRCM_BAND_AUTO indicates the current band.
- */
-bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
-                   bool verbose)
+int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+                          uint *blocks)
 {
-       struct brcms_c_rateset *hw_rateset;
-       uint i;
+       if (fifo >= NFIFO)
+               return -EINVAL;
 
-       if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
-               hw_rateset = &wlc->band->hw_rateset;
-       else if (wlc->pub->_nbands > 1)
-               hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
-       else
-               /* other band specified and we are a single band device */
-               return false;
+       *blocks = wlc_hw->xmtfifo_sz[fifo];
 
-       /* check if this is a mimo rate */
-       if (is_mcs_rate(rspec)) {
-               if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
-                       goto error;
+       return 0;
+}
 
-               return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
-       }
+void
+brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
+                 const u8 *addr)
+{
+       brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
+       if (match_reg_offset == RCM_BSSID_OFFSET)
+               memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
+}
 
-       for (i = 0; i < hw_rateset->count; i++)
-               if (hw_rateset->rates[i] == rspec2rate(rspec))
-                       return true;
- error:
-       if (verbose)
-               wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
-                         "not in hw_rateset\n", wlc->pub->unit, rspec);
+/*
+ * Flag 'scan in progress' to withhold dynamic phy calibration
+ */
+void brcms_c_scan_start(struct brcms_c_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
+}
 
-       return false;
+void brcms_c_scan_stop(struct brcms_c_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
 }
 
-void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
+void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
 {
-       const struct brcms_c_rateset *rs_dflt;
-       struct brcms_c_rateset rs;
-       u8 rate;
-       u16 entry_ptr;
-       u8 plcp[D11_PHY_HDR_LEN];
-       u16 dur, sifs;
-       uint i;
+       wlc->pub->associated = state;
+       wlc->bsscfg->associated = state;
+}
 
-       sifs = get_sifs(wlc->band);
+/*
+ * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
+ * AMPDU traffic, packets pending in hardware have to be invalidated so that
+ * when later on hardware releases them, they can be handled appropriately.
+ */
+void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
+                              struct ieee80211_sta *sta,
+                              void (*dma_callback_fn))
+{
+       struct dma_pub *dmah;
+       int i;
+       for (i = 0; i < NFIFO; i++) {
+               dmah = hw->di[i];
+               if (dmah != NULL)
+                       dma_walk_packets(dmah, dma_callback_fn, sta);
+       }
+}
 
-       rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+int brcms_c_get_curband(struct brcms_c_info *wlc)
+{
+       return wlc->band->bandunit;
+}
 
-       brcms_c_rateset_copy(rs_dflt, &rs);
-       brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
+{
+       /* flush packet queue when requested */
+       if (drop)
+               brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
 
-       /*
-        * walk the phy rate table and update MAC core SHM
-        * basic rate table entries
-        */
-       for (i = 0; i < rs.count; i++) {
-               rate = rs.rates[i] & BRCMS_RATE_MASK;
+       /* wait for queue and DMA fifos to run dry */
+       while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
+               brcms_msleep(wlc->wl, 1);
+}
 
-               entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
+void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
+{
+       wlc->bcn_li_bcn = interval;
+       if (wlc->pub->up)
+               brcms_c_bcn_li_upd(wlc);
+}
 
-               /* Calculate the Probe Response PLCP for the given rate */
-               brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
+int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
+{
+       uint qdbm;
 
-               /*
-                * Calculate the duration of the Probe Response
-                * frame plus SIFS for the MAC
-                */
-               dur = (u16) brcms_c_calc_frame_time(wlc, rate,
-                                               BRCMS_LONG_PREAMBLE, frame_len);
-               dur += sifs;
+       /* Remove override bit and clip to max qdbm value */
+       qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
+       return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
+}
 
-               /* Update the SHM Rate Table entry Probe Response values */
-               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
-                             (u16) (plcp[0] + (plcp[1] << 8)));
-               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
-                             (u16) (plcp[2] + (plcp[3] << 8)));
-               brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
-       }
+int brcms_c_get_tx_power(struct brcms_c_info *wlc)
+{
+       uint qdbm;
+       bool override;
+
+       wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
+
+       /* Return qdbm units */
+       return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
 }
 
-/*     Max buffering needed for beacon template/prb resp template is 142 bytes.
- *
- *     PLCP header is 6 bytes.
- *     802.11 A3 header is 24 bytes.
- *     Max beacon frame body template length is 112 bytes.
- *     Max probe resp frame body template length is 110 bytes.
- *
- *      *len on input contains the max length of the packet available.
- *
- *     The *len value is set to the number of bytes in buf used, and starts
- *     with the PLCP and included up to, but not including, the 4 byte FCS.
- */
-static void
-brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
-                        u32 bcn_rspec,
-                        struct brcms_bss_cfg *cfg, u16 *buf, int *len)
+void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
 {
-       static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
-       struct cck_phy_hdr *plcp;
-       struct ieee80211_mgmt *h;
-       int hdr_len, body_len;
+       wlc->mpc = mpc;
+       brcms_c_radio_mpc_upd(wlc);
+}
 
-       hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
+/* Process received frames */
+/*
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
+ */
+static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
+{
+       struct d11rxhdr *rxh;
+       struct ieee80211_hdr *h;
+       uint len;
+       bool is_amsdu;
 
-       /* calc buffer size provided for frame body */
-       body_len = *len - hdr_len;
-       /* return actual size */
-       *len = hdr_len + body_len;
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
-       /* format PHY and MAC headers */
-       memset((char *)buf, 0, hdr_len);
+       /* frame starts with rxhdr */
+       rxh = (struct d11rxhdr *) (p->data);
 
-       plcp = (struct cck_phy_hdr *) buf;
+       /* strip off rxhdr */
+       skb_pull(p, BRCMS_HWRXOFF);
 
-       /*
-        * PLCP for Probe Response frames are filled in from
-        * core's rate table
-        */
-       if (type == IEEE80211_STYPE_BEACON)
-               /* fill in PLCP */
-               brcms_c_compute_plcp(wlc, bcn_rspec,
-                                (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
-                                (u8 *) plcp);
+       /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
+       if (rxh->RxStatus1 & RXS_PBPRES) {
+               if (p->len < 2) {
+                       wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
+                                 "len %d\n", wlc->pub->unit, p->len);
+                       goto toss;
+               }
+               skb_pull(p, 2);
+       }
 
-       /* "Regular" and 16 MBSS but not for 4 MBSS */
-       /* Update the phytxctl for the beacon based on the rspec */
-       brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+       h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
+       len = p->len;
 
-       h = (struct ieee80211_mgmt *)&plcp[1];
+       if (rxh->RxStatus1 & RXS_FCSERR) {
+               if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
+                       wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
+                                 " tossing\n");
+                       goto toss;
+               } else {
+                       wiphy_err(wlc->wiphy, "RCSERR!!!\n");
+                       goto toss;
+               }
+       }
 
-       /* fill in 802.11 header */
-       h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
+       /* check received pkt has at least frame control field */
+       if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
+               goto toss;
 
-       /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
-       /* A1 filled in by MAC for prb resp, broadcast for bcn */
-       if (type == IEEE80211_STYPE_BEACON)
-               memcpy(&h->da, &ether_bcast, ETH_ALEN);
-       memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
-       memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+       /* not supporting A-MSDU */
+       is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
+       if (is_amsdu)
+               goto toss;
 
-       /* SEQ filled in by MAC */
-}
+       brcms_c_recvctl(wlc, rxh, p);
+       return;
 
-int brcms_c_get_header_len(void)
-{
-       return TXOFF;
+ toss:
+       brcmu_pkt_buf_free_skb(p);
 }
 
+/* Process received frames */
 /*
- * Update all beacons for the system.
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
  */
-void brcms_c_update_beacon(struct brcms_c_info *wlc)
+static bool
+brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
 {
-       struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+       struct sk_buff *p;
+       struct sk_buff *head = NULL;
+       struct sk_buff *tail = NULL;
+       uint n = 0;
+       uint bound_limit = bound ? RXBND : -1;
 
-       if (bsscfg->up && !bsscfg->BSS)
-               /* Clear the soft intmask */
-               wlc->defmacintmask &= ~MI_BCNTPL;
-}
+       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       /* gather received frames */
+       while ((p = dma_rx(wlc_hw->di[fifo]))) {
 
-/* Write ssid into shared memory */
-void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
-{
-       u8 *ssidptr = cfg->SSID;
-       u16 base = M_SSID;
-       u8 ssidbuf[IEEE80211_MAX_SSID_LEN];
+               if (!tail)
+                       head = tail = p;
+               else {
+                       tail->prev = p;
+                       tail = p;
+               }
 
-       /* padding the ssid with zero and copy it into shm */
-       memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);
-       memcpy(ssidbuf, ssidptr, cfg->SSID_len);
+               /* !give others some time to run! */
+               if (++n >= bound_limit)
+                       break;
+       }
 
-       brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
-       brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
+       /* post more rbufs */
+       dma_rxfill(wlc_hw->di[fifo]);
+
+       /* process each frame */
+       while ((p = head) != NULL) {
+               struct d11rxhdr_le *rxh_le;
+               struct d11rxhdr *rxh;
+               head = head->prev;
+               p->prev = NULL;
+
+               rxh_le = (struct d11rxhdr_le *)p->data;
+               rxh = (struct d11rxhdr *)p->data;
+
+               /* fixup rx header endianness */
+               rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
+               rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
+               rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
+               rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
+               rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
+               rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
+               rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
+               rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
+               rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
+               rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
+               rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
+
+               brcms_c_recv(wlc_hw->wlc, p);
+       }
+
+       return n >= bound_limit;
 }
 
-void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
+/* 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.
+ */
+bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
 {
-       struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+       u32 macintstatus;
+       struct brcms_hardware *wlc_hw = wlc->hw;
+       struct d11regs __iomem *regs = wlc_hw->regs;
+       struct wiphy *wiphy = wlc->wiphy;
 
-       /* update AP or IBSS probe responses */
-       if (bsscfg->up && !bsscfg->BSS)
-               brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+       if (brcms_deviceremoved(wlc)) {
+               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+                         __func__);
+               brcms_down(wlc->wl);
+               return false;
+       }
+
+       /* grab and clear the saved software intstatus bits */
+       macintstatus = wlc->macintstatus;
+       wlc->macintstatus = 0;
+
+       BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
+              wlc_hw->unit, macintstatus);
+
+       WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
+
+       /* tx status */
+       if (macintstatus & MI_TFS) {
+               bool fatal;
+               if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
+                       wlc->macintstatus |= MI_TFS;
+               if (fatal) {
+                       wiphy_err(wiphy, "MI_TFS: fatal\n");
+                       goto fatal;
+               }
+       }
+
+       if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
+               brcms_c_tbtt(wlc);
+
+       /* ATIM window end */
+       if (macintstatus & MI_ATIMWINEND) {
+               BCMMSG(wlc->wiphy, "end of ATIM window\n");
+               OR_REG(&regs->maccommand, wlc->qvalid);
+               wlc->qvalid = 0;
+       }
+
+       /*
+        * received data or control frame, MI_DMAINT is
+        * indication of RX_FIFO interrupt
+        */
+       if (macintstatus & MI_DMAINT)
+               if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
+                       wlc->macintstatus |= MI_DMAINT;
+
+       /* noise sample collected */
+       if (macintstatus & MI_BG_NOISE)
+               wlc_phy_noise_sample_intr(wlc_hw->band->pi);
+
+       if (macintstatus & MI_GP0) {
+               wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
+                       "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
+
+               printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
+                                       __func__, wlc_hw->sih->chip,
+                                       wlc_hw->sih->chiprev);
+               /* big hammer */
+               brcms_init(wlc->wl);
+       }
+
+       /* gptimer timeout */
+       if (macintstatus & MI_TO)
+               W_REG(&regs->gptimer, 0);
+
+       if (macintstatus & MI_RFDISABLE) {
+               BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
+                      " RF Disable Input\n", wlc_hw->unit);
+               brcms_rfkill_set_hw_state(wlc->wl);
+       }
+
+       /* send any enq'd tx packets. Just makes sure to jump start tx */
+       if (!pktq_empty(&wlc->pkt_queue->q))
+               brcms_c_send_q(wlc);
+
+       /* it isn't done and needs to be resched if macintstatus is non-zero */
+       return wlc->macintstatus != 0;
+
+ fatal:
+       brcms_init(wlc->wl);
+       return wlc->macintstatus != 0;
 }
 
-void
-brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
-                             struct brcms_bss_cfg *cfg,
-                             bool suspend)
+void brcms_c_init(struct brcms_c_info *wlc)
 {
-       u16 prb_resp[BCN_TMPL_LEN / 2];
-       int len = BCN_TMPL_LEN;
+       struct d11regs __iomem *regs;
+       u16 chanspec;
+       bool mute = false;
+
+       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+       regs = wlc->regs;
 
        /*
-        * write the probe response to hardware, or save in
-        * the config structure
+        * 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);
 
-       /* create the probe response template */
-       brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
-                                cfg, prb_resp, &len);
+       brcms_b_init(wlc->hw, chanspec, mute);
 
-       if (suspend)
-               brcms_c_suspend_mac_and_wait(wlc);
+       /* update beacon listen interval */
+       brcms_c_bcn_li_upd(wlc);
 
-       /* write the probe response into the template region */
-       brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
-                                   (len + 3) & ~3, prb_resp);
+       /* write ethernet address to core */
+       brcms_c_set_mac(wlc->bsscfg);
+       brcms_c_set_bssid(wlc->bsscfg);
 
-       /* write the length of the probe response frame (+PLCP/-FCS) */
-       brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
+       /* Update tsf_cfprep if associated and up */
+       if (wlc->pub->associated && wlc->bsscfg->up) {
+               u32 bi;
 
-       /* write the SSID and SSID length */
-       brcms_c_shm_ssid_upd(wlc, cfg);
+               /* get beacon period and convert to uS */
+               bi = wlc->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);
+       }
+
+       brcms_c_bandinit_ordered(wlc, chanspec);
+
+       /* init probe response timeout */
+       brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+
+       /* init max burst txop (framebursting) */
+       brcms_b_write_shm(wlc->hw, 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);
 
        /*
-        * Write PLCP headers and durations for probe response frames
-        * at all rates. Use the actual frame length covered by the
-        * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
-        * by subtracting the PLCP len and adding the FCS.
+        * Update some shared memory locations related to
+        * max AMPDU size allowed to received
         */
-       len += (-D11_PHY_HDR_LEN + FCS_LEN);
-       brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+       brcms_c_ampdu_shm_upd(wlc->ampdu);
 
-       if (suspend)
-               brcms_c_enable_mac(wlc);
-}
+       /* band-specific inits */
+       brcms_c_bsinit(wlc);
 
-/* prepares pdu for transmission. returns BCM error codes */
-int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
-{
-       uint fifo;
-       struct d11txh *txh;
-       struct ieee80211_hdr *h;
-       struct scb *scb;
+       /* Enable EDCF mode (while the MAC is suspended) */
+       OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
+       brcms_c_edcf_setparams(wlc, false);
 
-       txh = (struct d11txh *) (pdu->data);
-       h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
+       /* Init precedence maps for empty FIFOs */
+       brcms_c_tx_prec_map_init(wlc);
 
-       /* get the pkt queue info. This was put at brcms_c_sendctl or
-        * brcms_c_send for PDU */
-       fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
+       /* read the ucode version if we have not yet done so */
+       if (wlc->ucode_rev == 0) {
+               wlc->ucode_rev =
+                   brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
+               wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+       }
 
-       scb = NULL;
+       /* ..now really unleash hell (allow the MAC out of suspend) */
+       brcms_c_enable_mac(wlc);
 
-       *fifop = fifo;
+       /* clear tx flow control */
+       brcms_c_txflowcontrol_reset(wlc);
 
-       /* return if insufficient dma resources */
-       if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
-               /* Mark precedences related to this FIFO, unsendable */
-               /* A fifo is full. Clear precedences related to that FIFO */
-               wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
-               return -EBUSY;
-       }
-       return 0;
-}
+       /* enable the RF Disable Delay timer */
+       W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
 
-void brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
-{
-       brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
-               wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
-               (bool) (wlc->pub->_n_enab & SUPPORT_11N),
-               brcms_chspec_bw(wlc->default_bss->chanspec),
-               wlc->stf->txstreams);
-}
+       /* initialize mpc delay */
+       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
 
-/* Copy a buffer to shared memory.
- * SHM 'offset' needs to be an even address and
- * Buffer length 'len' must be an even number of bytes
- */
-void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset, const void *buf,
-                       int len)
-{
-       brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
+       /*
+        * Initialize WME parameters; if they haven't been set by some other
+        * mechanism (IOVar, etc) then read them from the hardware.
+        */
+       if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
+               /* Uninitialized; read from HW */
+               int ac;
+
+               for (ac = 0; ac < AC_COUNT; ac++)
+                       wlc->wme_retries[ac] =
+                           brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
+       }
 }
 
-int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
-                          uint *blocks)
+/*
+ * 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 __iomem *regsva, struct pci_dev *btparam,
+              uint *perr)
 {
-       if (fifo >= NFIFO)
-               return -EINVAL;
+       struct brcms_c_info *wlc;
+       uint err = 0;
+       uint i, j;
+       struct brcms_pub *pub;
 
-       *blocks = wlc_hw->xmtfifo_sz[fifo];
+       /* 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;
 
-       return 0;
-}
+#if defined(BCMDBG)
+       wlc_info_dbg = wlc;
+#endif
 
-void
-brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
-                 const u8 *addr)
-{
-       brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
-       if (match_reg_offset == RCM_BSSID_OFFSET)
-               memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
-}
+       wlc->band = wlc->bandstate[0];
+       wlc->core = wlc->corestate;
+       wlc->wl = wl;
+       pub->unit = unit;
+       pub->_piomode = piomode;
+       wlc->bandinit_pending = false;
 
-/* check for the particular priority flow control bit being set */
-bool
-brcms_c_txflowcontrol_prio_isset(struct brcms_c_info *wlc,
-                                struct brcms_txq_info *q,
-                                int prio)
-{
-       uint prio_mask;
+       /* populate struct brcms_c_info with default values  */
+       brcms_c_info_init(wlc, unit);
 
-       if (prio == ALLPRIO)
-               prio_mask = TXQ_STOP_FOR_PRIOFC_MASK;
-       else
-               prio_mask = NBITVAL(prio);
+       /* update sta/ap related parameters */
+       brcms_c_ap_upd(wlc);
 
-       return (q->stopped & prio_mask) == prio_mask;
-}
+       /*
+        * low level attach steps(all hw accesses go
+        * inside, no more in rest of the attach)
+        */
+       err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva,
+                            btparam);
+       if (err)
+               goto fail;
 
-/* propagate the flow control to all interfaces using the given tx queue */
-void brcms_c_txflowcontrol(struct brcms_c_info *wlc,
-                          struct brcms_txq_info *qi,
-                          bool on, int prio)
-{
-       uint prio_bits;
-       uint cur_bits;
+       brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
 
-       BCMMSG(wlc->wiphy, "flow control kicks in\n");
+       pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
 
-       if (prio == ALLPRIO)
-               prio_bits = TXQ_STOP_FOR_PRIOFC_MASK;
-       else
-               prio_bits = NBITVAL(prio);
+       /* disable allowed duty cycle */
+       wlc->tx_duty_cycle_ofdm = 0;
+       wlc->tx_duty_cycle_cck = 0;
 
-       cur_bits = qi->stopped & prio_bits;
+       brcms_c_stf_phy_chain_calc(wlc);
 
-       /* Check for the case of no change and return early
-        * Otherwise update the bit and continue
-        */
-       if (on) {
-               if (cur_bits == prio_bits)
-                       return;
+       /* txchain 1: txant 0, txchain 2: txant 1 */
+       if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
+               wlc->stf->txant = wlc->stf->hw_txchain - 1;
 
-               mboolset(qi->stopped, prio_bits);
-       } else {
-               if (cur_bits == 0)
-                       return;
+       /* push to BMAC driver */
+       wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
+                              wlc->stf->hw_rxchain);
 
-               mboolclr(qi->stopped, prio_bits);
-       }
+       /* pull up some info resulting from the low attach */
+       for (i = 0; i < NFIFO; i++)
+               wlc->core->txavail[i] = wlc->hw->txavail[i];
 
-       /* If there is a flow control override we will not change the external
-        * flow control state.
-        */
-       if (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK)
-               return;
+       memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
+       memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
 
-       brcms_c_txflowcontrol_signal(wlc, qi, on, prio);
-}
+       for (j = 0; j < wlc->pub->_nbands; j++) {
+               wlc->band = wlc->bandstate[j];
 
-void
-brcms_c_txflowcontrol_override(struct brcms_c_info *wlc,
-                              struct brcms_txq_info *qi,
-                              bool on, uint override)
-{
-       uint prev_override;
+               if (!brcms_c_attach_stf_ant_init(wlc)) {
+                       err = 24;
+                       goto fail;
+               }
 
-       prev_override = (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK);
+               /* default contention windows size limits */
+               wlc->band->CWmin = APHY_CWMIN;
+               wlc->band->CWmax = PHY_CWMAX;
 
-       /* Update the flow control bits and do an early return if there is
-        * no change in the external flow control state.
-        */
-       if (on) {
-               mboolset(qi->stopped, override);
-               /* if there was a previous override bit on, then setting this
-                * makes no difference.
-                */
-               if (prev_override)
-                       return;
+               /* init gmode value */
+               if (wlc->band->bandtype == BRCM_BAND_2G) {
+                       wlc->band->gmode = GMODE_AUTO;
+                       brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
+                                          wlc->band->gmode);
+               }
 
-               brcms_c_txflowcontrol_signal(wlc, qi, ON, ALLPRIO);
-       } else {
-               mboolclr(qi->stopped, override);
-               /* clearing an override bit will only make a difference for
-                * flow control if it was the only bit set. For any other
-                * override setting, just return
-                */
-               if (prev_override != override)
-                       return;
+               /* init _n_enab supported mode */
+               if (BRCMS_PHY_11N_CAP(wlc->band)) {
+                       pub->_n_enab = SUPPORT_11N;
+                       brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
+                                                  ((pub->_n_enab ==
+                                                    SUPPORT_11N) ? WL_11N_2x2 :
+                                                   WL_11N_3x3));
+               }
 
-               if (qi->stopped == 0) {
-                       brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
-               } else {
-                       int prio;
+               /* init per-band default rateset, depend on band->gmode */
+               brcms_default_rateset(wlc, &wlc->band->defrateset);
 
-                       for (prio = MAXPRIO; prio >= 0; prio--) {
-                               if (!mboolisset(qi->stopped, NBITVAL(prio)))
-                                       brcms_c_txflowcontrol_signal(
-                                               wlc, qi, OFF, prio);
-                       }
-               }
+               /* fill in hw_rateset */
+               brcms_c_rateset_filter(&wlc->band->defrateset,
+                                  &wlc->band->hw_rateset, false,
+                                  BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+                                  (bool) (wlc->pub->_n_enab & SUPPORT_11N));
        }
-}
 
-/*
- * Flag 'scan in progress' to withhold dynamic phy calibration
- */
-void brcms_c_scan_start(struct brcms_c_info *wlc)
-{
-       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
-}
+       /*
+        * update antenna config due to
+        * wlc->stf->txant/txchain/ant_rx_ovr change
+        */
+       brcms_c_stf_phy_txant_upd(wlc);
 
-void brcms_c_scan_stop(struct brcms_c_info *wlc)
-{
-       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
-}
+       /* attach each modules */
+       err = brcms_c_attach_module(wlc);
+       if (err != 0)
+               goto fail;
 
-void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
-{
-       wlc->pub->associated = state;
-       wlc->bsscfg->associated = state;
-}
+       if (!brcms_c_timers_init(wlc, unit)) {
+               wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
+                         __func__);
+               err = 32;
+               goto fail;
+       }
 
-/*
- * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
- * AMPDU traffic, packets pending in hardware have to be invalidated so that
- * when later on hardware releases them, they can be handled appropriately.
- */
-void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
-                              struct ieee80211_sta *sta,
-                              void (*dma_callback_fn))
-{
-       struct dma_pub *dmah;
-       int i;
-       for (i = 0; i < NFIFO; i++) {
-               dmah = hw->di[i];
-               if (dmah != NULL)
-                       dma_walk_packets(dmah, dma_callback_fn, sta);
+       /* depend on rateset, gmode */
+       wlc->cmi = brcms_c_channel_mgr_attach(wlc);
+       if (!wlc->cmi) {
+               wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
+                         "\n", unit, __func__);
+               err = 33;
+               goto fail;
        }
-}
 
-int brcms_c_get_curband(struct brcms_c_info *wlc)
-{
-       return wlc->band->bandunit;
-}
+       /* init default when all parameters are ready, i.e. ->rateset */
+       brcms_c_bss_default_init(wlc);
 
-void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
-{
-       /* flush packet queue when requested */
-       if (drop)
-               brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
+       /*
+        * Complete the wlc default state initializations..
+        */
 
-       /* wait for queue and DMA fifos to run dry */
-       while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
-               brcms_msleep(wlc->wl, 1);
-}
+       /* allocate our initial queue */
+       wlc->pkt_queue = brcms_c_txq_alloc(wlc);
+       if (wlc->pkt_queue == NULL) {
+               wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
+                         unit, __func__);
+               err = 100;
+               goto fail;
+       }
 
-void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
-{
-       wlc->bcn_li_bcn = interval;
-       if (wlc->pub->up)
-               brcms_c_bcn_li_upd(wlc);
-}
+       wlc->bsscfg->wlc = wlc;
 
-int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
-{
-       uint qdbm;
+       wlc->mimoft = FT_HT;
+       wlc->mimo_40txbw = AUTO;
+       wlc->ofdm_40txbw = AUTO;
+       wlc->cck_40txbw = AUTO;
+       brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
 
-       /* Remove override bit and clip to max qdbm value */
-       qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
-       return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
-}
+       /* Set default values of SGI */
+       if (BRCMS_SGI_CAP_PHY(wlc)) {
+               brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+                                              BRCMS_N_SGI_40));
+       } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
+               brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+                                              BRCMS_N_SGI_40));
+       } else {
+               brcms_c_ht_update_sgi_rx(wlc, 0);
+       }
 
-int brcms_c_get_tx_power(struct brcms_c_info *wlc)
-{
-       uint qdbm;
-       bool override;
+       /* initialize radio_mpc_disable according to wlc->mpc */
+       brcms_c_radio_mpc_upd(wlc);
+       brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
 
-       wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
+       if (perr)
+               *perr = 0;
 
-       /* Return qdbm units */
-       return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
-}
+       return wlc;
 
-void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
-{
-       wlc->mpc = mpc;
-       brcms_c_radio_mpc_upd(wlc);
+ fail:
+       wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
+                 unit, __func__, err);
+       if (wlc)
+               brcms_c_detach(wlc);
+
+       if (perr)
+               *perr = err;
+       return NULL;
 }
index 7a2554f611a63c27a3e23a0f28b59759201eb1c1..c0e0fcfdfaf8e7988e5ec6d22919df019218f08e 100644 (file)
@@ -653,9 +653,6 @@ struct brcms_bss_cfg {
        struct brcms_bss_info *current_bss;
 };
 
-extern void brcms_c_fatal_error(struct brcms_c_info *wlc);
-extern void brcms_b_rpc_watchdog(struct brcms_c_info *wlc);
-extern void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p);
 extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
                           struct sk_buff *p,
                           bool commit, s8 txpktpend);
@@ -663,47 +660,22 @@ extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo,
                                    s8 txpktpend);
 extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
                            struct sk_buff *sdu, uint prec);
-extern void brcms_c_info_init(struct brcms_c_info *wlc, int unit);
 extern void brcms_c_print_txstatus(struct tx_status *txs);
 extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
                   uint *blocks);
 
 #if defined(BCMDBG)
-extern void brcms_c_print_rxh(struct d11rxhdr *rxh);
 extern void brcms_c_print_txdesc(struct d11txh *txh);
 #else
 #define brcms_c_print_txdesc(a)
 #endif
 
-extern void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit);
-extern void brcms_c_coredisable(struct brcms_hardware *wlc_hw);
-
-extern bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rate,
-                              int band, bool verbose);
-extern void brcms_c_ap_upd(struct brcms_c_info *wlc);
-
-/* helper functions */
-extern void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc,
-                                struct brcms_bss_cfg *cfg);
 extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
-
 extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
                                           bool promisc);
-extern void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc);
-extern void brcms_c_mac_promisc(struct brcms_c_info *wlc);
-extern void brcms_c_txflowcontrol(struct brcms_c_info *wlc,
-                                 struct brcms_txq_info *qi,
-                                 bool on, int prio);
-extern void brcms_c_txflowcontrol_override(struct brcms_c_info *wlc,
-                                      struct brcms_txq_info *qi,
-                                      bool on, uint override);
-extern bool brcms_c_txflowcontrol_prio_isset(struct brcms_c_info *wlc,
-                                            struct brcms_txq_info *qi,
-                                            int prio);
 extern void brcms_c_send_q(struct brcms_c_info *wlc);
 extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
                            uint *fifo);
-
 extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
                                uint mac_len);
 extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,
@@ -715,82 +687,26 @@ extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
                                      u8 rts_preamble_type,
                                      u8 frame_preamble_type, uint frame_len,
                                      bool ba);
-
-extern void brcms_c_tbtt(struct brcms_c_info *wlc);
 extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
                               struct ieee80211_sta *sta,
                               void (*dma_callback_fn));
-
-/* Shared memory access */
-extern void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
-                              const void *buf, int len);
-
 extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
-
 extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
-extern void brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
-                                         struct brcms_bss_cfg *cfg,
-                                         bool suspend);
-extern bool brcms_c_ismpc(struct brcms_c_info *wlc);
-extern bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc);
-extern void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc);
-extern bool brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
-                             struct sk_buff *pkt, int prec, bool head);
-extern u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec);
-extern void brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rate,
-                                uint length, u8 *plcp);
-extern uint brcms_c_calc_frame_time(struct brcms_c_info *wlc,
-                                   u32 ratespec,
-                                   u8 preamble_type, uint mac_len);
-
-extern void brcms_c_set_chanspec(struct brcms_c_info *wlc,
-                                u16 chanspec);
-
-extern bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit);
-
 extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
-extern void brcms_c_mimops_action_ht_send(struct brcms_c_info *wlc,
-                                     struct brcms_bss_cfg *bsscfg,
-                                     u8 mimops_mode);
-
-extern void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot);
-extern void brcms_c_set_bssid(struct brcms_bss_cfg *cfg);
-extern void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend);
-
-extern void brcms_c_set_ratetable(struct brcms_c_info *wlc);
-extern int brcms_c_set_mac(struct brcms_bss_cfg *cfg);
 extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
                                          u32 bcn_rate);
-extern void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc,
-                                          uint frame_len);
-extern u32 brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc,
-                                            struct brcms_c_rateset *rs);
-extern void brcms_c_radio_disable(struct brcms_c_info *wlc);
-extern void brcms_c_bcn_li_upd(struct brcms_c_info *wlc);
-extern void brcms_c_set_home_chanspec(struct brcms_c_info *wlc,
-                                     u16 chanspec);
-extern bool brcms_c_ps_allowed(struct brcms_c_info *wlc);
-extern bool brcms_c_stay_awake(struct brcms_c_info *wlc);
-
 extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
                                     u8 antsel_type);
-
-/* chanspec, ucode interface */
 extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw,
                                  u16 chanspec,
                                  bool mute, struct txpwr_limits *txpwr);
-
 extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset,
                              u16 v);
 extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset);
-
 extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask,
                        u16 val, int bands);
-
 extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags);
-
 extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val);
-
 extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw);
 extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw);
 extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw);
index 3942f47b15c367ed72d3db4440aafe236a7c751e..37bb2dcc113f179d990d7d9007d779d26e95540e 100644 (file)
@@ -563,7 +563,7 @@ struct brcms_antselcfg {
 };
 
 /* common functions for every port */
-struct brcms_c_info *
+extern struct brcms_c_info *
 brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
               bool piomode, void __iomem *regsva, struct pci_dev *btparam,
               uint *perr);
@@ -585,14 +585,9 @@ extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc,
                                     struct sk_buff *sdu,
                                     struct ieee80211_hw *hw);
 extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid);
-
-/* helper functions */
-extern void brcms_c_statsupd(struct brcms_c_info *wlc);
 extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx,
                                   int val);
 extern int brcms_c_get_header_len(void);
-extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
-                                          bool promisc);
 extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc,
                                  int match_reg_offset,
                                  const u8 *addr);
@@ -600,26 +595,12 @@ extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
                              const struct ieee80211_tx_queue_params *arg,
                              bool suspend);
 extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc);
-
-/* common functions for every port */
-extern void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val,
-                   int bands);
-extern void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
-                                    struct brcms_c_rateset *rateset);
-extern void brcms_default_rateset(struct brcms_c_info *wlc,
-                                 struct brcms_c_rateset *rs);
-
 extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
                            struct ieee80211_sta *sta, u16 tid);
 extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
                                         u8 ba_wsize, uint max_rx_ampdu_bytes);
 extern char *getvar(struct si_pub *sih, enum brcms_srom_id id);
 extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
-
-/* wlc_phy.c helper functions */
-extern void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc);
-extern void brcms_c_mctrl(struct brcms_c_info *wlc, u32 mask, u32 val);
-
 extern int brcms_c_module_register(struct brcms_pub *pub,
                                   const char *name, struct brcms_info *hdl,
                                   int (*down_fn)(void *handle));
@@ -633,23 +614,21 @@ extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
 extern int brcms_c_get_curband(struct brcms_c_info *wlc);
 extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
                                           bool drop);
-
-int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
-int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
-void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
+extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
                                 struct brcm_rateset *currs);
-int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs);
-int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
-u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
-void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
+extern int brcms_c_set_rateset(struct brcms_c_info *wlc,
+                                       struct brcm_rateset *rs);
+extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
+extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
+extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
                                    s8 sslot_override);
-void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval);
-int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
-int brcms_c_get_tx_power(struct brcms_c_info *wlc);
-void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
-
-/* helper functions */
+extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
+                                       u8 interval);
+extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
+extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
+extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
 extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
-extern bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc);
 
 #endif                         /* _BRCM_PUB_H_ */