* [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back
@ 2025-03-20 2:29 Baochen Qiang
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
` (5 more replies)
0 siblings, 6 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:29 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
To handle the Lenovo unexpected wakeup issue [1], previously we revert
commit 166a490f59ac ("wifi: ath11k: support hibernation"). However we
need to bring it back, of course with additional changes such that Lenovo
machines would not break.
As those machines work well in Non-WoWLAN suspend mode, the thought here
is that we do WoWLAN suspend on Lenovo machines while do non-WoWLAN
suspend (which is done in the reverted commit) on other machines. This
requires us to identify Lenovo machines from others. For that purpose,
read machine info from DMI interface, match it against all known affected
machines. If there is a match, choose WoWLAN suspend mode, else choose
non-WoWLAN mode.
[1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
Baochen Qiang (5):
wifi: ath11k: determine PM policy based on machine model
wifi: ath11k: introduce ath11k_core_continue_suspend_resume()
wifi: ath11k: refactor ath11k_core_suspend/_resume()
wifi: ath11k: support non-WoWLAN mode suspend as well
Reapply "wifi: ath11k: restore country code during resume"
drivers/net/wireless/ath/ath11k/ahb.c | 4 +-
drivers/net/wireless/ath/ath11k/core.c | 245 +++++++++++++++++++++++--
drivers/net/wireless/ath/ath11k/core.h | 11 ++
drivers/net/wireless/ath/ath11k/hif.h | 14 +-
drivers/net/wireless/ath/ath11k/mhi.c | 14 +-
drivers/net/wireless/ath/ath11k/mhi.h | 5 +-
drivers/net/wireless/ath/ath11k/pci.c | 44 ++++-
drivers/net/wireless/ath/ath11k/qmi.c | 4 +-
8 files changed, 301 insertions(+), 40 deletions(-)
base-commit: b6f473c96421b8b451a8df8ccb620bcd71d4b3f4
--
2.25.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
@ 2025-03-20 2:29 ` Baochen Qiang
2025-03-20 22:43 ` kernel test robot
` (2 more replies)
2025-03-20 2:30 ` [PATCH ath-next 2/5] wifi: ath11k: introduce ath11k_core_continue_suspend_resume() Baochen Qiang
` (4 subsequent siblings)
5 siblings, 3 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:29 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
To handle the Lenovo unexpected wakeup issue [1], previously we revert
commit 166a490f59ac ("wifi: ath11k: support hibernation"). So currently
WLAN target is put into WoWLAN mode during suspend. This is a temporary
solution as it does not work on machines where WLAN power is cut off.
The thought here is that we do WoWLAN suspend on Lenovo machines while
do non-WoWLAN suspend (which is done in the reverted commit) on other
machines. This requires us to identify Lenovo machines from others.
For that purpose, read board vendor and product name from DMI interface,
match it against all known affected machines. If there is a match, choose
WoWLAN suspend mode, else choose non-WoWLAN mode. Save the mode in ab
for later reference.
[1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
drivers/net/wireless/ath/ath11k/core.c | 55 ++++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/core.h | 7 ++++
2 files changed, 62 insertions(+)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 3d39ff85ba94..8657e735bf16 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -907,6 +907,52 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
},
};
+static const struct dmi_system_id ath11k_pm_quirk_table[] = {
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21J4"),
+ },
+ },
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21K4"),
+ },
+ },
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21K6"),
+ },
+ },
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21K8"),
+ },
+ },
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21KA"),
+ },
+ },
+ {
+ .driver_data = (void *)ATH11K_PM_WOW,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),
+ },
+ },
+ {}
+};
+
static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab)
{
WARN_ON(!ab->hw_params.single_pdev_only);
@@ -2327,8 +2373,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init);
int ath11k_core_init(struct ath11k_base *ab)
{
+ const struct dmi_system_id *dmi_id;
int ret;
+ dmi_id = dmi_first_match(ath11k_pm_quirk_table);
+ if (dmi_id)
+ ab->pm_policy = (enum ath11k_pm_policy)dmi_id->driver_data;
+ else
+ ab->pm_policy = ATH11K_PM_DEFAULT;
+
+ ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n", ab->pm_policy);
+
ret = ath11k_core_soc_create(ab);
if (ret) {
ath11k_err(ab, "failed to create soc core: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 1a3d0de4afde..df2b0cb2f0b5 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -892,6 +892,11 @@ struct ath11k_msi_config {
u16 hw_rev;
};
+enum ath11k_pm_policy {
+ ATH11K_PM_DEFAULT,
+ ATH11K_PM_WOW,
+};
+
/* Master structure to hold the hw data which may be used in core module */
struct ath11k_base {
enum ath11k_hw_rev hw_rev;
@@ -1058,6 +1063,8 @@ struct ath11k_base {
} testmode;
#endif
+ enum ath11k_pm_policy pm_policy;
+
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH ath-next 2/5] wifi: ath11k: introduce ath11k_core_continue_suspend_resume()
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
@ 2025-03-20 2:30 ` Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 3/5] wifi: ath11k: refactor ath11k_core_suspend/_resume() Baochen Qiang
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:30 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
Currently ath11k_core_suspend() and ath11k_core_resume() have the same
check before going on. In upcoming patches the check is needed by some
newly added functions as well.
To avoid duplicate code, introduce a new helper
ath11k_core_continue_suspend_resume() which does such check internally.
Callers can decide whether to go on based on its return value.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
drivers/net/wireless/ath/ath11k/core.c | 46 +++++++++++++++-----------
1 file changed, 27 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 8657e735bf16..d3241a0df407 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1018,23 +1018,37 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab)
return ab->hw_params.coldboot_cal_mm;
}
-int ath11k_core_suspend(struct ath11k_base *ab)
+/* Check if we need to continue with suspend/resume operation.
+ * Return:
+ * a negative value: error happens and don't continue.
+ * 0: no error but don't continue.
+ * positive value: no error and do continue.
+ */
+static int ath11k_core_continue_suspend_resume(struct ath11k_base *ab)
{
- int ret;
- struct ath11k_pdev *pdev;
struct ath11k *ar;
if (!ab->hw_params.supports_suspend)
return -EOPNOTSUPP;
/* so far single_pdev_only chips have supports_suspend as true
- * and only the first pdev is valid.
+ * so pass 0 as a dummy pdev_id here.
*/
- pdev = ath11k_core_get_single_pdev(ab);
- ar = pdev->ar;
+ ar = ab->pdevs[0].ar;
if (!ar || ar->state != ATH11K_STATE_OFF)
return 0;
+ return 1;
+}
+
+int ath11k_core_suspend(struct ath11k_base *ab)
+{
+ int ret;
+
+ ret = ath11k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
ret = ath11k_dp_rx_pktlog_stop(ab, true);
if (ret) {
ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
@@ -1042,7 +1056,10 @@ int ath11k_core_suspend(struct ath11k_base *ab)
return ret;
}
- ret = ath11k_mac_wait_tx_complete(ar);
+ /* So far only single_pdev_only devices can reach here,
+ * so it is valid to handle the first, and the only, pdev.
+ */
+ ret = ath11k_mac_wait_tx_complete(ab->pdevs[0].ar);
if (ret) {
ath11k_warn(ab, "failed to wait tx complete: %d\n", ret);
return ret;
@@ -1080,19 +1097,10 @@ EXPORT_SYMBOL(ath11k_core_suspend);
int ath11k_core_resume(struct ath11k_base *ab)
{
int ret;
- struct ath11k_pdev *pdev;
- struct ath11k *ar;
- if (!ab->hw_params.supports_suspend)
- return -EOPNOTSUPP;
-
- /* so far signle_pdev_only chips have supports_suspend as true
- * and only the first pdev is valid.
- */
- pdev = ath11k_core_get_single_pdev(ab);
- ar = pdev->ar;
- if (!ar || ar->state != ATH11K_STATE_OFF)
- return 0;
+ ret = ath11k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
ret = ath11k_hif_resume(ab);
if (ret) {
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH ath-next 3/5] wifi: ath11k: refactor ath11k_core_suspend/_resume()
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 2/5] wifi: ath11k: introduce ath11k_core_continue_suspend_resume() Baochen Qiang
@ 2025-03-20 2:30 ` Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 4/5] wifi: ath11k: support non-WoWLAN mode suspend as well Baochen Qiang
` (2 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:30 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
Due to [1] we currently put WLAN target into WoWLAN mode regardless of
machine models. In upcoming patches we will support another mode, and
finally which mode is chosen depends on the exact machine model.
To prepare for such change, refactor the actual WoWLAN stuff in
ath11k_core_suspend() into a new helper ath11k_core_suspend_wow(), this
increase the code readability when the new suspend mode is added in
upcoming patches.
Same change applies to ath11k_core_resume();
[1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
drivers/net/wireless/ath/ath11k/core.c | 28 +++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index d3241a0df407..0396eb557e3b 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1041,14 +1041,10 @@ static int ath11k_core_continue_suspend_resume(struct ath11k_base *ab)
return 1;
}
-int ath11k_core_suspend(struct ath11k_base *ab)
+static int ath11k_core_suspend_wow(struct ath11k_base *ab)
{
int ret;
- ret = ath11k_core_continue_suspend_resume(ab);
- if (ret <= 0)
- return ret;
-
ret = ath11k_dp_rx_pktlog_stop(ab, true);
if (ret) {
ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
@@ -1092,9 +1088,8 @@ int ath11k_core_suspend(struct ath11k_base *ab)
return 0;
}
-EXPORT_SYMBOL(ath11k_core_suspend);
-int ath11k_core_resume(struct ath11k_base *ab)
+int ath11k_core_suspend(struct ath11k_base *ab)
{
int ret;
@@ -1102,6 +1097,14 @@ int ath11k_core_resume(struct ath11k_base *ab)
if (ret <= 0)
return ret;
+ return ath11k_core_suspend_wow(ab);
+}
+EXPORT_SYMBOL(ath11k_core_suspend);
+
+static int ath11k_core_resume_wow(struct ath11k_base *ab)
+{
+ int ret;
+
ret = ath11k_hif_resume(ab);
if (ret) {
ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);
@@ -1126,6 +1129,17 @@ int ath11k_core_resume(struct ath11k_base *ab)
return 0;
}
+
+int ath11k_core_resume(struct ath11k_base *ab)
+{
+ int ret;
+
+ ret = ath11k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ return ath11k_core_resume_wow(ab);
+}
EXPORT_SYMBOL(ath11k_core_resume);
static void ath11k_core_check_cc_code_bdfext(const struct dmi_header *hdr, void *data)
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH ath-next 4/5] wifi: ath11k: support non-WoWLAN mode suspend as well
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
` (2 preceding siblings ...)
2025-03-20 2:30 ` [PATCH ath-next 3/5] wifi: ath11k: refactor ath11k_core_suspend/_resume() Baochen Qiang
@ 2025-03-20 2:30 ` Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 5/5] Reapply "wifi: ath11k: restore country code during resume" Baochen Qiang
2025-03-23 20:12 ` [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Muhammad Usama Anjum
5 siblings, 0 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:30 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
Previously commit 166a490f59ac ("wifi: ath11k: support hibernation") was
reverted due to [1], so currently we only support WoWLAN mode suspend.
This works well in scenarios where WLAN power is sustained during suspend,
however breaks in those where power is cut off.
This change basically brings the reverted commit back, but differs in that
we decide based on the PM policy to choose WoWLAN mode suspend or the
non-WoWLAN mode. As stated in the previous patch for now the PM policy is
determined based on machine models. That said we will choose WoWLAN mode
suspend if we are running on machines listed in ath11k_pm_quirk_table,
otherwise we choose the other one.
[1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
drivers/net/wireless/ath/ath11k/ahb.c | 4 +-
drivers/net/wireless/ath/ath11k/core.c | 123 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/core.h | 4 +
drivers/net/wireless/ath/ath11k/hif.h | 14 ++-
drivers/net/wireless/ath/ath11k/mhi.c | 14 ++-
drivers/net/wireless/ath/ath11k/mhi.h | 5 +-
drivers/net/wireless/ath/ath11k/pci.c | 44 +++++++--
drivers/net/wireless/ath/ath11k/qmi.c | 4 +-
8 files changed, 187 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index eedba3766ba2..511f5f91da0f 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -413,7 +413,7 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab)
return ret;
}
-static void ath11k_ahb_power_down(struct ath11k_base *ab)
+static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
@@ -1280,7 +1280,7 @@ static void ath11k_ahb_remove(struct platform_device *pdev)
struct ath11k_base *ab = platform_get_drvdata(pdev);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
- ath11k_ahb_power_down(ab);
+ ath11k_ahb_power_down(ab, false);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 0396eb557e3b..b248237302ac 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1089,6 +1089,52 @@ static int ath11k_core_suspend_wow(struct ath11k_base *ab)
return 0;
}
+static int ath11k_core_suspend_default(struct ath11k_base *ab)
+{
+ int ret;
+
+ ret = ath11k_dp_rx_pktlog_stop(ab, true);
+ if (ret) {
+ ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* So far only single_pdev_only devices can reach here,
+ * so it is valid to handle the first, and the only, pdev.
+ */
+ ret = ath11k_mac_wait_tx_complete(ab->pdevs[0].ar);
+ if (ret) {
+ ath11k_warn(ab, "failed to wait tx complete: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath11k_dp_rx_pktlog_stop(ab, false);
+ if (ret) {
+ ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
+ ret);
+ return ret;
+ }
+
+ ath11k_ce_stop_shadow_timers(ab);
+ ath11k_dp_stop_shadow_timers(ab);
+
+ /* PM framework skips suspend_late/resume_early callbacks
+ * if other devices report errors in their suspend callbacks.
+ * However ath11k_core_resume() would still be called because
+ * here we return success thus kernel put us on dpm_suspended_list.
+ * Since we won't go through a power down/up cycle, there is
+ * no chance to call complete(&ab->restart_completed) in
+ * ath11k_core_restart(), making ath11k_core_resume() timeout.
+ * So call it here to avoid this issue. This also works in case
+ * no error happens thus suspend_late/resume_early get called,
+ * because it will be reinitialized in ath11k_core_resume_early().
+ */
+ complete(&ab->restart_completed);
+
+ return 0;
+}
+
int ath11k_core_suspend(struct ath11k_base *ab)
{
int ret;
@@ -1097,10 +1143,73 @@ int ath11k_core_suspend(struct ath11k_base *ab)
if (ret <= 0)
return ret;
- return ath11k_core_suspend_wow(ab);
+ if (ab->pm_policy == ATH11K_PM_WOW)
+ return ath11k_core_suspend_wow(ab);
+
+ return ath11k_core_suspend_default(ab);
}
EXPORT_SYMBOL(ath11k_core_suspend);
+int ath11k_core_suspend_late(struct ath11k_base *ab)
+{
+ int ret;
+
+ ret = ath11k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ if (ab->pm_policy == ATH11K_PM_WOW)
+ return 0;
+
+ ath11k_hif_irq_disable(ab);
+ ath11k_hif_ce_irq_disable(ab);
+
+ ath11k_hif_power_down(ab, true);
+
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_core_suspend_late);
+
+int ath11k_core_resume_early(struct ath11k_base *ab)
+{
+ int ret;
+
+ ret = ath11k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ if (ab->pm_policy == ATH11K_PM_WOW)
+ return 0;
+
+ reinit_completion(&ab->restart_completed);
+ ret = ath11k_hif_power_up(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to power up hif during resume: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(ath11k_core_resume_early);
+
+static int ath11k_core_resume_default(struct ath11k_base *ab)
+{
+ long time_left;
+ int ret;
+
+ time_left = wait_for_completion_timeout(&ab->restart_completed,
+ ATH11K_RESET_TIMEOUT_HZ);
+ if (time_left == 0) {
+ ath11k_warn(ab, "timeout while waiting for restart complete");
+ return -ETIMEDOUT;
+ }
+
+ ret = ath11k_dp_rx_pktlog_start(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
+ ret);
+
+ return ret;
+}
+
static int ath11k_core_resume_wow(struct ath11k_base *ab)
{
int ret;
@@ -1138,7 +1247,10 @@ int ath11k_core_resume(struct ath11k_base *ab)
if (ret <= 0)
return ret;
- return ath11k_core_resume_wow(ab);
+ if (ab->pm_policy == ATH11K_PM_WOW)
+ return ath11k_core_resume_wow(ab);
+
+ return ath11k_core_resume_default(ab);
}
EXPORT_SYMBOL(ath11k_core_resume);
@@ -2273,6 +2385,8 @@ static void ath11k_core_restart(struct work_struct *work)
if (!ab->is_reset)
ath11k_core_post_reconfigure_recovery(ab);
+
+ complete(&ab->restart_completed);
}
static void ath11k_core_reset(struct work_struct *work)
@@ -2343,7 +2457,7 @@ static void ath11k_core_reset(struct work_struct *work)
ath11k_hif_irq_disable(ab);
ath11k_hif_ce_irq_disable(ab);
- ath11k_hif_power_down(ab);
+ ath11k_hif_power_down(ab, false);
ath11k_hif_power_up(ab);
ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n");
@@ -2425,7 +2539,7 @@ void ath11k_core_deinit(struct ath11k_base *ab)
mutex_unlock(&ab->core_lock);
- ath11k_hif_power_down(ab);
+ ath11k_hif_power_down(ab, false);
ath11k_mac_destroy(ab);
ath11k_core_soc_destroy(ab);
}
@@ -2478,6 +2592,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
init_completion(&ab->wow.wakeup_completed);
+ init_completion(&ab->restart_completed);
ab->dev = dev;
ab->hif.bus = bus;
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index df2b0cb2f0b5..7a9354e0eadb 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1055,6 +1055,8 @@ struct ath11k_base {
DECLARE_BITMAP(fw_features, ATH11K_FW_FEATURE_COUNT);
} fw;
+ struct completion restart_completed;
+
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 data_pos;
@@ -1256,8 +1258,10 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
int ath11k_core_check_dt(struct ath11k_base *ath11k);
int ath11k_core_check_smbios(struct ath11k_base *ab);
void ath11k_core_halt(struct ath11k *ar);
+int ath11k_core_resume_early(struct ath11k_base *ab);
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
+int ath11k_core_suspend_late(struct ath11k_base *ab);
void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab);
bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab);
diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h
index 770c39ff99b4..cd9c4b838246 100644
--- a/drivers/net/wireless/ath/ath11k/hif.h
+++ b/drivers/net/wireless/ath/ath11k/hif.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _HIF_H_
@@ -18,7 +18,7 @@ struct ath11k_hif_ops {
int (*start)(struct ath11k_base *ab);
void (*stop)(struct ath11k_base *ab);
int (*power_up)(struct ath11k_base *ab);
- void (*power_down)(struct ath11k_base *ab);
+ void (*power_down)(struct ath11k_base *ab, bool is_suspend);
int (*suspend)(struct ath11k_base *ab);
int (*resume)(struct ath11k_base *ab);
int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id,
@@ -68,12 +68,18 @@ static inline void ath11k_hif_irq_disable(struct ath11k_base *ab)
static inline int ath11k_hif_power_up(struct ath11k_base *ab)
{
+ if (!ab->hif.ops->power_up)
+ return -EOPNOTSUPP;
+
return ab->hif.ops->power_up(ab);
}
-static inline void ath11k_hif_power_down(struct ath11k_base *ab)
+static inline void ath11k_hif_power_down(struct ath11k_base *ab, bool is_suspend)
{
- ab->hif.ops->power_down(ab);
+ if (!ab->hif.ops->power_down)
+ return;
+
+ ab->hif.ops->power_down(ab, is_suspend);
}
static inline int ath11k_hif_suspend(struct ath11k_base *ab)
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index fc77eac83e95..acd76e9392d3 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/msi.h>
@@ -454,9 +454,17 @@ int ath11k_mhi_start(struct ath11k_pci *ab_pci)
return 0;
}
-void ath11k_mhi_stop(struct ath11k_pci *ab_pci)
+void ath11k_mhi_stop(struct ath11k_pci *ab_pci, bool is_suspend)
{
- mhi_power_down(ab_pci->mhi_ctrl, true);
+ /* During suspend we need to use mhi_power_down_keep_dev()
+ * workaround, otherwise ath11k_core_resume() will timeout
+ * during resume.
+ */
+ if (is_suspend)
+ mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true);
+ else
+ mhi_power_down(ab_pci->mhi_ctrl, true);
+
mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
}
diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h
index 651470091bd5..be997652b2cd 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.h
+++ b/drivers/net/wireless/ath/ath11k/mhi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_MHI_H
#define _ATH11K_MHI_H
@@ -18,7 +18,7 @@
#define MHICTRL_RESET_MASK 0x2
int ath11k_mhi_start(struct ath11k_pci *ar_pci);
-void ath11k_mhi_stop(struct ath11k_pci *ar_pci);
+void ath11k_mhi_stop(struct ath11k_pci *ar_pci, bool is_suspend);
int ath11k_mhi_register(struct ath11k_pci *ar_pci);
void ath11k_mhi_unregister(struct ath11k_pci *ar_pci);
void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab);
@@ -27,5 +27,4 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab);
int ath11k_mhi_suspend(struct ath11k_pci *ar_pci);
int ath11k_mhi_resume(struct ath11k_pci *ar_pci);
void ath11k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic);
-
#endif
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 412f4a134e4a..37f5ed7f74f2 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -821,7 +821,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab)
return 0;
}
-static void ath11k_pci_power_down(struct ath11k_base *ab)
+static void ath11k_pci_power_down(struct ath11k_base *ab, bool is_suspend)
{
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
@@ -832,7 +832,7 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
ath11k_pci_msi_disable(ab_pci);
- ath11k_mhi_stop(ab_pci);
+ ath11k_mhi_stop(ab_pci, is_suspend);
clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags);
ath11k_pci_sw_reset(ab_pci->ab, false);
}
@@ -1161,7 +1161,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev)
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
- ath11k_pci_power_down(ab);
+ ath11k_pci_power_down(ab, false);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
@@ -1192,7 +1192,7 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
- ath11k_pci_power_down(ab);
+ ath11k_pci_power_down(ab, false);
}
static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
@@ -1229,9 +1229,39 @@ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
- ath11k_pci_pm_suspend,
- ath11k_pci_pm_resume);
+static __maybe_unused int ath11k_pci_pm_suspend_late(struct device *dev)
+{
+ struct ath11k_base *ab = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ath11k_core_suspend_late(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to late suspend core: %d\n", ret);
+
+ /* Similar to ath11k_pci_pm_suspend(), we return success here
+ * even error happens, to allow system suspend/hibernation survive.
+ */
+ return 0;
+}
+
+static __maybe_unused int ath11k_pci_pm_resume_early(struct device *dev)
+{
+ struct ath11k_base *ab = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ath11k_core_resume_early(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to early resume core: %d\n", ret);
+
+ return ret;
+}
+
+static const struct dev_pm_ops __maybe_unused ath11k_pci_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend,
+ ath11k_pci_pm_resume)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend_late,
+ ath11k_pci_pm_resume_early)
+};
static struct pci_driver ath11k_pci_driver = {
.name = "ath11k_pci",
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 4f8b08ed1bbc..47b9d4126d3a 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/elf.h>
@@ -2887,7 +2887,7 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab)
}
/* reset the firmware */
- ath11k_hif_power_down(ab);
+ ath11k_hif_power_down(ab, false);
ath11k_hif_power_up(ab);
ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n");
return 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH ath-next 5/5] Reapply "wifi: ath11k: restore country code during resume"
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
` (3 preceding siblings ...)
2025-03-20 2:30 ` [PATCH ath-next 4/5] wifi: ath11k: support non-WoWLAN mode suspend as well Baochen Qiang
@ 2025-03-20 2:30 ` Baochen Qiang
2025-03-23 20:12 ` [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Muhammad Usama Anjum
5 siblings, 0 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-20 2:30 UTC (permalink / raw)
To: ath11k; +Cc: linux-wireless, quic_bqiang
This reverts commit d3e154d7776ba57ab679fb816fb87b627fba21c9.
With non-WoWLAN suspend support brought back, commit 7f0343b7b871 ("wifi:
ath11k: restore country code during resume") needs to be brought back
as well.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
drivers/net/wireless/ath/ath11k/core.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index b248237302ac..2fd2c24f5715 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1192,6 +1192,7 @@ EXPORT_SYMBOL(ath11k_core_resume_early);
static int ath11k_core_resume_default(struct ath11k_base *ab)
{
+ struct ath11k *ar;
long time_left;
int ret;
@@ -1202,6 +1203,20 @@ static int ath11k_core_resume_default(struct ath11k_base *ab)
return -ETIMEDOUT;
}
+ /* So far only single_pdev_only devices can reach here,
+ * so it is valid to handle the first, and the only, pdev.
+ */
+ ar = ab->pdevs[0].ar;
+ if (ab->hw_params.current_cc_support &&
+ ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {
+ ret = ath11k_reg_set_cc(ar);
+ if (ret) {
+ ath11k_warn(ab, "failed to set country code during resume: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = ath11k_dp_rx_pktlog_start(ab);
if (ret)
ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
@ 2025-03-20 22:43 ` kernel test robot
2025-03-21 16:24 ` Jeff Johnson
2025-03-25 10:40 ` Julian Wollrath
2 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2025-03-20 22:43 UTC (permalink / raw)
To: Baochen Qiang, ath11k; +Cc: llvm, oe-kbuild-all, linux-wireless, quic_bqiang
Hi Baochen,
kernel test robot noticed the following build warnings:
[auto build test WARNING on b6f473c96421b8b451a8df8ccb620bcd71d4b3f4]
url: https://github.com/intel-lab-lkp/linux/commits/Baochen-Qiang/wifi-ath11k-determine-PM-policy-based-on-machine-model/20250320-103536
base: b6f473c96421b8b451a8df8ccb620bcd71d4b3f4
patch link: https://lore.kernel.org/r/20250320023003.65028-2-quic_bqiang%40quicinc.com
patch subject: [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20250321/202503210624.I3zealnl-lkp@intel.com/config)
compiler: clang version 20.1.1 (https://github.com/llvm/llvm-project 424c2d9b7e4de40d0804dd374721e6411c27d1d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250321/202503210624.I3zealnl-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503210624.I3zealnl-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/net/wireless/ath/ath11k/core.c:2381:19: warning: cast to smaller integer type 'enum ath11k_pm_policy' from 'void *' [-Wvoid-pointer-to-enum-cast]
2381 | ab->pm_policy = (enum ath11k_pm_policy)dmi_id->driver_data;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
vim +2381 drivers/net/wireless/ath/ath11k/core.c
2373
2374 int ath11k_core_init(struct ath11k_base *ab)
2375 {
2376 const struct dmi_system_id *dmi_id;
2377 int ret;
2378
2379 dmi_id = dmi_first_match(ath11k_pm_quirk_table);
2380 if (dmi_id)
> 2381 ab->pm_policy = (enum ath11k_pm_policy)dmi_id->driver_data;
2382 else
2383 ab->pm_policy = ATH11K_PM_DEFAULT;
2384
2385 ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n", ab->pm_policy);
2386
2387 ret = ath11k_core_soc_create(ab);
2388 if (ret) {
2389 ath11k_err(ab, "failed to create soc core: %d\n", ret);
2390 return ret;
2391 }
2392
2393 return 0;
2394 }
2395 EXPORT_SYMBOL(ath11k_core_init);
2396
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
2025-03-20 22:43 ` kernel test robot
@ 2025-03-21 16:24 ` Jeff Johnson
2025-03-25 10:40 ` Julian Wollrath
2 siblings, 0 replies; 11+ messages in thread
From: Jeff Johnson @ 2025-03-21 16:24 UTC (permalink / raw)
To: Baochen Qiang, ath11k; +Cc: linux-wireless
On 3/19/2025 7:29 PM, Baochen Qiang wrote:
> To handle the Lenovo unexpected wakeup issue [1], previously we revert
> commit 166a490f59ac ("wifi: ath11k: support hibernation"). So currently
> WLAN target is put into WoWLAN mode during suspend. This is a temporary
> solution as it does not work on machines where WLAN power is cut off.
>
> The thought here is that we do WoWLAN suspend on Lenovo machines while
> do non-WoWLAN suspend (which is done in the reverted commit) on other
> machines. This requires us to identify Lenovo machines from others.
> For that purpose, read board vendor and product name from DMI interface,
> match it against all known affected machines. If there is a match, choose
> WoWLAN suspend mode, else choose non-WoWLAN mode. Save the mode in ab
> for later reference.
>
> [1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
>
> Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
>
> Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
> ---
> drivers/net/wireless/ath/ath11k/core.c | 55 ++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath11k/core.h | 7 ++++
> 2 files changed, 62 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
> index 3d39ff85ba94..8657e735bf16 100644
> --- a/drivers/net/wireless/ath/ath11k/core.c
> +++ b/drivers/net/wireless/ath/ath11k/core.c
> @@ -907,6 +907,52 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
> },
> };
>
> +static const struct dmi_system_id ath11k_pm_quirk_table[] = {
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21J4"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K4"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K6"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K8"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21KA"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),
> + },
> + },
> + {}
> +};
> +
> static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab)
> {
> WARN_ON(!ab->hw_params.single_pdev_only);
> @@ -2327,8 +2373,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init);
>
> int ath11k_core_init(struct ath11k_base *ab)
> {
> + const struct dmi_system_id *dmi_id;
> int ret;
>
> + dmi_id = dmi_first_match(ath11k_pm_quirk_table);
> + if (dmi_id)
> + ab->pm_policy = (enum ath11k_pm_policy)dmi_id->driver_data;
Cast via (kernel_ulong_t) to address the kernel test robot issue
> + else
> + ab->pm_policy = ATH11K_PM_DEFAULT;
> +
> + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n", ab->pm_policy);
> +
> ret = ath11k_core_soc_create(ab);
> if (ret) {
> ath11k_err(ab, "failed to create soc core: %d\n", ret);
> diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
> index 1a3d0de4afde..df2b0cb2f0b5 100644
> --- a/drivers/net/wireless/ath/ath11k/core.h
> +++ b/drivers/net/wireless/ath/ath11k/core.h
> @@ -892,6 +892,11 @@ struct ath11k_msi_config {
> u16 hw_rev;
> };
>
> +enum ath11k_pm_policy {
> + ATH11K_PM_DEFAULT,
> + ATH11K_PM_WOW,
> +};
> +
> /* Master structure to hold the hw data which may be used in core module */
> struct ath11k_base {
> enum ath11k_hw_rev hw_rev;
> @@ -1058,6 +1063,8 @@ struct ath11k_base {
> } testmode;
> #endif
>
> + enum ath11k_pm_policy pm_policy;
> +
> /* must be last */
> u8 drv_priv[] __aligned(sizeof(void *));
> };
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
` (4 preceding siblings ...)
2025-03-20 2:30 ` [PATCH ath-next 5/5] Reapply "wifi: ath11k: restore country code during resume" Baochen Qiang
@ 2025-03-23 20:12 ` Muhammad Usama Anjum
5 siblings, 0 replies; 11+ messages in thread
From: Muhammad Usama Anjum @ 2025-03-23 20:12 UTC (permalink / raw)
To: Baochen Qiang, ath11k; +Cc: linux-wireless
On 3/20/25 7:29 AM, Baochen Qiang wrote:
> To handle the Lenovo unexpected wakeup issue [1], previously we revert
> commit 166a490f59ac ("wifi: ath11k: support hibernation"). However we
> need to bring it back, of course with additional changes such that Lenovo
> machines would not break.
>
> As those machines work well in Non-WoWLAN suspend mode, the thought here
> is that we do WoWLAN suspend on Lenovo machines while do non-WoWLAN
> suspend (which is done in the reverted commit) on other machines. This
> requires us to identify Lenovo machines from others. For that purpose,
> read machine info from DMI interface, match it against all known affected
> machines. If there is a match, choose WoWLAN suspend mode, else choose
> non-WoWLAN mode.
>
> [1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
I've tested the series and it works. Feel free to add my tag to the
series. Let me know any more help with testing is required.
Tested-on: QCNFA765
WLAN.HSP.1.1-03926.13-QCAHSPSWPL_V2_SILICONZ_CE-2.52297.6
Tested-by: Muhammad Usama Anjum <usama.anjum@collabora.com>
>
> Baochen Qiang (5):
> wifi: ath11k: determine PM policy based on machine model
> wifi: ath11k: introduce ath11k_core_continue_suspend_resume()
> wifi: ath11k: refactor ath11k_core_suspend/_resume()
> wifi: ath11k: support non-WoWLAN mode suspend as well
> Reapply "wifi: ath11k: restore country code during resume"
>
> drivers/net/wireless/ath/ath11k/ahb.c | 4 +-
> drivers/net/wireless/ath/ath11k/core.c | 245 +++++++++++++++++++++++--
> drivers/net/wireless/ath/ath11k/core.h | 11 ++
> drivers/net/wireless/ath/ath11k/hif.h | 14 +-
> drivers/net/wireless/ath/ath11k/mhi.c | 14 +-
> drivers/net/wireless/ath/ath11k/mhi.h | 5 +-
> drivers/net/wireless/ath/ath11k/pci.c | 44 ++++-
> drivers/net/wireless/ath/ath11k/qmi.c | 4 +-
> 8 files changed, 301 insertions(+), 40 deletions(-)
>
>
> base-commit: b6f473c96421b8b451a8df8ccb620bcd71d4b3f4
--
Regards,
Usama
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
2025-03-20 22:43 ` kernel test robot
2025-03-21 16:24 ` Jeff Johnson
@ 2025-03-25 10:40 ` Julian Wollrath
2025-03-25 10:45 ` Baochen Qiang
2 siblings, 1 reply; 11+ messages in thread
From: Julian Wollrath @ 2025-03-25 10:40 UTC (permalink / raw)
To: Baochen Qiang; +Cc: ath11k, linux-wireless
Hi,
Am Do, 20 Mär 2025 10:29:59 +0800
schrieb Baochen Qiang <quic_bqiang@quicinc.com>:
> To handle the Lenovo unexpected wakeup issue [1], previously we revert
> commit 166a490f59ac ("wifi: ath11k: support hibernation"). So
> currently WLAN target is put into WoWLAN mode during suspend. This is
> a temporary solution as it does not work on machines where WLAN power
> is cut off.
>
> The thought here is that we do WoWLAN suspend on Lenovo machines while
> do non-WoWLAN suspend (which is done in the reverted commit) on other
> machines. This requires us to identify Lenovo machines from others.
> For that purpose, read board vendor and product name from DMI
> interface, match it against all known affected machines. If there is
> a match, choose WoWLAN suspend mode, else choose non-WoWLAN mode.
> Save the mode in ab for later reference.
>
> [1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
>
> Tested-on: WCN6855 hw2.0 PCI
> WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
>
> Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
> ---
> drivers/net/wireless/ath/ath11k/core.c | 55
> ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h |
> 7 ++++ 2 files changed, 62 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath11k/core.c
> b/drivers/net/wireless/ath/ath11k/core.c index
> 3d39ff85ba94..8657e735bf16 100644 ---
> a/drivers/net/wireless/ath/ath11k/core.c +++
> b/drivers/net/wireless/ath/ath11k/core.c @@ -907,6 +907,52 @@ static
> const struct ath11k_hw_params ath11k_hw_params[] = { },
> };
>
> +static const struct dmi_system_id ath11k_pm_quirk_table[] = {
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21J4"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K4"),
> + },
> + },
including the quirk for 21K4 is not needed (at least for my machine)
but causes the interface to not come up again after putting the system
into hibernation.
Cheers,
Julian
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K6"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21K8"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21KA"),
> + },
> + },
> + {
> + .driver_data = (void *)ATH11K_PM_WOW,
> + .matches = {
> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),
> + },
> + },
> + {}
> +};
> +
> static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct
> ath11k_base *ab) {
> WARN_ON(!ab->hw_params.single_pdev_only);
> @@ -2327,8 +2373,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init);
>
> int ath11k_core_init(struct ath11k_base *ab)
> {
> + const struct dmi_system_id *dmi_id;
> int ret;
>
> + dmi_id = dmi_first_match(ath11k_pm_quirk_table);
> + if (dmi_id)
> + ab->pm_policy = (enum
> ath11k_pm_policy)dmi_id->driver_data;
> + else
> + ab->pm_policy = ATH11K_PM_DEFAULT;
> +
> + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n",
> ab->pm_policy); +
> ret = ath11k_core_soc_create(ab);
> if (ret) {
> ath11k_err(ab, "failed to create soc core: %d\n",
> ret); diff --git a/drivers/net/wireless/ath/ath11k/core.h
> b/drivers/net/wireless/ath/ath11k/core.h index
> 1a3d0de4afde..df2b0cb2f0b5 100644 ---
> a/drivers/net/wireless/ath/ath11k/core.h +++
> b/drivers/net/wireless/ath/ath11k/core.h @@ -892,6 +892,11 @@ struct
> ath11k_msi_config { u16 hw_rev;
> };
>
> +enum ath11k_pm_policy {
> + ATH11K_PM_DEFAULT,
> + ATH11K_PM_WOW,
> +};
> +
> /* Master structure to hold the hw data which may be used in core
> module */ struct ath11k_base {
> enum ath11k_hw_rev hw_rev;
> @@ -1058,6 +1063,8 @@ struct ath11k_base {
> } testmode;
> #endif
>
> + enum ath11k_pm_policy pm_policy;
> +
> /* must be last */
> u8 drv_priv[] __aligned(sizeof(void *));
> };
--
() ascii ribbon campaign - against html e-mail
/\ - against proprietary attachments
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model
2025-03-25 10:40 ` Julian Wollrath
@ 2025-03-25 10:45 ` Baochen Qiang
0 siblings, 0 replies; 11+ messages in thread
From: Baochen Qiang @ 2025-03-25 10:45 UTC (permalink / raw)
To: Julian Wollrath; +Cc: ath11k, linux-wireless
On 3/25/2025 6:40 PM, Julian Wollrath wrote:
> Hi,
>
> Am Do, 20 Mär 2025 10:29:59 +0800
> schrieb Baochen Qiang <quic_bqiang@quicinc.com>:
>
>> To handle the Lenovo unexpected wakeup issue [1], previously we revert
>> commit 166a490f59ac ("wifi: ath11k: support hibernation"). So
>> currently WLAN target is put into WoWLAN mode during suspend. This is
>> a temporary solution as it does not work on machines where WLAN power
>> is cut off.
>>
>> The thought here is that we do WoWLAN suspend on Lenovo machines while
>> do non-WoWLAN suspend (which is done in the reverted commit) on other
>> machines. This requires us to identify Lenovo machines from others.
>> For that purpose, read board vendor and product name from DMI
>> interface, match it against all known affected machines. If there is
>> a match, choose WoWLAN suspend mode, else choose non-WoWLAN mode.
>> Save the mode in ab for later reference.
>>
>> [1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
>>
>> Tested-on: WCN6855 hw2.0 PCI
>> WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
>>
>> Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
>> ---
>> drivers/net/wireless/ath/ath11k/core.c | 55
>> ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/core.h |
>> 7 ++++ 2 files changed, 62 insertions(+)
>>
>> diff --git a/drivers/net/wireless/ath/ath11k/core.c
>> b/drivers/net/wireless/ath/ath11k/core.c index
>> 3d39ff85ba94..8657e735bf16 100644 ---
>> a/drivers/net/wireless/ath/ath11k/core.c +++
>> b/drivers/net/wireless/ath/ath11k/core.c @@ -907,6 +907,52 @@ static
>> const struct ath11k_hw_params ath11k_hw_params[] = { },
>> };
>>
>> +static const struct dmi_system_id ath11k_pm_quirk_table[] = {
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21J4"),
>> + },
>> + },
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21K4"),
>> + },
>> + },
>
> including the quirk for 21K4 is not needed (at least for my machine)
hmm, I got info from OEM that 21K4 is also affected, so can not remove it.
I do hear that for same machine someone is able to hit the unexpected wakeup while someone
is not.
> but causes the interface to not come up again after putting the system
> into hibernation.
I will send v2 to address this issue in several days if everything goes fine.
>
>
> Cheers,
> Julian
>
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21K6"),
>> + },
>> + },
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21K8"),
>> + },
>> + },
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21KA"),
>> + },
>> + },
>> + {
>> + .driver_data = (void *)ATH11K_PM_WOW,
>> + .matches = {
>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),
>> + },
>> + },
>> + {}
>> +};
>> +
>> static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct
>> ath11k_base *ab) {
>> WARN_ON(!ab->hw_params.single_pdev_only);
>> @@ -2327,8 +2373,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init);
>>
>> int ath11k_core_init(struct ath11k_base *ab)
>> {
>> + const struct dmi_system_id *dmi_id;
>> int ret;
>>
>> + dmi_id = dmi_first_match(ath11k_pm_quirk_table);
>> + if (dmi_id)
>> + ab->pm_policy = (enum
>> ath11k_pm_policy)dmi_id->driver_data;
>> + else
>> + ab->pm_policy = ATH11K_PM_DEFAULT;
>> +
>> + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n",
>> ab->pm_policy); +
>> ret = ath11k_core_soc_create(ab);
>> if (ret) {
>> ath11k_err(ab, "failed to create soc core: %d\n",
>> ret); diff --git a/drivers/net/wireless/ath/ath11k/core.h
>> b/drivers/net/wireless/ath/ath11k/core.h index
>> 1a3d0de4afde..df2b0cb2f0b5 100644 ---
>> a/drivers/net/wireless/ath/ath11k/core.h +++
>> b/drivers/net/wireless/ath/ath11k/core.h @@ -892,6 +892,11 @@ struct
>> ath11k_msi_config { u16 hw_rev;
>> };
>>
>> +enum ath11k_pm_policy {
>> + ATH11K_PM_DEFAULT,
>> + ATH11K_PM_WOW,
>> +};
>> +
>> /* Master structure to hold the hw data which may be used in core
>> module */ struct ath11k_base {
>> enum ath11k_hw_rev hw_rev;
>> @@ -1058,6 +1063,8 @@ struct ath11k_base {
>> } testmode;
>> #endif
>>
>> + enum ath11k_pm_policy pm_policy;
>> +
>> /* must be last */
>> u8 drv_priv[] __aligned(sizeof(void *));
>> };
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-03-25 10:45 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-20 2:29 [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Baochen Qiang
2025-03-20 2:29 ` [PATCH ath-next 1/5] wifi: ath11k: determine PM policy based on machine model Baochen Qiang
2025-03-20 22:43 ` kernel test robot
2025-03-21 16:24 ` Jeff Johnson
2025-03-25 10:40 ` Julian Wollrath
2025-03-25 10:45 ` Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 2/5] wifi: ath11k: introduce ath11k_core_continue_suspend_resume() Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 3/5] wifi: ath11k: refactor ath11k_core_suspend/_resume() Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 4/5] wifi: ath11k: support non-WoWLAN mode suspend as well Baochen Qiang
2025-03-20 2:30 ` [PATCH ath-next 5/5] Reapply "wifi: ath11k: restore country code during resume" Baochen Qiang
2025-03-23 20:12 ` [PATCH ath-next 0/5] wifi: ath11k: bring hibernation support back Muhammad Usama Anjum
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox