diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_sdio.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_sdio.c | 1407 |
1 files changed, 1104 insertions, 303 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 422ad034f5e..138e8e5d0f0 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * 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 357859 2012-09-20 06:34:26Z $ + * $Id: dhd_sdio.c 394690 2013-04-03 09:18:44Z $ */ #include <typedefs.h> @@ -79,10 +79,13 @@ #define PRIOMASK 7 #define TXRETRIES 2 /* # of retries for tx frames */ - +#ifndef DHD_RXBOUND #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ +#endif +#ifndef DHD_TXBOUND #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ +#endif #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ @@ -155,7 +158,9 @@ extern void bcmsdh_set_irq(int flag); #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ #ifdef PROP_TXSTATUS extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); +extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd); #endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) DEFINE_MUTEX(_dhd_sdio_mutex_lock_); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ @@ -183,14 +188,16 @@ typedef struct dhd_console { #define MIN_RSRC_SR 0x3 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define RCTL_LOGIC_DISABLE_MASK (1 << 27) +#define RCTL_MACPHY_DISABLE_MASK (1 << 26) +#define RCTL_LOGIC_DISABLE_MASK (1 << 27) #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) +#define OVERFLOW_BLKSZ512_WM 48 +#define OVERFLOW_BLKSZ512_MES 80 #define CC_PMUCC3 (0x3) /* Private data for SDIO bus interaction */ @@ -304,6 +311,13 @@ typedef struct dhd_bus { uint pktgen_ptick; /* Burst counter for printing */ uint pktgen_sent; /* Number of test packets generated */ uint pktgen_rcvd; /* Number of test packets received */ + uint pktgen_prev_time; /* Time at which previous stats where printed */ + uint pktgen_prev_sent; /* Number of test packets generated when + * previous stats were printed + */ + uint pktgen_prev_rcvd; /* Number of test packets received when + * previous stats were printed + */ uint pktgen_fail; /* Number of failed send attempts */ uint16 pktgen_len; /* Length of next packet to send */ #define PKTGEN_RCV_IDLE (0) @@ -391,7 +405,11 @@ uint dhd_txminmax = DHD_TXMINMAX; #define DONGLE_MIN_MEMSIZE (128 *1024) int dhd_dongle_memsize; +#ifndef REPEAT_READFRAME static bool dhd_doflow; +#else +extern bool dhd_doflow; +#endif /* REPEAT_READFRAME */ static bool dhd_alignctl; static bool sd1idle; @@ -399,13 +417,17 @@ static bool sd1idle; static bool retrydata; #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) -#if defined(SDIO_CRC_ERROR_FIX) +#ifdef BCMSPI +/* At a watermark around 8 the spid hits underflow error. */ +static const uint watermark = 32; +static const uint mesbusyctrl = 0; +#elif defined(SDIO_CRC_ERROR_FIX) static uint watermark = 48; static uint mesbusyctrl = 80; #else static const uint watermark = 8; static const uint mesbusyctrl = 0; -#endif +#endif /* BCMSPI */ static const uint firstread = DHD_FIRSTREAD; #define HDATLEN (firstread - (SDPCM_HDRLEN)) @@ -443,7 +465,6 @@ static const uint max_roundup = 512; /* Try doing readahead */ static bool dhd_readahead; - /* To check if there's window offered */ #define DATAOK(bus) \ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ @@ -538,7 +559,7 @@ do { \ \ R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \ printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \ - dstatussw, dstatushw, intstatuserr); \ + dstatussw, dstatushw, intstatuserr); \ \ bus->nextlen = 0; \ *finished = TRUE; \ @@ -561,7 +582,7 @@ do { \ #ifdef SDTEST static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count); +static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); #endif #ifdef DHD_DEBUG @@ -591,7 +612,7 @@ static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); #ifdef BCMSDIOH_TXGLOM -static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); +static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len); static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); #endif @@ -613,6 +634,39 @@ extern uint32 dhd_get_htsf(void *dhd, int ifidx); #endif /* WLMEDIA_HTSF */ static void +dhd_overflow_war(struct dhd_bus *bus) +{ + int err; + uint8 devctl, wm, mes; + + /* See .ppt in PR for these recommended values */ + if (bus->blocksize == 512) { + wm = OVERFLOW_BLKSZ512_WM; + mes = OVERFLOW_BLKSZ512_MES; + } else { + mes = bus->blocksize/4; + wm = bus->blocksize/4; + } + + + /* Update watermark */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); + + devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl |= SBSDIO_DEVCTL_F2WM_ENAB; + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + + /* Update MES */ + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, + (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); + + DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), + bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); +} + +static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) { int32 min_size = DONGLE_MIN_MEMSIZE; @@ -693,7 +747,7 @@ static bool dhdsdio_sr_cap(dhd_bus_t *bus) { bool cap = FALSE; - uint32 min = 0, core_capext, addr, data; + uint32 core_capext, addr, data; if (bus->sih->chip == BCM4324_CHIP_ID) { addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); @@ -712,9 +766,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus) if (bus->sih->chip == BCM4324_CHIP_ID) { /* FIX: Should change to query SR control register instead */ - min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); - if (min == MIN_RSRC_SR) - cap = TRUE; + cap = TRUE; } else if (bus->sih->chip == BCM4335_CHIP_ID) { uint32 enabval = 0; addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); @@ -807,7 +859,12 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus) } #define KSO_DBG(x) +#define KSO_WAIT_US 50 +#if defined(CUSTOMER_HW4) #define MAX_KSO_ATTEMPTS 64 +#else +#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) +#endif /* CUSTOMER_HW4 */ static int dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) { @@ -826,9 +883,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) bmask = cmp_val; msleep(3); - } else { - /* Put device to sleep, turn off KSO */ + /* Put device to sleep, turn off KSO */ cmp_val = 0; bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; } @@ -839,17 +895,15 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) break; KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); - OSL_DELAY(50); + 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); - if (try_cnt > 1) { + 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) { DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", @@ -1061,6 +1115,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) bus->kso = on ? FALSE : TRUE; else { DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err)); + if (!on && retry > 2) + bus->kso = TRUE; } return err; @@ -1078,9 +1134,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) - pendok = FALSE; -#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ clkctl = 0; sdh = bus->sdh; @@ -1119,12 +1172,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) ht_avail_error = 0; } - if (pendok && - ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { - uint32 dummy, retries; - R_SDREG(dummy, &bus->regs->clockctlstatus, retries); - BCM_REFERENCE(dummy); - } /* Check current status */ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -1133,6 +1180,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) return BCME_ERROR; } +#if !defined(OOB_INTR_ONLY) /* Go to pending and await interrupt if appropriate */ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { /* Allow only clock-available interrupt */ @@ -1148,11 +1196,15 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) DHD_INFO(("CLKCTL: set PENDING\n")); bus->clkstate = CLK_PENDING; return BCME_OK; - } else if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } else +#endif /* !defined (OOB_INTR_ONLY) */ + { + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); + } } /* Otherwise, wait here (polling) for HT Avail */ @@ -1196,6 +1248,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) #endif /* DHD_USE_IDLECOUNT */ } else { clkreq = 0; + if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); @@ -1484,16 +1537,15 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) return err; } -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) -int -dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) +#if defined(CUSTOMER_HW4) && defined(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), 0); + bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, + sizeof(int), &result, sizeof(int), IOV_GET); if (bcmerr != BCME_OK) { DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num)); @@ -1501,14 +1553,11 @@ dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) } if (result != block_size) { - - DHD_ERROR(("%s: F%d Block size set from %d to %d\n", __FUNCTION__, - function_num, 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", &func_blk_size, sizeof(int32), - &result, sizeof(int32), 1); - + 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; @@ -1516,9 +1565,8 @@ dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) } return BCME_OK; - } -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ #if defined(OOB_INTR_ONLY) void @@ -1551,6 +1599,236 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) } #endif /* defined(OOB_INTR_ONLY) */ + +#ifdef DHDTCPACK_SUPPRESS +extern bool dhd_use_tcpack_suppress; + +/* Please be sure this function is called under dhd_os_tcpacklock() */ +void dhd_onoff_tcpack_sup(void *pub, bool on) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)pub; + + if (dhd_use_tcpack_suppress != on) { + + DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on)); + dhd_use_tcpack_suppress = on; + dhdp->tcp_ack_info_cnt = 0; + bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); + + } else + DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on)); + + return; +} + +inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) +{ + uint8 i; + tcp_ack_info_t *tcp_ack_info = NULL; + int tbl_cnt; + + dhd_os_tcpacklock(dhdp); + tbl_cnt = dhdp->tcp_ack_info_cnt; + for (i = 0; i < tbl_cnt; i++) { + tcp_ack_info = &dhdp->tcp_ack_info_tbl[i]; + if (tcp_ack_info->p_tcpackinqueue == pkt) { + /* This pkt is being transmitted so remove the tcp_ack_info of it. + * compact the array unless the last element, + * then the pkt's array is removed. + */ + if (i < tbl_cnt-1) { + memmove(&dhdp->tcp_ack_info_tbl[i], + &dhdp->tcp_ack_info_tbl[i+1], + sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1))); + } + bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info)); + if (--dhdp->tcp_ack_info_cnt < 0) { + DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d" + " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt)); + dhd_onoff_tcpack_sup(dhdp, FALSE); + } + break; + } + } + dhd_os_tcpackunlock(dhdp); +} + +bool +dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) +{ + uint8 *eh_header; + uint16 eh_type; + uint8 *ip_header; + uint8 *tcp_header; + uint32 ip_hdr_len; + uint32 cur_framelen; + uint8 bdc_hdr_len = BDC_HEADER_LEN; + uint8 wlfc_hdr_len = 0; + uint8 *data = PKTDATA(dhdp->osh, pkt); + cur_framelen = PKTLEN(dhdp->osh, pkt); + +#ifdef PROP_TXSTATUS + /* In this case, BDC header is not pushed in dhd_sendpkt() */ + if (dhdp->wlfc_state) { + bdc_hdr_len = 0; + wlfc_hdr_len = 8; + } +#endif + if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) { + DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen)); + return FALSE; + } + + /* Get rid of BDC header */ + eh_header = data + bdc_hdr_len; + cur_framelen -= bdc_hdr_len; + eh_type = eh_header[12] << 8 | eh_header[13]; + + if (eh_type != ETHER_TYPE_IP) { + DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type)); + return FALSE; + } + + DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type)); + + ip_header = eh_header + ETHER_HDR_LEN; + cur_framelen -= ETHER_HDR_LEN; + ip_hdr_len = 4 * (ip_header[0] & 0x0f); + + if ((ip_header[0] & 0xf0) != 0x40) { + DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n")); + return FALSE; + } + + if (cur_framelen < ip_hdr_len) { + DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen)); + return FALSE; + } + + /* not tcp */ + if (ip_header[9] != 0x06) { + DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9])); + return FALSE; + } + + DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n")); + + tcp_header = ip_header + ip_hdr_len; + + /* is it an ack ? */ + if (tcp_header[13] == 0x10) { +#if defined(DHD_DEBUG) + uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 | + tcp_header[6] << 8 | tcp_header[7]; +#endif + uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 | + tcp_header[10] << 8 | tcp_header[11]; + uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8); + uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4); + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n", + tcp_seq_num, tcp_ack_num)); + + + /* zero length ? */ + if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) { + int i; + tcp_ack_info_t *tcp_ack_info = NULL; + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n")); + /* Look for tcp_ack_info that has the same + * ip src/dst addrs and tcp src/dst ports + */ + dhd_os_tcpacklock(dhdp); + for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) { + if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue && + !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) && + !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) { + tcp_ack_info = &dhdp->tcp_ack_info_tbl[i]; + break; + } + } + + if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS) + tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++]; + + if (!tcp_ack_info) { + DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info" + "%d %d %d %d, %d %d %d %d\n", + tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3], + dhdp->tcp_ack_info_tbl[i].tcpports[0], + dhdp->tcp_ack_info_tbl[i].tcpports[1], + dhdp->tcp_ack_info_tbl[i].tcpports[2], + dhdp->tcp_ack_info_tbl[i].tcpports[3])); + dhd_os_tcpackunlock(dhdp); + return FALSE; + } + + if (tcp_ack_info->p_tcpackinqueue) { + if (tcp_ack_num > tcp_ack_info->tcpack_number) { + void *prevpkt = tcp_ack_info->p_tcpackinqueue; + uint8 pushed_len = SDPCM_HDRLEN + + (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len; +#ifdef PROP_TXSTATUS + /* In case the prev pkt is delayenqueued + * but not delayedequeued yet, it may not have + * any additional header yet. + */ + if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) == + tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN)) + pushed_len = 0; +#endif + if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) && + (PKTLEN(dhdp->osh, pkt) == + PKTLEN(dhdp->osh, prevpkt) - pushed_len)) { + bcopy(PKTDATA(dhdp->osh, pkt), + PKTDATA(dhdp->osh, prevpkt) + pushed_len, + PKTLEN(dhdp->osh, pkt)); + PKTFREE(dhdp->osh, pkt, FALSE); + DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p" + " TCP ACK replace %ud -> %ud\n", prevpkt, + tcp_ack_info->tcpack_number, tcp_ack_num)); + tcp_ack_info->tcpack_number = tcp_ack_num; + dhd_os_tcpackunlock(dhdp); + return TRUE; + } else + DHD_TRACE(("dhd_tcpack_suppress: len mismatch" + " %d(%d) %d(%d)\n", + PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen, + PKTLEN(dhdp->osh, prevpkt), + tcp_ack_info->ip_tcp_ttllen)); + } else { +#ifdef TCPACK_TEST + void *prevpkt = tcp_ack_info->p_tcpackinqueue; +#endif + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse" + " prev %ud (0x%p) new %ud (0x%p)\n", + tcp_ack_info->tcpack_number, + tcp_ack_info->p_tcpackinqueue, + tcp_ack_num, pkt)); +#ifdef TCPACK_TEST + if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) { + PKTFREE(dhdp->osh, pkt, FALSE); + dhd_os_tcpackunlock(dhdp); + return TRUE; + } +#endif + } + } else { + tcp_ack_info->p_tcpackinqueue = pkt; + tcp_ack_info->tcpack_number = tcp_ack_num; + tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen; + bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8); + bcopy(tcp_header, tcp_ack_info->tcpports, 4); + } + dhd_os_tcpackunlock(dhdp); + } else + DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n", + ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len)); + } + return FALSE; +} +#endif /* DHDTCPACK_SUPPRESS */ + + /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ static int @@ -1562,6 +1840,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on uint16 len, pad1 = 0; uint32 swheader; uint retries = 0; + uint32 real_pad = 0; bcmsdh_info_t *sdh; void *new; int i; @@ -1574,12 +1853,17 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on htsfts_t *htsf_ts; #endif - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); sdh = bus->sdh; osh = bus->dhd->osh; +#ifdef DHDTCPACK_SUPPRESS + if (dhd_use_tcpack_suppress) { + dhd_tcpack_check_xmit(bus->dhd, pkt); + } +#endif /* DHDTCPACK_SUPPRESS */ + if (bus->dhd->dongle_reset) { ret = BCME_NOTREADY; goto done; @@ -1599,7 +1883,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on #endif /* WLMEDIA_HTSF */ /* Add alignment padding, allocate new packet if needed */ - if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { + 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)); @@ -1649,8 +1933,13 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); if (queue_only) { - if (forcealign && (len & (ALIGNMENT - 1))) - len = ROUNDUP(len, ALIGNMENT); + uint8 alignment = ALIGNMENT; +#if defined(BCMLXSDMMC) && defined(CUSTOMER_HW4) + if (bus->glom_mode == SDPCM_TXGLOM_MDESC) + alignment = DHD_SDALIGN; +#endif /* defined(BCMLXSDMMC) && defined(CUSTOMER_HW4) */ + if (forcealign && (len & (alignment - 1))) + len = ROUNDUP(len, alignment); /* Hardware extention tag */ /* 2byte frame length, 1byte-, 1byte frame flag, * 2byte-hdrlength, 2byte padlenght @@ -1659,8 +1948,19 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on 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(("padding error size %d\n", real_pad)); + } + } +#ifdef BCMLXSDMMC + PKTSETLEN(osh, pkt, len); +#endif /* BCMLXSDMMC */ /* Post the frame pointer to sdio glom array */ - dhd_bcmsdh_glom_post(bus, frame, len); + dhd_bcmsdh_glom_post(bus, frame, pkt, len); /* Save the pkt pointer in bus glom array */ bus->glom_pkt_arr[bus->glom_cnt] = pkt; bus->glom_total_len += len; @@ -1692,9 +1992,20 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on 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(("padding error size %d\n", real_pad)); + } + } +#ifdef BCMLXSDMMC + PKTSETLEN(osh, pkt, len); +#endif /* BCMLXSDMMC */ /* Post the frame pointer to sdio glom array */ - dhd_bcmsdh_glom_post(bus, frame, len); + dhd_bcmsdh_glom_post(bus, frame, pkt, len); /* Save the pkt pointer in bus glom array */ bus->glom_pkt_arr[bus->glom_cnt] = pkt; bus->glom_cnt++; @@ -1708,6 +2019,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on } else #endif /* BCMSDIOH_TXGLOM */ { + uint32 act_len = len; /* Software tag: channel, sequence number, data offset */ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); @@ -1752,8 +2064,15 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on 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(("padding error size %d\n", real_pad)); + } + } } - do { ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, frame, len, pkt, NULL, NULL); @@ -1816,13 +2135,20 @@ done: #ifdef BCMSDIOH_TXGLOM uint32 doff; if (bus->glom_enable) { +#ifdef BCMLXSDMMC + uint32 pad2 = 0; +#endif /* BCMLXSDMMC */ pkt = bus->glom_pkt_arr[bus->glom_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 +#endif /* BCMSDIOH_TXGLOM */ { PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); } @@ -1833,7 +2159,13 @@ done: 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); @@ -1956,8 +2288,6 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) } else ret = BCME_OK; - dhd_os_sdunlock_txq(bus->dhd); - if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); @@ -1965,6 +2295,8 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt) if (pktq_plen(&bus->txq, prec) > qcount[prec]) qcount[prec] = pktq_plen(&bus->txq, prec); #endif + dhd_os_sdunlock_txq(bus->dhd); + /* Schedule DPC if needed to send queued packet(s) */ if (dhd_deferred_tx && !bus->dpc_sched) { bus->dpc_sched = TRUE; @@ -2018,6 +2350,7 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) uint cnt = 0; uint datalen; uint8 tx_prec_map; + uint8 txpktqlen = 0; #ifdef BCMSDIOH_TXGLOM uint i; uint8 glom_cnt; @@ -2034,31 +2367,35 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) } 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->glom_enable) { + void *pkttable[SDPCM_MAXGLOM_SIZE]; + dhd_os_sdlock_txq(bus->dhd); glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); glom_cnt = MIN(glom_cnt, maxframes-cnt); /* Limiting the size to 2pkts in case of copy */ if (bus->glom_mode == SDPCM_TXGLOM_CPY) - glom_cnt = MIN(glom_cnt, 5); + glom_cnt = MIN(glom_cnt, 10); + + for (i = 0; i < glom_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 (glom_cnt == 0) break; datalen = 0; for (i = 0; i < glom_cnt; i++) { - dhd_os_sdlock_txq(bus->dhd); - if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { + if ((pkt = pkttable[i]) == NULL) { /* This case should not happen */ DHD_ERROR(("No pkts in the queue for glomming\n")); - dhd_os_sdunlock_txq(bus->dhd); break; } - dhd_os_sdunlock_txq(bus->dhd); datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); #ifndef SDTEST @@ -2081,9 +2418,11 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) { 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; @@ -2118,12 +2457,68 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) /* Deflow-control stack if needed */ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && - dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) + dhd->txoff && (txpktqlen < FCLOW)) dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); return cnt; } +static void +dhdsdio_sendpendctl(dhd_bus_t *bus) +{ + bcmsdh_info_t *sdh = bus->sdh; + int ret, i; + uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; + +#ifdef BCMSDIOH_TXGLOM + if (bus->glom_enable) + frame_seq += SDPCM_HWEXT_LEN; +#endif + + if (*frame_seq != bus->tx_seq) { + DHD_INFO(("%s IOCTL frame seq lag detected!" + " frm_seq:%d != bus->tx_seq:%d, corrected\n", + __FUNCTION__, *frame_seq, bus->tx_seq)); + *frame_seq = bus->tx_seq; + } + + 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); + 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_INFO(("%s: sdio error %d, abort command and terminate frame.\n", + __FUNCTION__, ret)); + bus->tx_sderrs++; + + bcmsdh_abort(sdh, SDIO_FUNC_2); + + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + bus->f1regdata++; + + for (i = 0; i < 3; 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) { + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + } + + bus->ctrl_frame_stat = FALSE; + dhd_wait_event_wakeup(bus->dhd); +} + int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) { @@ -2235,9 +2630,18 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) ret = 0; } else { bus->dhd->txcnt_timeout++; - if (!bus->dhd->hang_was_sent) + if (!bus->dhd->hang_was_sent) { +#ifdef CUSTOMER_HW4 + 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 */ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", __FUNCTION__, bus->dhd->txcnt_timeout)); + } ret = -1; bus->ctrl_frame_stat = FALSE; goto done; @@ -2309,7 +2713,7 @@ done: else bus->dhd->tx_ctlpkts++; - if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) + if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) return -ETIMEDOUT; return ret ? -EIO : 0; @@ -2338,7 +2742,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) if (rxlen) { DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", - __FUNCTION__, rxlen, msglen)); + __FUNCTION__, rxlen, msglen)); } else if (timeleft == 0) { #ifdef DHD_DEBUG uint32 status, retry = 0; @@ -2367,8 +2771,10 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) #endif /* DHD_DEBUG */ } if (timeleft == 0) { - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); + if (rxlen == 0) + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, + bus->dhd->rxcnt_timeout, rxlen)); } else bus->dhd->rxcnt_timeout = 0; @@ -2378,7 +2784,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) else bus->dhd->rx_ctlerrs++; - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) return -ETIMEDOUT; if (bus->dhd->dongle_trap_occured) @@ -2646,12 +3052,15 @@ dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) bus->pktgen_stop = pktgen.stop; bus->pktgen_tick = bus->pktgen_ptick = 0; + bus->pktgen_prev_time = jiffies; bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); /* Clear counts for a new pktgen (mode change, or was stopped) */ - if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) - bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0; + if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { + bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; + bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; + } return 0; } @@ -2886,6 +3295,9 @@ dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (DHD_NOCHECKDIED_ON()) + return 0; + if (data == NULL) { /* * Called after a rx ctrl timeout. "data" is NULL. @@ -3113,7 +3525,8 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; } else if (bus->sih->chip == BCM4334_CHIP_ID || - bus->sih->chip == BCM43341_CHIP_ID) { + bus->sih->chip == BCM43341_CHIP_ID || + 0) { if (enable) { /* Moved to PMU chipcontrol 1 from 4330 */ int_val &= ~gpio_sel; @@ -3309,6 +3722,16 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, (set ? "write" : "read"), size, address)); + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (address == 0) { + bus->resetinstr = *(((uint32*)params) + 2); + } + /* Add start of RAM address to the address given by user */ + address += bus->dongle_ram_base; + } else { /* If we know about SOCRAM, check for a fit */ if ((bus->orig_ramsize) && ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) @@ -3350,6 +3773,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; } } + } /* Generate the actual data pointer */ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; @@ -3604,13 +4028,14 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_SVAL(IOV_MESBUSYCTRL): mesbusyctrl = (uint)int_val; mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) - ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; + ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ((uint8)mesbusyctrl | 0x80), NULL); break; #endif /* SDIO_CRC_ERROR_FIX */ + case IOV_GVAL(IOV_DONGLEISOLATION): int_val = bus->dhd->dongle_isolation; bcopy(&int_val, arg, val_size); @@ -3840,6 +4265,8 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) int bcmerror = 0; int foundcr4 = 0; + if (!bus->sih) + return BCME_ERROR; /* To enter download state, disable ARM and reset SOCRAM. * To exit download state, simply reset ARM (default is RAM boot). */ @@ -3851,45 +4278,47 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { foundcr4 = 1; } else { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } } if (!foundcr4) { - si_core_disable(bus->sih, 0); - if (bcmsdh_regfail(bus->sdh)) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } + si_core_disable(bus->sih, 0); + if (bcmsdh_regfail(bus->sdh)) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } - /* Disable remap for download */ - if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, FALSE); + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { + si_core_reset(bus->sih, 0, 0); + if (bcmsdh_regfail(bus->sdh)) { + DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", + __FUNCTION__)); bcmerror = BCME_SDIO_ERROR; goto fail; } - } - } else { + + /* Disable remap for download */ + if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, FALSE); + + /* Clear the top bit of memory */ + if (bus->ramsize) { + uint32 zeros = 0; + if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, + (uint8*)&zeros, 4) < 0) { + bcmerror = BCME_SDIO_ERROR; + goto fail; + } + } + } else { /* For CR4, * Halt ARM * Remove ARM reset @@ -3903,42 +4332,44 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) } } else { if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!si_iscoreup(bus->sih)) { + DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, TRUE); + if ((bcmerror = dhdsdio_write_vars(bus))) { + DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); + goto fail; + } - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + /* Enable remap before ARM reset but after vars. + * No backplane access in remap mode + */ + if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) + dhdsdio_devram_remap(bus, TRUE); - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } + if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && + !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { + DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } + W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); + + + if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && + !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { + DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); + bcmerror = BCME_ERROR; + goto fail; + } } else { /* cr4 has no socram, but tcm's */ /* write vars */ @@ -4055,6 +4486,9 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, } else { DHD_INFO(("%s: noted %s update, value now %d\n", __FUNCTION__, "sd_blocksize", bus->blocksize)); + + if (bus->sih->chip == BCM4335_CHIP_ID) + dhd_overflow_war(bus); } } bus->roundup = MIN(max_roundup, bus->blocksize); @@ -4114,10 +4548,12 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) dhd_os_sdlock(bus->dhd); if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { + /* if Firmware already hangs disbale any interrupt */ bus->dhd->busstate = DHD_BUS_DOWN; bus->hostintmask = 0; bcmsdh_intr_disable(bus->sdh); } else { + BUS_WAKE(bus); if (KSO_ENAB(bus)) { @@ -4132,33 +4568,34 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) if (KSO_ENAB(bus)) { - /* Enable clock for device interrupts */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + /* Enable clock for device interrupts */ + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - /* Disable and clear interrupts at the chip level also */ - W_SDREG(0, &bus->regs->hostintmask, retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; + /* Disable and clear interrupts at the chip level also */ + W_SDREG(0, &bus->regs->hostintmask, retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - } + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", + __FUNCTION__, err)); + } - /* Turn off the bus (F2), free any pending packets */ - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); + /* Turn off the bus (F2), free any pending packets */ + DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); + bcmsdh_intr_disable(bus->sdh); #ifndef BCMSPI - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); -#endif + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); +#endif /* !BCMSPI */ - /* Clear any pending interrupts now that F2 is disabled */ - W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); + /* Clear any pending interrupts now that F2 is disabled */ + W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); } /* Turn off the backplane clock (only) */ @@ -4185,6 +4622,8 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) bus->rxskip = FALSE; bus->tx_seq = bus->rx_seq = 0; + bus->tx_max = 4; + if (enforce_mutex) dhd_os_sdunlock(bus->dhd); } @@ -4327,8 +4766,10 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) mesbusyctrl = watermark = bus->blocksize / 4; } #endif /* SDIO_CRC_ERROR_FIX */ - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); + if (bus->sih->chip != BCM4335_CHIP_ID) { + bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, + (uint8)watermark, &err); + } #ifdef SDIO_CRC_ERROR_FIX bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, (uint8)mesbusyctrl|0x80, &err); @@ -4401,12 +4842,21 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) } bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); + goto fail; + } bus->f1regdata++; /* Wait until the packet has been flushed (device/FIFO stable) */ for (lastrbc = retries = 0xffff; retries > 0; retries--) { hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); + lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); + if (err) { + DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); + goto fail; + } + bus->f1regdata += 2; if ((hi == 0) && (lo == 0)) @@ -4437,6 +4887,7 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) /* Clear partial in any case */ bus->nextlen = 0; +fail: /* If we can't reach the device, signal failure */ if (err || bcmsdh_regfail(sdh)) bus->dhd->busstate = DHD_BUS_DOWN; @@ -4542,11 +4993,6 @@ done: dhd_os_ioctl_resp_wake(bus->dhd); } -#ifdef CUSTOMER_HW4 -int pkt_free; -int caller; -void *free_ptr; -#endif static uint8 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) { @@ -4569,9 +5015,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) int ifidx = 0; bool usechain = bus->use_rxchain; -#ifdef CUSTOMER_HW4 - pkt_free = 0; -#endif /* If packets, issue read(s) and send up packet chain */ /* Return sequence numbers consumed? */ @@ -4889,11 +5332,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) reorder_info_len = sizeof(reorder_info_buf); if (PKTLEN(osh, pfirst) == 0) { -#ifdef CUSTOMER_HW4 - pkt_free = 1; - caller = 1; - free_ptr = pfirst; -#endif PKTFREE(bus->dhd->osh, pfirst, FALSE); continue; } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, @@ -4986,7 +5424,12 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) /* Return TRUE if there may be more frames to read */ static uint +#ifdef REPEAT_READFRAME +dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished, bool tx_enable) +#else dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) +#endif + { osl_t *osh = bus->dhd->osh; bcmsdh_info_t *sdh = bus->sdh; @@ -5018,9 +5461,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) bool sdtest = FALSE; /* To limit message spew from test mode */ #endif -#ifdef CUSTOMER_HW4 - pkt_free = 0; -#endif DHD_TRACE(("%s: Enter\n", __FUNCTION__)); bus->readframes = TRUE; @@ -5043,7 +5483,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) /* Not finished unless we encounter no more frames indication */ *finished = FALSE; - #ifdef BCMSPI /* Get pktlen from gSPI device F0 reg. */ if (bus->bus == SPI_BUS) { @@ -5082,8 +5521,19 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) rxseq++, rxleft--) { #ifdef DHDTHREAD + + if ( +#ifdef REPEAT_READFRAME + tx_enable && +#endif + TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) + dhdsdio_sendpendctl(bus); /* tx more to improve rx performance */ - if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + else if ( +#ifdef REPEAT_READFRAME + tx_enable && +#endif + (bus->clkstate == CLK_AVAIL) && !bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { dhdsdio_sendfromq(bus, dhd_txbound); } @@ -5665,11 +6115,6 @@ deliver: if (PKTLEN(osh, pkt) == 0) { dhd_os_sdlock_rxq(bus->dhd); -#ifdef CUSTOMER_HW4 - pkt_free = 1; - caller = 0; - free_ptr = pkt; -#endif PKTFREE(bus->dhd->osh, pkt, FALSE); dhd_os_sdunlock_rxq(bus->dhd); continue; @@ -5692,7 +6137,6 @@ deliver: else pkt_count = 1; - /* Unlock during rx call */ dhd_os_sdunlock(bus->dhd); dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); @@ -5803,7 +6247,7 @@ dhdsdio_hostmail(dhd_bus_t *bus) #ifdef DHD_DEBUG /* At least print a message if FW halted */ if (hmb_data & HMB_DATA_FWHALT) { - DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n")); + DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); dhdsdio_checkdied(bus, NULL, 0); bus->dhd->busstate = DHD_BUS_DOWN; } @@ -5823,6 +6267,10 @@ dhdsdio_hostmail(dhd_bus_t *bus) return intstatus; } +#ifdef REPEAT_READFRAME +extern uint dhd_dpcpoll; +#endif + static bool dhdsdio_dpc(dhd_bus_t *bus) { @@ -5900,7 +6348,6 @@ dhdsdio_dpc(dhd_bus_t *bus) } BUS_WAKE(bus); - /* Make sure backplane clock is on */ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); if (bus->clkstate != CLK_AVAIL) @@ -5931,6 +6378,7 @@ dhdsdio_dpc(dhd_bus_t *bus) intstatus |= newstatus; bus->intstatus = 0; + /* Handle flow-control change: read new state in case our ack * crossed another change interrupt. If change still set, assume * FC ON for safety, let next loop through do the debounce. @@ -5985,7 +6433,11 @@ dhdsdio_dpc(dhd_bus_t *bus) /* On frame indication, read available frames */ if (PKT_AVAILABLE(bus, intstatus)) { +#ifdef REPEAT_READFRAME + framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone, true); +#else framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); +#endif if (rxdone || bus->rxskip) intstatus &= ~FRAME_AVAIL_MASK(bus); rxlimit -= MIN(framecnt, rxlimit); @@ -6025,54 +6477,13 @@ clkwait: } #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - int ret, i; - - uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - - if (*frame_seq != bus->tx_seq) { - DHD_INFO(("%s IOCTL frame seq lag detected!" - " frm_seq:%d != bus->tx_seq:%d, corrected\n", - __FUNCTION__, *frame_seq, bus->tx_seq)); - *frame_seq = bus->tx_seq; - } - - 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); - 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_INFO(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - - bcmsdh_abort(sdh, SDIO_FUNC_2); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; +#ifdef PROP_TXSTATUS + dhd_wlfc_trigger_pktcommit(bus->dhd); +#endif - for (i = 0; i < 3; 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) { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - bus->ctrl_frame_stat = FALSE; - dhd_wait_event_wakeup(bus->dhd); - } + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) + dhdsdio_sendpendctl(bus); /* Send queued frames (limit 1 if rx may still be pending) */ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { @@ -6081,11 +6492,8 @@ clkwait: txlimit -= framecnt; } /* Resched the DPC if ctrl cmd is pending on bus credit */ - if (bus->ctrl_frame_stat) { - DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n", - __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate)); + if (bus->ctrl_frame_stat) 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 */ @@ -6118,6 +6526,12 @@ clkwait: } exit: +#ifdef REPEAT_READFRAME + if (!resched && dhd_dpcpoll) { + resched = dhdsdio_readframes(bus, dhd_rxbound, &rxdone, true); + } +#endif + dhd_os_sdunlock(bus->dhd); return resched; } @@ -6185,7 +6599,6 @@ dhdsdio_isr(void *arg) while (dhdsdio_dpc(bus)); DHD_OS_WAKE_UNLOCK(bus->dhd); #else - bus->dpc_sched = TRUE; dhd_sched_dpc(bus->dhd); @@ -6209,7 +6622,7 @@ dhdsdio_pktgen_init(dhd_bus_t *bus) /* Default to per-watchdog burst with 10s print time */ bus->pktgen_freq = 1; - bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; + bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; /* Default to echo mode */ @@ -6226,19 +6639,37 @@ dhdsdio_pktgen(dhd_bus_t *bus) uint fillbyte; osl_t *osh = bus->dhd->osh; uint16 len; + ulong time_lapse; + uint sent_pkts; + uint rcvd_pkts; /* Display current count if appropriate */ if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { bus->pktgen_ptick = 0; - printf("%s: send attempts %d rcvd %d\n", - __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd); + printf("%s: send attempts %d, rcvd %d, errors %d\n", + __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); + + /* Print throughput stats only for constant length packet runs */ + if (bus->pktgen_minlen == bus->pktgen_maxlen) { + time_lapse = jiffies - bus->pktgen_prev_time; + bus->pktgen_prev_time = jiffies; + sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; + bus->pktgen_prev_sent = bus->pktgen_sent; + rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; + bus->pktgen_prev_rcvd = bus->pktgen_rcvd; + + printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", + __FUNCTION__, + (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, + (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); + } } /* For recv mode, just make sure dongle has started sending */ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; - dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total); + dhdsdio_sdtest_set(bus, bus->pktgen_total); } return; } @@ -6252,7 +6683,11 @@ dhdsdio_pktgen(dhd_bus_t *bus) } /* Allocate an appropriate-sized packet */ - len = bus->pktgen_len; + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + len = SDPCM_TEST_PKT_CNT_FLD_LEN; + } else { + len = bus->pktgen_len; + } if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), TRUE))) {; DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); @@ -6275,7 +6710,7 @@ dhdsdio_pktgen(dhd_bus_t *bus) case DHD_PKTGEN_RXBURST: *data++ = SDPCM_TEST_BURST; - *data++ = (uint8)bus->pktgen_count; + *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ break; default: @@ -6286,12 +6721,23 @@ dhdsdio_pktgen(dhd_bus_t *bus) } /* Write test header length field */ - *data++ = (len >> 0); - *data++ = (len >> 8); + *data++ = (bus->pktgen_len >> 0); + *data++ = (bus->pktgen_len >> 8); - /* Then fill in the remainder -- N/A for burst, but who cares... */ - for (fillbyte = 0; fillbyte < len; fillbyte++) - *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); + /* Write frame count in a 4 byte field adjucent to SDPCM test header for + * burst mode + */ + if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { + *data++ = (uint8)(bus->pktgen_count >> 0); + *data++ = (uint8)(bus->pktgen_count >> 8); + *data++ = (uint8)(bus->pktgen_count >> 16); + *data++ = (uint8)(bus->pktgen_count >> 24); + } else { + + /* Then fill in the remainder -- N/A for burst */ + for (fillbyte = 0; fillbyte < len; fillbyte++) + *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); + } #ifdef DHD_DEBUG if (DHD_BYTES_ON() && DHD_DATA_ON()) { @@ -6319,25 +6765,31 @@ dhdsdio_pktgen(dhd_bus_t *bus) } static void -dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count) +dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) { void *pkt; uint8 *data; osl_t *osh = bus->dhd->osh; /* Allocate the packet */ - if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) { + if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); return; } - PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); + PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + + SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; /* Fill in the test header */ *data++ = SDPCM_TEST_SEND; - *data++ = count; + *data++ = (count > 0)?TRUE:FALSE; *data++ = (bus->pktgen_maxlen >> 0); *data++ = (bus->pktgen_maxlen >> 8); + *data++ = (uint8)(count >> 0); + *data++ = (uint8)(count >> 8); + *data++ = (uint8)(count >> 16); + *data++ = (uint8)(count >> 24); /* Send it */ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) @@ -6505,7 +6957,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (!bus->dpc_sched) { uint32 devpend; devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, - SPID_STATUS_REG, NULL); + SPID_STATUS_REG, NULL); intstatus = devpend & STATUS_F2_PKT_AVAILABLE; } #endif /* !BCMSPI */ @@ -6548,7 +7000,10 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) /* Generate packets if configured */ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (SLPAUTO_ENAB(bus)) + dhdsdio_bussleep(bus, FALSE); + else + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); bus->pktgen_tick = 0; dhdsdio_pktgen(bus); } @@ -6563,7 +7018,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (bus->idlecount >= bus->idletime) { DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - if (SLPAUTO_ENAB(bus)) { if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) dhd_os_wd_timer(bus->dhd, 0); @@ -6708,16 +7162,24 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4314_CHIP_ID) return TRUE; - if (chipid == BCM4334_CHIP_ID) + if (chipid == BCM43242_CHIP_ID) return TRUE; if (chipid == BCM43341_CHIP_ID) return TRUE; + if (chipid == BCM43143_CHIP_ID) + return TRUE; + if (chipid == BCM43342_CHIP_ID) + return TRUE; + if (chipid == BCM4334_CHIP_ID) + return TRUE; if (chipid == BCM43239_CHIP_ID) return TRUE; if (chipid == BCM4324_CHIP_ID) return TRUE; if (chipid == BCM4335_CHIP_ID) return TRUE; + if (chipid == BCM4350_CHIP_ID) + return TRUE; return FALSE; } @@ -6732,7 +7194,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, #endif /* GET_CUSTOM_MAC_ENABLE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); } @@ -6758,7 +7219,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, sd1idle = TRUE; dhd_readahead = TRUE; retrydata = FALSE; +#ifndef REPEAT_READFRAME dhd_doflow = FALSE; +#else + dhd_doflow = TRUE; +#endif /* REPEAT_READFRAME */ dhd_dongle_memsize = 0; dhd_txminmax = DHD_TXMINMAX; @@ -6899,7 +7364,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, if (dhd_download_fw_on_driverload) { if ((ret = dhd_bus_start(bus->dhd)) != 0) { DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); - if (ret == BCME_NOTUP) goto fail; } } @@ -6933,6 +7397,284 @@ 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) @@ -7031,6 +7773,12 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } +#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); if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { @@ -7062,10 +7810,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, } if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } + if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { + DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); + goto fail; + } } else { /* cr4 has a different way to find the RAM size from TCM's */ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { @@ -7073,14 +7821,28 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, goto fail; } /* also populate base address */ - bus->dongle_ram_base = CR4_RAM_BASE; + switch ((uint16)bus->sih->chip) { + case BCM4335_CHIP_ID: + bus->dongle_ram_base = CR4_4335_RAM_BASE; + break; + case BCM4350_CHIP_ID: + bus->dongle_ram_base = CR4_4350_RAM_BASE; + break; + case BCM4360_CHIP_ID: + bus->dongle_ram_base = CR4_4360_RAM_BASE; + break; + default: + bus->dongle_ram_base = 0; + DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", + __FUNCTION__, bus->dongle_ram_base)); + } } bus->ramsize = bus->orig_ramsize; if (dhd_dongle_memsize) dhd_dongle_setmemsize(bus, dhd_dongle_memsize); - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", - bus->ramsize, bus->orig_ramsize)); + DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", + bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); bus->srmemsize = si_socram_srmem_size(bus->sih); } @@ -7123,7 +7885,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, #ifdef BCMSDIOH_TXGLOM /* Setting default Glom mode */ - bus->glom_mode = SDPCM_TXGLOM_CPY; + bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE); /* Setting default Glom size */ bus->glomsize = SDPCM_DEFGLOM_SIZE; #endif @@ -7233,6 +7995,9 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) } else { DHD_INFO(("%s: Initial value for %s is %d\n", __FUNCTION__, "sd_blocksize", bus->blocksize)); + + if (bus->sih->chip == BCM4335_CHIP_ID) + dhd_overflow_war(bus); } bus->roundup = MIN(max_roundup, bus->blocksize); @@ -7372,10 +8137,10 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r return; if (bus->sih) { +#if !defined(BCMLXSDMMC) if (bus->dhd) { dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); } -#if !defined(BCMLXSDMMC) if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) si_watchdog(bus->sih, 4); #endif /* !defined(BCMLXSDMMC) */ @@ -7397,8 +8162,9 @@ dhdsdio_disconnect(void *ptr) { dhd_bus_t *bus = (dhd_bus_t *)ptr; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); } @@ -7408,7 +8174,6 @@ dhdsdio_disconnect(void *ptr) mutex_lock(&_dhd_sdio_mutex_lock_); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (bus) { ASSERT(bus->dhd); @@ -7420,6 +8185,7 @@ dhdsdio_disconnect(void *ptr) DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); } @@ -7475,6 +8241,17 @@ dhdsdio_download_code_array(struct dhd_bus *bus) /* Download image */ while ((offset + MEMBLOCK) < sizeof(dlarray)) { + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)dlarray)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + bcmerror = dhdsdio_membytes(bus, TRUE, offset, (uint8 *) (dlarray + offset), MEMBLOCK); if (bcmerror) { @@ -7572,6 +8349,17 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) bcmerror = BCME_ERROR; goto err; } + /* check if CR4 */ + if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { + /* if address is 0, store the reset instruction to be written in 0 */ + + if (offset == 0) { + bus->resetinstr = *(((uint32*)memptr)); + /* Add start of RAM address to the address given by user */ + offset += bus->dongle_ram_base; + } + } + bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", @@ -7721,6 +8509,7 @@ _dhdsdio_download_firmware(struct dhd_bus *bus) dlok = TRUE; } } + #ifdef BCMEMBEDIMAGE if (embed) { if (dhdsdio_download_code_array(bus)) { @@ -7791,9 +8580,9 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf #ifdef BCMSDIOH_TXGLOM static void -dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) +dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len) { - bcmsdh_glom_post(bus->sdh, frame, len); + bcmsdh_glom_post(bus->sdh, frame, pkt, len); } static void @@ -7947,23 +8736,6 @@ uint dhd_bus_chip_id(dhd_pub_t *dhdp) return bus->sih->chip; } - -/* Get Chip Rev ID version */ -uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chiprev; -} - -/* Get Chip Pkg ID version */ -uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = dhdp->bus; - - return bus->sih->chippkg; -} - int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) { @@ -7972,7 +8744,7 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si bus = dhdp->bus; return dhdsdio_membytes(bus, set, address, data, size); } -#if defined(SUPPORT_MULTIPLE_REVISION) +#if defined(CUSTOMER_HW4) && defined(SUPPORT_MULTIPLE_REVISION) static int concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len) { @@ -7982,7 +8754,7 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len) uint chipver; uint32 unique_id; uint8 data[4]; - char chipver_tag[4] = "_b0"; + char chipver_tag[4] = "_b?"; DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__)); if (bus->sih->chip != BCM4334_CHIP_ID) { @@ -7999,14 +8771,12 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len) DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); if (chipver == 1) { DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); - chipver_tag[2] = '0'; strcpy(chipver_tag, "_b0"); } else if (chipver == 2) { DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); - chipver_tag[2] = '1'; + strcpy(chipver_tag, "_b1"); } else if (chipver == 3) { DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); - chipver_tag[2] = '2'; strcpy(chipver_tag, "_b2"); } else { @@ -8019,18 +8789,49 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len) return 0; } -int -concate_revision(dhd_bus_t *bus, char *path, int path_len) +static int +concate_revision_bcm4335 + (dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len) { + uint chipver; + char chipver_tag[4] = {0, }; + + DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__)); + if (bus->sih->chip != BCM4335_CHIP_ID) { + DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__)); + return -1; + } + chipver = bus->sih->chiprev; + DHD_ERROR(("CHIP VER = [0x%x]\n", chipver)); + if (chipver == 0x0) { + DHD_ERROR(("----- CHIP bcm4335_A0 -----\n")); + strcpy(chipver_tag, "_a0"); + } else if (chipver == 0x1) { + DHD_ERROR(("----- CHIP bcm4335_B0 -----\n")); + } + strcat(fw_path, chipver_tag); + strcat(nv_path, chipver_tag); + + return 0; + +} +int +concate_revision(dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len) +{ if (!bus || !bus->sih) { DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__)); return -1; } - if (bus->sih->chip == BCM4334_CHIP_ID) { - return concate_revision_bcm4334(bus, path, path_len); + switch (bus->sih->chip) { + case BCM4334_CHIP_ID: + return concate_revision_bcm4334(bus, fw_path, fw_path_len); + case BCM4335_CHIP_ID: + return concate_revision_bcm4335(bus, fw_path, fw_path_len, + nv_path, nv_path_len); } + DHD_ERROR(("REVISION SPECIFIC feature is not required\n")); - return -1; + return 0; } -#endif /* MULTIPLE_REVISION */ +#endif /* CUSTOMER_HW4 && SUPPORT_MULTIPLE_REVISION */ |