On Fri, May 13, 2011 at 2:59 AM, Arend van Spriel <[email protected]> wrote:
> From: Sukesh Srikakula <[email protected]>
>
> 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: [email protected]
> Cc: [email protected]
> Cc: Grant Grundler <[email protected]>
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 <[email protected]>
> Reviewed-by: Brett Rudley <[email protected]>
> Signed-off-by: Arend van Spriel <[email protected]>
> ---
> 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
>
>
>
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel