diff mbox series

[V2,5/9] platform/x86: intel_pmc_core: Get LPM requirements for Tiger Lake

Message ID 20210417031252.3020837-6-david.e.box@linux.intel.com (mailing list archive)
State Accepted, archived
Headers show
Series intel_pmc_core: Add sub-state requirements and mode | expand

Commit Message

David E. Box April 17, 2021, 3:12 a.m. UTC
From: Gayatri Kammela <gayatri.kammela@intel.com>

Platforms that support low power modes (LPM) such as Tiger Lake maintain
requirements for each sub-state that a readable in the PMC. However, unlike
LPM status registers, requirement registers are not memory mapped but are
available from an ACPI _DSM. Collect the requirements for Tiger Lake using
the _DSM method and store in a buffer.

Signed-off-by: Gayatri Kammela <gayatri.kammela@intel.com>
Co-developed-by: David E. Box <david.e.box@linux.intel.com>
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
---

V2:	- Move buffer allocation so that it does not need to be freed
	  (which was missing anyway) when an error is encountered.
	- Use label to free out_obj after errors
	- Use memcpy instead of memcpy_fromio for ACPI memory

 drivers/platform/x86/intel_pmc_core.c | 56 +++++++++++++++++++++++++++
 drivers/platform/x86/intel_pmc_core.h |  2 +
 2 files changed, 58 insertions(+)

Comments

kernel test robot April 17, 2021, 5:55 a.m. UTC | #1
Hi "David,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on 823b31517ad3196324322804ee365d5fcff704d6]

url:    https://github.com/0day-ci/linux/commits/David-E-Box/intel_pmc_core-Add-sub-state-requirements-and-mode/20210417-111530
base:   823b31517ad3196324322804ee365d5fcff704d6
config: i386-randconfig-a001-20210417 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/703038f16e99686bf2538222cee482f823bfa60f
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review David-E-Box/intel_pmc_core-Add-sub-state-requirements-and-mode/20210417-111530
        git checkout 703038f16e99686bf2538222cee482f823bfa60f
        # save the attached .config to linux build tree
        make W=1 W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/platform/x86/intel_pmc_core.c:14:
   drivers/platform/x86/intel_pmc_core.c: In function 'pmc_core_get_tgl_lpm_reqs':
>> drivers/platform/x86/intel_pmc_core.c:621:5: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
     621 |     "_DSM returned unexpected buffer size,"
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     622 |     " have %d, expect %ld\n", size, lpm_size);
         |                                     ~~~~~~~~
         |                                     |
         |                                     size_t {aka unsigned int}
   include/linux/acpi.h:1073:42: note: in definition of macro 'acpi_handle_debug'
    1073 |   acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); \
         |                                          ^~~
   drivers/platform/x86/intel_pmc_core.c:622:25: note: format string is defined here
     622 |     " have %d, expect %ld\n", size, lpm_size);
         |                       ~~^
         |                         |
         |                         long int
         |                       %d


vim +621 drivers/platform/x86/intel_pmc_core.c

   597	
   598	static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
   599	{
   600		struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
   601		const int num_maps = pmcdev->map->lpm_num_maps;
   602		size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
   603		union acpi_object *out_obj;
   604		struct acpi_device *adev;
   605		guid_t s0ix_dsm_guid;
   606		u32 *lpm_req_regs, *addr;
   607	
   608		adev = ACPI_COMPANION(&pdev->dev);
   609		if (!adev)
   610			return;
   611	
   612		guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
   613	
   614		out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
   615					    ACPI_GET_LOW_MODE_REGISTERS, NULL);
   616		if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
   617			int size = out_obj->buffer.length;
   618	
   619			if (size != lpm_size) {
   620				acpi_handle_debug(adev->handle,
 > 621					"_DSM returned unexpected buffer size,"
   622					" have %d, expect %ld\n", size, lpm_size);
   623				goto free_acpi_obj;
   624			}
   625		} else {
   626			acpi_handle_debug(adev->handle,
   627					  "_DSM function 0 evaluation failed\n");
   628			goto free_acpi_obj;
   629		}
   630	
   631		addr = (u32 *)out_obj->buffer.pointer;
   632	
   633		lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
   634					     GFP_KERNEL);
   635		if (!lpm_req_regs)
   636			goto free_acpi_obj;
   637	
   638		memcpy(lpm_req_regs, addr, lpm_size);
   639		pmcdev->lpm_req_regs = lpm_req_regs;
   640	
   641	free_acpi_obj:
   642		ACPI_FREE(out_obj);
   643	}
   644	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot April 17, 2021, 6:25 a.m. UTC | #2
Hi "David,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on 823b31517ad3196324322804ee365d5fcff704d6]

url:    https://github.com/0day-ci/linux/commits/David-E-Box/intel_pmc_core-Add-sub-state-requirements-and-mode/20210417-111530
base:   823b31517ad3196324322804ee365d5fcff704d6
config: i386-randconfig-a012-20210416 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/703038f16e99686bf2538222cee482f823bfa60f
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review David-E-Box/intel_pmc_core-Add-sub-state-requirements-and-mode/20210417-111530
        git checkout 703038f16e99686bf2538222cee482f823bfa60f
        # save the attached .config to linux build tree
        make W=1 W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/platform/x86/intel_pmc_core.c: In function 'pmc_core_get_tgl_lpm_reqs':
>> <command-line>: warning: format '%ld' expects argument of type 'long int', but argument 5 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
   drivers/platform/x86/intel_pmc_core.c:12:21: note: in expansion of macro 'KBUILD_MODNAME'
      12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
         |                     ^~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:129:15: note: in expansion of macro 'pr_fmt'
     129 |   func(&id, ##__VA_ARGS__);  \
         |               ^~~~~~~~~~~
   include/linux/dynamic_debug.h:147:2: note: in expansion of macro '__dynamic_func_call'
     147 |  __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
         |  ^~~~~~~~~~~~~~~~~~~
   include/linux/acpi.h:1067:2: note: in expansion of macro '_dynamic_func_call'
    1067 |  _dynamic_func_call(fmt, __acpi_handle_debug,   \
         |  ^~~~~~~~~~~~~~~~~~
   drivers/platform/x86/intel_pmc_core.c:620:4: note: in expansion of macro 'acpi_handle_debug'
     620 |    acpi_handle_debug(adev->handle,
         |    ^~~~~~~~~~~~~~~~~

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hans de Goede April 17, 2021, 8:52 a.m. UTC | #3
Hi David,

On 4/17/21 5:12 AM, David E. Box wrote:
> From: Gayatri Kammela <gayatri.kammela@intel.com>
> 
> Platforms that support low power modes (LPM) such as Tiger Lake maintain
> requirements for each sub-state that a readable in the PMC. However, unlike
> LPM status registers, requirement registers are not memory mapped but are
> available from an ACPI _DSM. Collect the requirements for Tiger Lake using
> the _DSM method and store in a buffer.
> 
> Signed-off-by: Gayatri Kammela <gayatri.kammela@intel.com>
> Co-developed-by: David E. Box <david.e.box@linux.intel.com>
> Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Erm, I did not give my "Reviewed-by: Hans de Goede <hdegoede@redhat.com>"
for this patch, because it still needed some work.

Next time please only add my Reviewed-by to patches where I
explicitly replied with a Reviewed-by.

The same goes for patch 7/9

Regards,

Hans



> ---
> 
> V2:	- Move buffer allocation so that it does not need to be freed
> 	  (which was missing anyway) when an error is encountered.
> 	- Use label to free out_obj after errors
> 	- Use memcpy instead of memcpy_fromio for ACPI memory
> 
>  drivers/platform/x86/intel_pmc_core.c | 56 +++++++++++++++++++++++++++
>  drivers/platform/x86/intel_pmc_core.h |  2 +
>  2 files changed, 58 insertions(+)
> 
> diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
> index 0e59a84b51bf..97efe9a6bd01 100644
> --- a/drivers/platform/x86/intel_pmc_core.c
> +++ b/drivers/platform/x86/intel_pmc_core.c
> @@ -23,7 +23,9 @@
>  #include <linux/slab.h>
>  #include <linux/suspend.h>
>  #include <linux/uaccess.h>
> +#include <linux/uuid.h>
>  
> +#include <acpi/acpi_bus.h>
>  #include <asm/cpu_device_id.h>
>  #include <asm/intel-family.h>
>  #include <asm/msr.h>
> @@ -31,6 +33,9 @@
>  
>  #include "intel_pmc_core.h"
>  
> +#define ACPI_S0IX_DSM_UUID		"57a6512e-3979-4e9d-9708-ff13b2508972"
> +#define ACPI_GET_LOW_MODE_REGISTERS	1
> +
>  /* PKGC MSRs are common across Intel Core SoCs */
>  static const struct pmc_bit_map msr_map[] = {
>  	{"Package C2",                  MSR_PKG_C2_RESIDENCY},
> @@ -590,6 +595,53 @@ static const struct pmc_reg_map tgl_reg_map = {
>  	.etr3_offset = ETR3_OFFSET,
>  };
>  
> +static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
> +{
> +	struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
> +	const int num_maps = pmcdev->map->lpm_num_maps;
> +	size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
> +	union acpi_object *out_obj;
> +	struct acpi_device *adev;
> +	guid_t s0ix_dsm_guid;
> +	u32 *lpm_req_regs, *addr;
> +
> +	adev = ACPI_COMPANION(&pdev->dev);
> +	if (!adev)
> +		return;
> +
> +	guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
> +
> +	out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
> +				    ACPI_GET_LOW_MODE_REGISTERS, NULL);
> +	if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
> +		int size = out_obj->buffer.length;
> +
> +		if (size != lpm_size) {
> +			acpi_handle_debug(adev->handle,
> +				"_DSM returned unexpected buffer size,"
> +				" have %d, expect %ld\n", size, lpm_size);
> +			goto free_acpi_obj;
> +		}
> +	} else {
> +		acpi_handle_debug(adev->handle,
> +				  "_DSM function 0 evaluation failed\n");
> +		goto free_acpi_obj;
> +	}
> +
> +	addr = (u32 *)out_obj->buffer.pointer;
> +
> +	lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
> +				     GFP_KERNEL);
> +	if (!lpm_req_regs)
> +		goto free_acpi_obj;
> +
> +	memcpy(lpm_req_regs, addr, lpm_size);
> +	pmcdev->lpm_req_regs = lpm_req_regs;
> +
> +free_acpi_obj:
> +	ACPI_FREE(out_obj);
> +}
> +
>  static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
>  {
>  	return readl(pmcdev->regbase + reg_offset);
> @@ -1424,10 +1476,14 @@ static int pmc_core_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  
>  	mutex_init(&pmcdev->lock);
> +
>  	pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev);
>  	pmc_core_get_low_power_modes(pmcdev);
>  	pmc_core_do_dmi_quirks(pmcdev);
>  
> +	if (pmcdev->map == &tgl_reg_map)
> +		pmc_core_get_tgl_lpm_reqs(pdev);
> +
>  	/*
>  	 * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when
>  	 * a cable is attached. Tell the PMC to ignore it.
> diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
> index aa44fd5399cc..64fb368f40f6 100644
> --- a/drivers/platform/x86/intel_pmc_core.h
> +++ b/drivers/platform/x86/intel_pmc_core.h
> @@ -294,6 +294,7 @@ struct pmc_reg_map {
>   * @s0ix_counter:	S0ix residency (step adjusted)
>   * @num_lpm_modes:	Count of enabled modes
>   * @lpm_en_modes:	Array of enabled modes from lowest to highest priority
> + * @lpm_req_regs:	List of substate requirements
>   *
>   * pmc_dev contains info about power management controller device.
>   */
> @@ -310,6 +311,7 @@ struct pmc_dev {
>  	u64 s0ix_counter;
>  	int num_lpm_modes;
>  	int lpm_en_modes[LPM_MAX_NUM_MODES];
> +	u32 *lpm_req_regs;
>  };
>  
>  #define pmc_for_each_mode(i, mode, pmcdev)		\
>
Hans de Goede April 17, 2021, 9 a.m. UTC | #4
Hi,

On 4/17/21 5:12 AM, David E. Box wrote:
> From: Gayatri Kammela <gayatri.kammela@intel.com>
> 
> Platforms that support low power modes (LPM) such as Tiger Lake maintain
> requirements for each sub-state that a readable in the PMC. However, unlike
> LPM status registers, requirement registers are not memory mapped but are
> available from an ACPI _DSM. Collect the requirements for Tiger Lake using
> the _DSM method and store in a buffer.
> 
> Signed-off-by: Gayatri Kammela <gayatri.kammela@intel.com>
> Co-developed-by: David E. Box <david.e.box@linux.intel.com>
> Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
> ---
> 
> V2:	- Move buffer allocation so that it does not need to be freed
> 	  (which was missing anyway) when an error is encountered.
> 	- Use label to free out_obj after errors
> 	- Use memcpy instead of memcpy_fromio for ACPI memory
> 
>  drivers/platform/x86/intel_pmc_core.c | 56 +++++++++++++++++++++++++++
>  drivers/platform/x86/intel_pmc_core.h |  2 +
>  2 files changed, 58 insertions(+)
> 
> diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
> index 0e59a84b51bf..97efe9a6bd01 100644
> --- a/drivers/platform/x86/intel_pmc_core.c
> +++ b/drivers/platform/x86/intel_pmc_core.c
> @@ -23,7 +23,9 @@
>  #include <linux/slab.h>
>  #include <linux/suspend.h>
>  #include <linux/uaccess.h>
> +#include <linux/uuid.h>
>  
> +#include <acpi/acpi_bus.h>
>  #include <asm/cpu_device_id.h>
>  #include <asm/intel-family.h>
>  #include <asm/msr.h>
> @@ -31,6 +33,9 @@
>  
>  #include "intel_pmc_core.h"
>  
> +#define ACPI_S0IX_DSM_UUID		"57a6512e-3979-4e9d-9708-ff13b2508972"
> +#define ACPI_GET_LOW_MODE_REGISTERS	1
> +
>  /* PKGC MSRs are common across Intel Core SoCs */
>  static const struct pmc_bit_map msr_map[] = {
>  	{"Package C2",                  MSR_PKG_C2_RESIDENCY},
> @@ -590,6 +595,53 @@ static const struct pmc_reg_map tgl_reg_map = {
>  	.etr3_offset = ETR3_OFFSET,
>  };
>  
> +static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
> +{
> +	struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
> +	const int num_maps = pmcdev->map->lpm_num_maps;
> +	size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;

The type of lpm_size should be an u32, so that it matches
the type of out_obj->buffer.length.

> +	union acpi_object *out_obj;
> +	struct acpi_device *adev;
> +	guid_t s0ix_dsm_guid;
> +	u32 *lpm_req_regs, *addr;
> +
> +	adev = ACPI_COMPANION(&pdev->dev);
> +	if (!adev)
> +		return;
> +
> +	guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
> +
> +	out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
> +				    ACPI_GET_LOW_MODE_REGISTERS, NULL);
> +	if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
> +		int size = out_obj->buffer.length;

out_obj->buffer.length is an u32, please make this an u32 too.

> +
> +		if (size != lpm_size) {
> +			acpi_handle_debug(adev->handle,
> +				"_DSM returned unexpected buffer size,"
> +				" have %d, expect %ld\n", size, lpm_size);

And use %u here (twice), this should also fix the warnings reported
by the kernel test robot.

If there are no objections against the suggested changes, then I can
fix this up while merging this.

Please let me know if the suggested changes are ok with you.

Regards,

Hans


> +			goto free_acpi_obj;
> +		}
> +	} else {
> +		acpi_handle_debug(adev->handle,
> +				  "_DSM function 0 evaluation failed\n");
> +		goto free_acpi_obj;
> +	}
> +
> +	addr = (u32 *)out_obj->buffer.pointer;
> +
> +	lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
> +				     GFP_KERNEL);
> +	if (!lpm_req_regs)
> +		goto free_acpi_obj;
> +
> +	memcpy(lpm_req_regs, addr, lpm_size);
> +	pmcdev->lpm_req_regs = lpm_req_regs;
> +
> +free_acpi_obj:
> +	ACPI_FREE(out_obj);
> +}
> +
>  static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
>  {
>  	return readl(pmcdev->regbase + reg_offset);
> @@ -1424,10 +1476,14 @@ static int pmc_core_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  
>  	mutex_init(&pmcdev->lock);
> +
>  	pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev);
>  	pmc_core_get_low_power_modes(pmcdev);
>  	pmc_core_do_dmi_quirks(pmcdev);
>  
> +	if (pmcdev->map == &tgl_reg_map)
> +		pmc_core_get_tgl_lpm_reqs(pdev);
> +
>  	/*
>  	 * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when
>  	 * a cable is attached. Tell the PMC to ignore it.
> diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
> index aa44fd5399cc..64fb368f40f6 100644
> --- a/drivers/platform/x86/intel_pmc_core.h
> +++ b/drivers/platform/x86/intel_pmc_core.h
> @@ -294,6 +294,7 @@ struct pmc_reg_map {
>   * @s0ix_counter:	S0ix residency (step adjusted)
>   * @num_lpm_modes:	Count of enabled modes
>   * @lpm_en_modes:	Array of enabled modes from lowest to highest priority
> + * @lpm_req_regs:	List of substate requirements
>   *
>   * pmc_dev contains info about power management controller device.
>   */
> @@ -310,6 +311,7 @@ struct pmc_dev {
>  	u64 s0ix_counter;
>  	int num_lpm_modes;
>  	int lpm_en_modes[LPM_MAX_NUM_MODES];
> +	u32 *lpm_req_regs;
>  };
>  
>  #define pmc_for_each_mode(i, mode, pmcdev)		\
>
David E. Box April 18, 2021, 1:43 a.m. UTC | #5
On Sat, 2021-04-17 at 11:00 +0200, Hans de Goede wrote:
> Hi,
> 
> On 4/17/21 5:12 AM, David E. Box wrote:
> > From: Gayatri Kammela <gayatri.kammela@intel.com>
> > 
> > Platforms that support low power modes (LPM) such as Tiger Lake
> > maintain
> > requirements for each sub-state that a readable in the PMC.
> > However, unlike
> > LPM status registers, requirement registers are not memory mapped
> > but are
> > available from an ACPI _DSM. Collect the requirements for Tiger
> > Lake using
> > the _DSM method and store in a buffer.
> > 
> > Signed-off-by: Gayatri Kammela <gayatri.kammela@intel.com>
> > Co-developed-by: David E. Box <david.e.box@linux.intel.com>
> > Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> > Reviewed-by: Hans de Goede <hdegoede@redhat.com>
> > ---
> > 
> > V2:     - Move buffer allocation so that it does not need to be
> > freed
> >           (which was missing anyway) when an error is encountered.
> >         - Use label to free out_obj after errors
> >         - Use memcpy instead of memcpy_fromio for ACPI memory
> > 
> >  drivers/platform/x86/intel_pmc_core.c | 56
> > +++++++++++++++++++++++++++
> >  drivers/platform/x86/intel_pmc_core.h |  2 +
> >  2 files changed, 58 insertions(+)
> > 
> > diff --git a/drivers/platform/x86/intel_pmc_core.c
> > b/drivers/platform/x86/intel_pmc_core.c
> > index 0e59a84b51bf..97efe9a6bd01 100644
> > --- a/drivers/platform/x86/intel_pmc_core.c
> > +++ b/drivers/platform/x86/intel_pmc_core.c
> > @@ -23,7 +23,9 @@
> >  #include <linux/slab.h>
> >  #include <linux/suspend.h>
> >  #include <linux/uaccess.h>
> > +#include <linux/uuid.h>
> >  
> > +#include <acpi/acpi_bus.h>
> >  #include <asm/cpu_device_id.h>
> >  #include <asm/intel-family.h>
> >  #include <asm/msr.h>
> > @@ -31,6 +33,9 @@
> >  
> >  #include "intel_pmc_core.h"
> >  
> > +#define ACPI_S0IX_DSM_UUID             "57a6512e-3979-4e9d-9708-
> > ff13b2508972"
> > +#define ACPI_GET_LOW_MODE_REGISTERS    1
> > +
> >  /* PKGC MSRs are common across Intel Core SoCs */
> >  static const struct pmc_bit_map msr_map[] = {
> >         {"Package C2",                  MSR_PKG_C2_RESIDENCY},
> > @@ -590,6 +595,53 @@ static const struct pmc_reg_map tgl_reg_map =
> > {
> >         .etr3_offset = ETR3_OFFSET,
> >  };
> >  
> > +static void pmc_core_get_tgl_lpm_reqs(struct platform_device
> > *pdev)
> > +{
> > +       struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
> > +       const int num_maps = pmcdev->map->lpm_num_maps;
> > +       size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
> 
> The type of lpm_size should be an u32, so that it matches
> the type of out_obj->buffer.length.
> 
> > +       union acpi_object *out_obj;
> > +       struct acpi_device *adev;
> > +       guid_t s0ix_dsm_guid;
> > +       u32 *lpm_req_regs, *addr;
> > +
> > +       adev = ACPI_COMPANION(&pdev->dev);
> > +       if (!adev)
> > +               return;
> > +
> > +       guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
> > +
> > +       out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid,
> > 0,
> > +                                   ACPI_GET_LOW_MODE_REGISTERS,
> > NULL);
> > +       if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
> > +               int size = out_obj->buffer.length;
> 
> out_obj->buffer.length is an u32, please make this an u32 too.
> 
> > +
> > +               if (size != lpm_size) {
> > +                       acpi_handle_debug(adev->handle,
> > +                               "_DSM returned unexpected buffer
> > size,"
> > +                               " have %d, expect %ld\n", size,
> > lpm_size);
> 
> And use %u here (twice), this should also fix the warnings reported
> by the kernel test robot.
> 
> If there are no objections against the suggested changes, then I can
> fix this up while merging this.
> 
> Please let me know if the suggested changes are ok with you.

Changes are good with me. Thanks for the fixup.

David

> 
> Regards,
> 
> Hans
> 
> 
> > +                       goto free_acpi_obj;
> > +               }
> > +       } else {
> > +               acpi_handle_debug(adev->handle,
> > +                                 "_DSM function 0 evaluation
> > failed\n");
> > +               goto free_acpi_obj;
> > +       }
> > +
> > +       addr = (u32 *)out_obj->buffer.pointer;
> > +
> > +       lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size *
> > sizeof(u32),
> > +                                    GFP_KERNEL);
> > +       if (!lpm_req_regs)
> > +               goto free_acpi_obj;
> > +
> > +       memcpy(lpm_req_regs, addr, lpm_size);
> > +       pmcdev->lpm_req_regs = lpm_req_regs;
> > +
> > +free_acpi_obj:
> > +       ACPI_FREE(out_obj);
> > +}
> > +
> >  static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int
> > reg_offset)
> >  {
> >         return readl(pmcdev->regbase + reg_offset);
> > @@ -1424,10 +1476,14 @@ static int pmc_core_probe(struct
> > platform_device *pdev)
> >                 return -ENOMEM;
> >  
> >         mutex_init(&pmcdev->lock);
> > +
> >         pmcdev->pmc_xram_read_bit =
> > pmc_core_check_read_lock_bit(pmcdev);
> >         pmc_core_get_low_power_modes(pmcdev);
> >         pmc_core_do_dmi_quirks(pmcdev);
> >  
> > +       if (pmcdev->map == &tgl_reg_map)
> > +               pmc_core_get_tgl_lpm_reqs(pdev);
> > +
> >         /*
> >          * On TGL, due to a hardware limitation, the GBE LTR blocks
> > PC10 when
> >          * a cable is attached. Tell the PMC to ignore it.
> > diff --git a/drivers/platform/x86/intel_pmc_core.h
> > b/drivers/platform/x86/intel_pmc_core.h
> > index aa44fd5399cc..64fb368f40f6 100644
> > --- a/drivers/platform/x86/intel_pmc_core.h
> > +++ b/drivers/platform/x86/intel_pmc_core.h
> > @@ -294,6 +294,7 @@ struct pmc_reg_map {
> >   * @s0ix_counter:      S0ix residency (step adjusted)
> >   * @num_lpm_modes:     Count of enabled modes
> >   * @lpm_en_modes:      Array of enabled modes from lowest to
> > highest priority
> > + * @lpm_req_regs:      List of substate requirements
> >   *
> >   * pmc_dev contains info about power management controller device.
> >   */
> > @@ -310,6 +311,7 @@ struct pmc_dev {
> >         u64 s0ix_counter;
> >         int num_lpm_modes;
> >         int lpm_en_modes[LPM_MAX_NUM_MODES];
> > +       u32 *lpm_req_regs;
> >  };
> >  
> >  #define pmc_for_each_mode(i, mode, pmcdev)             \
> > 
>
David E. Box April 18, 2021, 1:59 a.m. UTC | #6
On Sat, 2021-04-17 at 10:52 +0200, Hans de Goede wrote:
> Hi David,
> 
> On 4/17/21 5:12 AM, David E. Box wrote:
> > From: Gayatri Kammela <gayatri.kammela@intel.com>
> > 
> > Platforms that support low power modes (LPM) such as Tiger Lake
> > maintain
> > requirements for each sub-state that a readable in the PMC.
> > However, unlike
> > LPM status registers, requirement registers are not memory mapped
> > but are
> > available from an ACPI _DSM. Collect the requirements for Tiger
> > Lake using
> > the _DSM method and store in a buffer.
> > 
> > Signed-off-by: Gayatri Kammela <gayatri.kammela@intel.com>
> > Co-developed-by: David E. Box <david.e.box@linux.intel.com>
> > Signed-off-by: David E. Box <david.e.box@linux.intel.com>
> > Reviewed-by: Hans de Goede <hdegoede@redhat.com>
> 
> Erm, I did not give my "Reviewed-by: Hans de Goede < 
> hdegoede@redhat.com>"
> for this patch, because it still needed some work.
> 
> Next time please only add my Reviewed-by to patches where I
> explicitly replied with a Reviewed-by.

Sure thing. Sorry about that.

David

> The same goes for patch 7/9
> 
> Regards,
> 
> Hans
> 
> 
> 
> > ---
> > 
> > V2:     - Move buffer allocation so that it does not need to be
> > freed
> >           (which was missing anyway) when an error is encountered.
> >         - Use label to free out_obj after errors
> >         - Use memcpy instead of memcpy_fromio for ACPI memory
> > 
> >  drivers/platform/x86/intel_pmc_core.c | 56
> > +++++++++++++++++++++++++++
> >  drivers/platform/x86/intel_pmc_core.h |  2 +
> >  2 files changed, 58 insertions(+)
> > 
> > diff --git a/drivers/platform/x86/intel_pmc_core.c
> > b/drivers/platform/x86/intel_pmc_core.c
> > index 0e59a84b51bf..97efe9a6bd01 100644
> > --- a/drivers/platform/x86/intel_pmc_core.c
> > +++ b/drivers/platform/x86/intel_pmc_core.c
> > @@ -23,7 +23,9 @@
> >  #include <linux/slab.h>
> >  #include <linux/suspend.h>
> >  #include <linux/uaccess.h>
> > +#include <linux/uuid.h>
> >  
> > +#include <acpi/acpi_bus.h>
> >  #include <asm/cpu_device_id.h>
> >  #include <asm/intel-family.h>
> >  #include <asm/msr.h>
> > @@ -31,6 +33,9 @@
> >  
> >  #include "intel_pmc_core.h"
> >  
> > +#define ACPI_S0IX_DSM_UUID             "57a6512e-3979-4e9d-9708-
> > ff13b2508972"
> > +#define ACPI_GET_LOW_MODE_REGISTERS    1
> > +
> >  /* PKGC MSRs are common across Intel Core SoCs */
> >  static const struct pmc_bit_map msr_map[] = {
> >         {"Package C2",                  MSR_PKG_C2_RESIDENCY},
> > @@ -590,6 +595,53 @@ static const struct pmc_reg_map tgl_reg_map =
> > {
> >         .etr3_offset = ETR3_OFFSET,
> >  };
> >  
> > +static void pmc_core_get_tgl_lpm_reqs(struct platform_device
> > *pdev)
> > +{
> > +       struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
> > +       const int num_maps = pmcdev->map->lpm_num_maps;
> > +       size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
> > +       union acpi_object *out_obj;
> > +       struct acpi_device *adev;
> > +       guid_t s0ix_dsm_guid;
> > +       u32 *lpm_req_regs, *addr;
> > +
> > +       adev = ACPI_COMPANION(&pdev->dev);
> > +       if (!adev)
> > +               return;
> > +
> > +       guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
> > +
> > +       out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid,
> > 0,
> > +                                   ACPI_GET_LOW_MODE_REGISTERS,
> > NULL);
> > +       if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
> > +               int size = out_obj->buffer.length;
> > +
> > +               if (size != lpm_size) {
> > +                       acpi_handle_debug(adev->handle,
> > +                               "_DSM returned unexpected buffer
> > size,"
> > +                               " have %d, expect %ld\n", size,
> > lpm_size);
> > +                       goto free_acpi_obj;
> > +               }
> > +       } else {
> > +               acpi_handle_debug(adev->handle,
> > +                                 "_DSM function 0 evaluation
> > failed\n");
> > +               goto free_acpi_obj;
> > +       }
> > +
> > +       addr = (u32 *)out_obj->buffer.pointer;
> > +
> > +       lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size *
> > sizeof(u32),
> > +                                    GFP_KERNEL);
> > +       if (!lpm_req_regs)
> > +               goto free_acpi_obj;
> > +
> > +       memcpy(lpm_req_regs, addr, lpm_size);
> > +       pmcdev->lpm_req_regs = lpm_req_regs;
> > +
> > +free_acpi_obj:
> > +       ACPI_FREE(out_obj);
> > +}
> > +
> >  static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int
> > reg_offset)
> >  {
> >         return readl(pmcdev->regbase + reg_offset);
> > @@ -1424,10 +1476,14 @@ static int pmc_core_probe(struct
> > platform_device *pdev)
> >                 return -ENOMEM;
> >  
> >         mutex_init(&pmcdev->lock);
> > +
> >         pmcdev->pmc_xram_read_bit =
> > pmc_core_check_read_lock_bit(pmcdev);
> >         pmc_core_get_low_power_modes(pmcdev);
> >         pmc_core_do_dmi_quirks(pmcdev);
> >  
> > +       if (pmcdev->map == &tgl_reg_map)
> > +               pmc_core_get_tgl_lpm_reqs(pdev);
> > +
> >         /*
> >          * On TGL, due to a hardware limitation, the GBE LTR blocks
> > PC10 when
> >          * a cable is attached. Tell the PMC to ignore it.
> > diff --git a/drivers/platform/x86/intel_pmc_core.h
> > b/drivers/platform/x86/intel_pmc_core.h
> > index aa44fd5399cc..64fb368f40f6 100644
> > --- a/drivers/platform/x86/intel_pmc_core.h
> > +++ b/drivers/platform/x86/intel_pmc_core.h
> > @@ -294,6 +294,7 @@ struct pmc_reg_map {
> >   * @s0ix_counter:      S0ix residency (step adjusted)
> >   * @num_lpm_modes:     Count of enabled modes
> >   * @lpm_en_modes:      Array of enabled modes from lowest to
> > highest priority
> > + * @lpm_req_regs:      List of substate requirements
> >   *
> >   * pmc_dev contains info about power management controller device.
> >   */
> > @@ -310,6 +311,7 @@ struct pmc_dev {
> >         u64 s0ix_counter;
> >         int num_lpm_modes;
> >         int lpm_en_modes[LPM_MAX_NUM_MODES];
> > +       u32 *lpm_req_regs;
> >  };
> >  
> >  #define pmc_for_each_mode(i, mode, pmcdev)             \
> > 
>
diff mbox series

Patch

diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 0e59a84b51bf..97efe9a6bd01 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -23,7 +23,9 @@ 
 #include <linux/slab.h>
 #include <linux/suspend.h>
 #include <linux/uaccess.h>
+#include <linux/uuid.h>
 
+#include <acpi/acpi_bus.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include <asm/msr.h>
@@ -31,6 +33,9 @@ 
 
 #include "intel_pmc_core.h"
 
+#define ACPI_S0IX_DSM_UUID		"57a6512e-3979-4e9d-9708-ff13b2508972"
+#define ACPI_GET_LOW_MODE_REGISTERS	1
+
 /* PKGC MSRs are common across Intel Core SoCs */
 static const struct pmc_bit_map msr_map[] = {
 	{"Package C2",                  MSR_PKG_C2_RESIDENCY},
@@ -590,6 +595,53 @@  static const struct pmc_reg_map tgl_reg_map = {
 	.etr3_offset = ETR3_OFFSET,
 };
 
+static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
+{
+	struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
+	const int num_maps = pmcdev->map->lpm_num_maps;
+	size_t lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
+	union acpi_object *out_obj;
+	struct acpi_device *adev;
+	guid_t s0ix_dsm_guid;
+	u32 *lpm_req_regs, *addr;
+
+	adev = ACPI_COMPANION(&pdev->dev);
+	if (!adev)
+		return;
+
+	guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
+
+	out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
+				    ACPI_GET_LOW_MODE_REGISTERS, NULL);
+	if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
+		int size = out_obj->buffer.length;
+
+		if (size != lpm_size) {
+			acpi_handle_debug(adev->handle,
+				"_DSM returned unexpected buffer size,"
+				" have %d, expect %ld\n", size, lpm_size);
+			goto free_acpi_obj;
+		}
+	} else {
+		acpi_handle_debug(adev->handle,
+				  "_DSM function 0 evaluation failed\n");
+		goto free_acpi_obj;
+	}
+
+	addr = (u32 *)out_obj->buffer.pointer;
+
+	lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
+				     GFP_KERNEL);
+	if (!lpm_req_regs)
+		goto free_acpi_obj;
+
+	memcpy(lpm_req_regs, addr, lpm_size);
+	pmcdev->lpm_req_regs = lpm_req_regs;
+
+free_acpi_obj:
+	ACPI_FREE(out_obj);
+}
+
 static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
 {
 	return readl(pmcdev->regbase + reg_offset);
@@ -1424,10 +1476,14 @@  static int pmc_core_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	mutex_init(&pmcdev->lock);
+
 	pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev);
 	pmc_core_get_low_power_modes(pmcdev);
 	pmc_core_do_dmi_quirks(pmcdev);
 
+	if (pmcdev->map == &tgl_reg_map)
+		pmc_core_get_tgl_lpm_reqs(pdev);
+
 	/*
 	 * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when
 	 * a cable is attached. Tell the PMC to ignore it.
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index aa44fd5399cc..64fb368f40f6 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -294,6 +294,7 @@  struct pmc_reg_map {
  * @s0ix_counter:	S0ix residency (step adjusted)
  * @num_lpm_modes:	Count of enabled modes
  * @lpm_en_modes:	Array of enabled modes from lowest to highest priority
+ * @lpm_req_regs:	List of substate requirements
  *
  * pmc_dev contains info about power management controller device.
  */
@@ -310,6 +311,7 @@  struct pmc_dev {
 	u64 s0ix_counter;
 	int num_lpm_modes;
 	int lpm_en_modes[LPM_MAX_NUM_MODES];
+	u32 *lpm_req_regs;
 };
 
 #define pmc_for_each_mode(i, mode, pmcdev)		\