6.15-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baochen Qiang quic_bqiang@quicinc.com
[ Upstream commit ce8669a27016354dfa8bf3c954255cb9f3583bae ]
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
Tested-by: Muhammad Usama Anjum usama.anjum@collabora.com Tested-by: Takashi Iwai tiwai@suse.de Signed-off-by: Baochen Qiang quic_bqiang@quicinc.com Link: https://patch.msgid.link/20250328-ath11k-bring-hibernation-back-v3-1-23405ae... Signed-off-by: Jeff Johnson jeff.johnson@oss.qualcomm.com Signed-off-by: Sasha Levin sashal@kernel.org --- 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 22eb1b0377ffe..0281ce6fb7177 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); @@ -2334,8 +2380,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 = (kernel_ulong_t)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 529aca4f40621..81a8fe7bed448 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -894,6 +894,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; @@ -1060,6 +1065,8 @@ struct ath11k_base { } testmode; #endif
+ enum ath11k_pm_policy pm_policy; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); };