Skip to content

Commit

Permalink
staging: brcm80211: Fix for suspend issue in brcmfmac driver
Browse files Browse the repository at this point in the history
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@linuxdriverproject.org
Cc: linux-wireless@vger.kernel.org
Cc: Grant Grundler <grundler@chromium.org>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Brett Rudley <brudley@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Sukesh Srikakula authored and Greg Kroah-Hartman committed May 17, 2011
1 parent 22d5d59 commit e6e8f89
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 28 deletions.
5 changes: 1 addition & 4 deletions drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 13 additions & 9 deletions drivers/staging/brcm80211/brcmfmac/dhd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 { \
Expand Down
20 changes: 15 additions & 5 deletions drivers/staging/brcm80211/brcmfmac/dhd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down
77 changes: 67 additions & 10 deletions drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */

0 comments on commit e6e8f89

Please sign in to comment.