summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-08-18 23:32:14 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-10-13 10:04:43 +0200
commit31a59450487a189e6b148364c5965ad7f1982b41 (patch)
tree0f5003aa1a04652600a8869af81603ebbc32f4bd
parent5b48061fc3276dadaceeff6c152e8f5b0f250c2e (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-xdrivers/staging/cw1200/ap.c8
-rw-r--r--drivers/staging/cw1200/pm.c59
-rw-r--r--drivers/staging/cw1200/scan.c2
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);