Commit bbbf4f42 authored by Arend van Spriel's avatar Arend van Spriel Committed by Greg Kroah-Hartman

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: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarRoland Vossen <rvossen@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3956b4a2
...@@ -2694,7 +2694,10 @@ static int brcmf_sdbrcm_dpc_thread(void *data) ...@@ -2694,7 +2694,10 @@ static int brcmf_sdbrcm_dpc_thread(void *data)
if (brcmf_sdbrcm_dpc(bus)) if (brcmf_sdbrcm_dpc(bus))
complete(&bus->dpc_wait); complete(&bus->dpc_wait);
} else { } else {
/* after stopping the bus, exit thread */
brcmf_sdbrcm_bus_stop(bus); brcmf_sdbrcm_bus_stop(bus);
bus->dpc_tsk = NULL;
break;
} }
} else } else
break; break;
...@@ -3601,25 +3604,25 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) ...@@ -3601,25 +3604,25 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
brcmf_dbg(TRACE, "Enter\n"); 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) { if (bus->watchdog_tsk) {
send_sig(SIGTERM, bus->watchdog_tsk, 1); send_sig(SIGTERM, bus->watchdog_tsk, 1);
kthread_stop(bus->watchdog_tsk); kthread_stop(bus->watchdog_tsk);
bus->watchdog_tsk = NULL; bus->watchdog_tsk = NULL;
} }
if (bus->dpc_tsk) { if (bus->dpc_tsk && bus->dpc_tsk != current) {
send_sig(SIGTERM, bus->dpc_tsk, 1); send_sig(SIGTERM, bus->dpc_tsk, 1);
kthread_stop(bus->dpc_tsk); kthread_stop(bus->dpc_tsk);
bus->dpc_tsk = NULL; 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 */ /* Disable and clear interrupts at the chip level also */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
local_hostintmask = bus->hostintmask; local_hostintmask = bus->hostintmask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment