From c1b193eb6557279d037ab18c00ab628c6c78847f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 23 Mar 2011 22:22:15 +0200 Subject: wl12xx: rearrange some ELP wake_up/sleep calls ELP (Extremely/Enhanced Low Power, or something like that ;)) refers to the powerstate of the 12xx chip, in which very low power is consumed, and no commands (from the host) can be issued until the chip is woken up. Wakeup/sleep commands must be protected by a wl->mutex, so it's generally a good idea to call wakeup/sleep along with the mutex lock/unlock (where needed). However, in some places the wl12xx driver calls wakeup/sleep in some "inner" functions. This result in some "nested" wakeup/sleep calls which might end up letting the chip go to sleep prematurely (e.g. during event handling). Fix it by rearranging the elp calls to come along with mutex_lock/unlock. Signed-off-by: Eliad Peller Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 971f13e792d..b8deada5d02 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -149,9 +149,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return ret; /* disable beacon early termination */ ret = wl1271_acx_bet_enable(wl, false); -- cgit v1.2.3-18-g5258 From a665d6e260f0233aac73f74d15bb6a029cc5ec47 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 3 Apr 2011 02:01:59 +0300 Subject: 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 Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/ps.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/wl12xx/ps.c') diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index b8deada5d02..b59b67711a1 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; -- cgit v1.2.3-18-g5258