diff mbox series

[ath-next,1/5] wifi: ath11k: determine PM policy based on machine model

Message ID 20250320023003.65028-2-quic_bqiang@quicinc.com (mailing list archive)
State New
Delegated to: Jeff Johnson
Headers show
Series wifi: ath11k: bring hibernation support back | expand

Checks

Context Check Description
wifibot/fixes_present success Fixes tag not required for -next series
wifibot/series_format success Posting correctly formatted
wifibot/tree_selection success Clearly marked for ath-next
wifibot/ynl success Generated files up to date; no warnings/errors; no diff in generated;
wifibot/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
wifibot/build_clang fail Errors and warnings before: 0 this patch: 2
wifibot/build_clang_rust success No Rust files in patch. Skipping build
wifibot/build_tools success No tools touched, skip
wifibot/check_selftest success No net selftest shell script
wifibot/deprecated_api success None detected
wifibot/header_inline success No static functions without inline keyword in header files
wifibot/source_inline success Was 0 now: 0
wifibot/verify_fixes success No Fixes tag
wifibot/build_32bit success Errors and warnings before: 0 this patch: 0
wifibot/checkpatch success total: 0 errors, 0 warnings, 0 checks, 88 lines checked
wifibot/kdoc success Errors and warnings before: 0 this patch: 0
wifibot/verify_signedoff success Signed-off-by tag matches author and committer

Commit Message

Baochen Qiang March 20, 2025, 2:29 a.m. UTC
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(+)

Comments

kernel test robot March 20, 2025, 10:43 p.m. UTC | #1
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
Jeff Johnson March 21, 2025, 4:24 p.m. UTC | #2
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 *));
>  };
Julian Wollrath March 25, 2025, 10:40 a.m. UTC | #3
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 *));
>  };
Baochen Qiang March 25, 2025, 10:45 a.m. UTC | #4
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 *));
>>  };
> 
> 
>
diff mbox series

Patch

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 *));
 };