net: rkwifi: fix ap6330 sdio write/read abnormal when doing stress test
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_sdio.c
index 43eb231bf0eebbdab867d8ed0761d54cefa67089..e7fea676456053da798f7048573bfaaa5f855bdf 100755 (executable)
@@ -1,9 +1,30 @@
 /*
  * DHD Bus Module for SDIO
  *
- * $Copyright Open Broadcom Corporation$
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_sdio.c 506046 2014-10-02 12:40:12Z $
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_sdio.c 593728 2015-10-19 09:20:32Z $
  */
 
 #include <typedefs.h>
 #include <hndpmu.h>
 #include <hndsoc.h>
 #include <bcmsdpcm.h>
-#if defined(DHD_DEBUG)
 #include <hnd_armtrap.h>
 #include <hnd_cons.h>
-#endif /* defined(DHD_DEBUG) */
 #include <sbchipc.h>
 #include <sbhnddma.h>
 
@@ -83,7 +102,6 @@ extern bool  bcmsdh_fatal_error(void *sdh);
 #define DHD_TXMINMAX   1       /* Max tx frames if rx still pending */
 
 #define MEMBLOCK       2048            /* Block size used for downloading of dongle image */
-#define MAX_NVRAMBUF_SIZE      4096    /* max nvram buf size */
 #define MAX_DATA_BUF   (64 * 1024)     /* Must be large enough to hold biggest possible glom */
 
 #ifndef DHD_FIRSTREAD
@@ -145,6 +163,11 @@ extern bool  bcmsdh_fatal_error(void *sdh);
  */
 #define PKTFREE2()             if ((bus->bus != SPI_BUS) || bus->usebufpool) \
                                        PKTFREE(bus->dhd->osh, pkt, FALSE);
+
+#ifdef PKT_STATICS
+pkt_statics_t tx_statics = {0};
+#endif
+
 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
 
 #if defined(MULTIPLE_SUPPLICANT)
@@ -153,7 +176,6 @@ DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
 #endif 
 
-#ifdef DHD_DEBUG
 /* Device console log buffer state */
 #define CONSOLE_LINE_MAX       192
 #define CONSOLE_BUFFER_MAX     2024
@@ -165,7 +187,6 @@ typedef struct dhd_console {
        uint8           *buf;                   /* Log buffer (host copy) */
        uint            last;                   /* Last buffer read index */
 } dhd_console_t;
-#endif /* DHD_DEBUG */
 
 #define        REMAP_ENAB(bus)                 ((bus)->remap)
 #define        REMAP_ISADDR(bus, a)            (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
@@ -218,7 +239,6 @@ typedef struct dhd_bus {
        uint16          cl_devid;               /* cached devid for dhdsdio_probe_attach() */
        char            *fw_path;               /* module_param: path to firmware image */
        char            *nv_path;               /* module_param: path to nvram vars file */
-       const char      *nvram_params;          /* user specified nvram params. */
 
        uint            blocksize;              /* Block size of SDIO transfers */
        uint            roundup;                /* Max roundup limit */
@@ -275,7 +295,9 @@ typedef struct dhd_bus {
        int32           sd_rxchain;             /* If bcmsdh api accepts PKT chains */
        bool            use_rxchain;            /* If dhd should use PKT chains */
        bool            sleeping;               /* Is SDIO bus sleeping? */
+#if defined(SUPPORT_P2P_GO_PS)
        wait_queue_head_t bus_sleep;
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
        uint            rxflow_mode;            /* Rx flow control mode */
        bool            rxflow;                 /* Is rx flow control on */
        uint            prev_rxlim_hit;         /* Is prev rx limit exceeded (per dpc schedule) */
@@ -367,8 +389,8 @@ typedef struct dhd_bus {
 #ifdef DHDENABLE_TAILPAD
        void            *pad_pkt;
 #endif /* DHDENABLE_TAILPAD */
-       uint        txglomframes;       /* Number of tx glom frames (superframes) */
-       uint        txglompkts;         /* Number of packets from tx glom frames */
+       uint            txglomframes;   /* Number of tx glom frames (superframes) */
+       uint            txglompkts;             /* Number of packets from tx glom frames */
 } dhd_bus_t;
 
 /* clkstate */
@@ -379,6 +401,10 @@ typedef struct dhd_bus {
 
 #define DHD_NOPMU(dhd) (FALSE)
 
+#if defined(BCMSDIOH_STD)
+#define BLK_64_MAXTXGLOM 20
+#endif /* BCMSDIOH_STD */
+
 #ifdef DHD_DEBUG
 static int qcount[NUMPRIO];
 static int tx_packets[NUMPRIO];
@@ -390,6 +416,7 @@ const uint dhd_deferred_tx = 1;
 extern uint dhd_watchdog_ms;
 
 extern void dhd_os_wd_timer(void *bus, uint wdtick);
+int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
 
 /* Tx/Rx bounds */
 uint dhd_txbound;
@@ -425,7 +452,7 @@ static bool forcealign;
 
 #define ALIGNMENT  4
 
-#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
 #endif
 
@@ -450,10 +477,27 @@ static const uint max_roundup = 512;
 /* Try doing readahead */
 static bool dhd_readahead;
 
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+bool
+dhdsdio_is_dataok(dhd_bus_t *bus) {
+       return (((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset > 1) && \
+       (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0));
+}
+
+uint8
+dhdsdio_get_databufcnt(dhd_bus_t *bus) {
+       return ((uint8)(bus->tx_max - bus->tx_seq) - 1 - bus->dhd->conf->tx_max_offset);
+}
+#endif
+
 /* To check if there's window offered */
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+#define DATAOK(bus) dhdsdio_is_dataok(bus)
+#else
 #define DATAOK(bus) \
        (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
        (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+#endif
 
 /* To check if there's window offered for ctrl frame */
 #define TXCTLOK(bus) \
@@ -461,8 +505,12 @@ static bool dhd_readahead;
        (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
 
 /* Number of pkts available in dongle for data RX */
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+#define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus)
+#else
 #define DATABUFCNT(bus) \
        ((uint8)(bus->tx_max - bus->tx_seq) - 1)
+#endif
 
 /* Macros to get register read/write status */
 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
@@ -541,11 +589,14 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
 #endif
 
-#ifdef DHD_DEBUG
 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
+#ifdef DHD_DEBUG
 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
 #endif /* DHD_DEBUG */
 
+#if defined(DHD_FW_COREDUMP)
+static int dhdsdio_mem_dump(dhd_bus_t *bus);
+#endif /* DHD_FW_COREDUMP */
 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
 
@@ -570,7 +621,11 @@ static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
        int prev_chain_total_len, bool last_chained_pkt,
-       int *pad_pkt_len, void **new_pkt);
+       int *pad_pkt_len, void **new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+       , int frist_frame
+#endif
+);
 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
 
 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
@@ -715,6 +770,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
                (bus->sih->chip == BCM4339_CHIP_ID) ||
                (bus->sih->chip == BCM43349_CHIP_ID) ||
                (bus->sih->chip == BCM4345_CHIP_ID) ||
+               (bus->sih->chip == BCM43454_CHIP_ID) ||
                (bus->sih->chip == BCM4354_CHIP_ID) ||
                (bus->sih->chip == BCM4356_CHIP_ID) ||
                (bus->sih->chip == BCM4358_CHIP_ID) ||
@@ -736,6 +792,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
                (bus->sih->chip == BCM4339_CHIP_ID) ||
                (bus->sih->chip == BCM43349_CHIP_ID) ||
                (bus->sih->chip == BCM4345_CHIP_ID) ||
+               (bus->sih->chip == BCM43454_CHIP_ID) ||
                (bus->sih->chip == BCM4354_CHIP_ID) ||
                (bus->sih->chip == BCM4356_CHIP_ID) ||
                (bus->sih->chip == BCM4358_CHIP_ID) ||
@@ -749,6 +806,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
 
                if ((bus->sih->chip == BCM4350_CHIP_ID) ||
                        (bus->sih->chip == BCM4345_CHIP_ID) ||
+                       (bus->sih->chip == BCM43454_CHIP_ID) ||
                        (bus->sih->chip == BCM4354_CHIP_ID) ||
                        (bus->sih->chip == BCM4356_CHIP_ID) ||
                        (bus->sih->chip == BCM4358_CHIP_ID) ||
@@ -770,9 +828,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
 static int
 dhdsdio_srwar_init(dhd_bus_t *bus)
 {
-#if !defined(NDISVER) || (NDISVER < 0x0630)
        bcmsdh_gpio_init(bus->sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
 
 #ifdef USE_OOB_GPIO1
        dhdsdio_oobwakeup_init(bus);
@@ -847,9 +903,14 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus)
 #define KSO_WAIT_US 50
 #define KSO_WAIT_MS 1
 #define KSO_SLEEP_RETRY_COUNT 20
+#define KSO_WAKE_RETRY_COUNT 100
 #define ERROR_BCME_NODEVICE_MAX 1
 
-#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+#define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+#ifndef CUSTOM_MAX_KSO_ATTEMPTS
+#define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
+#endif
+
 static int
 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
 {
@@ -857,9 +918,6 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
        int err = 0;
        int try_cnt = 0;
 
-       if (!bus->dhd->conf->kso_enable)
-               return 0;
-
        KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
 
        wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
@@ -871,6 +929,7 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
                bmask = cmp_val;
 
                OSL_SLEEP(3);
+
        } else {
                /* Put device to sleep, turn off  KSO  */
                cmp_val = 0;
@@ -890,17 +949,18 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
                        OSL_DELAY(KSO_WAIT_US);
 
                bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
-       } while (try_cnt++ < MAX_KSO_ATTEMPTS);
+       } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS);
 
 
        if (try_cnt > 2)
                KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
                        __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
 
-       if (try_cnt > MAX_KSO_ATTEMPTS)  {
+       if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS)  {
                DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
                        __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
        }
+
        return err;
 }
 
@@ -1007,12 +1067,12 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
 #ifdef USE_CMD14
                err = bcmsdh_sleep(bus->sdh, TRUE);
 #else
+
+
                err = dhdsdio_clk_kso_enab(bus, FALSE);
                if (OOB_WAKEUP_ENAB(bus))
                {
-#if !defined(NDISVER) || (NDISVER < 0x0630)
                        err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE);  /* GPIO_1 is off */
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
                }
 #endif /* USE_CMD14 */
        } else {
@@ -1022,7 +1082,6 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
                        DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
                        dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
                }
-#if !defined(NDISVER) || (NDISVER < 0x0630)
 
                if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
                        SPINWAIT_SLEEP(sdioh_spinwait_sleep,
@@ -1033,7 +1092,6 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
                                DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
                        }
                }
-#endif
 #ifdef USE_CMD14
                err = bcmsdh_sleep(bus->sdh, FALSE);
                if (SLPAUTO_ENAB(bus) && (err != 0)) {
@@ -1064,9 +1122,7 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
 #else
                if (OOB_WAKEUP_ENAB(bus))
                {
-#if !defined(NDISVER) || (NDISVER < 0x0630)
                        err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE);  /* GPIO_1 is on */
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
                }
                do {
                        err = dhdsdio_clk_kso_enab(bus, TRUE);
@@ -1078,6 +1134,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
                        DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
                        err = 0; /* continue anyway */
                }
+
+
 #endif /* !USE_CMD14 */
 
                if (err == 0) {
@@ -1163,6 +1221,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
                        else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
+                               bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
                                dhd_os_send_hang_message(bus->dhd);
                        }
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
@@ -1450,7 +1509,12 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
        /* Going to sleep: set the alarm and turn off the lights... */
        if (sleep) {
                /* Don't sleep if something is pending */
+#ifdef DHD_USE_IDLECOUNT
+               if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes ||
+                       bus->ctrl_frame_stat)
+#else
                if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
+#endif /* DHD_USE_IDLECOUNT */
                        return BCME_BUSY;
 
 
@@ -1487,7 +1551,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
 
                /* Change state */
                bus->sleeping = TRUE;
+#if defined(SUPPORT_P2P_GO_PS)
                wake_up(&bus->bus_sleep);
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
        } else {
                /* Waking up: bus power up is ok, set local state */
 
@@ -1530,12 +1596,42 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
        return err;
 }
 
+#ifdef USE_DYNAMIC_F2_BLKSIZE
+int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
+{
+       int func_blk_size = function_num;
+       int bcmerr = 0;
+       int result;
+
+       bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
+               sizeof(int), &result, sizeof(int), IOV_GET);
 
-#if defined(OOB_INTR_ONLY)
+       if (bcmerr != BCME_OK) {
+               DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
+               return BCME_ERROR;
+       }
+
+       if (result != block_size) {
+               DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
+                       __FUNCTION__, function_num, result, block_size));
+               func_blk_size = function_num << 16 | block_size;
+               bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
+                       0, &func_blk_size, sizeof(int32), IOV_SET);
+               if (bcmerr != BCME_OK) {
+                       DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__));
+                       return BCME_ERROR;
+               }
+       }
+
+       return BCME_OK;
+}
+#endif /* USE_DYNAMIC_F2_BLKSIZE */
+
+#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN)
 void
 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
 {
-#if defined(HW_OOB)
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
        bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
 #else
        sdpcmd_regs_t *regs = bus->regs;
@@ -1649,8 +1745,20 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
 
                /* Schedule DPC if needed to send queued packet(s) */
                if (dhd_deferred_tx && !bus->dpc_sched) {
-                       bus->dpc_sched = TRUE;
-                       dhd_sched_dpc(bus->dhd);
+                       if (bus->dhd->conf->deferred_tx_len) {
+                               if(dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
+                                       bus->dpc_sched = TRUE;
+                                       dhd_sched_dpc(bus->dhd);
+                               }
+                               if(pktq_len(&bus->txq) >= bus->dhd->conf->deferred_tx_len &&
+                                               dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
+                                       bus->dpc_sched = TRUE;
+                                       dhd_sched_dpc(bus->dhd);
+                               }
+                       } else {
+                               bus->dpc_sched = TRUE;
+                               dhd_sched_dpc(bus->dhd);
+                       }
                }
        } else {
                int chan = SDPCM_DATA_CHANNEL;
@@ -1700,7 +1808,11 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
  */
 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
        int prev_chain_total_len, bool last_chained_pkt,
-       int *pad_pkt_len, void **new_pkt)
+       int *pad_pkt_len, void **new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+       , int first_frame
+#endif
+)
 {
        osl_t *osh;
        uint8 *frame;
@@ -1712,6 +1824,9 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
        uint32 swhdr_offset;
        bool alloc_new_pkt = FALSE;
        uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
+#ifdef PKT_STATICS
+       uint16 len;
+#endif
 
        *new_pkt = NULL;
        osh = bus->dhd->osh;
@@ -1741,6 +1856,34 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
                }
        }
 #endif /* WLMEDIA_HTSF */
+#ifdef PKT_STATICS
+       len = (uint16)PKTLEN(osh, pkt);
+       switch(chan) {
+               case SDPCM_CONTROL_CHANNEL:
+                       tx_statics.ctrl_count++;
+                       tx_statics.ctrl_size += len;
+                       break;
+               case SDPCM_DATA_CHANNEL:
+                       tx_statics.data_count++;
+                       tx_statics.data_size += len;
+                       break;
+               case SDPCM_GLOM_CHANNEL:
+                       tx_statics.glom_count++;
+                       tx_statics.glom_size += len;
+                       break;
+               case SDPCM_EVENT_CHANNEL:
+                       tx_statics.event_count++;
+                       tx_statics.event_size += len;
+                       break;
+               case SDPCM_TEST_CHANNEL:
+                       tx_statics.test_count++;
+                       tx_statics.test_size += len;
+                       break;
+
+               default:
+                       break;
+       }
+#endif /* PKT_STATICS */
 #ifdef DHD_DEBUG
        if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
                tx_packets[PKTPRIO(pkt)]++;
@@ -1881,6 +2024,10 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
         * referred to in sdioh_request_buffer(). The tail length will be excluded in
         * dhdsdio_txpkt_postprocess().
         */
+#if defined(BCMSDIOH_TXGLOM_EXT)
+       if (bus->dhd->conf->txglom_bucket_size)
+               tail_padding = 0;
+#endif
        *(uint16*)frame = (uint16)htol16(pkt_len);
        *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
        pkt_len += tail_padding;
@@ -1889,13 +2036,43 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
        if (bus->txglom_enable) {
                uint32 hwheader1;
                uint32 hwheader2;
-
-               swhdr_offset += SDPCM_HWEXT_LEN;
-               hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
-                       (last_chained_pkt << 24);
-               hwheader2 = (tail_padding) << 16;
-               htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
-               htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+#ifdef BCMSDIOH_TXGLOM_EXT
+               uint32 act_len = pkt_len - tail_padding;
+               uint32 real_pad = 0;
+               if(bus->dhd->conf->txglom_ext && !last_chained_pkt) {
+                       tail_padding = 0;
+                       if(first_frame == 0) {
+                               // first pkt, add pad to bucket size - recv offset
+                               pkt_len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
+                       } else {
+                               // add pad to bucket size
+                               pkt_len = bus->dhd->conf->txglom_bucket_size;
+                       }
+                       swhdr_offset += SDPCM_HWEXT_LEN;
+                       hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 24);
+                       hwheader2 = (pkt_len - act_len) << 16;
+                       htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+                       htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+                       real_pad = pkt_len - act_len;
+
+                       if (PKTTAILROOM(osh, pkt) < real_pad) {
+                               DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n", 
+                                       __func__, (int)PKTTAILROOM(osh, pkt), real_pad));
+                               if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+                                       DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
+                               } else
+                                       frame = (uint8 *)PKTDATA(osh, pkt);
+                       }
+               } else 
+#endif
+               {
+                       swhdr_offset += SDPCM_HWEXT_LEN;
+                       hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
+                               (last_chained_pkt << 24);
+                       hwheader2 = (tail_padding) << 16;
+                       htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+                       htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+               }
        }
        PKTSETLEN((osh), (pkt), (pkt_len));
 
@@ -1920,41 +2097,650 @@ static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
        (void)osh;
        osh = bus->dhd->osh;
 
-       /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
-       frame = (uint8*)PKTDATA(osh, pkt);
+       /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
+       frame = (uint8*)PKTDATA(osh, pkt);
+
+       DHD_INFO(("%s PKTLEN before postprocess %d",
+               __FUNCTION__, PKTLEN(osh, pkt)));
+
+       /* PKTLEN still includes tail_padding, so exclude it.
+        * We shall have head_padding + original pkt_len for PKTLEN afterwards.
+        */
+       if (bus->txglom_enable) {
+               /* txglom pkts have tail_padding length in HW ext header */
+               tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
+               PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
+               DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
+                       tail_padding, PKTLEN(osh, pkt)));
+       } else {
+               /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
+                * We cannot refer to this field for txglom pkts as the first pkt of the chain will
+                * have the field for the total length of the chain.
+                */
+               PKTSETLEN(osh, pkt, *(uint16*)frame);
+               DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
+                       *(uint16*)frame, PKTLEN(osh, pkt)));
+       }
+
+       data_offset = ltoh32_ua(frame + swhdr_offset);
+       data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
+       /* Get rid of sdpcm header + head_padding */
+       PKTPULL(osh, pkt, data_offset);
+
+       DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
+               __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
+
+       return BCME_OK;
+}
+
+#if defined(SWTXGLOM)
+static int
+dhd_bcmsdh_send_swtxglom_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
+       void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
+{
+       int ret;
+       int i = 0;
+       int retries = 0;
+       bcmsdh_info_t *sdh;
+
+       if (!KSO_ENAB(bus)) {
+               DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
+               return BCME_NODEVICE;
+       }
+
+       sdh = bus->sdh;
+       do {
+               ret = bcmsdh_send_swtxglom_buf(bus->sdh, addr, fn, flags, buf, nbytes,
+                       pkt, complete, handle);
+
+               bus->f2txdata++;
+               ASSERT(ret != BCME_PENDING);
+
+               if (ret == BCME_NODEVICE) {
+                       DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
+               } else if (ret < 0) {
+                       /* On failure, abort the command and terminate the frame */
+                       DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
+                               __FUNCTION__, ret));
+                       bus->tx_sderrs++;
+                       bus->f1regdata++;
+                       bus->dhd->tx_errors++;
+                       bcmsdh_abort(sdh, SDIO_FUNC_2);
+                       bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
+                               SFC_WF_TERM, NULL);
+                       for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
+                               uint8 hi, lo;
+                               hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
+                                       NULL);
+                               lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
+                                       NULL);
+                               bus->f1regdata += 2;
+                               if ((hi == 0) && (lo == 0))
+                                       break;
+                       }
+               }
+               if (ret == 0) {
+#ifdef BCMSDIOH_TXGLOM
+                       if (bus->txglom_enable) {
+                               bus->tx_seq = (bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP;
+                       } else
+#endif
+                       {
+                               bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+                       }
+               }
+       } while ((ret < 0) && retrydata && ++retries < max_retry);
+
+       return ret;
+}
+
+/* Writes a HW/SW header into the packet and sends it. */
+/* Assumes: (a) header space already there, (b) caller holds lock */
+static int
+dhdsdio_txpkt_swtxglom(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
+{
+       int ret;
+       osl_t *osh;
+       uint8 *frame;
+       uint16 len, pad1 = 0, act_len = 0;
+       uint32 swheader;
+       uint32 real_pad = 0;
+       bcmsdh_info_t *sdh;
+       void *new;
+       int pkt_cnt;
+#ifdef BCMSDIOH_TXGLOM
+       uint8 *frame_tmp;
+#endif
+#ifdef WLMEDIA_HTSF
+       char *p;
+       htsfts_t *htsf_ts;
+#endif
+
+       DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+       sdh = bus->sdh;
+       osh = bus->dhd->osh;
+
+#ifdef DHDTCPACK_SUPPRESS
+       if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
+               DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
+                       __FUNCTION__, __LINE__));
+               dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
+       }
+#endif /* DHDTCPACK_SUPPRESS */
+
+       /* Add space for the header */
+       PKTPUSH(osh, pkt, SDPCM_HDRLEN_TXGLOM);
+       ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
+
+       if (bus->dhd->dongle_reset) {
+               ret = BCME_NOTREADY;
+               goto done;
+       }
+
+       frame = (uint8*)PKTDATA(osh, pkt);
+
+#ifdef WLMEDIA_HTSF
+       if (PKTLEN(osh, pkt) >= 100) {
+               p = PKTDATA(osh, pkt);
+               htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
+               if (htsf_ts->magic == HTSFMAGIC) {
+                       htsf_ts->c20 = get_cycles();
+                       htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
+               }
+       }
+#endif /* WLMEDIA_HTSF */
+
+#ifdef PKT_STATICS
+       len = (uint16)PKTLEN(osh, pkt);
+       switch(chan) {
+               case SDPCM_CONTROL_CHANNEL:
+                       tx_statics.ctrl_count++;
+                       tx_statics.ctrl_size += len;
+                       break;
+               case SDPCM_DATA_CHANNEL:
+                       tx_statics.data_count++;
+                       tx_statics.data_size += len;
+                       break;
+               case SDPCM_GLOM_CHANNEL:
+                       tx_statics.glom_count++;
+                       tx_statics.glom_size += len;
+                       break;
+               case SDPCM_EVENT_CHANNEL:
+                       tx_statics.event_count++;
+                       tx_statics.event_size += len;
+                       break;
+               case SDPCM_TEST_CHANNEL:
+                       tx_statics.test_count++;
+                       tx_statics.test_size += len;
+                       break;
+
+               default:
+                       break;
+       }
+#endif /* PKT_STATICS */
+
+       /* Add alignment padding, allocate new packet if needed */
+       if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
+               if (PKTHEADROOM(osh, pkt) < pad1) {
+                       DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
+                                 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
+                       bus->dhd->tx_realloc++;
+                       new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
+                       if (!new) {
+                               DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
+                                          __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
+                               ret = BCME_NOMEM;
+                               goto done;
+                       }
+
+                       PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
+                       bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
+                       if (free_pkt)
+                               PKTFREE(osh, pkt, TRUE);
+                       /* free the pkt if canned one is not used */
+                       free_pkt = TRUE;
+                       pkt = new;
+                       frame = (uint8*)PKTDATA(osh, pkt);
+                       ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
+                       pad1 = 0;
+               } else {
+                       PKTPUSH(osh, pkt, pad1);
+                       frame = (uint8*)PKTDATA(osh, pkt);
+
+                       ASSERT((pad1 + SDPCM_HDRLEN_TXGLOM) <= (int) PKTLEN(osh, pkt));
+                       bzero(frame, pad1 + SDPCM_HDRLEN_TXGLOM);
+               }
+       }
+       ASSERT(pad1 < DHD_SDALIGN);
+
+       /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+       len = (uint16)PKTLEN(osh, pkt);
+       *(uint16*)frame = htol16(len);
+       *(((uint16*)frame) + 1) = htol16(~len);
+
+#ifdef BCMSDIOH_TXGLOM
+       if (bus->txglom_enable) {
+               uint32 hwheader1 = 0, hwheader2 = 0;
+               act_len = len;
+
+               /* Software tag: channel, sequence number, data offset */
+               swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
+                       ((bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP) |
+                       (((pad1 + SDPCM_HDRLEN_TXGLOM) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+               htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
+               htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
+
+               if (queue_only) {
+                       if (bus->dhd->conf->txglom_ext) {
+                               if(bus->txglom_cnt == 0) {
+                                       // first pkt, add pad to bucket size - recv offset
+                                       len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
+                               } else {
+                                       // add pad to bucket size
+                                       len = bus->dhd->conf->txglom_bucket_size;
+                               }
+                       } else {
+                               uint8 alignment = ALIGNMENT;
+                               if (forcealign && (len & (alignment - 1)))
+                                       len = ROUNDUP(len, alignment);
+                       }
+                       /* Hardware extention tag */
+                       /* 2byte frame length, 1byte-, 1byte frame flag,
+                        * 2byte-hdrlength, 2byte padlenght
+                        */
+                       hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
+                       hwheader2 = (len - act_len) << 16;
+                       htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+                       htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+                       real_pad = len - act_len;
+                       if (PKTTAILROOM(osh, pkt) < real_pad) {
+                               DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
+                               __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+                               if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+                                       DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
+                                       ret = BCME_NOMEM;
+                                       goto done;
+                               }
+#ifndef BCMLXSDMMC
+                               else
+                                       PKTSETLEN(osh, pkt, act_len);
+#endif
+                       }
+#ifdef BCMLXSDMMC
+                       PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+                       /* Post the frame pointer to sdio glom array */
+                       bcmsdh_glom_post(bus->sdh, frame, pkt, len);
+                       /* Save the pkt pointer in bus glom array */
+                       bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+                       bus->txglom_total_len += len;
+                       bus->txglom_cnt++;
+                       return BCME_OK;
+               } else {
+                       /* Raise len to next SDIO block to eliminate tail command */
+                       if (bus->roundup && bus->blocksize &&
+                               ((bus->txglom_total_len + len) > bus->blocksize)) {
+                               uint16 pad2 = bus->blocksize -
+                                       ((bus->txglom_total_len + len) % bus->blocksize);
+                               if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
+                                               len += pad2;
+                               } else {
+                               }
+                       } else if ((bus->txglom_total_len + len) % DHD_SDALIGN) {
+                               len += DHD_SDALIGN
+                                   - ((bus->txglom_total_len + len) % DHD_SDALIGN);
+                       }
+                       if (forcealign && (len & (ALIGNMENT - 1))) {
+                               len = ROUNDUP(len, ALIGNMENT);
+                       }
+
+                       /* Hardware extention tag */
+                       /* 2byte frame length, 1byte-, 1byte frame flag,
+                        * 2byte-hdrlength, 2byte padlenght
+                        */
+                       if (bus->dhd->conf->txglom_ext) {
+                               // copy way, the last packet pad2 is set to 0 it will be dropped by HW
+                               hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
+                               hwheader2 = 0;
+                               htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+                               htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+                       } else {
+                               hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
+                               hwheader2 = (len - act_len) << 16;
+                               htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+                               htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+                       }
+                       real_pad = len - act_len;
+                       if (PKTTAILROOM(osh, pkt) < real_pad) {
+                               DHD_INFO(("%s 2: insufficient tailroom %d"
+                               " for %d real_pad\n",
+                               __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+                               if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+                                       DHD_ERROR(("CHK2: padding error size %d."
+                                               " %d more pkts are discarded together.\n",
+                                               real_pad, bus->txglom_cnt));
+                                       /* Save the pkt pointer in bus glom array
+                                       * Otherwise, this last pkt will not be
+                                       * cleaned under "goto done"
+                                       */
+                                       bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+                                       bus->txglom_cnt++;
+                                       bus->txglom_total_len += len;
+                                       ret = BCME_NOMEM;
+                                       goto done;
+                               }
+#ifndef BCMLXSDMMC
+                               else
+                                       PKTSETLEN(osh, pkt, act_len);
+#endif
+                       }
+#ifdef BCMLXSDMMC
+                       PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+
+                       /* Post the frame pointer to sdio glom array */
+                       bcmsdh_glom_post(bus->sdh, frame, pkt, len);
+                       /* Save the pkt pointer in bus glom array */
+                       bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+                       bus->txglom_cnt++;
+                       if (bus->dhd->conf->txglom_ext)
+                               //copy way, the last buffer padding is not need add to len
+                               bus->txglom_total_len += act_len;
+                       else
+                               bus->txglom_total_len += len;
+
+                       /* Update the total length on the first pkt */
+                       frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
+                       *(uint16*)frame_tmp = htol16(bus->txglom_total_len);
+                       *(((uint16*)frame_tmp) + 1) = htol16(~bus->txglom_total_len);
+               }
+       } else
+#endif /* BCMSDIOH_TXGLOM */
+       {
+               act_len = len;
+               /* Software tag: channel, sequence number, data offset */
+               swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
+                               (((pad1 + SDPCM_HDRLEN_TXGLOM) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+               htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
+               htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+
+#ifdef DHD_DEBUG
+               if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
+                       tx_packets[PKTPRIO(pkt)]++;
+               }
+               if (DHD_BYTES_ON() &&
+                       (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
+                       (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
+                       prhex("Tx Frame", frame, len);
+               } else if (DHD_HDRS_ON()) {
+                       prhex("TxHdr", frame, MIN(len, 16));
+               }
+#endif
+
+               /* Raise len to next SDIO block to eliminate tail command */
+               if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+                       uint16 pad2 = bus->blocksize - (len % bus->blocksize);
+                       if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
+#ifdef NOTUSED
+                               if (pad2 <= PKTTAILROOM(osh, pkt))
+#endif /* NOTUSED */
+                                       len += pad2;
+               } else if (len % DHD_SDALIGN) {
+                       len += DHD_SDALIGN - (len % DHD_SDALIGN);
+               }
+
+               /* Some controllers have trouble with odd bytes -- round to even */
+               if (forcealign && (len & (ALIGNMENT - 1))) {
+#ifdef NOTUSED
+                       if (PKTTAILROOM(osh, pkt))
+#endif
+                               len = ROUNDUP(len, ALIGNMENT);
+#ifdef NOTUSED
+                       else
+                               DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
+#endif
+               }
+               real_pad = len - act_len;
+               if (PKTTAILROOM(osh, pkt) < real_pad) {
+                       DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
+                       __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+                       if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+                               DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
+                               ret = BCME_NOMEM;
+                               goto done;
+                       }
+#ifndef BCMLXSDMMC
+                       else
+                               PKTSETLEN(osh, pkt, act_len);
+#endif
+               }
+#ifdef BCMLXSDMMC
+               PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+       }
+#ifdef DHD_DEBUG
+       if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
+               tx_packets[PKTPRIO(pkt)]++;
+       }
+#endif
+       ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+                                 frame, len, pkt, NULL, NULL, TXRETRIES);
+
+done:
+
+#ifdef BCMSDIOH_TXGLOM
+       if (bus->txglom_enable && !queue_only) {
+               bcmsdh_glom_clear(bus->sdh);
+               pkt_cnt = bus->txglom_cnt;
+       } else
+#endif
+       {
+               pkt_cnt = 1;
+       }
+               /* restore pkt buffer pointer before calling tx complete routine */
+       while (pkt_cnt) {
+#ifdef BCMSDIOH_TXGLOM
+               uint32 doff;
+               if (bus->txglom_enable) {
+#ifdef BCMLXSDMMC
+                       uint32 pad2 = 0;
+#endif /* BCMLXSDMMC */
+                       if (!queue_only)
+                               pkt = bus->glom_pkt_arr[bus->txglom_cnt - pkt_cnt];
+
+                       frame = (uint8*)PKTDATA(osh, pkt);
+                       doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
+                       doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
+#ifdef BCMLXSDMMC
+                       pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
+                       PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
+#endif /* BCMLXSDMMC */
+                       PKTPULL(osh, pkt, doff);
+               } else
+#endif /* BCMSDIOH_TXGLOM */
+               {
+#ifdef BCMLXSDMMC
+                       if (act_len > 0)
+                               PKTSETLEN(osh, pkt, act_len);
+#endif /* BCMLXSDMMC */
+                       PKTPULL(osh, pkt, SDPCM_HDRLEN_TXGLOM + pad1);
+               }
+#ifdef PROP_TXSTATUS
+               if (bus->dhd->wlfc_state) {
+                       dhd_os_sdunlock(bus->dhd);
+                       dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
+                       dhd_os_sdlock(bus->dhd);
+               } else {
+#endif /* PROP_TXSTATUS */
+#ifdef SDTEST
+                       if (chan != SDPCM_TEST_CHANNEL) {
+                               dhd_txcomplete(bus->dhd, pkt, ret != 0);
+                       }
+#else /* SDTEST */
+                       dhd_txcomplete(bus->dhd, pkt, ret != 0);
+#endif /* SDTEST */
+                       if (free_pkt)
+                               PKTFREE(osh, pkt, TRUE);
+#ifdef PROP_TXSTATUS
+               }
+#endif
+               pkt_cnt--;
+       }
+
+#ifdef BCMSDIOH_TXGLOM
+       /* Reset the glom array */
+       if (bus->txglom_enable && !queue_only) {
+               bus->txglom_cnt = 0;
+               bus->txglom_total_len = 0;
+       }
+#endif
+       return ret;
+}
+
+static uint
+dhdsdio_sendfromq_swtxglom(dhd_bus_t *bus, uint maxframes)
+{
+       void *pkt;
+       uint32 intstatus = 0;
+       uint retries = 0;
+       int ret = 0, prec_out;
+       uint cnt = 0;
+       uint datalen;
+       uint8 tx_prec_map;
+       uint16 txpktqlen = 0;
+#ifdef BCMSDIOH_TXGLOM
+       uint i;
+       uint8 txglom_cnt;
+#endif
+
+       dhd_pub_t *dhd = bus->dhd;
+       sdpcmd_regs_t *regs = bus->regs;
+
+       DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+       if (!KSO_ENAB(bus)) {
+               DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
+               return BCME_NODEVICE;
+       }
+
+       tx_prec_map = ~bus->flowcontrol;
+       /* Send frames until the limit or some other event */
+       for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
+#ifdef BCMSDIOH_TXGLOM
+               if (bus->txglom_enable) {
+                       void *pkttable[SDPCM_MAXGLOM_SIZE];
+                       dhd_os_sdlock_txq(bus->dhd);
+                       txglom_cnt = MIN(DATABUFCNT(bus), bus->txglomsize);
+                       txglom_cnt = MIN(txglom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
+                       txglom_cnt = MIN(txglom_cnt, maxframes-cnt);
+
+                       /* Limiting the size to 2pkts in case of copy */
+                       if (bus->dhd->conf->txglom_ext)
+                               txglom_cnt = MIN(txglom_cnt, SDPCM_MAXGLOM_SIZE);
+                       else
+                               txglom_cnt = MIN(txglom_cnt, 10);
+
+                       for (i = 0; i < txglom_cnt; i++)
+                               pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+
+                       txpktqlen = pktq_len(&bus->txq);
+                       dhd_os_sdunlock_txq(bus->dhd);
+
+                       if (txglom_cnt == 0)
+                               break;
+                       datalen = 0;
+
+#ifdef PKT_STATICS
+                       if (txglom_cnt < 2)
+                               tx_statics.glom_1_count++;
+                       else if (txglom_cnt < 3)
+                               tx_statics.glom_3_count++;
+                       else if (txglom_cnt < 8)
+                               tx_statics.glom_3_8_count++;
+                       else
+                               tx_statics.glom_8_count++;
+                       if (txglom_cnt > tx_statics.glom_max)
+                               tx_statics.glom_max = txglom_cnt;
+#endif
+                       for (i = 0; i < txglom_cnt; i++) {
+                               uint datalen_tmp = 0;
+
+                               if ((pkt = pkttable[i]) == NULL) {
+                                       /* This case should not happen */
+                                       DHD_ERROR(("No pkts in the queue for glomming\n"));
+                                       break;
+                               }
+
+                               datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM);
+
+#ifndef SDTEST
+                               ret = dhdsdio_txpkt_swtxglom(bus,
+                                       pkt,
+                                       SDPCM_DATA_CHANNEL,
+                                       TRUE,
+                                       (i == (txglom_cnt-1))? FALSE: TRUE);
+#else
+                               ret = dhdsdio_txpkt_swtxglom(bus,
+                                       pkt,
+                                       (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
+                                       TRUE,
+                                       (i == (txglom_cnt-1))? FALSE: TRUE);
+#endif
+                               if (ret == BCME_OK)
+                                       datalen += datalen_tmp;
+                       }
+                       cnt += i-1;
+               } else
+#endif /* BCMSDIOH_TXGLOM */
+               {
+               dhd_os_sdlock_txq(bus->dhd);
+               if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
+                       txpktqlen = pktq_len(&bus->txq);
+                       dhd_os_sdunlock_txq(bus->dhd);
+                       break;
+               }
+               txpktqlen = pktq_len(&bus->txq);
+               dhd_os_sdunlock_txq(bus->dhd);
+               datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM;
+
+#ifndef SDTEST
+               ret = dhdsdio_txpkt_swtxglom(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
+#else
+               ret = dhdsdio_txpkt_swtxglom(bus,
+                       pkt,
+                       (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
+                       TRUE,
+                       FALSE);
+#endif
+               }
 
-       DHD_INFO(("%s PKTLEN before postprocess %d",
-               __FUNCTION__, PKTLEN(osh, pkt)));
+               if (ret)
+                       bus->dhd->tx_errors++;
+               else
+                       bus->dhd->dstats.tx_bytes += datalen;
 
-       /* PKTLEN still includes tail_padding, so exclude it.
-        * We shall have head_padding + original pkt_len for PKTLEN afterwards.
-        */
-       if (bus->txglom_enable) {
-               /* txglom pkts have tail_padding length in HW ext header */
-               tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
-               PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
-               DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
-                       tail_padding, PKTLEN(osh, pkt)));
-       } else {
-               /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
-                * We cannot refer to this field for txglom pkts as the first pkt of the chain will
-                * have the field for the total length of the chain.
-                */
-               PKTSETLEN(osh, pkt, *(uint16*)frame);
-               DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
-                       *(uint16*)frame, PKTLEN(osh, pkt)));
+               /* In poll mode, need to check for other events */
+               if (!bus->intr && cnt)
+               {
+                       /* Check device status, signal pending interrupt */
+                       R_SDREG(intstatus, &regs->intstatus, retries);
+                       bus->f2txdata++;
+                       if (bcmsdh_regfail(bus->sdh))
+                               break;
+                       if (intstatus & bus->hostintmask)
+                               bus->ipend = TRUE;
+               }
        }
 
-       data_offset = ltoh32_ua(frame + swhdr_offset);
-       data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
-       /* Get rid of sdpcm header + head_padding */
-       PKTPULL(osh, pkt, data_offset);
-
-       DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
-               __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
+       /* Deflow-control stack if needed */
+       if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
+           dhd->txoff && (txpktqlen < FCLOW))
+               dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
 
-       return BCME_OK;
+       return cnt;
 }
+#endif
 
 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
 {
@@ -1989,7 +2775,11 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bo
                ASSERT(pkt);
                last_pkt = (i == num_pkt - 1);
                pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
-                       total_len, last_pkt, &pad_pkt_len, &new_pkt);
+                       total_len, last_pkt, &pad_pkt_len, &new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+                       , i
+#endif
+               );
                if (pkt_len <= 0)
                        goto done;
                if (new_pkt) {
@@ -2029,6 +2819,12 @@ static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bo
         * so it will take the aligned length and buffer pointer.
         */
        pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
+#if defined(SWTXGLOM)
+       if (bus->dhd->conf->swtxglom)
+               ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+                       PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
+       else
+#endif
        ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
                PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
        if (ret == BCME_OK)
@@ -2095,6 +2891,9 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
 
        osh = dhd->osh;
        tx_prec_map = ~bus->flowcontrol;
+#ifdef DHD_LOSSLESS_ROAMING
+       tx_prec_map &= dhd->dequeue_prec_map;
+#endif
        for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
                int i;
                int num_pkt = 1;
@@ -2103,12 +2902,18 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
 
                dhd_os_sdlock_txq(bus->dhd);
                if (bus->txglom_enable) {
-                       num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
+                       uint32 glomlimit = (uint32)bus->txglomsize;
+#if defined(BCMSDIOH_STD)
+                       if (bus->blocksize == 64) {
+                               glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
+                       }
+#endif /* BCMSDIOH_STD */
+                       num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
                        num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
                }
                num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
                for (i = 0; i < num_pkt; i++) {
-                       pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
+                       pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
                        if (!pkts[i]) {
                                DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
                                        __FUNCTION__));
@@ -2130,6 +2935,18 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
                        bus->txglompkts += num_pkt;
                }
                cnt += i;
+#ifdef PKT_STATICS
+               if (num_pkt < 2)
+                       tx_statics.glom_1_count++;
+               else if (num_pkt < 3)
+                       tx_statics.glom_3_count++;
+               else if (num_pkt < 8)
+                       tx_statics.glom_3_8_count++;
+               else
+                       tx_statics.glom_8_count++;
+               if (num_pkt > tx_statics.glom_max)
+                       tx_statics.glom_max = num_pkt;
+#endif
 
                /* In poll mode, need to check for other events */
                if (!bus->intr && cnt)
@@ -2180,6 +2997,13 @@ dhdsdio_sendpendctl(dhd_bus_t *bus)
                *frame_seq = bus->tx_seq;
        }
 
+#if defined(SWTXGLOM)
+       if (bus->dhd->conf->swtxglom)
+               ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+                       (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
+                       NULL, NULL, NULL, 1);
+       else
+#endif
        ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
                (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
                NULL, NULL, NULL, 1);
@@ -2297,6 +3121,14 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
                } else {
                        bus->dhd->txcnt_timeout++;
                        if (!bus->dhd->hang_was_sent) {
+#ifdef CUSTOMER_HW4_DEBUG
+                               uint32 status, retry = 0;
+                               R_SDREG(status, &bus->regs->intstatus, retry);
+                               DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
+                                       __FUNCTION__, status));
+                               DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
+                                       __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
+#endif /* CUSTOMER_HW4_DEBUG */
                                DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
                                        __FUNCTION__, bus->dhd->txcnt_timeout));
                        }
@@ -2316,6 +3148,16 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
                } else if (DHD_HDRS_ON()) {
                        prhex("TxHdr", frame, MIN(len, 16));
                }
+#endif
+#ifdef PKT_STATICS
+               tx_statics.ctrl_count++;
+               tx_statics.ctrl_size += len;
+#endif
+#if defined(SWTXGLOM)
+               if (bus->dhd->conf->swtxglom)
+                       ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+                                         frame, len, NULL, NULL, NULL, TXRETRIES);
+               else
 #endif
                ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
                                          frame, len, NULL, NULL, NULL, TXRETRIES);
@@ -2353,7 +3195,6 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 {
        int timeleft;
        uint rxlen = 0;
-       bool pending;
 
        DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -2361,7 +3202,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
                return -EIO;
 
        /* Wait until control frame is available */
-       timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
+       timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
 
        dhd_os_sdlock(bus->dhd);
        rxlen = bus->rxlen;
@@ -2381,23 +3222,14 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 #else
                DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
 #endif /* DHD_DEBUG */
-#ifdef DHD_DEBUG
-                       dhd_os_sdlock(bus->dhd);
-                       dhdsdio_checkdied(bus, NULL, 0);
-                       dhd_os_sdunlock(bus->dhd);
-#endif /* DHD_DEBUG */
-       } else if (pending == TRUE) {
-               /* signal pending */
-               DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
-               return -EINTR;
-
+               dhd_os_sdlock(bus->dhd);
+               dhdsdio_checkdied(bus, NULL, 0);
+               dhd_os_sdunlock(bus->dhd);
        } else {
                DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
-#ifdef DHD_DEBUG
                dhd_os_sdlock(bus->dhd);
                dhdsdio_checkdied(bus, NULL, 0);
                dhd_os_sdunlock(bus->dhd);
-#endif /* DHD_DEBUG */
        }
        if (timeleft == 0) {
                if (rxlen == 0)
@@ -2786,7 +3618,6 @@ xfer_done:
        return bcmerror;
 }
 
-#ifdef DHD_DEBUG
 static int
 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
 {
@@ -2794,6 +3625,17 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
        int rv, i;
        uint32 shaddr = 0;
 
+       if (bus->sih == NULL) {
+               if (bus->dhd && bus->dhd->dongle_reset) {
+                       DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
+                       return BCME_NOTREADY;
+               } else {
+                       ASSERT(bus->dhd);
+                       ASSERT(bus->sih);
+                       DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
+                       return BCME_ERROR;
+               }
+       }
        if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
                bus->srmemsize = 0;
 
@@ -2853,6 +3695,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
 
 #define CONSOLE_LINE_MAX       192
 
+#ifdef DHD_DEBUG
 static int
 dhdsdio_readconsole(dhd_bus_t *bus)
 {
@@ -2928,6 +3771,7 @@ break2:
 
        return BCME_OK;
 }
+#endif /* DHD_DEBUG */
 
 static int
 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
@@ -3097,6 +3941,12 @@ printbuf:
                DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
        }
 
+#if defined(DHD_FW_COREDUMP)
+       if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+               /* Mem dump to a file on device */
+               dhdsdio_mem_dump(bus);
+       }
+#endif /* #if defined(DHD_FW_COREDUMP) */
 
 done:
        if (mbuffer)
@@ -3108,8 +3958,68 @@ done:
 
        return bcmerror;
 }
-#endif /* #ifdef DHD_DEBUG */
 
+#if defined(DHD_FW_COREDUMP)
+static int
+dhdsdio_mem_dump(dhd_bus_t *bus)
+{
+       int ret = 0;
+       int size; /* Full mem size */
+       int start = bus->dongle_ram_base; /* Start address */
+       int read_size = 0; /* Read size of each iteration */
+       uint8 *buf = NULL, *databuf = NULL;
+
+       /* Get full mem size */
+       size = bus->ramsize;
+       buf = MALLOC(bus->dhd->osh, size);
+       if (!buf) {
+               printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
+               return -1;
+       }
+
+       /* Read mem content */
+       printf("Dump dongle memory");
+       databuf = buf;
+       while (size)
+       {
+               read_size = MIN(MEMBLOCK, size);
+               if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
+               {
+                       printf("%s: Error membytes %d\n", __FUNCTION__, ret);
+                       if (buf) {
+                               MFREE(bus->dhd->osh, buf, size);
+                       }
+                       return -1;
+               }
+               /* Decrement size and increment start address */
+               size -= read_size;
+               start += read_size;
+               databuf += read_size;
+       }
+       printf("Done\n");
+
+       dhd_save_fwdump(bus->dhd, buf, bus->ramsize);
+       /* free buf before return !!! */
+       if (write_to_file(bus->dhd, buf, bus->ramsize))
+       {
+               printf("%s: Error writing to files\n", __FUNCTION__);
+               return -1;
+       }
+
+       /* buf free handled in write_to_file, not here */
+       return 0;
+}
+#endif /* DHD_FW_COREDUMP */
+
+int
+dhd_socram_dump(dhd_bus_t * bus)
+{
+#if defined(DHD_FW_COREDUMP)
+       return (dhdsdio_mem_dump(bus));
+#else
+       return -1;
+#endif
+}
 
 int
 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
@@ -4038,6 +4948,23 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter)
                        bcmerror = dhdsdio_membytes(bus, TRUE, 0,
                                (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
 
+                       if (bcmerror == BCME_OK) {
+                               uint32 tmp;
+
+                               /* verify write */
+                               bcmerror = dhdsdio_membytes(bus, FALSE, 0,
+                                                           (uint8 *)&tmp, sizeof(tmp));
+
+                               if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
+                                       DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
+                                                 __FUNCTION__, bus->resetinstr));
+                                       DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
+                                                 __FUNCTION__, tmp));
+                                       bcmerror = BCME_SDIO_ERROR;
+                                       goto fail;
+                               }
+                       }
+
                        /* now remove reset and halt and continue to run CR4 */
                }
 
@@ -4199,9 +5126,6 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
 
                BUS_WAKE(bus);
 
-               /* Change our idea of bus state */
-               bus->dhd->busstate = DHD_BUS_DOWN;
-
                if (KSO_ENAB(bus)) {
 
                /* Enable clock for device interrupts */
@@ -4225,9 +5149,7 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
 
                /* Turn off the bus (F2), free any pending packets */
                DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
-#if !defined(NDISVER) || (NDISVER < 0x0630)
                bcmsdh_intr_disable(bus->sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
                bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
 
                /* Clear any pending interrupts now that F2 is disabled */
@@ -4236,6 +5158,9 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
 
                /* Turn off the backplane clock (only) */
                dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
+
+               /* Change our idea of bus state */
+               bus->dhd->busstate = DHD_BUS_DOWN;
        }
 
 #ifdef PROP_TXSTATUS
@@ -4315,6 +5240,7 @@ dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
 #endif /* BCMSDIOH_TXGLOM */
                bus->txglom_enable = FALSE;
        printf("%s: enable %d\n",  __FUNCTION__, bus->txglom_enable);
+       dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
 }
 
 int
@@ -4405,6 +5331,13 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
                /* Set bus state according to enable result */
                dhdp->busstate = DHD_BUS_DATA;
 
+               /* Need to set fn2 block size to match fn1 block size.
+                * Requests to fn2 go thru fn1. *
+                * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
+                * It would be cleaner to use the ->sdh->block_sz[fno] instead of
+                * 64, but this layer has no access to sdh types.
+                */
+
                /* bcmsdh_intr_unmask(bus->sdh); */
 
                bus->intdis = FALSE;
@@ -4420,6 +5353,10 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
 
 
        else {
+               if (dhdp->conf->chip == BCM4354_CHIP_ID) {
+                       ret = -1;
+                       goto exit;
+               }
                /* Disable F2 again */
                enable = SDIO_FUNC_ENABLE_1;
                bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
@@ -5126,7 +6063,13 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
                        dhdsdio_sendpendctl(bus);
                } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
                        !bus->fcstate && DATAOK(bus) &&
-                       (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
+                       (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres) &&
+                       bus->dhd->conf->tx_in_rx) {
+#if defined(SWTXGLOM)
+                       if (bus->dhd->conf->swtxglom)
+                               dhdsdio_sendfromq_swtxglom(bus, dhd_txbound);
+                       else
+#endif
                        dhdsdio_sendfromq(bus, dhd_txbound);
 #ifdef DHDTCPACK_SUPPRESS
                        /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
@@ -5773,14 +6716,12 @@ dhdsdio_hostmail(dhd_bus_t *bus)
                bus->flowcontrol = fcbits;
        }
 
-#ifdef DHD_DEBUG
        /* At least print a message if FW halted */
        if (hmb_data & HMB_DATA_FWHALT) {
                DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
                dhdsdio_checkdied(bus, NULL, 0);
                bus->dhd->busstate = DHD_BUS_DOWN;
        }
-#endif /* DHD_DEBUG */
 
        /* Shouldn't be any others */
        if (hmb_data & ~(HMB_DATA_DEVREADY |
@@ -5808,6 +6749,9 @@ dhdsdio_dpc(dhd_bus_t *bus)
        uint framecnt = 0;                /* Temporary counter of tx/rx frames */
        bool rxdone = TRUE;               /* Flag for no more read data */
        bool resched = FALSE;     /* Flag indicating resched wanted */
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+       bool is_resched_by_readframe = FALSE;
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
        DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
        dhd_os_sdlock(bus->dhd);
@@ -5982,9 +6926,7 @@ clkwait:
 #if defined(OOB_INTR_ONLY)
                bcmsdh_oob_intr_set(bus->sdh, TRUE);
 #endif /* defined(OOB_INTR_ONLY) */
-#if !defined(NDISVER) || (NDISVER < 0x0630)
                bcmsdh_intr_enable(sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
        }
 
 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
@@ -6014,12 +6956,24 @@ clkwait:
        else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
            pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
                framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
+#if defined(SWTXGLOM)
+               if (bus->dhd->conf->swtxglom)
+                       framecnt = dhdsdio_sendfromq_swtxglom(bus, framecnt);
+               else
+#endif
                framecnt = dhdsdio_sendfromq(bus, framecnt);
                txlimit -= framecnt;
        }
        /* Resched the DPC if ctrl cmd is pending on bus credit */
-       if (bus->ctrl_frame_stat)
+       if (bus->ctrl_frame_stat) {
+               if (bus->dhd->conf->txctl_tmo_fix) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (!kthread_should_stop())
+                               schedule_timeout(1);
+                       set_current_state(TASK_RUNNING);
+               }
                resched = TRUE;
+       }
 
        /* Resched if events or tx frames are pending, else await next interrupt */
        /* On failed register access, all bets are off: no resched or interrupts */
@@ -6054,11 +7008,26 @@ clkwait:
 exit:
 
        if (!resched && dhd_dpcpoll) {
-               if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
+               if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
                        resched = TRUE;
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+                       is_resched_by_readframe = TRUE;
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
+               }
        }
 
        dhd_os_sdunlock(bus->dhd);
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+       if (bus->dhd->dhd_bug_on) {
+               DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
+                       " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
+                       __FUNCTION__, resched, bus->ctrl_frame_stat,
+                       bus->intstatus, bus->ipend,
+                       pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe));
+
+                       bus->dhd->dhd_bug_on = FALSE;
+       }
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
        return resched;
 }
 
@@ -6116,9 +7085,7 @@ dhdsdio_isr(void *arg)
                DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
        }
 
-#if !defined(NDISVER) || (NDISVER < 0x0630)
        bcmsdh_intr_disable(sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
        bus->intdis = TRUE;
 
 #if defined(SDIO_ISR_THREAD)
@@ -6133,16 +7100,35 @@ dhdsdio_isr(void *arg)
        }
        DHD_OS_WAKE_UNLOCK(bus->dhd);
 #else
-
-#if !defined(NDISVER) || (NDISVER < 0x0630)
        bus->dpc_sched = TRUE;
        dhd_sched_dpc(bus->dhd);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
 
 #endif /* defined(SDIO_ISR_THREAD) */
 
 }
 
+#ifdef PKT_STATICS
+void dhdsdio_txpktstatics(void)
+{
+       uint total, f1, f2, f3, f4;
+       printf("Randy: TYPE EVENT: %d pkts (size=%d) transfered\n", tx_statics.event_count, tx_statics.event_size);
+       printf("Randy: TYPE CTRL:  %d pkts (size=%d) transfered\n", tx_statics.ctrl_count, tx_statics.ctrl_size);
+       printf("Randy: TYPE DATA:  %d pkts (size=%d) transfered\n", tx_statics.data_count, tx_statics.data_size);
+       if(tx_statics.glom_1_count || tx_statics.glom_3_count || tx_statics.glom_3_8_count || tx_statics.glom_8_count) {
+               total = tx_statics.glom_1_count + tx_statics.glom_3_count + tx_statics.glom_3_8_count + tx_statics.glom_8_count;
+               f1 = (tx_statics.glom_1_count*100) / total;
+               f2 = (tx_statics.glom_3_count*100) / total;
+               f3 = (tx_statics.glom_3_8_count*100) / total;
+               f4 = (tx_statics.glom_8_count*100) / total;
+               printf("Randy: glomsize==1: %d(%d), tglomsize==2: %d(%d), pkts 3<=glomsize<8: %d(%d), pkts glomszie>=8: %d(%d)\n",
+                       tx_statics.glom_1_count, f1, tx_statics.glom_3_count, f2, tx_statics.glom_3_8_count, f3, tx_statics.glom_8_count, f4);
+               printf("Randy: data/glom=%d, glom_max=%d\n", tx_statics.data_count/total, tx_statics.glom_max);
+       }
+       printf("Randy: TYPE RX GLOM: %d pkts (size=%d) transfered\n", tx_statics.glom_count, tx_statics.glom_size);
+       printf("Randy: TYPE TEST: %d pkts (size=%d) transfered\n\n\n", tx_statics.test_count, tx_statics.test_size);
+}
+#endif
+
 #ifdef SDTEST
 static void
 dhdsdio_pktgen_init(dhd_bus_t *bus)
@@ -6547,6 +7533,11 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
                bus->lastintrs = bus->intrcount;
        }
 
+       if ((!bus->dpc_sched) && pktq_len(&bus->txq)) {
+               bus->dpc_sched = TRUE;
+               dhd_sched_dpc(bus->dhd);
+       }
+
 #ifdef DHD_DEBUG
        /* Poll for console output periodically */
        if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
@@ -6586,7 +7577,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
 
                if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
                        DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
-                       if (SLPAUTO_ENAB(bus)) {
+                       if (!bus->poll && SLPAUTO_ENAB(bus)) {
                                if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
                                        dhd_os_wd_timer(bus->dhd, 0);
                        } else
@@ -6601,7 +7592,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
                        bus->idlecount = 0;
                        if (bus->activity) {
                                bus->activity = FALSE;
-                               if (SLPAUTO_ENAB(bus)) {
+                               if (!bus->poll && SLPAUTO_ENAB(bus)) {
                                        if (!bus->readframes)
                                                dhdsdio_bussleep(bus, TRUE);
                                        else
@@ -6754,7 +7745,7 @@ dhdsdio_chipmatch(uint16 chipid)
                return TRUE;
        if (chipid == BCM43349_CHIP_ID)
                return TRUE;
-       if (chipid == BCM4345_CHIP_ID)
+       if (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID)
                return TRUE;
        if (chipid == BCM4350_CHIP_ID)
                return TRUE;
@@ -6783,7 +7774,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 {
        int ret;
        dhd_bus_t *bus;
+#ifdef GET_OTP_MAC_ENABLE
        struct ether_addr ea_addr;
+#endif
 
 #if defined(MULTIPLE_SUPPLICANT)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
@@ -6809,11 +7802,10 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
        sd1idle = TRUE;
        dhd_readahead = TRUE;
        retrydata = FALSE;
-#if !defined(PLATFORM_MPS)
+
+#ifdef DISABLE_FLOW_CONTROL
        dhd_doflow = FALSE;
-#else
-       dhd_doflow = TRUE;
-#endif /* OEM_ANDROID */
+#endif /* DISABLE_FLOW_CONTROL */
        dhd_dongle_ramsize = 0;
        dhd_txminmax = DHD_TXMINMAX;
 
@@ -6893,6 +7885,10 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
        bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
        bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
 
+#if defined(SUPPORT_P2P_GO_PS)
+       init_waitqueue_head(&bus->bus_sleep);
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
+
        /* attempt to attach to the dongle */
        if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
                DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
@@ -6942,6 +7938,14 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
                                goto fail;
                }
        }
+       else {
+               /* Set random MAC address during boot time */
+               get_random_bytes(&bus->dhd->mac.octet[3], 3);
+               /* Adding BRCM OUI */
+               bus->dhd->mac.octet[0] = 0;
+               bus->dhd->mac.octet[1] = 0x90;
+               bus->dhd->mac.octet[2] = 0x4C;
+       }
 #endif
 
 #ifdef GET_OTP_MAC_ENABLE
@@ -6957,6 +7961,14 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
                goto fail;
        }
 
+#ifdef BCMHOST_XTAL_PU_TIME_MOD
+       bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11);
+#ifdef BCM4330_CHIP
+       bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x0000F801);
+#else
+       bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001);
+#endif /* BCM4330_CHIP */
+#endif /* BCMHOST_XTAL_PU_TIME_MOD */
 
 #if defined(MULTIPLE_SUPPLICANT)
        wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
@@ -6966,8 +7978,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
 #endif 
 
-       init_waitqueue_head(&bus->bus_sleep);
-
        return bus;
 
 fail:
@@ -6984,284 +7994,6 @@ forcereturn:
        return NULL;
 }
 
-#ifdef REGON_BP_HANG_FIX
-static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
-{
-       uint32 temp = 0;
-       DHD_ERROR(("Resetting  the backplane to avoid failure in firmware download..\n"));
-
-       temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
-       DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
-
-       /* Force HT req from PMU */
-       bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
-
-       /* Increase the clock stretch duration. */
-       bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
-
-       /* Setting ALP clock request in SDIOD clock control status register */
-       bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
-
-       /* Allowing clock from SR engine to SR memory */
-       bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
-       /* Disabling SR Engine before SR binary download. */
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
-
-       /* Enabling clock from backplane to SR memory */
-       bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
-
-       /* Initializing SR memory address register in SOCRAM */
-       bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
-
-       /* Downloading the SR binary */
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
-       bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
-       /* SR Binary Download complete */
-
-       /* Allowing clock from SR engine to SR memory */
-       bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
-
-       /* Turning ON SR Engine to initiate backplane reset  Repeated ?? Maharana */
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
-       bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
-       temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
-       DHD_INFO(("0x18000654 = %x\n", temp));
-       bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
-       OSL_DELAY(100000);
-       /* Rolling back the original values for clock stretch and PMU timers */
-       bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
-       bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
-       /* Removing ALP clock request in SDIOD clock control status register */
-       bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
-       OSL_DELAY(10000);
-       return TRUE;
-}
-
-static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
-{
-       uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
-       /* Removing reset of D11 Core */
-       bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
-       bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
-       bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
-       /* Reading CLB XTAL BT cntrl register */
-       bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
-       bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
-       bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
-       /* Read if BT is powered up */
-       temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
-       /* Read BT_ready from WLAN wireless register */
-       temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
-       /*
-       Check if the BT is powered up and ready. The duration between BT being powered up
-       and BT becoming ready is the problematic window for WLAN. If we move ahead at this
-       time then we may encounter a corrupted backplane later. So we wait for BT to be ready
-       and then proceed after checking the health of the backplane. If the backplane shows
-       indications of failure then we  have to do a full reset of the backplane using SR engine
-       and then proceed.
-       */
-       (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
-       (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
-       DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
-               "BT_ready = %x \n", BT_pwr_up, BT_ready));
-       while (BT_pwr_up && !BT_ready)
-       {
-               OSL_DELAY(1000);
-               bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
-               temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
-               temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
-               (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
-               (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
-               counter++;
-               if (counter == 5000)
-               {
-                       DHD_ERROR(("WARNING: Going ahead after 5 secs with"
-                                       "risk of failure because BT ready is not yet set\n"));
-                       break;
-               }
-       }
-       DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
-                       "\n", BT_pwr_up, BT_ready));
-       counter = 0;
-       OSL_DELAY(10000);
-       /*
-       Get the information of who accessed the crucial backplane entities
-       by reading read and write access registers
-       */
-       DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
-       DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
-                       "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
-       counter = 0;
-       while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
-               (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
-       {
-               if (++counter > 10)
-               {
-                       DHD_ERROR(("Unable to recover the backkplane corruption"
-                                       "..Tried %d times.. Exiting\n", counter));
-                       break;
-               }
-               OSL_DELAY(10000);
-               dhd_sdio_backplane_reset(bus);
-               /*
-               Get the information of who accessed the crucial backplane
-               entities by reading read and write access registers
-               */
-               DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
-               DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
-                               "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
-       }
-       /* Set the WL ready to indicate BT that we are done with backplane reset */
-       DHD_ERROR(("Setting up AXI_OK\n"));
-       bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
-       temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
-       temp |= 0x80000000;
-       bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
-       return TRUE;
-}
-#endif /* REGON_BP_HANG_FIX */
 static bool
 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
                      uint16 devid)
@@ -7277,10 +8009,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
                DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
        }
 
-#if defined(DHD_DEBUG)
+#if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG)
        DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
                bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
-#endif 
+#endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */
 
 
        /* Force PLL off until si_attach() programs PLL control regs */
@@ -7355,11 +8087,6 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
                bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
 #endif /* DHD_DEBUG */
 
-#ifdef REGON_BP_HANG_FIX
-       /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
-       if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
-                       dhdsdio_sdio_hang_war(bus);
-#endif /* REGON_BP_HANG_FIX */
 
        bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
 
@@ -7420,11 +8147,14 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
                                bus->dongle_ram_base = CR4_4360_RAM_BASE;
                                break;
                        case BCM4345_CHIP_ID:
+                       case BCM43454_CHIP_ID:
                                bus->dongle_ram_base = (bus->sih->chiprev < 6)  /* from 4345C0 */
                                        ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
                                break;
                        case BCM4349_CHIP_GRPID:
-                               bus->dongle_ram_base = CR4_4349_RAM_BASE;
+                               /* RAM base changed from 4349c0(revid=9) onwards */
+                               bus->dongle_ram_base = ((bus->sih->chiprev < 9) ?
+                               CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9);
                                break;
                        default:
                                bus->dongle_ram_base = 0;
@@ -7611,19 +8341,14 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
                          __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
        }
        bus->use_rxchain = (bool)bus->sd_rxchain;
-       if (bus->dhd->conf->use_rxchain >= 0) {
-               printf("%s: set use_rxchain %d from config.txt\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
-               bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
-       }
-       /* Setting default Glom size */
-       if (bus->dhd->conf->txglomsize >= 0) {
-               printf("%s: set txglomsize %d from config.txt\n", __FUNCTION__, bus->dhd->conf->txglomsize);
-               bus->txglomsize = bus->dhd->conf->txglomsize;
-       }
        bus->txinrx_thres = CUSTOM_TXINRX_THRES;
        /* TX first in dhdsdio_readframes() */
        bus->dotxinrx = TRUE;
 
+#ifdef PKT_STATICS
+       memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
+
        return TRUE;
 }
 
@@ -7648,6 +8373,7 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
 {
        int ret;
 
+
        DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
                __FUNCTION__, bus->fw_path, bus->nv_path));
        DHD_OS_WAKE_LOCK(bus->dhd);
@@ -7658,10 +8384,25 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
        /* External conf takes precedence if specified */
        dhd_conf_preinit(bus->dhd);
        dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
-       dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path);
+       dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
        dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
        dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
        dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
+       if (bus->dhd->conf->dhd_poll >= 0) {
+               printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
+               bus->poll = TRUE;
+               if (!bus->pollrate)
+                       bus->pollrate = 1;
+       }
+       if (bus->dhd->conf->use_rxchain >= 0) {
+               printf("%s: set use_rxchain %d\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
+               bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
+       }
+       if (bus->dhd->conf->txglomsize >= 0) {
+               printf("%s: set txglomsize %d\n", __FUNCTION__, bus->dhd->conf->txglomsize);
+               bus->txglomsize = bus->dhd->conf->txglomsize;
+       }
+       bcmsdh_set_mode(sdh, bus->dhd->conf->txglom_mode);
 
        printf("Final fw_path=%s\n", bus->fw_path);
        printf("Final nv_path=%s\n", bus->nv_path);
@@ -7821,20 +8562,24 @@ dhdsdio_suspend(void *context)
        int ret = 0;
 
        dhd_bus_t *bus = (dhd_bus_t*)context;
+#ifdef SUPPORT_P2P_GO_PS
        int wait_time = 0;
+
        if (bus->idletime > 0) {
                wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
        }
-
+#endif /* SUPPORT_P2P_GO_PS */
        ret = dhd_os_check_wakelock(bus->dhd);
+#ifdef SUPPORT_P2P_GO_PS
        // terence 20141124: fix for suspend issue
-       if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up)) {
+       if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
                if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
                        if (!bus->sleeping) {
                                return 1;
                        }
                }
        }
+#endif /* SUPPORT_P2P_GO_PS */
        return ret;
 }
 
@@ -8020,10 +8765,10 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
                // terence 20150412: fix for firmware failed to download
                if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
                                bus->dhd->conf->chip == BCM43341_CHIP_ID) {
-               if (len%64 != 0) {
-                   memset(memptr+len, 0, len%64);
-                   len += (64 - len%64);
-               }
+                       if (len%64 != 0) {
+                               memset(memptr+len, 0, len%64);
+                               len += (64 - len%64);
+                       }
                }
                if (len < 0) {
                        DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
@@ -8078,26 +8823,6 @@ err:
        return bcmerror;
 }
 
-/*
-       EXAMPLE: nvram_array
-       nvram_arry format:
-       name=value
-       Use carriage return at the end of each assignment, and an empty string with
-       carriage return at the end of array.
-
-       For example:
-       unsigned char  nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
-       Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
-
-       Search "EXAMPLE: nvram_array" to see how the array is activated.
-*/
-
-void
-dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
-{
-       bus->nvram_params = nvram_params;
-}
-
 static int
 dhdsdio_download_nvram(struct dhd_bus *bus)
 {
@@ -8112,9 +8837,8 @@ dhdsdio_download_nvram(struct dhd_bus *bus)
        pnv_path = bus->nv_path;
 
        nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
-       if (!nvram_file_exists && (bus->nvram_params == NULL))
-               return (0);
 
+       /* For Get nvram from UEFI */
        if (nvram_file_exists) {
                image = dhd_os_open_image(pnv_path);
                if (image == NULL) {
@@ -8130,15 +8854,9 @@ dhdsdio_download_nvram(struct dhd_bus *bus)
                goto err;
        }
 
-       /* Download variables */
-       if (nvram_file_exists) {
-               len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
-       }
-       else {
-               len = strlen(bus->nvram_params);
-               ASSERT(len <= MAX_NVRAMBUF_SIZE);
-               memcpy(memblock, bus->nvram_params, len);
-       }
+       /* For Get nvram from image or UEFI (when image == NULL ) */
+       len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
+
        if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
                bufp = (char *)memblock;
                bufp[len] = 0;
@@ -8228,10 +8946,6 @@ _dhdsdio_download_firmware(struct dhd_bus *bus)
                goto err;
        }
 
-       /* EXAMPLE: nvram_array */
-       /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
-       /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
-
        /* External nvram takes precedence if specified */
        if (dhdsdio_download_nvram(bus)) {
                DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
@@ -8316,6 +9030,18 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf
        return ret;
 }
 
+uint8
+dhd_bus_is_ioready(struct dhd_bus *bus)
+{
+       uint8 enable;
+       bcmsdh_info_t *sdh;
+       ASSERT(bus);
+       ASSERT(bus->sih != NULL);
+       enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
+       sdh = bus->sdh;
+       return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
+}
+
 uint
 dhd_bus_chip(struct dhd_bus *bus)
 {
@@ -8427,6 +9153,8 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                                bcmsdh_oob_intr_register(bus->sdh,
                                                        dhdsdio_isr, bus);
                                                bcmsdh_oob_intr_set(bus->sdh, TRUE);
+#elif defined(FORCE_WOWLAN)
+                                               dhd_enable_oob_intr(bus, TRUE);
 #endif 
 
                                                bus->dhd->dongle_reset = FALSE;
@@ -8444,8 +9172,15 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                                dhdsdio_release_dongle(bus, bus->dhd->osh,
                                                        TRUE, FALSE);
                                        }
-                               } else
+                               } else {
+                                       DHD_ERROR(("%s Failed to download binary to the dongle\n",
+                                               __FUNCTION__));
+                                       if (bus->sih != NULL) {
+                                               si_detach(bus->sih);
+                                               bus->sih = NULL;
+                                       }
                                        bcmerror = BCME_SDIO_ERROR;
+                               }
                        } else
                                bcmerror = BCME_SDIO_ERROR;
 
@@ -8456,7 +9191,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                __FUNCTION__);
                        printf("Will call dhd_bus_start instead\n");
                        dhd_bus_resume(dhdp, 1);
-#if defined(HW_OOB)
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
                        dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
 #endif
                        if ((bcmerror = dhd_bus_start(dhdp)) != 0)
@@ -8464,6 +9199,10 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                        __FUNCTION__, bcmerror));
                }
        }
+
+#ifdef PKT_STATICS
+       memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
        return bcmerror;
 }
 
@@ -8524,25 +9263,6 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si
        return dhdsdio_membytes(bus, set, address, data, size);
 }
 
-#if defined(NDISVER) && (NDISVER >= 0x0630)
-void
-dhd_bus_reject_ioreqs(dhd_pub_t *dhdp, bool reject)
-{
-
-       DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-       bcmsdh_reject_ioreqs(dhdp->bus->sdh, reject);
-}
-
-void
-dhd_bus_waitfor_iodrain(dhd_pub_t *dhdp)
-{
-
-       DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-       bcmsdh_waitfor_iodrain(dhdp->bus->sdh);
-}
-#endif /* (NDISVER) && (NDISVER >= 0x0630) */
 
 void
 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
@@ -8666,28 +9386,3 @@ void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
        dhd_os_sdunlock(bus->dhd);
 }
 #endif /* DEBUGGER */
-
-#if defined(SOFTAP_TPUT_ENHANCE)
-void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time)
-{
-       if (!dhdp || !dhdp->bus) {
-               DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
-               return;
-       }
-       dhdp->bus->idletime = idle_time;
-}
-
-void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time)
-{
-       if (!dhdp || !dhdp->bus) {
-               DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
-               return;
-       }
-
-       if (!idle_time) {
-               DHD_ERROR(("%s:Arg idle_time is NULL\n", __FUNCTION__));
-               return;
-       }
-       *idle_time = dhdp->bus->idletime;
-}
-#endif /* SOFTAP_TPUT_ENHANCE */