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:
parent
f795ea8b2f
commit
9439064cd9
4 changed files with 91 additions and 0 deletions
|
@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
|
|||
|
||||
/* enable beacon early termination */
|
||||
ret = wl1271_acx_bet_enable(wl, true);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
if (wl->ps_compl) {
|
||||
complete(wl->ps_compl);
|
||||
wl->ps_compl = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -1350,6 +1350,79 @@ static struct notifier_block wl1271_dev_notifier = {
|
|||
.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,
|
||||
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);
|
||||
wl->wow_enabled = !!wow;
|
||||
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 */
|
||||
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
|
||||
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_enable_interrupts(wl);
|
||||
}
|
||||
|
||||
wl1271_configure_resume(wl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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_end(struct wl1271 *wl, u8 hlid);
|
||||
|
||||
#define WL1271_PS_COMPLETE_TIMEOUT 500
|
||||
|
||||
#endif /* __WL1271_PS_H__ */
|
||||
|
|
|
@ -513,6 +513,7 @@ struct wl1271 {
|
|||
unsigned int rx_filter;
|
||||
|
||||
struct completion *elp_compl;
|
||||
struct completion *ps_compl;
|
||||
struct delayed_work elp_work;
|
||||
struct delayed_work pspoll_work;
|
||||
|
||||
|
|
Loading…
Reference in a new issue