wl12xx: enter/exit psm on wowlan suspend/resume

When operating as station, enter psm before suspending
the device into wowlan state.

Add a new completion event to signal when psm was entered
successfully.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
This commit is contained in:
Eliad Peller 2011-05-13 11:57:13 +03:00 committed by Luciano Coelho
parent f795ea8b2f
commit 9439064cd9
4 changed files with 91 additions and 0 deletions

View File

@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
/* enable beacon early termination */ /* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true); ret = wl1271_acx_bet_enable(wl, true);
if (ret < 0)
break;
if (wl->ps_compl) {
complete(wl->ps_compl);
wl->ps_compl = NULL;
}
break; break;
default: default:
break; break;

View File

@ -1350,6 +1350,79 @@ static struct notifier_block wl1271_dev_notifier = {
.notifier_call = wl1271_dev_notify, .notifier_call = wl1271_dev_notify,
}; };
static int wl1271_configure_suspend(struct wl1271 *wl)
{
int ret;
if (wl->bss_type != BSS_TYPE_STA_BSS)
return 0;
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
/* enter psm if needed*/
if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
DECLARE_COMPLETION_ONSTACK(compl);
wl->ps_compl = &compl;
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
wl->basic_rate, true);
if (ret < 0)
goto out_sleep;
/* we must unlock here so we will be able to get events */
wl1271_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
ret = wait_for_completion_timeout(
&compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
if (ret <= 0) {
wl1271_warning("couldn't enter ps mode!");
ret = -EBUSY;
goto out;
}
/* take mutex again, and wakeup */
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;
}
out_sleep:
wl1271_ps_elp_sleep(wl);
out_unlock:
mutex_unlock(&wl->mutex);
out:
return ret;
}
static void wl1271_configure_resume(struct wl1271 *wl)
{
int ret;
if (wl->bss_type != BSS_TYPE_STA_BSS)
return;
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
/* exit psm if it wasn't configured */
if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
wl->basic_rate, true);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
static int wl1271_op_suspend(struct ieee80211_hw *hw, static int wl1271_op_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wow) struct cfg80211_wowlan *wow)
{ {
@ -1357,6 +1430,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
wl->wow_enabled = !!wow; wl->wow_enabled = !!wow;
if (wl->wow_enabled) { if (wl->wow_enabled) {
int ret;
ret = wl1271_configure_suspend(wl);
if (ret < 0) {
wl1271_warning("couldn't prepare device to suspend");
return ret;
}
/* flush any remaining work */ /* flush any remaining work */
wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
flush_delayed_work(&wl->scan_complete_work); flush_delayed_work(&wl->scan_complete_work);
@ -1408,6 +1487,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
wl1271_irq(0, wl); wl1271_irq(0, wl);
wl1271_enable_interrupts(wl); wl1271_enable_interrupts(wl);
} }
wl1271_configure_resume(wl);
} }
return 0; return 0;

View File

@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work);
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
#define WL1271_PS_COMPLETE_TIMEOUT 500
#endif /* __WL1271_PS_H__ */ #endif /* __WL1271_PS_H__ */

View File

@ -513,6 +513,7 @@ struct wl1271 {
unsigned int rx_filter; unsigned int rx_filter;
struct completion *elp_compl; struct completion *elp_compl;
struct completion *ps_compl;
struct delayed_work elp_work; struct delayed_work elp_work;
struct delayed_work pspoll_work; struct delayed_work pspoll_work;