|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/vmalloc.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/irq.h>
|
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
|
|
#include "wlcore.h"
|
|
|
#include "debug.h"
|
|
@@ -43,6 +44,7 @@
|
|
|
|
|
|
#define WL1271_BOOT_RETRIES 3
|
|
|
#define WL1271_SUSPEND_SLEEP 100
|
|
|
+#define WL1271_WAKEUP_TIMEOUT 500
|
|
|
|
|
|
static char *fwlog_param;
|
|
|
static int fwlog_mem_blocks = -1;
|
|
@@ -153,9 +155,11 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work)
|
|
|
if (!wl->conf.rx_streaming.interval)
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl1271_set_rx_streaming(wl, wlvif, true);
|
|
|
if (ret < 0)
|
|
@@ -166,7 +170,8 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work)
|
|
|
jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -183,16 +188,19 @@ static void wl1271_rx_streaming_disable_work(struct work_struct *work)
|
|
|
if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl1271_set_rx_streaming(wl, wlvif, false);
|
|
|
if (ret)
|
|
|
goto out_sleep;
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -229,9 +237,11 @@ static void wlcore_rc_update_work(struct work_struct *work)
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
if (ieee80211_vif_is_mesh(vif)) {
|
|
|
ret = wl1271_acx_set_ht_capabilities(wl, &wlvif->rc_ht_cap,
|
|
@@ -243,7 +253,8 @@ static void wlcore_rc_update_work(struct work_struct *work)
|
|
|
}
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -539,15 +550,16 @@ static int wlcore_irq_locked(struct wl1271 *wl)
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
while (!done && loopcount--) {
|
|
|
/*
|
|
|
* In order to avoid a race with the hardirq, clear the flag
|
|
|
- * before acknowledging the chip. Since the mutex is held,
|
|
|
- * wl1271_ps_elp_wakeup cannot be called concurrently.
|
|
|
+ * before acknowledging the chip.
|
|
|
*/
|
|
|
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
|
|
smp_mb__after_atomic();
|
|
@@ -641,7 +653,8 @@ static int wlcore_irq_locked(struct wl1271 *wl)
|
|
|
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
return ret;
|
|
@@ -796,8 +809,6 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
|
|
|
|
|
wl->state = WLCORE_STATE_RESTARTING;
|
|
|
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
|
|
|
- wl1271_ps_elp_wakeup(wl);
|
|
|
- wlcore_disable_interrupts_nosync(wl);
|
|
|
ieee80211_queue_work(wl->hw, &wl->recovery_work);
|
|
|
}
|
|
|
}
|
|
@@ -819,6 +830,7 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
|
|
|
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
{
|
|
|
u32 end_of_log = 0;
|
|
|
+ int error;
|
|
|
|
|
|
if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
|
|
|
return;
|
|
@@ -830,8 +842,11 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
* Do not send a stop fwlog command if the fw is hanged or if
|
|
|
* dbgpins are used (due to some fw bug).
|
|
|
*/
|
|
|
- if (wl1271_ps_elp_wakeup(wl))
|
|
|
+ error = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (error < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
return;
|
|
|
+ }
|
|
|
if (!wl->watchdog_recovery &&
|
|
|
wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
|
|
|
wl12xx_cmd_stop_fwlog(wl);
|
|
@@ -919,12 +934,20 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|
|
container_of(work, struct wl1271, recovery_work);
|
|
|
struct wl12xx_vif *wlvif;
|
|
|
struct ieee80211_vif *vif;
|
|
|
+ int error;
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
|
if (wl->state == WLCORE_STATE_OFF || wl->plt)
|
|
|
goto out_unlock;
|
|
|
|
|
|
+ error = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (error < 0) {
|
|
|
+ wl1271_warning("Enable for recovery failed");
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
+ }
|
|
|
+ wlcore_disable_interrupts_nosync(wl);
|
|
|
+
|
|
|
if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) {
|
|
|
if (wl->conf.fwlog.output == WL12XX_FWLOG_OUTPUT_HOST)
|
|
|
wl12xx_read_fwlog_panic(wl);
|
|
@@ -958,6 +981,8 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|
|
}
|
|
|
|
|
|
wlcore_op_stop_locked(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
ieee80211_restart_hw(wl->hw);
|
|
|
|
|
@@ -978,24 +1003,6 @@ static int wlcore_fw_wakeup(struct wl1271 *wl)
|
|
|
return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
|
|
|
}
|
|
|
|
|
|
-static int wlcore_fw_sleep(struct wl1271 *wl)
|
|
|
-{
|
|
|
- int ret;
|
|
|
-
|
|
|
- mutex_lock(&wl->mutex);
|
|
|
- ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
|
|
|
- if (ret < 0) {
|
|
|
- wl12xx_queue_recovery_work(wl);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
|
|
-out:
|
|
|
- mutex_unlock(&wl->mutex);
|
|
|
- mdelay(WL1271_SUSPEND_SLEEP);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int wl1271_setup(struct wl1271 *wl)
|
|
|
{
|
|
|
wl->raw_fw_status = kzalloc(wl->fw_status_len, GFP_KERNEL);
|
|
@@ -1184,7 +1191,6 @@ int wl1271_plt_stop(struct wl1271 *wl)
|
|
|
wl1271_flush_deferred_work(wl);
|
|
|
cancel_work_sync(&wl->netstack_work);
|
|
|
cancel_work_sync(&wl->recovery_work);
|
|
|
- cancel_delayed_work_sync(&wl->elp_work);
|
|
|
cancel_delayed_work_sync(&wl->tx_watchdog_work);
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
@@ -1719,6 +1725,7 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
{
|
|
|
struct wl1271 *wl = hw->priv;
|
|
|
struct wl12xx_vif *wlvif;
|
|
|
+ unsigned long flags;
|
|
|
int ret;
|
|
|
|
|
|
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
|
|
@@ -1734,8 +1741,9 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
return ret;
|
|
|
}
|
|
@@ -1765,6 +1773,7 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw,
|
|
|
goto out_sleep;
|
|
|
|
|
|
out_sleep:
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
|
if (ret < 0) {
|
|
@@ -1775,21 +1784,7 @@ out_sleep:
|
|
|
/* flush any remaining work */
|
|
|
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
|
|
|
|
|
|
- /*
|
|
|
- * disable and re-enable interrupts in order to flush
|
|
|
- * the threaded_irq
|
|
|
- */
|
|
|
- wlcore_disable_interrupts(wl);
|
|
|
-
|
|
|
- /*
|
|
|
- * set suspended flag to avoid triggering a new threaded_irq
|
|
|
- * work. no need for spinlock as interrupts are disabled.
|
|
|
- */
|
|
|
- set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
|
|
|
-
|
|
|
- wlcore_enable_interrupts(wl);
|
|
|
flush_work(&wl->tx_work);
|
|
|
- flush_delayed_work(&wl->elp_work);
|
|
|
|
|
|
/*
|
|
|
* Cancel the watchdog even if above tx_flush failed. We will detect
|
|
@@ -1798,15 +1793,14 @@ out_sleep:
|
|
|
cancel_delayed_work(&wl->tx_watchdog_work);
|
|
|
|
|
|
/*
|
|
|
- * Use an immediate call for allowing the firmware to go into power
|
|
|
- * save during suspend.
|
|
|
- * Using a workque for this last write was only hapenning on resume
|
|
|
- * leaving the firmware with power save disabled during suspend,
|
|
|
- * while consuming full power during wowlan suspend.
|
|
|
+ * set suspended flag to avoid triggering a new threaded_irq
|
|
|
+ * work.
|
|
|
*/
|
|
|
- wlcore_fw_sleep(wl);
|
|
|
+ spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
+ set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
|
|
|
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
|
|
|
|
- return 0;
|
|
|
+ return pm_runtime_force_suspend(wl->dev);
|
|
|
}
|
|
|
|
|
|
static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
|
|
@@ -1821,6 +1815,12 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
|
|
|
wl->wow_enabled);
|
|
|
WARN_ON(!wl->wow_enabled);
|
|
|
|
|
|
+ ret = pm_runtime_force_resume(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_error("ELP wakeup failure!");
|
|
|
+ goto out_sleep;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* re-enable irq_work enqueuing, and call irq_work directly if
|
|
|
* there is a pending work.
|
|
@@ -1857,9 +1857,11 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
|
|
|
goto out_sleep;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
if (wlcore_is_p2p_mgmt(wlvif))
|
|
@@ -1878,7 +1880,8 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
|
|
|
goto out_sleep;
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
wl->wow_enabled = false;
|
|
@@ -1945,7 +1948,6 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
|
|
|
cancel_delayed_work_sync(&wl->scan_complete_work);
|
|
|
cancel_work_sync(&wl->netstack_work);
|
|
|
cancel_work_sync(&wl->tx_work);
|
|
|
- cancel_delayed_work_sync(&wl->elp_work);
|
|
|
cancel_delayed_work_sync(&wl->tx_watchdog_work);
|
|
|
|
|
|
/* let's notify MAC80211 about the remaining pending TX frames */
|
|
@@ -2060,13 +2062,16 @@ static void wlcore_channel_switch_work(struct work_struct *work)
|
|
|
vif = wl12xx_wlvif_to_vif(wlvif);
|
|
|
ieee80211_chswitch_done(vif, false);
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl12xx_cmd_stop_channel_switch(wl, wlvif);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -2128,14 +2133,17 @@ static void wlcore_pending_auth_complete_work(struct work_struct *work)
|
|
|
if (!time_after(time_spare, wlvif->pending_auth_reply_time))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/* cancel the ROC if active */
|
|
|
wlcore_update_inconn_sta(wl, wlvif, NULL, false);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -2537,9 +2545,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|
|
wl12xx_get_vif_count(hw, vif, &vif_count);
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
- goto out_unlock;
|
|
|
|
|
|
/*
|
|
|
* in some very corner case HW recovery scenarios its possible to
|
|
@@ -2568,14 +2573,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
|
- if (wl12xx_need_fw_change(wl, vif_count, true)) {
|
|
|
- wl12xx_force_active_psm(wl);
|
|
|
- set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
|
|
|
- mutex_unlock(&wl->mutex);
|
|
|
- wl1271_recovery_work(&wl->recovery_work);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
* TODO: after the nvs issue will be solved, move this block
|
|
|
* to start(), and make sure here the driver is ON.
|
|
@@ -2592,6 +2589,24 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Call runtime PM only after possible wl12xx_init_fw() above
|
|
|
+ * is done. Otherwise we do not have interrupts enabled.
|
|
|
+ */
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wl12xx_need_fw_change(wl, vif_count, true)) {
|
|
|
+ wl12xx_force_active_psm(wl);
|
|
|
+ set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
|
|
|
+ mutex_unlock(&wl->mutex);
|
|
|
+ wl1271_recovery_work(&wl->recovery_work);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
if (!wlcore_is_p2p_mgmt(wlvif)) {
|
|
|
ret = wl12xx_cmd_role_enable(wl, vif->addr,
|
|
|
role_type, &wlvif->role_id);
|
|
@@ -2622,7 +2637,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
|
|
else
|
|
|
wl->sta_count++;
|
|
|
out:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out_unlock:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -2677,9 +2693,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
|
|
|
|
|
if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
|
|
|
/* disable active roles */
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto deinit;
|
|
|
+ }
|
|
|
|
|
|
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
|
|
wlvif->bss_type == BSS_TYPE_IBSS) {
|
|
@@ -2697,7 +2715,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
|
|
goto deinit;
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
}
|
|
|
deinit:
|
|
|
wl12xx_tx_reset_wlvif(wl, wlvif);
|
|
@@ -3121,9 +3140,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/* configure each interface */
|
|
|
wl12xx_for_each_wlvif(wl, wlvif) {
|
|
@@ -3133,7 +3154,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
}
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -3202,9 +3224,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
if (wlcore_is_p2p_mgmt(wlvif))
|
|
@@ -3247,7 +3271,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
|
|
*/
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -3454,13 +3479,16 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|
|
goto out_wake_queues;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out_wake_queues;
|
|
|
+ }
|
|
|
|
|
|
ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out_wake_queues:
|
|
|
if (might_change_spare)
|
|
@@ -3600,9 +3628,11 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out_unlock;
|
|
|
+ }
|
|
|
|
|
|
wlvif->default_key = key_idx;
|
|
|
|
|
@@ -3616,7 +3646,8 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out_unlock:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -3634,7 +3665,7 @@ void wlcore_regdomain_config(struct wl1271 *wl)
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -3644,7 +3675,8 @@ void wlcore_regdomain_config(struct wl1271 *wl)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -3678,9 +3710,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/* fail if there is any role in ROC */
|
|
|
if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) {
|
|
@@ -3691,7 +3725,8 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
|
|
|
|
|
|
ret = wlcore_scan(hw->priv, vif, ssid, len, req);
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -3718,9 +3753,11 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
|
|
|
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
|
|
|
ret = wl->ops->scan_stop(wl, wlvif);
|
|
@@ -3741,7 +3778,8 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
|
|
|
ieee80211_scan_completed(wl->hw, &info);
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -3766,9 +3804,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
|
|
|
if (ret < 0)
|
|
@@ -3777,7 +3817,8 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
|
|
|
wl->sched_vif = wlvif;
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
return ret;
|
|
@@ -3797,13 +3838,16 @@ static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl->ops->sched_scan_stop(wl, wlvif);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -3822,15 +3866,18 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl1271_acx_frag_threshold(wl, value);
|
|
|
if (ret < 0)
|
|
|
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -3851,16 +3898,19 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
ret = wl1271_acx_rts_threshold(wl, wlvif, value);
|
|
|
if (ret < 0)
|
|
|
wl1271_warning("set rts threshold failed: %d", ret);
|
|
|
}
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -4607,9 +4657,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
if ((changed & BSS_CHANGED_TXPOWER) &&
|
|
|
bss_conf->txpower != wlvif->power_level) {
|
|
@@ -4626,7 +4678,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
else
|
|
|
wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -4665,9 +4718,11 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
|
@@ -4690,7 +4745,8 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -4719,9 +4775,11 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wlvif->band = ctx->def.chan->band;
|
|
|
wlvif->channel = channel;
|
|
@@ -4737,7 +4795,8 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
wlvif->radar_enabled = true;
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -4768,9 +4827,11 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
if (wlvif->radar_enabled) {
|
|
|
wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
|
|
@@ -4778,7 +4839,8 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
wlvif->radar_enabled = false;
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -4835,9 +4897,11 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&wl->mutex);
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
for (i = 0; i < n_vifs; i++) {
|
|
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif);
|
|
@@ -4847,7 +4911,8 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
goto out_sleep;
|
|
|
}
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -4878,9 +4943,11 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
|
|
|
if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* the txop is confed in units of 32us by the mac80211,
|
|
@@ -4899,7 +4966,8 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
|
|
|
0, 0);
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -4923,16 +4991,19 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
|
|
|
if (ret < 0)
|
|
|
goto out_sleep;
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -5238,13 +5309,16 @@ static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
if (new_state < old_state)
|
|
@@ -5293,9 +5367,11 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|
|
|
|
|
ba_bitmap = &wl->links[hlid].ba_bitmap;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
|
|
|
tid, action);
|
|
@@ -5368,7 +5444,8 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|
|
ret = -EINVAL;
|
|
|
}
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -5402,16 +5479,19 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
|
|
|
if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
|
|
|
!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
wl1271_set_band_rate(wl, wlvif);
|
|
|
wlvif->basic_rate =
|
|
|
wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
|
|
|
ret = wl1271_acx_sta_rate_policies(wl, wlvif);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
}
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -5441,9 +5521,11 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/* TODO: change mac80211 to pass vif as param */
|
|
|
|
|
@@ -5465,7 +5547,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
|
|
|
}
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -5532,9 +5615,11 @@ static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl->ops->channel_switch(wl, wlvif, &ch_switch);
|
|
|
if (ret)
|
|
@@ -5543,7 +5628,8 @@ static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw,
|
|
|
set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
}
|
|
@@ -5584,9 +5670,11 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
|
|
|
if (ret < 0)
|
|
@@ -5596,7 +5684,8 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
|
|
|
ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
|
|
|
msecs_to_jiffies(duration));
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
return ret;
|
|
@@ -5638,13 +5727,16 @@ static int wlcore_roc_completed(struct wl1271 *wl)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
ret = __wlcore_roc_completed(wl);
|
|
|
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
|
|
|
@@ -5719,19 +5811,22 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
|
|
|
if (unlikely(wl->state != WLCORE_STATE_ON))
|
|
|
goto out;
|
|
|
|
|
|
- ret = wl1271_ps_elp_wakeup(wl);
|
|
|
- if (ret < 0)
|
|
|
+ ret = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (ret < 0) {
|
|
|
+ pm_runtime_put_noidle(wl->dev);
|
|
|
goto out_sleep;
|
|
|
+ }
|
|
|
|
|
|
ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm);
|
|
|
if (ret < 0)
|
|
|
goto out_sleep;
|
|
|
|
|
|
- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
|
|
|
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
|
|
|
sinfo->signal = rssi_dbm;
|
|
|
|
|
|
out_sleep:
|
|
|
- wl1271_ps_elp_sleep(wl);
|
|
|
+ pm_runtime_mark_last_busy(wl->dev);
|
|
|
+ pm_runtime_put_autosuspend(wl->dev);
|
|
|
|
|
|
out:
|
|
|
mutex_unlock(&wl->mutex);
|
|
@@ -6300,7 +6395,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
|
|
|
skb_queue_head_init(&wl->deferred_rx_queue);
|
|
|
skb_queue_head_init(&wl->deferred_tx_queue);
|
|
|
|
|
|
- INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
|
|
|
INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
|
|
|
INIT_WORK(&wl->tx_work, wl1271_tx_work);
|
|
|
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
|
|
@@ -6575,6 +6669,99 @@ out:
|
|
|
complete_all(&wl->nvs_loading_complete);
|
|
|
}
|
|
|
|
|
|
+static int __maybe_unused wlcore_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ struct wl1271 *wl = dev_get_drvdata(dev);
|
|
|
+ struct wl12xx_vif *wlvif;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /* We do not enter elp sleep in PLT mode */
|
|
|
+ if (wl->plt)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Nothing to do if no ELP mode requested */
|
|
|
+ if (wl->sleep_auth != WL1271_PSM_ELP)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ wl12xx_for_each_wlvif(wl, wlvif) {
|
|
|
+ if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
|
|
|
+ test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ wl1271_debug(DEBUG_PSM, "chip to elp");
|
|
|
+ error = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
|
|
|
+ if (error < 0) {
|
|
|
+ wl12xx_queue_recovery_work(wl);
|
|
|
+
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __maybe_unused wlcore_runtime_resume(struct device *dev)
|
|
|
+{
|
|
|
+ struct wl1271 *wl = dev_get_drvdata(dev);
|
|
|
+ DECLARE_COMPLETION_ONSTACK(compl);
|
|
|
+ unsigned long flags;
|
|
|
+ int ret;
|
|
|
+ unsigned long start_time = jiffies;
|
|
|
+ bool pending = false;
|
|
|
+
|
|
|
+ /* Nothing to do if no ELP mode requested */
|
|
|
+ if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ wl1271_debug(DEBUG_PSM, "waking up chip from elp");
|
|
|
+
|
|
|
+ spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
+ if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
|
|
|
+ pending = true;
|
|
|
+ else
|
|
|
+ wl->elp_compl = &compl;
|
|
|
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
|
+
|
|
|
+ ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl12xx_queue_recovery_work(wl);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!pending) {
|
|
|
+ ret = wait_for_completion_timeout(&compl,
|
|
|
+ msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
|
|
|
+ if (ret == 0) {
|
|
|
+ wl1271_error("ELP wakeup timeout!");
|
|
|
+ wl12xx_queue_recovery_work(wl);
|
|
|
+
|
|
|
+ /* Return no error for runtime PM for recovery */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);
|
|
|
+
|
|
|
+ wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
|
|
|
+ jiffies_to_msecs(jiffies - start_time));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ spin_lock_irqsave(&wl->wl_lock, flags);
|
|
|
+ wl->elp_compl = NULL;
|
|
|
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct dev_pm_ops wlcore_pm_ops = {
|
|
|
+ SET_RUNTIME_PM_OPS(wlcore_runtime_suspend,
|
|
|
+ wlcore_runtime_resume,
|
|
|
+ NULL)
|
|
|
+};
|
|
|
+
|
|
|
int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|
|
{
|
|
|
struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
|
|
@@ -6602,6 +6789,11 @@ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
|
|
wlcore_nvs_cb(NULL, wl);
|
|
|
}
|
|
|
|
|
|
+ wl->dev->driver->pm = &wlcore_pm_ops;
|
|
|
+ pm_runtime_set_autosuspend_delay(wl->dev, 50);
|
|
|
+ pm_runtime_use_autosuspend(wl->dev);
|
|
|
+ pm_runtime_enable(wl->dev);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(wlcore_probe);
|
|
@@ -6610,6 +6802,13 @@ int wlcore_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
|
|
|
struct wl1271 *wl = platform_get_drvdata(pdev);
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = pm_runtime_get_sync(wl->dev);
|
|
|
+ if (error < 0)
|
|
|
+ dev_warn(wl->dev, "PM runtime failed: %i\n", error);
|
|
|
+
|
|
|
+ wl->dev->driver->pm = NULL;
|
|
|
|
|
|
if (pdev_data->family && pdev_data->family->nvs_name)
|
|
|
wait_for_completion(&wl->nvs_loading_complete);
|
|
@@ -6621,6 +6820,11 @@ int wlcore_remove(struct platform_device *pdev)
|
|
|
disable_irq_wake(wl->irq);
|
|
|
}
|
|
|
wl1271_unregister_hw(wl);
|
|
|
+
|
|
|
+ pm_runtime_put_sync(wl->dev);
|
|
|
+ pm_runtime_dont_use_autosuspend(wl->dev);
|
|
|
+ pm_runtime_disable(wl->dev);
|
|
|
+
|
|
|
free_irq(wl->irq, wl);
|
|
|
wlcore_free_hw(wl);
|
|
|
|