diff options
author | Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | 2011-08-18 23:32:14 +0200 |
---|---|---|
committer | Philippe LANGLAIS <philippe.langlais@stericsson.com> | 2011-10-13 10:04:43 +0200 |
commit | 31a59450487a189e6b148364c5965ad7f1982b41 (patch) | |
tree | 0f5003aa1a04652600a8869af81603ebbc32f4bd | |
parent | 5b48061fc3276dadaceeff6c152e8f5b0f250c2e (diff) |
cw1200: do not allow suspend when it is useless.
Do not allow entering suspend state if firmware is polling
for multicasts and when scanning.
+ bugfix: remove blocking calls from wow_suspend() callback
to reduce suspend time and make sure watchdog is not triggered.
Change-Id: I69196fda25b56d01b90311582705ba586759ae35
Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/29079
Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33511
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rwxr-xr-x | drivers/staging/cw1200/ap.c | 8 | ||||
-rw-r--r-- | drivers/staging/cw1200/pm.c | 59 | ||||
-rw-r--r-- | drivers/staging/cw1200/scan.c | 2 |
3 files changed, 54 insertions, 15 deletions
diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c index 39c11172544..e4bf98d46ed 100755 --- a/drivers/staging/cw1200/ap.c +++ b/drivers/staging/cw1200/ap.c @@ -539,6 +539,13 @@ void cw1200_suspend_resume(struct cw1200_common *priv, if (arg->stop) { priv->tx_multicast = false; } else { + /* Firmware sends this indication every DTIM if there + * is a STA in powersave connected. There is no reason + * to suspend, following wakeup will consume much more + * power than could be saved. */ + cw1200_pm_stay_awake(&priv->pm_state, + priv->join_dtim_period * + (priv->beacon_int + 20) * HZ / 1024); priv->tx_multicast = priv->aid0_bit_set && priv->buffered_multicasts; if (priv->tx_multicast) @@ -652,6 +659,7 @@ static int cw1200_start_ap(struct cw1200_common *priv) .ssidLength = priv->ssid_length, }; priv->beacon_int = conf->beacon_int; + priv->join_dtim_period = conf->dtim_period; memcpy(&start.ssid[0], priv->ssid, start.ssidLength); diff --git a/drivers/staging/cw1200/pm.c b/drivers/staging/cw1200/pm.c index e27c4144f51..1d9207c8761 100644 --- a/drivers/staging/cw1200/pm.c +++ b/drivers/staging/cw1200/pm.c @@ -23,6 +23,7 @@ struct cw1200_suspend_state { unsigned long bss_loss_tmo; unsigned long connection_loss_tmo; unsigned long join_tmo; + unsigned long direct_probe; }; static struct dev_pm_ops cw1200_pm_ops = { @@ -165,24 +166,45 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) return -EAGAIN; #endif - /* Ensure pending operations are done. */ - ret = wait_event_interruptible_timeout( - priv->channel_switch_done, - !priv->channel_switch_in_progress, 3 * HZ); - if (WARN_ON(!ret)) - return -ETIMEDOUT; - else if (WARN_ON(ret < 0)) - return ret; + /* Make sure there is no configuration requests in progress. */ + if (!mutex_trylock(&priv->conf_mutex)) + return -EBUSY; + + /* Ensure pending operations are done. + * Note also that wow_suspend must return in ~2.5sec, before + * watchdog is triggered. */ + if (priv->channel_switch_in_progress) { + mutex_unlock(&priv->conf_mutex); + return -EBUSY; + } + + /* Do not suspend when join work is scheduled */ + if (work_pending(&priv->join_work)) { + mutex_unlock(&priv->conf_mutex); + return -EBUSY; + } + + /* Do not suspend when scanning */ + if (down_trylock(&priv->scan.lock)) { + mutex_unlock(&priv->conf_mutex); + return -EBUSY; + } - /* Flush and lock TX. */ - ret = __cw1200_flush(priv, false); - if (WARN_ON(ret < 0)) - return ret; + /* Lock TX. */ + wsm_lock_tx_async(priv); + if (priv->hw_bufs_used) { + wsm_unlock_tx(priv); + up(&priv->scan.lock); + mutex_unlock(&priv->conf_mutex); + return -EBUSY; + } /* Allocate state */ state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); if (!state) { wsm_unlock_tx(priv); + up(&priv->scan.lock); + mutex_unlock(&priv->conf_mutex); return -ENOMEM; } @@ -193,9 +215,8 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) cw1200_suspend_work(&priv->connection_loss_work); state->join_tmo = cw1200_suspend_work(&priv->join_timeout); - - /* Flush workqueue */ - flush_workqueue(priv->workqueue); + state->direct_probe = + cw1200_suspend_work(&priv->scan.probe_work); /* Stop serving thread */ cw1200_bh_suspend(priv); @@ -244,10 +265,18 @@ int cw1200_wow_resume(struct ieee80211_hw *hw) state->connection_loss_tmo); cw1200_resume_work(priv, &priv->join_timeout, state->join_tmo); + cw1200_resume_work(priv, &priv->scan.probe_work, + state->direct_probe); /* Unlock datapath */ wsm_unlock_tx(priv); + /* Unlock scan */ + up(&priv->scan.lock); + + /* Unlock configuration mutex */ + mutex_unlock(&priv->conf_mutex); + /* Free memory */ kfree(state); diff --git a/drivers/staging/cw1200/scan.c b/drivers/staging/cw1200/scan.c index c663f6dc173..4daf4e2daa2 100644 --- a/drivers/staging/cw1200/scan.c +++ b/drivers/staging/cw1200/scan.c @@ -13,6 +13,7 @@ #include "cw1200.h" #include "scan.h" #include "sta.h" +#include "pm.h" static void cw1200_scan_restart_delayed(struct cw1200_common *priv); @@ -25,6 +26,7 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) tmo += scan->ch[i].maxChannelTime + 10; atomic_set(&priv->scan.in_progress, 1); + cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000); queue_delayed_work(priv->workqueue, &priv->scan.timeout, tmo * HZ / 1000); ret = wsm_scan(priv, scan); |