Runtime PM support for wlcore
Subsystems (2)
v4 cover Runtime PM support for wlcore
Hi all,
Here's the fourth version of wlcore runtime PM changes. Please test one more time.
For testing, please make sure you have also applied patch "[PATCHv2] wlcore: sdio: Fix flakey SDIO runtime PM handling" to avoid bogus errors.
Regards,
Tony
Changes since v3:
- Fixed remaining known issues caused by changes to runtime PM
- Enabled autosuspend
Changes since v2:
- Add fix "wclore: Fix timout errors after recovery" that is not needed before runtime PM conversion
- Add fix from Eyal for "wlcore: Use generic runtime pm calls for wowlan elp configuration" that is also not needed before runtime PM conversion
- Return early from wlcore_runtime_resume() on ELP timeout to avoid clearing WL1271_FLAG_IN_ELP bit
- Tag as RFT as we still need to do more testing and add runtime PM autosuspend support before merging
- Drop "wlcore: sdio: Warn about runtime PM suspend errors" that should no longer be needed
Changes since v1:
- Fix issues reported by Eyal for recovery
- Add few patches for enable/disable issues found when using runtime PM
- Remove unused ps.h includes
Eyal Reizer (1):
wlcore: Use generic runtime pm calls for wowlan elp configuration
Tony Lindgren (7):
wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()
wlcore: Make sure PM calls are paired
wlcore: Add support for runtime PM
wlcore: Fix misplaced PM call for scan_complete_work()
wclore: Fix timout errors after recovery
wlcore: Make sure firmware is initialized in wl1271_op_add_interface()
wlcore: Enable runtime PM autosuspend support
drivers/net/wireless/ti/wl18xx/debugfs.c | 29 +- drivers/net/wireless/ti/wlcore/acx.c | 1 - drivers/net/wireless/ti/wlcore/cmd.c | 10 + drivers/net/wireless/ti/wlcore/debugfs.c | 90 ++-- drivers/net/wireless/ti/wlcore/main.c | 526 ++++++++++++++------ drivers/net/wireless/ti/wlcore/ps.c | 146 ------ drivers/net/wireless/ti/wlcore/ps.h | 3 - drivers/net/wireless/ti/wlcore/scan.c | 13 +- drivers/net/wireless/ti/wlcore/sysfs.c | 13 +- drivers/net/wireless/ti/wlcore/testmode.c | 20 +- drivers/net/wireless/ti/wlcore/tx.c | 10 +- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 30 +- drivers/net/wireless/ti/wlcore/wlcore.h | 1 - drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 - 14 files changed, 512 insertions(+), 381 deletions(-)
Signature · 1 line
2.17.1
A message that is not in the archive (sent off-list or not yet received): 20180619094342.81831-1-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org
PATCH v4 1/8 wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()
Otherwise we can get:
WARNING: CPU: 0 PID: 55 at drivers/net/wireless/ti/wlcore/io.h:84
I've only seen this few times with the runtime PM patches enabled so this one is probably not needed before that. This seems to work currently based on the current PM implementation timer. Let's apply this separately though in case others are hitting this issue.
--- drivers/net/wireless/ti/wlcore/cmd.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/wireless/ti/wlcore/cmd.c +6 -0
@@ -35,6 +35,7 @@#include "wl12xx_80211.h" #include "cmd.h" #include "event.h" +#include "ps.h" #include "tx.h" #include "hw_ops.h"
@@ -191,6 +192,10 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, timeout_time = jiffies +msecs_to_jiffies (WL1271_EVENT_TIMEOUT ); + ret =wl1271_ps_elp_wakeup (wl); +if (ret <0 ) +return ret; + do { if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
@@ -222,6 +227,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, }while (!event); out: +wl1271_ps_elp_sleep (wl);kfree (events_vector);return ret; }
Signature · 1 line
2.17.1
A message that is not in the archive (sent off-list or not yet received): 20180619094342.81831-2-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org
Re: [1/8] wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()
Quoted 10 lines · Tony Lindgren
Otherwise we can get:
WARNING: CPU: 0 PID: 55 at drivers/net/wireless/ti/wlcore/io.h:84I've only seen this few times with the runtime PM patches enabled so this one is probably not needed before that. This seems to work currently based on the current PM implementation timer. Let's apply this separately though in case others are hitting this issue.
Signed-off-by Tony Lindgren <[email protected]>
8 patches applied to wireless-drivers-next.git, thanks.
4ec7cece87b3 wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout() 02edf81362fe wlcore: Make sure PM calls are pairedfa2648a34e73 wlcore: Add support for runtime PM3ebbabea4219 wlcore: Fix misplaced PM call for scan_complete_work() db68052bdf58 wlcore: Fix timout errors after recovery45aa7f071b06 wlcore: Use generic runtime pm calls for wowlan elp configuration c40aad28a3cf wlcore: Make sure firmware is initialized in wl1271_op_add_interface() 9b71578de087 wlcore: Enable runtime PM autosuspend support
Signature · 3 lines
https://patchwork.kernel.org/patch/10473893/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
PATCH v4 2/8 wlcore: Make sure PM calls are paired
In reply to a message not in the archiveThe call to wl1271_ps_elp_wakeup() in wl12xx_queue_recovery_work() is unpaired. Let's remove it and add paired calls to wl1271_recovery_work() instead in preparation for changing things to use runtime PM.
--- drivers/net/wireless/ti/wlcore/main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/wireless/ti/wlcore/main.c +8 -2
@@ -796,8 +796,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); } }
@@ -919,12 +917,18 @@ 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 =wl1271_ps_elp_wakeup (wl); +if (error <0 ) +wl1271_warning ("Enable for recovery failed" ); +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);
@@ -967,6 +971,8 @@ static void wl1271_recovery_work(struct work_struct *work)*/ wlcore_wake_queues (wl,WLCORE_QUEUE_STOP_REASON_FW_RESTART ); +wl1271_ps_elp_sleep (wl); + out_unlock: wl->watchdog_recovery = false;clear_bit (WL1271_FLAG_RECOVERY_IN_PROGRESS , &wl->flags);
Signature · 1 line
2.17.1
PATCH v4 3/8 wlcore: Add support for runtime PM
In reply to a message not in the archiveWe can update wlcore to use PM runtime by adding functions for wlcore_runtime_suspend() and wlcore_runtime_resume() and replacing calls to wl1271_ps_elp_wakeup() and wl1271_ps_elp_sleep() with calls to pm_runtime_get_sync() and pm_runtime_put().
Note that the new wlcore_runtime_suspend() and wlcore_runtime_resume() functions are based on simplified versions of wl1271_ps_elp_sleep() and wl1271_ps_elp_wakeup().
We don't want to use the old functions as we can now take advantage of the runtime PM usage count. And we don't need the old elp_work at all. And we can also remove WL1271_FLAG_ELP_REQUESTED that is no longer needed.
Pretty much the only place where we are not just converting the existing functions is wl1271_op_suspend() where we add pm_runtime_put_noidle() to keep the calls paired.
As the next step is to implement runtime PM autosuspend, let's not add wrapper functions for the generic runtime PM calls. We would be getting rid of any wrapper functions anyways.
After autoidle we should be able to start using Linux generic wakeirqs for the padconf interrupt.
--- drivers/net/wireless/ti/wl18xx/debugfs.c | 26 +- drivers/net/wireless/ti/wlcore/acx.c | 1 - drivers/net/wireless/ti/wlcore/cmd.c | 11 +- drivers/net/wireless/ti/wlcore/debugfs.c | 79 ++-- drivers/net/wireless/ti/wlcore/main.c | 410 ++++++++++++++------ drivers/net/wireless/ti/wlcore/ps.c | 146 ------- drivers/net/wireless/ti/wlcore/ps.h | 3 - drivers/net/wireless/ti/wlcore/scan.c | 10 +- drivers/net/wireless/ti/wlcore/sysfs.c | 12 +- drivers/net/wireless/ti/wlcore/testmode.c | 18 +- drivers/net/wireless/ti/wlcore/tx.c | 9 +- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 27 +- drivers/net/wireless/ti/wlcore/wlcore.h | 1 - drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 - 14 files changed, 416 insertions(+), 338 deletions(-)
drivers/net/wireless/ti/wl18xx/debugfs.c +17 -9
@@ -20,6 +20,8 @@* */ +#include <linux/pm_runtime.h> +#include "../wlcore/debugfs.h" #include "../wlcore/wlcore.h" #include "../wlcore/debug.h"
@@ -276,15 +278,17 @@ static ssize_t radar_detection_write(struct file *file,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 =wl18xx_cmd_radar_detection_debug (wl, channel);if (ret <0 ) count = ret; -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -315,15 +319,17 @@ static ssize_t dynamic_fw_traces_write(struct file *file,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 =wl18xx_acx_dynamic_fw_traces (wl);if (ret <0 ) count = ret; -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -374,9 +380,11 @@ static ssize_t radar_debug_mode_write(struct file *file,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_ap (wl, wlvif) { wlcore_cmd_generic_cfg(wl, wlvif,
@@ -384,7 +392,7 @@ static ssize_t radar_debug_mode_write(struct file *file, wl->radar_debug_mode, 0); } -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);return count;
drivers/net/wireless/ti/wlcore/acx.c +0 -1
@@ -31,7 +31,6 @@#include "wlcore.h" #include "debug.h" #include "wl12xx_80211.h" -#include "ps.h" #include "hw_ops.h" int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
drivers/net/wireless/ti/wlcore/cmd.c +7 -4
@@ -23,6 +23,7 @@#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/etherdevice.h> #include <linux/ieee80211.h>
@@ -35,7 +36,6 @@#include "wl12xx_80211.h" #include "cmd.h" #include "event.h" -#include "ps.h" #include "tx.h" #include "hw_ops.h"
@@ -192,9 +192,12 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, timeout_time = jiffies +msecs_to_jiffies (WL1271_EVENT_TIMEOUT ); - 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); +return ret; + } do { if (time_after(jiffies, timeout_time)) {
@@ -227,7 +230,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, }while (!event); out: -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev);kfree (events_vector);return ret; }
drivers/net/wireless/ti/wlcore/debugfs.c +49 -30
221 lines not on this page · raw message
drivers/net/wireless/ti/wlcore/main.c +295 -115
949 lines not on this page · raw message
drivers/net/wireless/ti/wlcore/ps.c +0 -146
152 lines not on this page · raw message
drivers/net/wireless/ti/wlcore/ps.h +0 -3
@@ -29,9 +29,6 @@int wl1271_ps_set_mode (struct wl1271 *wl,struct wl12xx_vif *wlvif,enum wl1271_cmd_ps_mode mode); -void wl1271_ps_elp_sleep (struct wl1271 *wl); -int wl1271_ps_elp_wakeup (struct wl1271 *wl); -void wl1271_elp_work (struct work_struct *work);void wl12xx_ps_link_start (struct wl1271 *wl,struct wl12xx_vif *wlvif,u8 hlid,bool clean_queues);void wl12xx_ps_link_end (struct wl1271 *wl,struct wl12xx_vif *wlvif,u8 hlid);
drivers/net/wireless/ti/wlcore/scan.c +6 -4
@@ -22,13 +22,13 @@*/ #include <linux/ieee80211.h> +#include <linux/pm_runtime.h> #include "wlcore.h" #include "debug.h" #include "cmd.h" #include "scan.h" #include "acx.h" -#include "ps.h" #include "tx.h" void wl1271_scan_complete_work (struct work_struct *work)
@@ -67,16 +67,18 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.req =NULL ; wl->scan_wlvif =NULL ; - 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 (test_bit (WLVIF_FLAG_STA_ASSOCIATED , &wlvif->flags)) {/* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req (wl, wlvif, wlvif->probereq); } -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev);if (wl->scan.failed) {wl1271_info ("Scan completed due to error." );
drivers/net/wireless/ti/wlcore/sysfs.c +8 -4
@@ -19,9 +19,11 @@* */ +#include <linux/pm_runtime.h> + +#include "acx.h" #include "wlcore.h" #include "debug.h" -#include "ps.h" #include "sysfs.h" static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
@@ -68,12 +70,14 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,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; + }wl1271_acx_sg_enable (wl, wl->sg_enabled); -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/testmode.c +11 -7
@@ -22,13 +22,13 @@*/ #include "testmode.h" +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <net/genetlink.h> #include "wlcore.h" #include "debug.h" #include "acx.h" -#include "ps.h" #include "io.h" #define WL1271_TM_MAX_DATA_LENGTH 1024
@@ -97,9 +97,11 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) 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_cmd_test (wl, buf, buf_len, answer);if (ret <0 ) {
@@ -141,7 +143,7 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) } out_sleep: -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -169,9 +171,11 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) 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; + } cmd =kzalloc (sizeof (*cmd),GFP_KERNEL );if (!cmd) {
@@ -205,7 +209,7 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) out_free:kfree (cmd); out_sleep: -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/tx.c +6 -3
@@ -24,6 +24,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <linux/etherdevice.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include "wlcore.h"
@@ -868,9 +869,11 @@ void wl1271_tx_work(struct work_struct *work)int ret;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; + } ret =wlcore_tx_work_locked (wl);if (ret <0 ) {
@@ -878,7 +881,7 @@ void wl1271_tx_work(struct work_struct *work) goto out; } -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex); }
drivers/net/wireless/ti/wlcore/vendor_cmd.c +17 -10
@@ -8,12 +8,13 @@* version 2 as published by the Free Software Foundation. */ +#include <linux/pm_runtime.h> +#include <net/mac80211.h> #include <net/netlink.h> #include "wlcore.h" #include "debug.h" -#include "ps.h" #include "hw_ops.h" #include "vendor_cmd.h"
@@ -55,14 +56,16 @@ wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, 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_smart_config_start (wl,nla_get_u32 (tb[WLCORE_VENDOR_ATTR_GROUP_ID ])); -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -87,13 +90,15 @@ wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, 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_smart_config_stop (wl); -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -131,16 +136,18 @@ wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy, 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_smart_config_set_group_key (wl,nla_get_u32 (tb[WLCORE_VENDOR_ATTR_GROUP_ID ]),nla_len (tb[WLCORE_VENDOR_ATTR_GROUP_KEY ]),nla_data (tb[WLCORE_VENDOR_ATTR_GROUP_KEY ])); -wl1271_ps_elp_sleep (wl); +pm_runtime_put (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/wlcore.h +0 -1
@@ -348,7 +348,6 @@ struct wl1271 {enum nl80211_band band;struct completion *elp_compl; -struct delayed_work elp_work;/* in dBm */ int power_level;
drivers/net/wireless/ti/wlcore/wlcore_i.h +0 -1
@@ -233,7 +233,6 @@ enum wl12xx_flags {WL1271_FLAG_TX_QUEUE_STOPPED ,WL1271_FLAG_TX_PENDING ,WL1271_FLAG_IN_ELP , -WL1271_FLAG_ELP_REQUESTED ,WL1271_FLAG_IRQ_RUNNING ,WL1271_FLAG_FW_TX_BUSY , WL1271_FLAG_DUMMY_PACKET_PENDING,
Signature · 1 line
2.17.1
PATCH v4 4/8 wlcore: Fix misplaced PM call for scan_complete_work()
In reply to a message not in the archiveWith runtime PM enabled, we now need to have wlcore enabled longer until after we're done calling wlcore_cmd_regdomain_config_locked():
scan_complete_work()
wlcore_cmd_regdomain_config_locked()
wlcore_cmd_send_failsafe()
wl12xx_sdio_raw_read()
Note that this is not needed before runtime PM support as the custom PM code had it's own timer. We have not yet enabled runtime PM autosuspend for wlcore and this is why this issue now shows up.
Let's fix the issues first before we enable runtime PM autosuspend.
--- drivers/net/wireless/ti/wlcore/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/ti/wlcore/scan.c +0 -1
@@ -78,8 +78,6 @@ void wl1271_scan_complete_work(struct work_struct *work)wl1271_cmd_build_ap_probe_req (wl, wlvif, wlvif->probereq); } -pm_runtime_put (wl->dev);
PATCH v4 5/8 wclore: Fix timout errors after recovery
In reply to a message not in the archiveAfter enabling runtime PM, if we force hardware reset multiple times with:
# echo 1 > /sys/kernel/debug/ieee80211/phy0/wlcore/start_recovery
We will after few tries get the following error:
wlcore: ERROR timeout waiting for the hardware to complete initialization
And then wlcore is unable to reconnect until after the wlcore related modules are reloaded.
Let's fix this by moving pm_runtime_put() earlier before we restart the hardware. And let's use the sync version to make sure we're done before we restart.
Note that we still will get -EBUSY warning from wl12xx_sdio_set_power() but let's fix that separately once we know exactly why we get the warning.
--- drivers/net/wireless/ti/wlcore/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/net/wireless/ti/wlcore/main.c +1 -1
@@ -977,6 +977,7 @@ static void wl1271_recovery_work(struct work_struct *work) }wlcore_op_stop_locked (wl); +pm_runtime_put_sync (wl->dev);ieee80211_restart_hw (wl->hw);
@@ -986,8 +987,6 @@ static void wl1271_recovery_work(struct work_struct *work)*/ wlcore_wake_queues (wl,WLCORE_QUEUE_STOP_REASON_FW_RESTART ); -pm_runtime_put (wl->dev);
A message that is not in the archive (sent off-list or not yet received): 20180619094342.81831-6-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org
Re: [5/8] wclore: Fix timout errors after recovery
Quoted 11 lines · Tony Lindgren
After enabling runtime PM, if we force hardware reset multiple times with:
# echo 1 > /sys/kernel/debug/ieee80211/phy0/wlcore/start_recoveryWe will after few tries get the following error:
wlcore: ERROR timeout waiting for the hardware to complete initialization
And then wlcore is unable to reconnect until after the wlcore related modules are reloaded.
Quoted 8 lines
Let's fix this by moving
pm_runtime_put()earlier before we restart the hardware. And let's use the sync version to make sure we're done before we restart.Note that we still will get
-EBUSYwarning fromwl12xx_sdio_set_power()but let's fix that separately once we know exactly why we get the warning.Reported-by Eyal Reizer <[email protected]>Signed-off-by Tony Lindgren <[email protected]>
I'll do s/wclore/wlcore/ to the title.
Signature · 3 lines
https://patchwork.kernel.org/patch/10473897/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): 20180627154152.BCECB60714-4h6buKAYkuurB/[email protected]
Re: [5/8] wclore: Fix timout errors after recovery
Quoted 2 lines · Kalle Valo
I'll do s/wclore/wlcore/ to the title.
OK thanks and sorry about that one.
Tony
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [5/8] wclore: Fix timout errors after recovery
Quoted 5 lines · Tony Lindgren
Quoted 2 lines · Kalle Valo
I'll do s/wclore/wlcore/ to the title.
OK thanks and sorry about that one.
No problem. I would not have even noticed the typo but I did 'list -s new wlcore' (which prints all patches in new state with wlcore on the subject) on my patchwork script and started to wonder where did the patch 5 go :)
Signature · 1 line
Kalle Valo
PATCH v4 6/8 wlcore: Use generic runtime pm calls for wowlan elp configuration
In reply to a message not in the archiveFrom: Eyal Reizer <[email protected]>
With runtime PM enabled, we can now use calls to pm_runtime_force_suspend and pm_runtime_force_resume for enabling elp during suspend when wowlan is enabled and waking the chip from elp on resume.
Remove the custom API that was used to ensure that the command that is used to allow ELP during suspend is completed before the system suspend.
--- drivers/net/wireless/ti/wlcore/main.c | 51 +++++++-------------------- 1 file changed, 13 insertions(+), 38 deletions(-)
drivers/net/wireless/ti/wlcore/main.c +13 -38
@@ -998,24 +998,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 );
@@ -1738,6 +1720,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);
@@ -1796,19 +1779,6 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw,/* 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);/*
@@ -1818,15 +1788,14 @@ static int __maybe_unused wl1271_op_suspend(struct ieee80211_hw *hw,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)
@@ -1841,6 +1810,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.
Signature · 1 line
2.17.1
PATCH v4 7/8 wlcore: Make sure firmware is initialized in wl1271_op_add_interface()
In reply to a message not in the archiveWe have wl12xx_boot() call wl12xx_enable_interrupts() and if we have wl1271_op_add_interface() call pm_runtime_get_sync() before the interrupts are enabled. And then we get the following error during boot:
wlcore: ERROR ELP wakeup timeout!
Let's fix this by first checking if we need to boot the firmware. And only after that call pm_runtime_get_sync() when interrupts are enabled. And only after that do the check for wl12xx_need_fw_change().
--- drivers/net/wireless/ti/wlcore/main.c | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-)
drivers/net/wireless/ti/wlcore/main.c +18 -13
@@ -2537,11 +2537,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,wl12xx_get_vif_count (hw, vif, &vif_count);mutex_lock (&wl->mutex); - ret =pm_runtime_get_sync (wl->dev); -if (ret <0 ) { -pm_runtime_put_noidle (wl->dev); - goto out_unlock; - }/* * in some very corner case HW recovery scenarios its possible to
@@ -2570,14 +2565,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.
@@ -2594,6 +2581,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);
Signature · 1 line
2.17.1
PATCH v4 8/8 wlcore: Enable runtime PM autosuspend support
In reply to a message not in the archiveWith runtime PM tested working for wlcore with no autosuspend, we can now enable autosuspend to cut down on enable/disable for interrupts. Basically we just replace pm_runtime_put() with the autosuspend variants.
Let's use autosuspend delay of 50ms that MMC drivers typically use.
--- drivers/net/wireless/ti/wl18xx/debugfs.c | 9 +- drivers/net/wireless/ti/wlcore/cmd.c | 3 +- drivers/net/wireless/ti/wlcore/debugfs.c | 33 ++++-- drivers/net/wireless/ti/wlcore/main.c | 111 +++++++++++++------- drivers/net/wireless/ti/wlcore/scan.c | 3 +- drivers/net/wireless/ti/wlcore/sysfs.c | 3 +- drivers/net/wireless/ti/wlcore/testmode.c | 6 +- drivers/net/wireless/ti/wlcore/tx.c | 3 +- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 9 +- 9 files changed, 121 insertions(+), 59 deletions(-)
drivers/net/wireless/ti/wl18xx/debugfs.c +6 -3
@@ -288,7 +288,8 @@ static ssize_t radar_detection_write(struct file *file,if (ret <0 ) count = ret; -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -329,7 +330,8 @@ static ssize_t dynamic_fw_traces_write(struct file *file,if (ret <0 ) count = ret; -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -392,7 +394,8 @@ static ssize_t radar_debug_mode_write(struct file *file, wl->radar_debug_mode, 0); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
drivers/net/wireless/ti/wlcore/cmd.c +2 -1
@@ -230,7 +230,8 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, }while (!event); out: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev);kfree (events_vector);return ret; }
drivers/net/wireless/ti/wlcore/debugfs.c +22 -11
@@ -79,7 +79,8 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl) wl->stats.fw_stats_update = jiffies; } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -131,7 +132,8 @@ static void chip_op_handler(struct wl1271 *wl, unsigned long value, chip_op = arg;chip_op (wl); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); }
@@ -313,7 +315,8 @@ static ssize_t dynamic_ps_timeout_write(struct file *file,wl1271_ps_set_mode (wl, wlvif,STATION_AUTO_PS_MODE ); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -384,7 +387,8 @@ static ssize_t forced_ps_write(struct file *file,wl1271_ps_set_mode (wl, wlvif, ps_mode); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -858,7 +862,8 @@ static ssize_t rx_streaming_interval_write(struct file *file,wl1271_recalc_rx_streaming (wl, wlvif); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -915,7 +920,8 @@ static ssize_t rx_streaming_always_write(struct file *file,wl1271_recalc_rx_streaming (wl, wlvif); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -964,7 +970,8 @@ static ssize_t beacon_filtering_write(struct file *file, ret =wl1271_acx_beacon_filter_opt (wl, wlvif, !!value); } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -1046,7 +1053,8 @@ static ssize_t sleep_auth_write(struct file *file, goto out_sleep; out_sleep: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);return count;
@@ -1120,7 +1128,8 @@ static ssize_t dev_mem_read(struct file *file, goto part_err; part_err: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); skip_read:mutex_unlock (&wl->mutex);
@@ -1201,7 +1210,8 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, goto part_err; part_err: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); skip_write:mutex_unlock (&wl->mutex);
@@ -1276,7 +1286,8 @@ static ssize_t fw_logger_write(struct file *file, ret =wl12xx_cmd_config_fwlog (wl); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/main.c +75 -36
339 lines not on this page · raw message
drivers/net/wireless/ti/wlcore/scan.c +2 -1
@@ -85,7 +85,8 @@ void wl1271_scan_complete_work(struct work_struct *work)wlcore_cmd_regdomain_config_locked (wl); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev);ieee80211_scan_completed (wl->hw, &info);
drivers/net/wireless/ti/wlcore/sysfs.c +2 -1
@@ -77,7 +77,8 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, }wl1271_acx_sg_enable (wl, wl->sg_enabled); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/testmode.c +4 -2
@@ -143,7 +143,8 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) } out_sleep: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -209,7 +210,8 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) out_free:kfree (cmd); out_sleep: -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
drivers/net/wireless/ti/wlcore/tx.c +2 -1
@@ -881,7 +881,8 @@ void wl1271_tx_work(struct work_struct *work) goto out; } -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex); }
drivers/net/wireless/ti/wlcore/vendor_cmd.c +6 -3
@@ -65,7 +65,8 @@ wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, ret =wlcore_smart_config_start (wl,nla_get_u32 (tb[WLCORE_VENDOR_ATTR_GROUP_ID ])); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -98,7 +99,8 @@ wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, ret =wlcore_smart_config_stop (wl); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
@@ -147,7 +149,8 @@ wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,nla_len (tb[WLCORE_VENDOR_ATTR_GROUP_KEY ]), nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY])); -pm_runtime_put (wl->dev); +pm_runtime_mark_last_busy (wl->dev); +pm_runtime_put_autosuspend (wl->dev); out:mutex_unlock (&wl->mutex);
Signature · 1 line
2.17.1
Quoted 6 lines · Tony Lindgren
Here's the fourth version of wlcore runtime PM changes. Please test one more time.
For testing, please make sure you have also applied patch "[PATCHv2] wlcore: sdio: Fix flakey SDIO runtime PM handling" to avoid bogus errors.
I assume this is ready to be applied now. If not, please holler.
Signature · 1 line
Kalle Valo