diff mbox series

[v6,03/15] platform/x86/amd/pmf: Change return type of amd_pmf_set_dram_addr()

Message ID 20231204101548.1458499-4-Shyam-sundar.S-k@amd.com
State Superseded
Headers show
Series Introduce PMF Smart PC Solution Builder Feature | expand

Commit Message

Shyam Sundar S K Dec. 4, 2023, 10:15 a.m. UTC
In the current code, the metrics table information was required only
for auto-mode or CnQF at a given time. Hence keeping the return type
of amd_pmf_set_dram_addr() as static made sense.

But with the addition of Smart PC builder feature, the metrics table
information has to be shared by the Smart PC also and this feature
resides outside of core.c.

To make amd_pmf_set_dram_addr() visible outside of core.c make it
as a non-static function and move the allocation of memory for
metrics table from amd_pmf_init_metrics_table() to amd_pmf_set_dram_addr()
as amd_pmf_set_dram_addr() is the common function to set the DRAM
address.

Add a suspend handler that can free up the allocated memory for getting
the metrics table information.

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
 drivers/platform/x86/amd/pmf/core.c | 42 ++++++++++++++++++++++-------
 drivers/platform/x86/amd/pmf/pmf.h  |  1 +
 2 files changed, 34 insertions(+), 9 deletions(-)

Comments

Hans de Goede Dec. 11, 2023, 8:40 a.m. UTC | #1
Hi,

On 12/4/23 11:15, Shyam Sundar S K wrote:
> In the current code, the metrics table information was required only
> for auto-mode or CnQF at a given time. Hence keeping the return type
> of amd_pmf_set_dram_addr() as static made sense.
> 
> But with the addition of Smart PC builder feature, the metrics table
> information has to be shared by the Smart PC also and this feature
> resides outside of core.c.
> 
> To make amd_pmf_set_dram_addr() visible outside of core.c make it
> as a non-static function and move the allocation of memory for
> metrics table from amd_pmf_init_metrics_table() to amd_pmf_set_dram_addr()
> as amd_pmf_set_dram_addr() is the common function to set the DRAM
> address.
> 
> Add a suspend handler that can free up the allocated memory for getting
> the metrics table information.
> 
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
>  drivers/platform/x86/amd/pmf/core.c | 42 ++++++++++++++++++++++-------
>  drivers/platform/x86/amd/pmf/pmf.h  |  1 +
>  2 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index ec92d1cc0dac..f50b7ec9a625 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -251,29 +251,35 @@ static const struct pci_device_id pmf_pci_ids[] = {
>  	{ }
>  };
>  
> -static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>  {
>  	u64 phys_addr;
>  	u32 hi, low;
>  
> +	/* Get Metrics Table Address */
> +	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
> +	if (!dev->buf)
> +		return -ENOMEM;
> +
>  	phys_addr = virt_to_phys(dev->buf);
>  	hi = phys_addr >> 32;
>  	low = phys_addr & GENMASK(31, 0);
>  
>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
> +
> +	return 0;
>  }
>  
>  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>  {
> -	/* Get Metrics Table Address */
> -	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
> -	if (!dev->buf)
> -		return -ENOMEM;
> +	int ret;
>  
>  	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
>  
> -	amd_pmf_set_dram_addr(dev);
> +	ret = amd_pmf_set_dram_addr(dev);
> +	if (ret)
> +		return ret;
>  
>  	/*
>  	 * Start collecting the metrics data after a small delay
> @@ -284,17 +290,35 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>  	return 0;
>  }
>  
> +static int amd_pmf_suspend_handler(struct device *dev)
> +{
> +	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
> +
> +	/*
> +	 * Free the buffer allocated for storing the metrics table
> +	 * information, as will have to allocate it freshly after
> +	 * resume.
> +	 */
> +	kfree(pdev->buf);

This seems quite risky. You are freeing the memory here,
but the SET_DRAM_ADDR_HIGH and SET_DRAM_ADDR_LO registers
still point to it, so the hw may still access it.

IMHO it would be better to add a "bool alloc_buffer"
parameter to amd_pmf_set_dram_addr() and set that
to true on init and false on resume.

Also I guess that this DRAM buffer is used by the new
smartpc mode and specifically by the command send by
amd_pmf_invoke_cmd() work. In that case you really
need to make sure to cancel the work before
freeing the buffer and then re-submit the work
on resume.

Regards,

Hans



> +
> +	return 0;
> +}
> +
>  static int amd_pmf_resume_handler(struct device *dev)
>  {
>  	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
> +	int ret;
>  
> -	if (pdev->buf)
> -		amd_pmf_set_dram_addr(pdev);
> +	if (pdev->buf) {
> +		ret = amd_pmf_set_dram_addr(pdev);
> +		if (ret)
> +			return ret;
> +	}
>  
>  	return 0;
>  }
>  
> -static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler);
> +static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler);
>  
>  static void amd_pmf_init_features(struct amd_pmf_dev *dev)
>  {
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index a24e34e42032..6a0e4c446dd3 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -421,6 +421,7 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
>  int amd_pmf_get_power_source(void);
>  int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
>  int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev);
>  
>  /* SPS Layer */
>  int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
Shyam Sundar S K Dec. 11, 2023, 3:15 p.m. UTC | #2
Hi Hans,

On 12/11/2023 2:10 PM, Hans de Goede wrote:
> Hi,
> 
> On 12/4/23 11:15, Shyam Sundar S K wrote:
>> In the current code, the metrics table information was required only
>> for auto-mode or CnQF at a given time. Hence keeping the return type
>> of amd_pmf_set_dram_addr() as static made sense.
>>
>> But with the addition of Smart PC builder feature, the metrics table
>> information has to be shared by the Smart PC also and this feature
>> resides outside of core.c.
>>
>> To make amd_pmf_set_dram_addr() visible outside of core.c make it
>> as a non-static function and move the allocation of memory for
>> metrics table from amd_pmf_init_metrics_table() to amd_pmf_set_dram_addr()
>> as amd_pmf_set_dram_addr() is the common function to set the DRAM
>> address.
>>
>> Add a suspend handler that can free up the allocated memory for getting
>> the metrics table information.
>>
>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> ---
>>  drivers/platform/x86/amd/pmf/core.c | 42 ++++++++++++++++++++++-------
>>  drivers/platform/x86/amd/pmf/pmf.h  |  1 +
>>  2 files changed, 34 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>> index ec92d1cc0dac..f50b7ec9a625 100644
>> --- a/drivers/platform/x86/amd/pmf/core.c
>> +++ b/drivers/platform/x86/amd/pmf/core.c
>> @@ -251,29 +251,35 @@ static const struct pci_device_id pmf_pci_ids[] = {
>>  	{ }
>>  };
>>  
>> -static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>>  {
>>  	u64 phys_addr;
>>  	u32 hi, low;
>>  
>> +	/* Get Metrics Table Address */
>> +	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>> +	if (!dev->buf)
>> +		return -ENOMEM;
>> +
>>  	phys_addr = virt_to_phys(dev->buf);
>>  	hi = phys_addr >> 32;
>>  	low = phys_addr & GENMASK(31, 0);
>>  
>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
>> +
>> +	return 0;
>>  }
>>  
>>  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>  {
>> -	/* Get Metrics Table Address */
>> -	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>> -	if (!dev->buf)
>> -		return -ENOMEM;
>> +	int ret;
>>  
>>  	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
>>  
>> -	amd_pmf_set_dram_addr(dev);
>> +	ret = amd_pmf_set_dram_addr(dev);
>> +	if (ret)
>> +		return ret;
>>  
>>  	/*
>>  	 * Start collecting the metrics data after a small delay
>> @@ -284,17 +290,35 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>  	return 0;
>>  }
>>  
>> +static int amd_pmf_suspend_handler(struct device *dev)
>> +{
>> +	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>> +
>> +	/*
>> +	 * Free the buffer allocated for storing the metrics table
>> +	 * information, as will have to allocate it freshly after
>> +	 * resume.
>> +	 */
>> +	kfree(pdev->buf);
> 
> This seems quite risky. You are freeing the memory here,
> but the SET_DRAM_ADDR_HIGH and SET_DRAM_ADDR_LO registers
> still point to it, so the hw may still access it.
> 
> IMHO it would be better to add a "bool alloc_buffer"
> parameter to amd_pmf_set_dram_addr() and set that
> to true on init and false on resume.
> 

Ok. I have made this change.

> Also I guess that this DRAM buffer is used by the new
> smartpc mode and specifically by the command send by
> amd_pmf_invoke_cmd() work. In that case you really
> need to make sure to cancel the work before
> freeing the buffer and then re-submit the work
> on resume.

With some sanity tests, I don't think so this is required. pdev->buf
is only used to get the metrics table info. So, I am keeping only the
freeing part + alloc_buffer thing and not cancel/resubmit in the
suspend/resume.

If there are issues in the future because of not including
cancel/resubmit thing, can we work that as a bug fix later? Would that
be OK for you?

Thanks,
Shyam

> 
> Regards,
> 
> Hans
> 
> 
> 
>> +
>> +	return 0;
>> +}
>> +
>>  static int amd_pmf_resume_handler(struct device *dev)
>>  {
>>  	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>> +	int ret;
>>  
>> -	if (pdev->buf)
>> -		amd_pmf_set_dram_addr(pdev);
>> +	if (pdev->buf) {
>> +		ret = amd_pmf_set_dram_addr(pdev);
>> +		if (ret)
>> +			return ret;
>> +	}
>>  
>>  	return 0;
>>  }
>>  
>> -static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler);
>> +static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler);
>>  
>>  static void amd_pmf_init_features(struct amd_pmf_dev *dev)
>>  {
>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
>> index a24e34e42032..6a0e4c446dd3 100644
>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>> @@ -421,6 +421,7 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
>>  int amd_pmf_get_power_source(void);
>>  int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
>>  int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
>> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev);
>>  
>>  /* SPS Layer */
>>  int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
>
Hans de Goede Dec. 11, 2023, 3:55 p.m. UTC | #3
Hi Shyam,

On 12/11/23 16:15, Shyam Sundar S K wrote:
> Hi Hans,
> 
> On 12/11/2023 2:10 PM, Hans de Goede wrote:
>> Hi,
>>
>> On 12/4/23 11:15, Shyam Sundar S K wrote:
>>> In the current code, the metrics table information was required only
>>> for auto-mode or CnQF at a given time. Hence keeping the return type
>>> of amd_pmf_set_dram_addr() as static made sense.
>>>
>>> But with the addition of Smart PC builder feature, the metrics table
>>> information has to be shared by the Smart PC also and this feature
>>> resides outside of core.c.
>>>
>>> To make amd_pmf_set_dram_addr() visible outside of core.c make it
>>> as a non-static function and move the allocation of memory for
>>> metrics table from amd_pmf_init_metrics_table() to amd_pmf_set_dram_addr()
>>> as amd_pmf_set_dram_addr() is the common function to set the DRAM
>>> address.
>>>
>>> Add a suspend handler that can free up the allocated memory for getting
>>> the metrics table information.
>>>
>>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>> ---
>>>  drivers/platform/x86/amd/pmf/core.c | 42 ++++++++++++++++++++++-------
>>>  drivers/platform/x86/amd/pmf/pmf.h  |  1 +
>>>  2 files changed, 34 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>>> index ec92d1cc0dac..f50b7ec9a625 100644
>>> --- a/drivers/platform/x86/amd/pmf/core.c
>>> +++ b/drivers/platform/x86/amd/pmf/core.c
>>> @@ -251,29 +251,35 @@ static const struct pci_device_id pmf_pci_ids[] = {
>>>  	{ }
>>>  };
>>>  
>>> -static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>>> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>>>  {
>>>  	u64 phys_addr;
>>>  	u32 hi, low;
>>>  
>>> +	/* Get Metrics Table Address */
>>> +	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>>> +	if (!dev->buf)
>>> +		return -ENOMEM;
>>> +
>>>  	phys_addr = virt_to_phys(dev->buf);
>>>  	hi = phys_addr >> 32;
>>>  	low = phys_addr & GENMASK(31, 0);
>>>  
>>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
>>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
>>> +
>>> +	return 0;
>>>  }
>>>  
>>>  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>>  {
>>> -	/* Get Metrics Table Address */
>>> -	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>>> -	if (!dev->buf)
>>> -		return -ENOMEM;
>>> +	int ret;
>>>  
>>>  	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
>>>  
>>> -	amd_pmf_set_dram_addr(dev);
>>> +	ret = amd_pmf_set_dram_addr(dev);
>>> +	if (ret)
>>> +		return ret;
>>>  
>>>  	/*
>>>  	 * Start collecting the metrics data after a small delay
>>> @@ -284,17 +290,35 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>>  	return 0;
>>>  }
>>>  
>>> +static int amd_pmf_suspend_handler(struct device *dev)
>>> +{
>>> +	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>>> +
>>> +	/*
>>> +	 * Free the buffer allocated for storing the metrics table
>>> +	 * information, as will have to allocate it freshly after
>>> +	 * resume.
>>> +	 */
>>> +	kfree(pdev->buf);
>>
>> This seems quite risky. You are freeing the memory here,
>> but the SET_DRAM_ADDR_HIGH and SET_DRAM_ADDR_LO registers
>> still point to it, so the hw may still access it.
>>
>> IMHO it would be better to add a "bool alloc_buffer"
>> parameter to amd_pmf_set_dram_addr() and set that
>> to true on init and false on resume.
>>
> 
> Ok. I have made this change.
> 
>> Also I guess that this DRAM buffer is used by the new
>> smartpc mode and specifically by the command send by
>> amd_pmf_invoke_cmd() work. In that case you really
>> need to make sure to cancel the work before
>> freeing the buffer and then re-submit the work
>> on resume.
> 
> With some sanity tests, I don't think so this is required. pdev->buf
> is only used to get the metrics table info. So, I am keeping only the
> freeing part + alloc_buffer thing and not cancel/resubmit in the
> suspend/resume.
> 
> If there are issues in the future because of not including
> cancel/resubmit thing, can we work that as a bug fix later? Would that
> be OK for you?

If you are sure that it is safe to keep the work running
after your suspend-handler has run and on resume to
have it running before your resume handler has run
then yes that is ok.

This seems unwise though, adding a sync kill of the
work + requeue is only a couple of lines of code.

And what about accessing other subsystems like the
AMD HID sensors, I guess the work item may do that
too? That esp. seems unwise to do after your
suspend-handler has run.

Even if you stop the work from your suspend handler
you may need to add some dev-links to ensure
that the PMF linux-device is suspended before
e.g. the AMD HID sensors. That can be done in
a follow up patch though.

Regards,

Hans
Shyam Sundar S K Dec. 11, 2023, 4:35 p.m. UTC | #4
Hi Hans,

On 12/11/2023 9:25 PM, Hans de Goede wrote:
> Hi Shyam,
> 
> On 12/11/23 16:15, Shyam Sundar S K wrote:
>> Hi Hans,
>>
>> On 12/11/2023 2:10 PM, Hans de Goede wrote:
>>> Hi,
>>>
>>> On 12/4/23 11:15, Shyam Sundar S K wrote:
>>>> In the current code, the metrics table information was required only
>>>> for auto-mode or CnQF at a given time. Hence keeping the return type
>>>> of amd_pmf_set_dram_addr() as static made sense.
>>>>
>>>> But with the addition of Smart PC builder feature, the metrics table
>>>> information has to be shared by the Smart PC also and this feature
>>>> resides outside of core.c.
>>>>
>>>> To make amd_pmf_set_dram_addr() visible outside of core.c make it
>>>> as a non-static function and move the allocation of memory for
>>>> metrics table from amd_pmf_init_metrics_table() to amd_pmf_set_dram_addr()
>>>> as amd_pmf_set_dram_addr() is the common function to set the DRAM
>>>> address.
>>>>
>>>> Add a suspend handler that can free up the allocated memory for getting
>>>> the metrics table information.
>>>>
>>>> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
>>>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>>> ---
>>>>  drivers/platform/x86/amd/pmf/core.c | 42 ++++++++++++++++++++++-------
>>>>  drivers/platform/x86/amd/pmf/pmf.h  |  1 +
>>>>  2 files changed, 34 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>>>> index ec92d1cc0dac..f50b7ec9a625 100644
>>>> --- a/drivers/platform/x86/amd/pmf/core.c
>>>> +++ b/drivers/platform/x86/amd/pmf/core.c
>>>> @@ -251,29 +251,35 @@ static const struct pci_device_id pmf_pci_ids[] = {
>>>>  	{ }
>>>>  };
>>>>  
>>>> -static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>>>> +int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
>>>>  {
>>>>  	u64 phys_addr;
>>>>  	u32 hi, low;
>>>>  
>>>> +	/* Get Metrics Table Address */
>>>> +	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>>>> +	if (!dev->buf)
>>>> +		return -ENOMEM;
>>>> +
>>>>  	phys_addr = virt_to_phys(dev->buf);
>>>>  	hi = phys_addr >> 32;
>>>>  	low = phys_addr & GENMASK(31, 0);
>>>>  
>>>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
>>>>  	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
>>>> +
>>>> +	return 0;
>>>>  }
>>>>  
>>>>  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>>>  {
>>>> -	/* Get Metrics Table Address */
>>>> -	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
>>>> -	if (!dev->buf)
>>>> -		return -ENOMEM;
>>>> +	int ret;
>>>>  
>>>>  	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
>>>>  
>>>> -	amd_pmf_set_dram_addr(dev);
>>>> +	ret = amd_pmf_set_dram_addr(dev);
>>>> +	if (ret)
>>>> +		return ret;
>>>>  
>>>>  	/*
>>>>  	 * Start collecting the metrics data after a small delay
>>>> @@ -284,17 +290,35 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
>>>>  	return 0;
>>>>  }
>>>>  
>>>> +static int amd_pmf_suspend_handler(struct device *dev)
>>>> +{
>>>> +	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
>>>> +
>>>> +	/*
>>>> +	 * Free the buffer allocated for storing the metrics table
>>>> +	 * information, as will have to allocate it freshly after
>>>> +	 * resume.
>>>> +	 */
>>>> +	kfree(pdev->buf);
>>>
>>> This seems quite risky. You are freeing the memory here,
>>> but the SET_DRAM_ADDR_HIGH and SET_DRAM_ADDR_LO registers
>>> still point to it, so the hw may still access it.
>>>
>>> IMHO it would be better to add a "bool alloc_buffer"
>>> parameter to amd_pmf_set_dram_addr() and set that
>>> to true on init and false on resume.
>>>
>>
>> Ok. I have made this change.
>>
>>> Also I guess that this DRAM buffer is used by the new
>>> smartpc mode and specifically by the command send by
>>> amd_pmf_invoke_cmd() work. In that case you really
>>> need to make sure to cancel the work before
>>> freeing the buffer and then re-submit the work
>>> on resume.
>>
>> With some sanity tests, I don't think so this is required. pdev->buf
>> is only used to get the metrics table info. So, I am keeping only the
>> freeing part + alloc_buffer thing and not cancel/resubmit in the
>> suspend/resume.
>>
>> If there are issues in the future because of not including
>> cancel/resubmit thing, can we work that as a bug fix later? Would that
>> be OK for you?
> 
> If you are sure that it is safe to keep the work running
> after your suspend-handler has run and on resume to
> have it running before your resume handler has run
> then yes that is ok.
> 
> This seems unwise though, adding a sync kill of the
> work + requeue is only a couple of lines of code.
> 
> And what about accessing other subsystems like the
> AMD HID sensors, I guess the work item may do that
> too? That esp. seems unwise to do after your
> suspend-handler has run.
> 
> Even if you stop the work from your suspend handler
> you may need to add some dev-links to ensure
> that the PMF linux-device is suspended before
> e.g. the AMD HID sensors. That can be done in
> a follow up patch though.
> 

Sure, thank you. Will address them separately as a followup patch later.

Thanks,
Shyam

> Regards,
> 
> Hans
> 
> 
>
diff mbox series

Patch

diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index ec92d1cc0dac..f50b7ec9a625 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -251,29 +251,35 @@  static const struct pci_device_id pmf_pci_ids[] = {
 	{ }
 };
 
-static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
+int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev)
 {
 	u64 phys_addr;
 	u32 hi, low;
 
+	/* Get Metrics Table Address */
+	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
+	if (!dev->buf)
+		return -ENOMEM;
+
 	phys_addr = virt_to_phys(dev->buf);
 	hi = phys_addr >> 32;
 	low = phys_addr & GENMASK(31, 0);
 
 	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
 	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
+
+	return 0;
 }
 
 int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
 {
-	/* Get Metrics Table Address */
-	dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
-	if (!dev->buf)
-		return -ENOMEM;
+	int ret;
 
 	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
 
-	amd_pmf_set_dram_addr(dev);
+	ret = amd_pmf_set_dram_addr(dev);
+	if (ret)
+		return ret;
 
 	/*
 	 * Start collecting the metrics data after a small delay
@@ -284,17 +290,35 @@  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
 	return 0;
 }
 
+static int amd_pmf_suspend_handler(struct device *dev)
+{
+	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
+
+	/*
+	 * Free the buffer allocated for storing the metrics table
+	 * information, as will have to allocate it freshly after
+	 * resume.
+	 */
+	kfree(pdev->buf);
+
+	return 0;
+}
+
 static int amd_pmf_resume_handler(struct device *dev)
 {
 	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
+	int ret;
 
-	if (pdev->buf)
-		amd_pmf_set_dram_addr(pdev);
+	if (pdev->buf) {
+		ret = amd_pmf_set_dram_addr(pdev);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
 
-static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler);
+static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, amd_pmf_suspend_handler, amd_pmf_resume_handler);
 
 static void amd_pmf_init_features(struct amd_pmf_dev *dev)
 {
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index a24e34e42032..6a0e4c446dd3 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -421,6 +421,7 @@  int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
 int amd_pmf_get_power_source(void);
 int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
 int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
+int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev);
 
 /* SPS Layer */
 int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);