summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNarayan Reddy <narayanr@nvidia.com>2011-10-25 16:35:48 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:52:35 -0800
commit84d261b7df0abd9ff03c4a111008d6f51cc1c4ce (patch)
treed76c8c921fbc780b132593b37661f6e74af2825d /drivers
parentf6b763f59a718390810e4031f07a0e9ee205131c (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.c33
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) */