From f9eee822b4205da4783c246b0bafd79d7392d53a Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 28 Mar 2025 13:32:24 +0800 Subject: [PATCH] wifi: ath11k: determine PM policy based on machine model [ 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 Tested-by: Takashi Iwai Signed-off-by: Baochen Qiang Link: https://patch.msgid.link/20250328-ath11k-bring-hibernation-back-v3-1-23405ae23431@quicinc.com Signed-off-by: Jeff Johnson Signed-off-by: Sasha Levin --- 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 8002fb32a2cc..2ec1771262fd 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -811,6 +811,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); @@ -2197,8 +2243,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 fcdec14eb3cf..09fdb7be0e19 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -891,6 +891,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; @@ -1053,6 +1058,8 @@ struct ath11k_base { } testmode; #endif + enum ath11k_pm_policy pm_policy; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); };