wl12xx: avoid premature elp entrance
authorEliad Peller <eliad@wizery.com>
Sat, 2 Apr 2011 23:01:59 +0000 (02:01 +0300)
committerLuciano Coelho <coelho@ti.com>
Mon, 2 May 2011 07:25:27 +0000 (10:25 +0300)
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>
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/wl12xx.h

index b8deada5d0206203a3d8462253dcb185662d1927..b59b67711a177ea6ca1160d5789a9efc62144ebe 100644 (file)
@@ -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;
 
index 7c521af58e7d477787e86f712b9e1b5bb9d2578e..f3de96212b96893c94a3c0fc56d62be87716fa6c 100644 (file)
@@ -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,