|
@@ -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;
|