summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2011-10-05 15:20:06 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-10-05 13:42:50 -0700
commitbbbf4f42f59e9e1412239102d055bcc1c5f54eaf (patch)
tree155384e3951d992aea3579206eb3c0083db205d3
parent3956b4a2ddb04524aa4a1c59fb1c2db8ac60f9ea (diff)
staging: brcm80211: fix thread blocking issue in brcmf_sdbrcm_bus_stop()
The function brcmf_sdbrcm_bus_stop() terminates the watchdog and dpc thread, but this function can be called from the dpc thread itself. Stopping the dpc thread is only done when it is not the 'current' thread. Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Roland Vossen <rvossen@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_sdio.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index 0f7b80da41d..6885755f4ec 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -2694,7 +2694,10 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
if (brcmf_sdbrcm_dpc(bus))
complete(&bus->dpc_wait);
} else {
+ /* after stopping the bus, exit thread */
brcmf_sdbrcm_bus_stop(bus);
+ bus->dpc_tsk = NULL;
+ break;
}
} else
break;
@@ -3601,25 +3604,25 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
brcmf_dbg(TRACE, "Enter\n");
- down(&bus->sdsem);
-
- bus_wake(bus);
-
- /* Enable clock for device interrupts */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-
if (bus->watchdog_tsk) {
send_sig(SIGTERM, bus->watchdog_tsk, 1);
kthread_stop(bus->watchdog_tsk);
bus->watchdog_tsk = NULL;
}
- if (bus->dpc_tsk) {
+ if (bus->dpc_tsk && bus->dpc_tsk != current) {
send_sig(SIGTERM, bus->dpc_tsk, 1);
kthread_stop(bus->dpc_tsk);
bus->dpc_tsk = NULL;
}
+ down(&bus->sdsem);
+
+ bus_wake(bus);
+
+ /* Enable clock for device interrupts */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
/* Disable and clear interrupts at the chip level also */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
local_hostintmask = bus->hostintmask;