staging: brcm80211: fix thread blocking issue in brcmf_sdbrcm_bus_stop()
authorArend van Spriel <arend@broadcom.com>
Wed, 5 Oct 2011 13:20:06 +0000 (15:20 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 5 Oct 2011 20:42:50 +0000 (13:42 -0700)
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>
drivers/staging/brcm80211/brcmfmac/dhd_sdio.c

index 0f7b80da41d0c8242f939d66540bf81e5f9a1c16..6885755f4ec6e7c633137993a501e8bb48e1b56b 100644 (file)
@@ -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;