On Fri, May 13, 2011 at 2:59 AM, Arend van Spriel <arend@xxxxxxxxxxxx> wrote: > From: Sukesh Srikakula <sukeshs@xxxxxxxxxxxx> > > Currently, there are 2 callbacks registered with OS for getting > notifications when system goes to suspend/resume. Racing between > these 2 callbacks results in random suspend failures. With this fix, > we avoid registering dhd callback for suspend/resume notification > when cfg80211 is used. Relevent functionality in dhd suspend/resume > callback function is moved to cfg80211 suspend/resume functions. > > Cc: devel@xxxxxxxxxxxxxxxxxxxxxx > Cc: linux-wireless@xxxxxxxxxxxxxxx > Cc: Grant Grundler <grundler@xxxxxxxxxxxx> Thanks guys again! :) Except for use of atomic_t instead of volatile, this appears to be the same as: http://codereview.chromium.org/6802002/ which I tested and fixes bug: http://crosbug.com/12337 thanks, grant > Reviewed-by: Franky (Zhenhui) Lin <frankyl@xxxxxxxxxxxx> > Reviewed-by: Brett Rudley <brudley@xxxxxxxxxxxx> > Signed-off-by: Arend van Spriel <arend@xxxxxxxxxxxx> > --- > Âdrivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c |  Â5 +- > Âdrivers/staging/brcm80211/brcmfmac/dhd.h     Â|  22 ++++--- > Âdrivers/staging/brcm80211/brcmfmac/dhd_linux.c  Â|  20 ++++-- > Âdrivers/staging/brcm80211/brcmfmac/wl_cfg80211.c Â|  77 ++++++++++++++++++--- > Âdrivers/staging/brcm80211/brcmfmac/wl_cfg80211.h Â|  Â1 + > Â5 files changed, 97 insertions(+), 28 deletions(-) > > diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c > index 43aebfd..c0ffbd3 100644 > --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c > +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c > @@ -26,14 +26,11 @@ > Â#include <linux/mmc/core.h> > Â#include <linux/mmc/sdio_func.h> > Â#include <linux/mmc/sdio_ids.h> > +#include <linux/suspend.h> > > Â#include <dngl_stats.h> > Â#include <dhd.h> > > -#if defined(CONFIG_PM_SLEEP) > -#include <linux/suspend.h> > -extern volatile bool dhd_mmc_suspend; > -#endif > Â#include "bcmsdh_sdmmc.h" > > Âextern int sdio_function_init(void); > diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h > index 99c38dd..a726b49 100644 > --- a/drivers/staging/brcm80211/brcmfmac/dhd.h > +++ b/drivers/staging/brcm80211/brcmfmac/dhd.h > @@ -31,6 +31,7 @@ > Â#include <linux/random.h> > Â#include <linux/spinlock.h> > Â#include <linux/ethtool.h> > +#include <linux/suspend.h> > Â#include <asm/uaccess.h> > Â#include <asm/unaligned.h> > Â/* The kernel threading is sdio-specific */ > @@ -122,19 +123,22 @@ typedef struct dhd_pub { > Â} dhd_pub_t; > > Â#if defined(CONFIG_PM_SLEEP) > - > +extern atomic_t dhd_mmc_suspend; > Â#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); > -#define _DHD_PM_RESUME_WAIT(a, b) do {\ > -            int retry = 0; \ > -            while (dhd_mmc_suspend && retry++ != b) { \ > -                wait_event_timeout(a, false, HZ/100); \ > -            } \ > -        }    while (0) > +#define _DHD_PM_RESUME_WAIT(a, b) do { \ > +        int retry = 0; \ > +        while (atomic_read(&dhd_mmc_suspend) && retry++ != b) { \ > +            wait_event_timeout(a, false, HZ/100); \ > +        } \ > +    }    while (0) > Â#define DHD_PM_RESUME_WAIT(a) Â_DHD_PM_RESUME_WAIT(a, 30) > Â#define DHD_PM_RESUME_WAIT_FOREVER(a) Â_DHD_PM_RESUME_WAIT(a, ~0) > Â#define DHD_PM_RESUME_RETURN_ERROR(a) Â\ > -    do { if (dhd_mmc_suspend) return a; } while (0) > -#define DHD_PM_RESUME_RETURN  do { if (dhd_mmc_suspend) return; } while (0) > +    do { if (atomic_read(&dhd_mmc_suspend)) return a; } while (0) > +#define DHD_PM_RESUME_RETURN  do { \ > +    if (atomic_read(&dhd_mmc_suspend)) \ > +        return; \ > +    } while (0) > > Â#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); > Â#define SPINWAIT_SLEEP(a, exp, us) do { \ > diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c > index ba73ce0..31a5ca0 100644 > --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c > +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c > @@ -166,7 +166,7 @@ void wifi_del_dev(void) > > Â#if defined(CONFIG_PM_SLEEP) > Â#include <linux/suspend.h> > -volatile bool dhd_mmc_suspend = false; > +atomic_t dhd_mmc_suspend; > ÂDECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); > Â#endif /* Âdefined(CONFIG_PM_SLEEP) */ > > @@ -407,11 +407,11 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, >    Âswitch (action) { >    Âcase PM_HIBERNATION_PREPARE: >    Âcase PM_SUSPEND_PREPARE: > -        dhd_mmc_suspend = true; > +        atomic_set(&dhd_mmc_suspend, true); >        Âreturn NOTIFY_OK; >    Âcase PM_POST_HIBERNATION: >    Âcase PM_POST_SUSPEND: > -        dhd_mmc_suspend = false; > +        atomic_set(&dhd_mmc_suspend, false); >        Âreturn NOTIFY_OK; >    Â} >    Âreturn 0; > @@ -2011,7 +2011,9 @@ dhd_pub_t *dhd_attach(struct dhd_bus *bus, uint bus_hdrlen) >    Âg_bus = bus; > Â#endif > Â#if defined(CONFIG_PM_SLEEP) > -    register_pm_notifier(&dhd_sleep_pm_notifier); > +    atomic_set(&dhd_mmc_suspend, false); > +    if (!IS_CFG80211_FAVORITE()) > +        register_pm_notifier(&dhd_sleep_pm_notifier); > Â#endif /* defined(CONFIG_PM_SLEEP) */ >    Â/* && defined(DHD_GPL) */ >    Â/* Init lock suspend to prevent kernel going to suspend */ > @@ -2305,7 +2307,8 @@ void dhd_detach(dhd_pub_t *dhdp) >                Âwl_cfg80211_detach(); > > Â#if defined(CONFIG_PM_SLEEP) > -            unregister_pm_notifier(&dhd_sleep_pm_notifier); > +            if (!IS_CFG80211_FAVORITE()) > +                unregister_pm_notifier(&dhd_sleep_pm_notifier); > Â#endif /* defined(CONFIG_PM_SLEEP) */ >            Â/* && defined(DHD_GPL) */ >            Âfree_netdev(ifp->net); > @@ -2816,6 +2819,13 @@ int dhd_wait_pend8021x(struct net_device *dev) >    Âreturn pend; > Â} > > +void wl_os_wd_timer(struct net_device *ndev, uint wdtick) > +{ > +    dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); > + > +    dhd_os_wd_timer(&dhd->pub, wdtick); > +} > + > Â#ifdef DHD_DEBUG > Âint write_to_file(dhd_pub_t *dhd, u8 *buf, int size) > Â{ > diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c > index c60fc7c..2d67048 100644 > --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c > +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c > @@ -1969,34 +1969,91 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, > > Âstatic s32 wl_cfg80211_resume(struct wiphy *wiphy) > Â{ > -    s32 err = 0; > +    struct wl_priv *wl = wiphy_to_wl(wiphy); > +    struct net_device *ndev = wl_to_ndev(wl); > > -    CHECK_SYS_UP(); > -    wl_invoke_iscan(wiphy_to_wl(wiphy)); > +    /* > +    Â* Check for WL_STATUS_READY before any function call which > +    Â* could result is bus access. Don't block the resume for > +    Â* any driver error conditions > +    Â*/ > > -    return err; > +#if defined(CONFIG_PM_SLEEP) > +    atomic_set(&dhd_mmc_suspend, false); > +#endif /* Âdefined(CONFIG_PM_SLEEP) */ > + > +    if (test_bit(WL_STATUS_READY, &wl->status)) { > +        /* Turn on Watchdog timer */ > +        wl_os_wd_timer(ndev, dhd_watchdog_ms); > +        wl_invoke_iscan(wiphy_to_wl(wiphy)); > +    } > + > +    return 0; > Â} > > Âstatic s32 wl_cfg80211_suspend(struct wiphy *wiphy) > Â{ >    Âstruct wl_priv *wl = wiphy_to_wl(wiphy); >    Âstruct net_device *ndev = wl_to_ndev(wl); > -    s32 err = 0; > + > + > +    /* > +    Â* Check for WL_STATUS_READY before any function call which > +    Â* could result is bus access. Don't block the suspend for > +    Â* any driver error conditions > +    Â*/ > + > +    /* > +    Â* While going to suspend if associated with AP disassociate > +    Â* from AP to save power while system is in suspended state > +    Â*/ > +    if (test_bit(WL_STATUS_CONNECTED, &wl->status) && > +        test_bit(WL_STATUS_READY, &wl->status)) { > +        WL_INFO("Disassociating from AP" > +            " while entering suspend state\n"); > +        wl_link_down(wl); > + > +        /* > +        Â* Make sure WPA_Supplicant receives all the event > +        Â* generated due to DISASSOC call to the fw to keep > +        Â* the state fw and WPA_Supplicant state consistent > +        Â*/ > +        rtnl_unlock(); > +        wl_delay(500); > +        rtnl_lock(); > +    } > >    Âset_bit(WL_STATUS_SCAN_ABORTING, &wl->status); > -    wl_term_iscan(wl); > +    if (test_bit(WL_STATUS_READY, &wl->status)) > +        wl_term_iscan(wl); > + >    Âif (wl->scan_request) { > -        cfg80211_scan_done(wl->scan_request, true);   /* true means > -                                Âabort */ > -        wl_set_mpc(ndev, 1); > +        /* Indidate scan abort to cfg80211 layer */ > +        WL_INFO("Terminating scan in progress\n"); > +        cfg80211_scan_done(wl->scan_request, true); >        Âwl->scan_request = NULL; >    Â} >    Âclear_bit(WL_STATUS_SCANNING, &wl->status); >    Âclear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); > +    clear_bit(WL_STATUS_CONNECTING, &wl->status); > +    clear_bit(WL_STATUS_CONNECTED, &wl->status); > > +    /* Inform SDIO stack not to switch off power to the chip */ >    Âsdioh_sdio_set_host_pm_flags(MMC_PM_KEEP_POWER); > > -    return err; > +    /* Turn off watchdog timer */ > +    if (test_bit(WL_STATUS_READY, &wl->status)) { > +        WL_INFO("Terminate watchdog timer and enable MPC\n"); > +        wl_set_mpc(ndev, 1); > +        wl_os_wd_timer(ndev, 0); > +    } > + > +#if defined(CONFIG_PM_SLEEP) > +    atomic_set(&dhd_mmc_suspend, true); > +#endif /* Âdefined(CONFIG_PM_SLEEP) */ > + > + > +    return 0; > Â} > > Âstatic __used s32 > diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h > index 5112160..3c8b902 100644 > --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h > +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h > @@ -375,5 +375,6 @@ extern s8 *wl_cfg80211_get_fwname(void);  Â/* get firmware name for >                         the dongle */ > Âextern s8 *wl_cfg80211_get_nvramname(void);  Â/* get nvram name for >                         the dongle */ > +extern void wl_os_wd_timer(struct net_device *ndev, uint wdtick); > > Â#endif             /* _wl_cfg80211_h_ */ > -- > 1.7.4.1 > > > -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html