diff options
author | Narayan Reddy <narayanr@nvidia.com> | 2011-10-25 16:35:48 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:52:35 -0800 |
commit | 84d261b7df0abd9ff03c4a111008d6f51cc1c4ce (patch) | |
tree | d76c8c921fbc780b132593b37661f6e74af2825d /drivers | |
parent | f6b763f59a718390810e4031f07a0e9ee205131c (diff) |
drivers: wireless: bcmdhd: clear pending interrupts before irq release
While using inband interrupt and SDIO_ISR_THREAD defined,
wifi irq handler run in context of ksdioirqd.
While turning off wifi, bcmdhd driver releases irq in a different thread.
If there is a pending wifi interrupt(not served) it never get cleared as driver
has removed the irq handler.
Bug 857429
Change-Id: Ib9b041f49d18e973824a5a5b9ce4a6d771b231ca
Reviewed-on: http://git-master/r/60220
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Rebase-Id: R6416b3a56b1987bb1fc5686ebdd29deb6fc99e6c
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 70bacbd3793d..7499a1ec55fd 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -248,28 +248,33 @@ sdioh_enable_func_intr(void) return SDIOH_API_RC_SUCCESS; } +#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + extern SDIOH_API_RC -sdioh_disable_func_intr(void) +sdioh_disable_func_intr(int func) { uint8 reg; int err; - if (gInstance->func[0]) { - sdio_claim_host(gInstance->func[0]); - reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); + if (gInstance->func[func]) { + sdio_claim_host(gInstance->func[func]); + reg = sdio_readb(gInstance->func[func], SDIOD_CCCR_INTEN, &err); if (err) { sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(gInstance->func[0]); + sdio_release_host(gInstance->func[func]); return SDIOH_API_RC_FAIL; } - +#if defined(HW_OOB) reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); +#else + reg &= ~(1 << func); +#endif /* Disable master interrupt with the last function interrupt */ if (!(reg & 0xFE)) reg = 0; - sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); + sdio_writeb(gInstance->func[func], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(gInstance->func[0]); + sdio_release_host(gInstance->func[func]); if (err) { sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); return SDIOH_API_RC_FAIL; @@ -277,7 +282,7 @@ sdioh_disable_func_intr(void) } return SDIOH_API_RC_SUCCESS; } -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ + /* Configure callback to client when we recieve client interrupt */ extern SDIOH_API_RC @@ -319,6 +324,9 @@ sdioh_interrupt_deregister(sdioh_info_t *sd) #if !defined(OOB_INTR_ONLY) if (gInstance->func[1]) { + sdioh_disable_func_intr(1); + /*Wait for the pending interrupts to be cleared*/ + msleep(300); /* register and unmask irq */ sdio_claim_host(gInstance->func[1]); sdio_release_irq(gInstance->func[1]); @@ -326,6 +334,9 @@ sdioh_interrupt_deregister(sdioh_info_t *sd) } if (gInstance->func[2]) { + sdioh_disable_func_intr(2); + /*Wait for the pending interrupts to be cleared*/ + msleep(300); /* Claim host controller F2 */ sdio_claim_host(gInstance->func[2]); sdio_release_irq(gInstance->func[2]); @@ -337,7 +348,7 @@ sdioh_interrupt_deregister(sdioh_info_t *sd) sd->intr_handler = NULL; sd->intr_handler_arg = NULL; #elif defined(HW_OOB) - sdioh_disable_func_intr(); + sdioh_disable_func_intr(0); #endif /* !defined(OOB_INTR_ONLY) */ return SDIOH_API_RC_SUCCESS; } @@ -1303,7 +1314,7 @@ sdioh_stop(sdioh_info_t *si) sdio_release_host(gInstance->func[0]); #else /* defined(OOB_INTR_ONLY) */ #if defined(HW_OOB) - sdioh_disable_func_intr(); + sdioh_disable_func_intr(0); #endif bcmsdh_oob_intr_set(FALSE); #endif /* !defined(OOB_INTR_ONLY) */ |