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 <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-23405ae23431@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Baochen Qiang
2025-03-28 13:32:24 +08:00
committed by Greg Kroah-Hartman
parent 42d0bfbe02
commit 6bd0f2e71b
2 changed files with 62 additions and 0 deletions

View File

@@ -704,6 +704,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) static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base *ab)
{ {
WARN_ON(!ab->hw_params.single_pdev_only); WARN_ON(!ab->hw_params.single_pdev_only);
@@ -2018,8 +2064,17 @@ EXPORT_SYMBOL(ath11k_core_pre_init);
int ath11k_core_init(struct ath11k_base *ab) int ath11k_core_init(struct ath11k_base *ab)
{ {
const struct dmi_system_id *dmi_id;
int ret; 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); ret = ath11k_core_soc_create(ab);
if (ret) { if (ret) {
ath11k_err(ab, "failed to create soc core: %d\n", ret); ath11k_err(ab, "failed to create soc core: %d\n", ret);

View File

@@ -842,6 +842,11 @@ struct ath11k_msi_config {
u16 hw_rev; 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 */ /* Master structure to hold the hw data which may be used in core module */
struct ath11k_base { struct ath11k_base {
enum ath11k_hw_rev hw_rev; enum ath11k_hw_rev hw_rev;
@@ -994,6 +999,8 @@ struct ath11k_base {
} testmode; } testmode;
#endif #endif
enum ath11k_pm_policy pm_policy;
/* must be last */ /* must be last */
u8 drv_priv[] __aligned(sizeof(void *)); u8 drv_priv[] __aligned(sizeof(void *));
}; };