wl_ops_get_stats(struct ieee80211_hw *hw,
                 struct ieee80211_low_level_stats *stats)
 {
-       WL_ERROR("%s: Enter\n", __func__);
+       struct wl_info *wl = hw->priv;
+       struct wl_cnt *cnt;
+
+       WL_LOCK(wl);
+       cnt = wl->pub->_cnt;
+       stats->dot11ACKFailureCount = cnt->txnoack;
+       stats->dot11RTSFailureCount = cnt->txnocts;
+       stats->dot11FCSErrorCount = cnt->rxcrc;
+       stats->dot11RTSSuccessCount = cnt->txrts;
+       WL_UNLOCK(wl);
        return 0;
 }
 
 static int wl_linux_watchdog(void *ctx)
 {
        struct wl_info *wl = (struct wl_info *) ctx;
+       struct wl_cnt *cnt;
        struct net_device_stats *stats = NULL;
        uint id;
        /* refresh stats */
        if (wl->pub->up) {
                ASSERT(wl->stats_id < 2);
 
+               cnt = wl->pub->_cnt;
                id = 1 - wl->stats_id;
-
                stats = &wl->stats_watchdog[id];
-               stats->rx_packets = WLCNTVAL(wl->pub->_cnt->rxframe);
-               stats->tx_packets = WLCNTVAL(wl->pub->_cnt->txframe);
-               stats->rx_bytes = WLCNTVAL(wl->pub->_cnt->rxbyte);
-               stats->tx_bytes = WLCNTVAL(wl->pub->_cnt->txbyte);
-               stats->rx_errors = WLCNTVAL(wl->pub->_cnt->rxerror);
-               stats->tx_errors = WLCNTVAL(wl->pub->_cnt->txerror);
+               stats->rx_packets = cnt->rxframe;
+               stats->tx_packets = cnt->txframe;
+               stats->rx_bytes = cnt->rxbyte;
+               stats->tx_bytes = cnt->txbyte;
+               stats->rx_errors = cnt->rxerror;
+               stats->tx_errors = cnt->txerror;
                stats->collisions = 0;
 
                stats->rx_length_errors = 0;
-               stats->rx_over_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
-               stats->rx_crc_errors = WLCNTVAL(wl->pub->_cnt->rxcrc);
+               stats->rx_over_errors = cnt->rxoflo;
+               stats->rx_crc_errors = cnt->rxcrc;
                stats->rx_frame_errors = 0;
-               stats->rx_fifo_errors = WLCNTVAL(wl->pub->_cnt->rxoflo);
+               stats->rx_fifo_errors = cnt->rxoflo;
                stats->rx_missed_errors = 0;
 
-               stats->tx_fifo_errors = WLCNTVAL(wl->pub->_cnt->txuflo);
+               stats->tx_fifo_errors = cnt->txuflo;
 
                wl->stats_id = id;
-
        }
 
        return 0;
 
 
        /* phy tx error */
        if (macintstatus & MI_PHYTXERR) {
-               WLCNTINCR(wlc->pub->_cnt->txphyerr);
+               wlc->pub->_cnt->txphyerr++;
        }
 
        /* received data or control frame, MI_DMAINT is indication of RX_FIFO interrupt */
                                        __func__, wlc_hw->sih->chip,
                                        wlc_hw->sih->chiprev);
 
-               WLCNTINCR(wlc->pub->_cnt->psmwds);
+               wlc->pub->_cnt->psmwds++;
 
                /* big hammer */
                wl_init(wlc->wl);
        if (macintstatus & MI_RFDISABLE) {
                WL_TRACE("wl%d: BMAC Detected a change on the RF Disable Input\n", wlc_hw->unit);
 
-               WLCNTINCR(wlc->pub->_cnt->rfdisable);
+               wlc->pub->_cnt->rfdisable++;
                wl_rfkill_set_hw_state(wlc->wl);
        }
 
 {
        WL_TRACE("wl%d: wlc_bmac_reset\n", wlc_hw->unit);
 
-       WLCNTINCR(wlc_hw->wlc->pub->_cnt->reset);
+       wlc_hw->wlc->pub->_cnt->reset++;
 
        /* reset the core */
        if (!DEVICEREMOVED(wlc_hw->wlc))
                if (intstatus & I_RO) {
                        WL_ERROR("wl%d: fifo %d: receive fifo overflow\n",
                                 unit, idx);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxoflo);
+                       wlc_hw->wlc->pub->_cnt->rxoflo++;
                        fatal = true;
                }
 
                if (intstatus & I_PC) {
                        WL_ERROR("wl%d: fifo %d: descriptor error\n",
                                 unit, idx);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmade);
+                       wlc_hw->wlc->pub->_cnt->dmade++;
                        fatal = true;
                }
 
                if (intstatus & I_PD) {
                        WL_ERROR("wl%d: fifo %d: data error\n", unit, idx);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmada);
+                       wlc_hw->wlc->pub->_cnt->dmada++;
                        fatal = true;
                }
 
                if (intstatus & I_DE) {
                        WL_ERROR("wl%d: fifo %d: descriptor protocol error\n",
                                 unit, idx);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->dmape);
+                       wlc_hw->wlc->pub->_cnt->dmape++;
                        fatal = true;
                }
 
                if (intstatus & I_RU) {
                        WL_ERROR("wl%d: fifo %d: receive descriptor underflow\n",
                                 idx, unit);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->rxuflo[idx]);
+                       wlc_hw->wlc->pub->_cnt->rxuflo[idx]++;
                }
 
                if (intstatus & I_XU) {
                        WL_ERROR("wl%d: fifo %d: transmit fifo underflow\n",
                                 idx, unit);
-                       WLCNTINCR(wlc_hw->wlc->pub->_cnt->txuflo);
+                       wlc_hw->wlc->pub->_cnt->txuflo++;
                        fatal = true;
                }
 
 
 #include <net/mac80211.h>
 #include <wl_dbg.h>
 
+/*
+ *     Disable statistics counting for WME
+ */
+#define WLCNTSET(a, b)
+#define WLCNTINCR(a)
+#define WLCNTADD(a, b)
 
 /*
  * WPA(2) definitions
        wlc->check_for_unaligned_tbtt = false;
 
        /* slurp up hw mac counters before core reset */
-       if (WLC_UPDATE_STATS(wlc)) {
-               wlc_statsupd(wlc);
+       wlc_statsupd(wlc);
 
-               /* reset our snapshot of macstat counters */
-               memset((char *)wlc->core->macstat_snapshot, 0,
-                       sizeof(macstat_t));
-       }
+       /* reset our snapshot of macstat counters */
+       memset((char *)wlc->core->macstat_snapshot, 0,
+               sizeof(macstat_t));
 
        wlc_bmac_reset(wlc->hw);
        wlc_ampdu_reset(wlc->ampdu);
        wlc->cfg->wlc = wlc;
        pub->txmaxpkts = MAXTXPKTS;
 
-       WLCNTSET(pub->_cnt->version, WL_CNT_T_VERSION);
-       WLCNTSET(pub->_cnt->length, sizeof(wl_cnt_t));
+       pub->_cnt->version = WL_CNT_T_VERSION;
+       pub->_cnt->length = sizeof(struct wl_cnt);
 
        WLCNTSET(pub->_wme_cnt->version, WL_WME_CNT_VERSION);
        WLCNTSET(pub->_wme_cnt->length, sizeof(wl_wme_cnt_t));
        wlc_bmac_watchdog(wlc);
 
        /* occasionally sample mac stat counters to detect 16-bit counter wrap */
-       if ((WLC_UPDATE_STATS(wlc))
-           && (!(wlc->pub->now % SW_TIMER_MAC_STAT_UPD)))
+       if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
                wlc_statsupd(wlc);
 
        /* Manage TKIP countermeasures timers */
 
        case WLC_GET_PKTCNTS:{
                        get_pktcnt_t *pktcnt = (get_pktcnt_t *) pval;
-                       if (WLC_UPDATE_STATS(wlc))
-                               wlc_statsupd(wlc);
-                       pktcnt->rx_good_pkt = WLCNTVAL(wlc->pub->_cnt->rxframe);
-                       pktcnt->rx_bad_pkt = WLCNTVAL(wlc->pub->_cnt->rxerror);
+                       wlc_statsupd(wlc);
+                       pktcnt->rx_good_pkt = wlc->pub->_cnt->rxframe;
+                       pktcnt->rx_bad_pkt = wlc->pub->_cnt->rxerror;
                        pktcnt->tx_good_pkt =
-                           WLCNTVAL(wlc->pub->_cnt->txfrmsnt);
+                           wlc->pub->_cnt->txfrmsnt;
                        pktcnt->tx_bad_pkt =
-                           WLCNTVAL(wlc->pub->_cnt->txerror) +
-                           WLCNTVAL(wlc->pub->_cnt->txfail);
+                           wlc->pub->_cnt->txerror +
+                           wlc->pub->_cnt->txfail;
                        if (len >= (int)sizeof(get_pktcnt_t)) {
                                /* Be backward compatible - only if buffer is large enough  */
                                pktcnt->rx_ocast_good_pkt =
-                                   WLCNTVAL(wlc->pub->_cnt->rxmfrmocast);
+                                   wlc->pub->_cnt->rxmfrmocast;
                        }
                        break;
                }
 #endif                         /* defined(BCMDBG) */
 }
 
+static void
+wlc_ctrupd_cache(u16 cur_stat, u16 *macstat_snapshot, u32 *macstat)
+{
+       u16 v;
+       u16 delta;
+
+       v = ltoh16(cur_stat);
+       delta = (u16)(v - *macstat_snapshot);
+
+       if (delta != 0) {
+               *macstat += delta;
+               *macstat_snapshot = v;
+       }
+}
+
 #define MACSTATUPD(name) \
        wlc_ctrupd_cache(macstats.name, &wlc->core->macstat_snapshot->name, &wlc->pub->_cnt->name)
 
 void wlc_statsupd(struct wlc_info *wlc)
 {
        int i;
+       macstat_t macstats;
 #ifdef BCMDBG
        u16 delta;
        u16 rxf0ovfl;
                txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
 #endif                         /* BCMDBG */
 
+       /* Read mac stats from contiguous shared memory */
+       wlc_bmac_copyfrom_shm(wlc->hw, M_UCODE_MACSTAT,
+                             &macstats, sizeof(macstat_t));
+
+       /* update mac stats */
+       MACSTATUPD(txallfrm);
+       MACSTATUPD(txrtsfrm);
+       MACSTATUPD(txctsfrm);
+       MACSTATUPD(txackfrm);
+       MACSTATUPD(txdnlfrm);
+       MACSTATUPD(txbcnfrm);
+       for (i = 0; i < NFIFO; i++)
+               MACSTATUPD(txfunfl[i]);
+       MACSTATUPD(txtplunfl);
+       MACSTATUPD(txphyerr);
+       MACSTATUPD(rxfrmtoolong);
+       MACSTATUPD(rxfrmtooshrt);
+       MACSTATUPD(rxinvmachdr);
+       MACSTATUPD(rxbadfcs);
+       MACSTATUPD(rxbadplcp);
+       MACSTATUPD(rxcrsglitch);
+       MACSTATUPD(rxstrt);
+       MACSTATUPD(rxdfrmucastmbss);
+       MACSTATUPD(rxmfrmucastmbss);
+       MACSTATUPD(rxcfrmucast);
+       MACSTATUPD(rxrtsucast);
+       MACSTATUPD(rxctsucast);
+       MACSTATUPD(rxackucast);
+       MACSTATUPD(rxdfrmocast);
+       MACSTATUPD(rxmfrmocast);
+       MACSTATUPD(rxcfrmocast);
+       MACSTATUPD(rxrtsocast);
+       MACSTATUPD(rxctsocast);
+       MACSTATUPD(rxdfrmmcast);
+       MACSTATUPD(rxmfrmmcast);
+       MACSTATUPD(rxcfrmmcast);
+       MACSTATUPD(rxbeaconmbss);
+       MACSTATUPD(rxdfrmucastobss);
+       MACSTATUPD(rxbeaconobss);
+       MACSTATUPD(rxrsptmout);
+       MACSTATUPD(bcntxcancl);
+       MACSTATUPD(rxf0ovfl);
+       MACSTATUPD(rxf1ovfl);
+       MACSTATUPD(rxf2ovfl);
+       MACSTATUPD(txsfovfl);
+       MACSTATUPD(pmqovfl);
+       MACSTATUPD(rxcgprqfrm);
+       MACSTATUPD(rxcgprsqovfl);
+       MACSTATUPD(txcgprsfail);
+       MACSTATUPD(txcgprssuc);
+       MACSTATUPD(prs_timeout);
+       MACSTATUPD(rxnack);
+       MACSTATUPD(frmscons);
+       MACSTATUPD(txnack);
+       MACSTATUPD(txglitch_nack);
+       MACSTATUPD(txburst);
+       MACSTATUPD(phywatchdog);
+       MACSTATUPD(pktengrxducast);
+       MACSTATUPD(pktengrxdmcast);
+
 #ifdef BCMDBG
        /* check for rx fifo 0 overflow */
        delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
                 wlc->pub->_cnt->rxgiant + wlc->pub->_cnt->rxnoscb +
                 wlc->pub->_cnt->rxbadsrcmac);
        for (i = 0; i < NFIFO; i++)
-               WLCNTADD(wlc->pub->_cnt->rxerror, wlc->pub->_cnt->rxuflo[i]);
+               wlc->pub->_cnt->rxerror += wlc->pub->_cnt->rxuflo[i];
 }
 
 bool wlc_chipmatch(u16 vendor, u16 device)
 
                ASSERT(0);
                pkt_buf_free_skb(wlc->osh, p, true);
-               WLCNTINCR(wlc->pub->_cnt->txnobuf);
+               wlc->pub->_cnt->txnobuf++;
        }
 
        /* Enqueue */
 
                /* ASSERT(9 == 8); *//* XXX we might hit this condtion in case packet flooding from mac80211 stack */
                pkt_buf_free_skb(wlc->osh, sdu, true);
-               WLCNTINCR(wlc->pub->_cnt->txnobuf);
+               wlc->pub->_cnt->txnobuf++;
        }
 
        /* Check if flow control needs to be turned on after enqueuing the packet
        wlc_txq_enq(wlc, scb, pkt, WLC_PRIO_TO_PREC(prio));
        wlc_send_q(wlc, wlc->active_queue);
 
-       WLCNTINCR(wlc->pub->_cnt->ieee_tx);
+       wlc->pub->_cnt->ieee_tx++;
        return 0;
 }
 
                       || !IS_MCS(rspec[0]));
                if (RSPEC2RATE(rspec[0]) != WLC_RATE_1M)
                        phyctl |= PHY_TXC_SHORT_HDR;
-               WLCNTINCR(wlc->pub->_cnt->txprshort);
+               wlc->pub->_cnt->txprshort++;
        }
 
        /* phytxant is properly bit shifted */
 {
        wlc_bsscfg_t *cfg = wlc->cfg;
 
-       WLCNTINCR(wlc->pub->_cnt->tbtt);
+       wlc->pub->_cnt->tbtt++;
 
        if (BSSCFG_STA(cfg)) {
                /* run watchdog here if the watchdog timer is not armed */
                                        __func__, wlc->pub->sih->chip,
                                        wlc->pub->sih->chiprev);
 
-               WLCNTINCR(wlc->pub->_cnt->psmwds);
+               wlc->pub->_cnt->psmwds++;
 
                /* big hammer */
                wl_init(wlc->wl);
 
        /* if tx ring is now empty, reset and re-init the tx dma channel */
        if (dma_txactive(wlc->hw->di[queue]) == 0) {
-               WLCNTINCR(wlc->pub->_cnt->txdmawar);
+               wlc->pub->_cnt->txdmawar++;
                if (!dma_txreset(di))
                        WL_ERROR("wl%d: %s: dma_txreset[%d]: cannot stop dma\n",
                                 wlc->pub->unit, __func__, queue);
        if (N_ENAB(wlc->pub)) {
                u8 *plcp = (u8 *) (txh + 1);
                if (PLCP3_ISSGI(plcp[3]))
-                       WLCNTINCR(wlc->pub->_cnt->txmpdu_sgi);
+                       wlc->pub->_cnt->txmpdu_sgi++;
                if (PLCP3_ISSTBC(plcp[3]))
-                       WLCNTINCR(wlc->pub->_cnt->txmpdu_stbc);
+                       wlc->pub->_cnt->txmpdu_stbc++;
        }
 
        if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
                skb_pull(p, D11_PHY_HDR_LEN);
                skb_pull(p, D11_TXH_LEN);
                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
-               WLCNTINCR(wlc->pub->_cnt->ieee_tx_status);
+               wlc->pub->_cnt->ieee_tx_status++;
        } else {
                WL_ERROR("%s: Not last frame => not calling tx_status\n",
                         __func__);
        memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
        ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
 
-       WLCNTINCR(wlc->pub->_cnt->ieee_rx);
+       wlc->pub->_cnt->ieee_rx++;
        osh->pktalloced--;
        return;
 }
        /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
        if (rxh->RxStatus1 & RXS_PBPRES) {
                if (p->len < 2) {
-                       WLCNTINCR(wlc->pub->_cnt->rxrunt);
+                       wlc->pub->_cnt->rxrunt++;
                        WL_ERROR("wl%d: wlc_recv: rcvd runt of len %d\n",
                                 wlc->pub->unit, p->len);
                        goto toss;
        if (len >= D11_PHY_HDR_LEN + sizeof(h->frame_control)) {
                fc = ltoh16(h->frame_control);
        } else {
-               WLCNTINCR(wlc->pub->_cnt->rxrunt);
+               wlc->pub->_cnt->rxrunt++;
                goto toss;
        }
 
                                WL_ERROR("wl%d: %s: dropping a frame with "
                                         "invalid src mac address, a2: %pM\n",
                                         wlc->pub->unit, __func__, h->addr2);
-                               WLCNTINCR(wlc->pub->_cnt->rxbadsrcmac);
+                               wlc->pub->_cnt->rxbadsrcmac++;
                                goto toss;
                        }
-                       WLCNTINCR(wlc->pub->_cnt->rxfrag);
+                       wlc->pub->_cnt->rxfrag++;
                }
        }
 
 
        if ((ltoh16(txh->MacFrameControl) & IEEE80211_FCTL_FTYPE) !=
            IEEE80211_FTYPE_DATA)
-               WLCNTINCR(wlc->pub->_cnt->txctl);
+               wlc->pub->_cnt->txctl++;
 
        return 0;
 }