diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 225 |
1 files changed, 177 insertions, 48 deletions
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 8137701bda7..8af2ca6ac30 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.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: bcmsdh_sdmmc.c 347640 2012-07-27 11:53:21Z $ + * $Id: bcmsdh_sdmmc.c 383350 2013-02-06 12:59:26Z $ */ #include <typedefs.h> @@ -76,6 +76,18 @@ uint sd_clock = 1; /* Default to SD Clock turned ON */ uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ uint sd_msglevel = 0x01; uint sd_use_dma = TRUE; + +#ifdef BCMSDIOH_TXGLOM +#ifndef CUSTOM_TXGLOM +#define CUSTOM_TXGLOM 0 +#endif +uint sd_txglom = CUSTOM_TXGLOM; +#endif /* BCMSDIOH_TXGLOM */ + +#ifndef CUSTOM_RXCHAIN +#define CUSTOM_RXCHAIN 0 +#endif + DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); @@ -154,7 +166,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->sd_blockmode = TRUE; sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; - sd->use_rxchain = FALSE; + sd->use_rxchain = CUSTOM_RXCHAIN; gInstance->sd = sd; @@ -250,9 +262,9 @@ sdioh_enable_func_intr(void) return SDIOH_API_RC_FAIL; } - /* Enable F1 and F2 interrupts, set master enable */ - reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN); - + /* Enable F1 and F2 interrupts, clear master enable */ + reg &= ~INTR_CTL_MASTER_EN; + reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); sdio_release_host(gInstance->func[0]); @@ -525,7 +537,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, /* Now set it */ si->client_block_size[func] = blksize; -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) +#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE) if (gInstance == NULL || gInstance->func[func] == NULL) { sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); bcmerror = BCME_NORESOURCE; @@ -533,12 +545,11 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, } sdio_claim_host(gInstance->func[func]); bcmerror = sdio_set_block_size(gInstance->func[func], blksize); - if (bcmerror) { - sd_err(("%s: Failed to set F%d blocksize to %d\n", __FUNCTION__, func, - blksize)); - } + if (bcmerror) + sd_err(("%s: Failed to set F%d blocksize to %d\n", + __FUNCTION__, func, blksize)); sdio_release_host(gInstance->func[func]); -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ break; } @@ -793,10 +804,11 @@ sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) { - int err_ret; + int err_ret = 0; #if defined(MMC_SDIO_ABORT) int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; #endif + sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); @@ -830,14 +842,18 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by #if defined(MMC_SDIO_ABORT) /* to allow abort command through F1 */ else if (regaddr == SDIOD_CCCR_IOABORT) { + /* Because of SDIO3.0 host issue on Manta, + * sometimes the abort fails. + * Retrying again will fix this issue. + */ while (sdio_abort_retry--) { if (gInstance->func[func]) { sdio_claim_host(gInstance->func[func]); /* - * this sdio_f0_writeb() can be replaced with - * another api depending upon MMC driver change. - * As of this time, this is temporaray one - */ + * this sdio_f0_writeb() can be replaced with + * another api depending upon MMC driver change. + * As of this time, this is temporaray one + */ sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); sdio_release_host(gInstance->func[func]); @@ -880,8 +896,9 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by } if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); + if (regaddr != 0x1001F && err_ret != -110) + sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); } return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -906,6 +923,7 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add DHD_PM_RESUME_WAIT(sdioh_request_word_wait); DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); + /* Claim host controller */ sdio_claim_host(gInstance->func[func]); @@ -937,10 +955,10 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add if (gInstance->func[0]) { sdio_claim_host(gInstance->func[0]); /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ + * this sdio_f0_writeb() can be replaced with another api + * depending upon MMC driver change. + * As of this time, this is temporaray one + */ sdio_writeb(gInstance->func[0], func, SDIOD_CCCR_IOABORT, &err_ret); sdio_release_host(gInstance->func[0]); @@ -951,14 +969,83 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add if (err_ret) #endif /* MMC_SDIO_ABORT */ { - sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", - rw ? "Write" : "Read", err_ret)); + sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x", + rw ? "Write" : "Read", err_ret)); } } return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); } +#ifdef BCMSDIOH_TXGLOM +void +sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, void *pkt, uint len) +{ + void *phead = sd->glom_info.glom_pkt_head; + void *ptail = sd->glom_info.glom_pkt_tail; + + BCM_REFERENCE(frame); + + ASSERT(!PKTLINK(pkt)); + if (!phead) { + ASSERT(!phead); + sd->glom_info.glom_pkt_head = sd->glom_info.glom_pkt_tail = pkt; + } + else { + ASSERT(ptail); + PKTSETNEXT(sd->osh, ptail, pkt); + sd->glom_info.glom_pkt_tail = pkt; + } + sd->glom_info.count++; +} + +void +sdioh_glom_clear(sdioh_info_t *sd) +{ + void *pnow, *pnext; + uint8 i = 0; + + pnext = sd->glom_info.glom_pkt_head; + + if (!pnext) { + sd_err(("sdioh_glom_clear: no first packet to clear!\n")); + return; + } + + while (pnext) { + pnow = pnext; + pnext = PKTNEXT(sd->osh, pnow); + PKTSETNEXT(sd->osh, pnow, NULL); + sd->glom_info.count--; + i++; + } + + sd->glom_info.glom_pkt_head = NULL; + sd->glom_info.glom_pkt_tail = NULL; + if (sd->glom_info.count != 0) { + sd_err(("sdioh_glom_clear: glom count mismatch!\n")); + sd->glom_info.count = 0; + } +} + +uint +sdioh_set_mode(sdioh_info_t *sd, uint mode) +{ + if (mode == SDPCM_TXGLOM_CPY) + sd->txglom_mode = mode; + else if (mode == SDPCM_TXGLOM_MDESC) + sd->txglom_mode = mode; + + return (sd->txglom_mode); +} + +bool +sdioh_glom_enabled(void) +{ + return sd_txglom; +} +#endif /* BCMSDIOH_TXGLOM */ + static SDIOH_API_RC sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, uint addr, void *pkt) @@ -966,12 +1053,20 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, bool fifo = (fix_inc == SDIOH_DATA_FIX); uint32 SGCount = 0; int err_ret = 0; - void *pnext, *pprev; + void *pnext; uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; uint blk_num; + int blk_size; struct mmc_request mmc_req; struct mmc_command mmc_cmd; struct mmc_data mmc_dat; +#ifdef BCMSDIOH_TXGLOM + uint8 *localbuf = NULL; + uint local_plen = 0; + bool need_txglom = write && sdioh_glom_enabled() && + (pkt == sd->glom_info.glom_pkt_tail) && + (sd->glom_info.glom_pkt_head != sd->glom_info.glom_pkt_tail); +#endif /* BCMSDIOH_TXGLOM */ sd_trace(("%s: Enter\n", __FUNCTION__)); @@ -980,17 +1075,29 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ttl_len = xfred_len = 0; +#ifdef BCMSDIOH_TXGLOM + if (need_txglom) { + pkt = sd->glom_info.glom_pkt_head; + } +#endif /* BCMSDIOH_TXGLOM */ + /* at least 4 bytes alignment of skb buff is guaranteed */ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) ttl_len += PKTLEN(sd->osh, pnext); - if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) { + blk_size = sd->client_block_size[func]; + if (((!write && sd->use_rxchain) || +#ifdef BCMSDIOH_TXGLOM + (need_txglom && sd->txglom_mode == SDPCM_TXGLOM_MDESC) || +#endif + 0) && (ttl_len > blk_size)) { + blk_num = ttl_len / blk_size; + dma_len = blk_num * blk_size; + } else { blk_num = 0; dma_len = 0; - } else { - blk_num = ttl_len / sd->client_block_size[func]; - dma_len = blk_num * sd->client_block_size[func]; } + lft_len = ttl_len - dma_len; sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", @@ -1003,7 +1110,6 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, memset(&mmc_dat, 0, sizeof(struct mmc_data)); /* Set up DMA descriptors */ - pprev = pkt; for (pnext = pkt; pnext && dma_len; pnext = PKTNEXT(sd->osh, pnext)) { @@ -1030,7 +1136,7 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, mmc_dat.sg = sd->sg_list; mmc_dat.sg_len = SGCount; - mmc_dat.blksz = sd->client_block_size[func]; + mmc_dat.blksz = blk_size; mmc_dat.blocks = blk_num; mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; @@ -1057,12 +1163,8 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, __FUNCTION__, write ? "write" : "read", err_ret)); - sd_err(("%s:Disabling rxchain and fire it with PIO\n", - __FUNCTION__)); - sd->use_rxchain = FALSE; - pkt = pprev; - lft_len = ttl_len; - } else if (!fifo) { + } + if (!fifo) { addr = addr + ttl_len - lft_len - dma_len; } } @@ -1079,20 +1181,40 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, pkt_len -= xfred_len; xfred_len = 0; } +#ifdef BCMSDIOH_TXGLOM + if (need_txglom) { + if (!localbuf) { + localbuf = (uint8 *)MALLOC(sd->osh, lft_len); + if (localbuf == NULL) { + sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", + __FUNCTION__, (write) ? "TX" : "RX")); + goto txglomfail; + } + } + bcopy(buf, (localbuf + local_plen), pkt_len); + local_plen += pkt_len; - /* Align Patch - * read or small packet(ex:BDC header) skip 32 byte align - * otherwise, padding DHD_SDALIGN for performance - */ - if (write == 0 || pkt_len < 32) + if (PKTNEXT(sd->osh, pnext)) { + continue; + } + + buf = localbuf; + pkt_len = local_plen; + } + +txglomfail: +#endif /* BCMSDIOH_TXGLOM */ + + /* Align Patch */ + if (!write || pkt_len < 32) pkt_len = (pkt_len + 3) & 0xFFFFFFFC; - else if (pkt_len % DHD_SDALIGN) - pkt_len += DHD_SDALIGN - (pkt_len % DHD_SDALIGN); + else if (pkt_len % blk_size) + pkt_len += blk_size - (pkt_len % blk_size); -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) +#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE) if (write && pkt_len > 64 && (pkt_len % 64) == 32) pkt_len += 32; -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ #ifdef CONFIG_MMC_MSM7X00A if ((pkt_len % 64) == 32) { sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); @@ -1134,6 +1256,10 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, } sdio_release_host(gInstance->func[func]); } +#ifdef BCMSDIOH_TXGLOM + if (localbuf) + MFREE(sd->osh, localbuf, lft_len); +#endif /* BCMSDIOH_TXGLOM */ sd_trace(("%s: Exit\n", __FUNCTION__)); return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -1192,7 +1318,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u #else PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); #endif /* CONFIG_DHD_USE_STATIC_BUF */ - } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { + } else if (((ulong)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { /* Case 2: We have a packet, but it is unaligned. */ /* In this case, we cannot have a chain. */ @@ -1380,7 +1506,10 @@ sdioh_start(sdioh_info_t *si, int stage) int ret; sdioh_info_t *sd = gInstance->sd; - if (!sd) return (0); + if (!sd) { + sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); + return (0); + } /* Need to do this stages as we can't enable the interrupt till downloading of the firmware is complete, other wise polling |