summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2011-04-03 02:01:59 +0300
committerLuciano Coelho <coelho@ti.com>2011-05-02 10:25:27 +0300
commita665d6e260f0233aac73f74d15bb6a029cc5ec47 (patch)
treed795995e4796d1b14e9a096ac2ca0bbdaf43b78c /drivers
parentc75bbcdb200e2815c855e42a4685d170858af306 (diff)
downloadlinux-a665d6e260f0233aac73f74d15bb6a029cc5ec47.tar.bz2
wl12xx: avoid premature elp entrance
The elp_work is being enqueued on wl1271_ps_elp_sleep, but doesn't get cancelled on wl1271_ps_elp_wakeup. This might cause immediate entrance to elp when the wl->mutex is being released, rather than using the delayed enqueueing optimization. Cancel elp_work on wakeup request, and add a new WL1271_FLAG_ELP_REQUESTED flag to further synchronize the elp actions. [Fixed a couple of typos in some comments -- Luca] Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/ps.c30
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h1
2 files changed, 25 insertions, 6 deletions
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index b8deada5d020..b59b67711a17 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
+ /* our work might have been already cancelled */
+ if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ goto out;
+
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,12 +65,16 @@ out:
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
- test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
- cancel_delayed_work(&wl->elp_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
- }
+ /* we shouldn't get consecutive sleep requests */
+ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ return;
+
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+ !test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return;
+
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
u32 start_time = jiffies;
bool pending = false;
+ /*
+ * we might try to wake up even if we didn't go to sleep
+ * before (e.g. on boot)
+ */
+ if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))
+ return 0;
+
+ /* don't cancel_sync as it might contend for a mutex and deadlock */
+ cancel_delayed_work(&wl->elp_work);
+
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 7c521af58e7d..f3de96212b96 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -345,6 +345,7 @@ enum wl12xx_flags {
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
+ WL1271_FLAG_ELP_REQUESTED,
WL1271_FLAG_PSM,
WL1271_FLAG_PSM_REQUESTED,
WL1271_FLAG_IRQ_RUNNING,