diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2010-12-01 14:22:52 -0800 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2010-12-02 15:46:54 -0800 |
commit | 27d88fb65fe2faaa65f519bd3b30154fa632be45 (patch) | |
tree | 29addc9cadafdf8d6d869a612aec01fe68b39509 | |
parent | 04dcc0f8bf9be6ef1a6ffba049819fe8a2a7368d (diff) |
net: wireless: bcm4329: Fix watchdog syncronization during start/stop
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r-- | drivers/net/wireless/bcm4329/dhd_linux.c | 80 | ||||
-rw-r--r-- | drivers/net/wireless/bcm4329/dhd_sdio.c | 36 |
2 files changed, 60 insertions, 56 deletions
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c index 472b992751e7..b6bb7d11b79f 100644 --- a/drivers/net/wireless/bcm4329/dhd_linux.c +++ b/drivers/net/wireless/bcm4329/dhd_linux.c @@ -1399,22 +1399,24 @@ dhd_watchdog_thread(void *data) /* Run until signal received */ while (1) { if (down_interruptible (&dhd->watchdog_sem) == 0) { - + dhd_os_sdlock(&dhd->pub); if (dhd->pub.dongle_reset == FALSE) { + DHD_TIMER(("%s:\n", __FUNCTION__)); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); - } - /* Count the tick for reference */ - dhd->pub.tickcnt++; - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + /* Count the tick for reference */ + dhd->pub.tickcnt++; + /* Reschedule the watchdog */ + if (dhd->wd_timer_valid) + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + } + dhd_os_sdunlock(&dhd->pub); dhd_os_wake_unlock(&dhd->pub); - } - else + } else { break; + } } complete_and_exit(&dhd->watchdog_exited, 0); @@ -1426,11 +1428,17 @@ dhd_watchdog(ulong data) dhd_info_t *dhd = (dhd_info_t *)data; dhd_os_wake_lock(&dhd->pub); + if (dhd->pub.dongle_reset) { + dhd_os_wake_unlock(&dhd->pub); + return; + } + if (dhd->watchdog_pid >= 0) { up(&dhd->watchdog_sem); return; } + dhd_os_sdlock(&dhd->pub); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -1440,6 +1448,7 @@ dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd_os_sdunlock(&dhd->pub); dhd_os_wake_unlock(&dhd->pub); } @@ -2198,8 +2207,8 @@ dhd_bus_start(dhd_pub_t *dhdp) #if defined(OOB_INTR_ONLY) /* Host registration for OOB interrupt */ if (bcmsdh_register_oob_intr(dhdp)) { - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); return -ENODEV; } @@ -2210,8 +2219,8 @@ dhd_bus_start(dhd_pub_t *dhdp) /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); return -ENODEV; } @@ -2420,8 +2429,8 @@ dhd_bus_detach(dhd_pub_t *dhdp) #endif /* defined(OOB_INTR_ONLY) */ /* Clear the watchdog timer */ - del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; + del_timer_sync(&dhd->timer); } } } @@ -2687,29 +2696,28 @@ void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; - static uint save_dhd_watchdog_ms = 0; dhd_info_t *dhd = (dhd_info_t *)pub->info; + unsigned long flags; + int del_timer_flag = FALSE; - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) - return; + flags = dhd_os_spin_lock(pub); - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - del_timer_sync(&dhd->timer); - dhd->wd_timer_valid = FALSE; - save_dhd_watchdog_ms = wdtick; - return; + /* don't start the wd until fw is loaded */ + if (pub->busstate != DHD_BUS_DOWN) { + if (wdtick) { + dhd_watchdog_ms = (uint)wdtick; + dhd->wd_timer_valid = TRUE; + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + } else if (dhd->wd_timer_valid == TRUE) { + /* Totally stop the timer */ + dhd->wd_timer_valid = FALSE; + del_timer_flag = TRUE; + } } - - if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - - dhd->wd_timer_valid = TRUE; - save_dhd_watchdog_ms = wdtick; + dhd_os_spin_unlock(pub, flags); + if (del_timer_flag) { + del_timer_sync(&dhd->timer); } } @@ -2927,20 +2935,12 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - /* Turning off watchdog */ - if (flag) - dhd_os_wd_timer(&dhd->pub, 0); - ret = dhd_bus_devreset(&dhd->pub, flag); if (ret) { DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); return ret; } - - /* Turning on watchdog back */ - if (!flag) - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); + DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON")); return ret; } diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c index 7494e3836732..88b656a0f8bf 100644 --- a/drivers/net/wireless/bcm4329/dhd_sdio.c +++ b/drivers/net/wireless/bcm4329/dhd_sdio.c @@ -705,6 +705,7 @@ dhdsdio_sdclk(dhd_bus_t *bus, bool on) static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) { + int ret = BCME_OK; #ifdef DHD_DEBUG uint oldstate = bus->clkstate; #endif /* DHD_DEBUG */ @@ -717,7 +718,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); bus->activity = TRUE; } - return BCME_OK; + return ret; } switch (target) { @@ -726,29 +727,32 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) if (bus->clkstate == CLK_NONE) dhdsdio_sdclk(bus, TRUE); /* Now request HT Avail on the backplane */ - dhdsdio_htclk(bus, TRUE, pendok); - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; + ret = dhdsdio_htclk(bus, TRUE, pendok); + if (ret == BCME_OK) { + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + bus->activity = TRUE; + } break; case CLK_SDONLY: /* Remove HT request, or bring up SD clock */ if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); + ret = dhdsdio_sdclk(bus, TRUE); else if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); + ret = dhdsdio_htclk(bus, FALSE, FALSE); else DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", bus->clkstate, target)); - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); + if (ret == BCME_OK) + dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); break; case CLK_NONE: /* Make sure to remove HT request */ if (bus->clkstate == CLK_AVAIL) - dhdsdio_htclk(bus, FALSE, FALSE); + ret = dhdsdio_htclk(bus, FALSE, FALSE); /* Now remove the SD clock */ - dhdsdio_sdclk(bus, FALSE); + ret = dhdsdio_sdclk(bus, FALSE); dhd_os_wd_timer(bus->dhd, 0); break; } @@ -756,7 +760,7 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); #endif /* DHD_DEBUG */ - return BCME_OK; + return ret; } int @@ -4631,8 +4635,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (bus->sleeping) return FALSE; - dhd_os_sdlock(bus->dhd); - /* Poll period: check device if appropriate. */ if (bus->poll && (++bus->polltick >= bus->pollrate)) { uint32 intstatus = 0; @@ -4702,8 +4704,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } } - dhd_os_sdunlock(bus->dhd); - return bus->ipend; } @@ -5797,13 +5797,15 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (flag == TRUE) { if (!bus->dhd->dongle_reset) { + dhd_os_sdlock(dhdp); + /* Turning off watchdog */ + dhd_os_wd_timer(dhdp, 0); #if !defined(IGNORE_ETH0_DOWN) /* Force flow control as protection when stop come before ifconfig_down */ dhd_txflowcontrol(bus->dhd, 0, ON); #endif /* !defined(IGNORE_ETH0_DOWN) */ /* Expect app to have torn down any connection before calling */ /* Stop the bus, disable F2 */ - dhd_os_sdlock(dhdp); dhd_bus_stop(bus, FALSE); /* Clean tx/rx buffer pointers, detach from the dongle */ @@ -5850,7 +5852,9 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) #if !defined(IGNORE_ETH0_DOWN) /* Restore flow control */ dhd_txflowcontrol(bus->dhd, 0, OFF); -#endif +#endif + /* Turning on watchdog back */ + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else |