diff mbox series

[v2,09/14] ASoC: amd: add Renoir ACP PCI driver PM ops

Message ID 20200511212014.2359225-10-alexander.deucher@amd.com (mailing list archive)
State New, archived
Headers show
Series Add Renoir ACP driver | expand

Commit Message

Alex Deucher May 11, 2020, 9:20 p.m. UTC
From: Vijendar Mukunda <Vijendar.Mukunda@amd.com>

Add Renoir ACP Pci driver pm ops.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---

v2:
- Changed PCI driver pm runtime sequence

 sound/soc/amd/renoir/rn-pci-acp3x.c | 48 +++++++++++++++++++++++++++++
 sound/soc/amd/renoir/rn_acp3x.h     |  2 ++
 2 files changed, 50 insertions(+)

Comments

Pierre-Louis Bossart May 11, 2020, 10:28 p.m. UTC | #1
> @@ -233,6 +234,11 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
>   		ret = PTR_ERR(adata->pdev);
>   		goto unregister_devs;
>   	}
> +	pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
> +	pm_runtime_use_autosuspend(&pci->dev);
> +	pm_runtime_allow(&pci->dev);
> +	pm_runtime_mark_last_busy(&pci->dev);
> +	pm_runtime_put_autosuspend(&pci->dev);

usually there is a pm_runtime_put_noidle() here?

[...]

>   static void snd_rn_acp_remove(struct pci_dev *pci)
>   {
>   	struct acp_dev_data *adata;
> @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev *pci)
>   	ret = rn_acp_deinit(adata->acp_base);
>   	if (ret)
>   		dev_err(&pci->dev, "ACP de-init failed\n");
> +	pm_runtime_put_noidle(&pci->dev);
> +	pm_runtime_get_sync(&pci->dev);
> +	pm_runtime_forbid(&pci->dev);

doing a put_noidle() followed by a get_sync() and immediately forbid() 
is very odd at best.
Isn't the recommendation to call get_noresume() here?



>   	pci_disable_msi(pci);
>   	pci_release_regions(pci);
>   	pci_disable_device(pci);
> @@ -278,6 +323,9 @@ static struct pci_driver rn_acp_driver  = {
>   	.id_table = snd_rn_acp_ids,
>   	.probe = snd_rn_acp_probe,
>   	.remove = snd_rn_acp_remove,
> +	.driver = {
> +		.pm = &rn_acp_pm,
> +	}
>   };
>   
>   module_pci_driver(rn_acp_driver);
> diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h
> index a4f654cf2df0..6e1888167fb3 100644
> --- a/sound/soc/amd/renoir/rn_acp3x.h
> +++ b/sound/soc/amd/renoir/rn_acp3x.h
> @@ -40,6 +40,8 @@
>   #define TWO_CH 0x02
>   #define DELAY_US 5
>   #define ACP_COUNTER 20000
> +/* time in ms for runtime suspend delay */
> +#define ACP_SUSPEND_DELAY_MS	2000
>   
>   #define ACP_SRAM_PTE_OFFSET	0x02050000
>   #define PAGE_SIZE_4K_ENABLE     0x2
>
Alex Deucher May 12, 2020, 1:46 p.m. UTC | #2
On Mon, May 11, 2020 at 6:37 PM Pierre-Louis Bossart
<pierre-louis.bossart@linux.intel.com> wrote:
>
>
> > @@ -233,6 +234,11 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
> >               ret = PTR_ERR(adata->pdev);
> >               goto unregister_devs;
> >       }
> > +     pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
> > +     pm_runtime_use_autosuspend(&pci->dev);
> > +     pm_runtime_allow(&pci->dev);
> > +     pm_runtime_mark_last_busy(&pci->dev);
> > +     pm_runtime_put_autosuspend(&pci->dev);
>
> usually there is a pm_runtime_put_noidle() here?

I'm not sure.

>
> [...]
>
> >   static void snd_rn_acp_remove(struct pci_dev *pci)
> >   {
> >       struct acp_dev_data *adata;
> > @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev *pci)
> >       ret = rn_acp_deinit(adata->acp_base);
> >       if (ret)
> >               dev_err(&pci->dev, "ACP de-init failed\n");
> > +     pm_runtime_put_noidle(&pci->dev);
> > +     pm_runtime_get_sync(&pci->dev);
> > +     pm_runtime_forbid(&pci->dev);
>
> doing a put_noidle() followed by a get_sync() and immediately forbid()
> is very odd at best.
> Isn't the recommendation to call get_noresume() here?
>

I'm not sure here either.  Is there some definitive documentation on
what exact sequences are supposed to be used in drivers?  A quick
browse through drivers that implement runtime pm seems to show a lot
of variation.  This sequence works.  I'm not sure if it's optimal or
not.

Alex

>
>
> >       pci_disable_msi(pci);
> >       pci_release_regions(pci);
> >       pci_disable_device(pci);
> > @@ -278,6 +323,9 @@ static struct pci_driver rn_acp_driver  = {
> >       .id_table = snd_rn_acp_ids,
> >       .probe = snd_rn_acp_probe,
> >       .remove = snd_rn_acp_remove,
> > +     .driver = {
> > +             .pm = &rn_acp_pm,
> > +     }
> >   };
> >
> >   module_pci_driver(rn_acp_driver);
> > diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h
> > index a4f654cf2df0..6e1888167fb3 100644
> > --- a/sound/soc/amd/renoir/rn_acp3x.h
> > +++ b/sound/soc/amd/renoir/rn_acp3x.h
> > @@ -40,6 +40,8 @@
> >   #define TWO_CH 0x02
> >   #define DELAY_US 5
> >   #define ACP_COUNTER 20000
> > +/* time in ms for runtime suspend delay */
> > +#define ACP_SUSPEND_DELAY_MS 2000
> >
> >   #define ACP_SRAM_PTE_OFFSET 0x02050000
> >   #define PAGE_SIZE_4K_ENABLE     0x2
> >
Pierre-Louis Bossart May 12, 2020, 3:16 p.m. UTC | #3
On 5/12/20 8:46 AM, Alex Deucher wrote:
> On Mon, May 11, 2020 at 6:37 PM Pierre-Louis Bossart
> <pierre-louis.bossart@linux.intel.com> wrote:
>>
>>
>>> @@ -233,6 +234,11 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
>>>                ret = PTR_ERR(adata->pdev);
>>>                goto unregister_devs;
>>>        }
>>> +     pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
>>> +     pm_runtime_use_autosuspend(&pci->dev);
>>> +     pm_runtime_allow(&pci->dev);
>>> +     pm_runtime_mark_last_busy(&pci->dev);
>>> +     pm_runtime_put_autosuspend(&pci->dev);
>>
>> usually there is a pm_runtime_put_noidle() here?
> 
> I'm not sure.
> 
>>
>> [...]
>>
>>>    static void snd_rn_acp_remove(struct pci_dev *pci)
>>>    {
>>>        struct acp_dev_data *adata;
>>> @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev *pci)
>>>        ret = rn_acp_deinit(adata->acp_base);
>>>        if (ret)
>>>                dev_err(&pci->dev, "ACP de-init failed\n");
>>> +     pm_runtime_put_noidle(&pci->dev);
>>> +     pm_runtime_get_sync(&pci->dev);
>>> +     pm_runtime_forbid(&pci->dev);
>>
>> doing a put_noidle() followed by a get_sync() and immediately forbid()
>> is very odd at best.
>> Isn't the recommendation to call get_noresume() here?
>>
> 
> I'm not sure here either.  Is there some definitive documentation on
> what exact sequences are supposed to be used in drivers?  A quick
> browse through drivers that implement runtime pm seems to show a lot
> of variation.  This sequence works.  I'm not sure if it's optimal or
> not.

We based our sequence on the comments in drivers/pci/pci-driver.c

/*
  * Unbound PCI devices are always put in D0, regardless of
  * runtime PM status.  During probe, the device is set to
  * active and the usage count is incremented.  If the driver
  * supports runtime PM, it should call pm_runtime_put_noidle(),
  * or any other runtime PM helper function decrementing the usage
  * count, in its probe routine and pm_runtime_get_noresume() in
  * its remove routine.
  */
Mukunda,Vijendar May 12, 2020, 7:54 p.m. UTC | #4
> -----Original Message-----
> From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Sent: Tuesday, May 12, 2020 8:46 PM
> To: Alex Deucher <alexdeucher@gmail.com>
> Cc: Takashi Iwai <tiwai@suse.de>; Deucher, Alexander
> <Alexander.Deucher@amd.com>; alsa-devel@alsa-project.org; Mark Brown
> <broonie@kernel.org>; Mukunda, Vijendar <Vijendar.Mukunda@amd.com>
> Subject: Re: [PATCH v2 09/14] ASoC: amd: add Renoir ACP PCI driver PM ops
> 
> 
> 
> On 5/12/20 8:46 AM, Alex Deucher wrote:
> > On Mon, May 11, 2020 at 6:37 PM Pierre-Louis Bossart
> > <pierre-louis.bossart@linux.intel.com> wrote:
> >>
> >>
> >>> @@ -233,6 +234,11 @@ static int snd_rn_acp_probe(struct pci_dev *pci,
> >>>                ret = PTR_ERR(adata->pdev);
> >>>                goto unregister_devs;
> >>>        }
> >>> +     pm_runtime_set_autosuspend_delay(&pci->dev,
> ACP_SUSPEND_DELAY_MS);
> >>> +     pm_runtime_use_autosuspend(&pci->dev);
> >>> +     pm_runtime_allow(&pci->dev);
> >>> +     pm_runtime_mark_last_busy(&pci->dev);
> >>> +     pm_runtime_put_autosuspend(&pci->dev);
> >>
> >> usually there is a pm_runtime_put_noidle() here?
> >
> > I'm not sure.
> >
> >>
> >> [...]
> >>
> >>>    static void snd_rn_acp_remove(struct pci_dev *pci)
> >>>    {
> >>>        struct acp_dev_data *adata;
> >>> @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev
> *pci)
> >>>        ret = rn_acp_deinit(adata->acp_base);
> >>>        if (ret)
> >>>                dev_err(&pci->dev, "ACP de-init failed\n");
> >>> +     pm_runtime_put_noidle(&pci->dev);
> >>> +     pm_runtime_get_sync(&pci->dev);
> >>> +     pm_runtime_forbid(&pci->dev);
> >>
> >> doing a put_noidle() followed by a get_sync() and immediately forbid()
> >> is very odd at best.
> >> Isn't the recommendation to call get_noresume() here?
> >>
> >
> > I'm not sure here either.  Is there some definitive documentation on
> > what exact sequences are supposed to be used in drivers?  A quick
> > browse through drivers that implement runtime pm seems to show a lot
> > of variation.  This sequence works.  I'm not sure if it's optimal or
> > not.
> 
> We based our sequence on the comments in drivers/pci/pci-driver.c
> 
> /*
>   * Unbound PCI devices are always put in D0, regardless of
>   * runtime PM status.  During probe, the device is set to
>   * active and the usage count is incremented.  If the driver
>   * supports runtime PM, it should call pm_runtime_put_noidle(),
>   * or any other runtime PM helper function decrementing the usage
>   * count, in its probe routine and pm_runtime_get_noresume() in
>   * its remove routine.
>   */

If I understood correctly, below should be  the correct sequence rite ?

acp pci driver probe sequence:

pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pci->dev);
pm_runtime_put_noidle(&pci->dev);
pm_runtime_allow(&pci->dev);	
	
acp pci driver remove sequence:

pm_runtime_get_noresume(&pci->dev);
pm_runtime_disable(&pci->dev);

I have still have a doubt. 
Do we need to call pm_runtime_disable() explicitly  in this case ?
Pierre-Louis Bossart May 12, 2020, 8:36 p.m. UTC | #5
>>>>> +     pm_runtime_set_autosuspend_delay(&pci->dev,
>> ACP_SUSPEND_DELAY_MS);
>>>>> +     pm_runtime_use_autosuspend(&pci->dev);
>>>>> +     pm_runtime_allow(&pci->dev);
>>>>> +     pm_runtime_mark_last_busy(&pci->dev);
>>>>> +     pm_runtime_put_autosuspend(&pci->dev);
>>>>
>>>> usually there is a pm_runtime_put_noidle() here?
>>>
>>> I'm not sure.
>>>
>>>>
>>>> [...]
>>>>
>>>>>     static void snd_rn_acp_remove(struct pci_dev *pci)
>>>>>     {
>>>>>         struct acp_dev_data *adata;
>>>>> @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev
>> *pci)
>>>>>         ret = rn_acp_deinit(adata->acp_base);
>>>>>         if (ret)
>>>>>                 dev_err(&pci->dev, "ACP de-init failed\n");
>>>>> +     pm_runtime_put_noidle(&pci->dev);
>>>>> +     pm_runtime_get_sync(&pci->dev);
>>>>> +     pm_runtime_forbid(&pci->dev);
>>>>
>>>> doing a put_noidle() followed by a get_sync() and immediately forbid()
>>>> is very odd at best.
>>>> Isn't the recommendation to call get_noresume() here?
>>>>
>>>
>>> I'm not sure here either.  Is there some definitive documentation on
>>> what exact sequences are supposed to be used in drivers?  A quick
>>> browse through drivers that implement runtime pm seems to show a lot
>>> of variation.  This sequence works.  I'm not sure if it's optimal or
>>> not.
>>
>> We based our sequence on the comments in drivers/pci/pci-driver.c
>>
>> /*
>>    * Unbound PCI devices are always put in D0, regardless of
>>    * runtime PM status.  During probe, the device is set to
>>    * active and the usage count is incremented.  If the driver
>>    * supports runtime PM, it should call pm_runtime_put_noidle(),
>>    * or any other runtime PM helper function decrementing the usage
>>    * count, in its probe routine and pm_runtime_get_noresume() in
>>    * its remove routine.
>>    */
> 
> If I understood correctly, below should be  the correct sequence rite ?
> 
> acp pci driver probe sequence:
> 
> pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
> pm_runtime_use_autosuspend(&pci->dev);
> pm_runtime_put_noidle(&pci->dev);
> pm_runtime_allow(&pci->dev);	

sounds about right. We added an extra pm_runtime_mark_last_busy() to 
make sure the information is updated, but that's probably on the 
paranoid side.
> 	
> acp pci driver remove sequence:
> 
> pm_runtime_get_noresume(&pci->dev);
> pm_runtime_disable(&pci->dev);
> 
> I have still have a doubt.
> Do we need to call pm_runtime_disable() explicitly  in this case ?

we don't call pm_runtime_disable().
Mukunda,Vijendar May 13, 2020, 5:44 p.m. UTC | #6
[AMD Official Use Only - Internal Distribution Only]



> -----Original Message-----
> From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Sent: Wednesday, May 13, 2020 2:06 AM
> To: Mukunda, Vijendar <Vijendar.Mukunda@amd.com>; Alex Deucher
> <alexdeucher@gmail.com>
> Cc: Takashi Iwai <tiwai@suse.de>; Deucher, Alexander
> <Alexander.Deucher@amd.com>; alsa-devel@alsa-project.org; Mark Brown
> <broonie@kernel.org>
> Subject: Re: [PATCH v2 09/14] ASoC: amd: add Renoir ACP PCI driver PM ops
> 
> 
> 
> >>>>> +     pm_runtime_set_autosuspend_delay(&pci->dev,
> >> ACP_SUSPEND_DELAY_MS);
> >>>>> +     pm_runtime_use_autosuspend(&pci->dev);
> >>>>> +     pm_runtime_allow(&pci->dev);
> >>>>> +     pm_runtime_mark_last_busy(&pci->dev);
> >>>>> +     pm_runtime_put_autosuspend(&pci->dev);
> >>>>
> >>>> usually there is a pm_runtime_put_noidle() here?
> >>>
> >>> I'm not sure.
> >>>
> >>>>
> >>>> [...]
> >>>>
> >>>>>     static void snd_rn_acp_remove(struct pci_dev *pci)
> >>>>>     {
> >>>>>         struct acp_dev_data *adata;
> >>>>> @@ -260,6 +302,9 @@ static void snd_rn_acp_remove(struct pci_dev
> >> *pci)
> >>>>>         ret = rn_acp_deinit(adata->acp_base);
> >>>>>         if (ret)
> >>>>>                 dev_err(&pci->dev, "ACP de-init failed\n");
> >>>>> +     pm_runtime_put_noidle(&pci->dev);
> >>>>> +     pm_runtime_get_sync(&pci->dev);
> >>>>> +     pm_runtime_forbid(&pci->dev);
> >>>>
> >>>> doing a put_noidle() followed by a get_sync() and immediately forbid()
> >>>> is very odd at best.
> >>>> Isn't the recommendation to call get_noresume() here?
> >>>>
> >>>
> >>> I'm not sure here either.  Is there some definitive documentation on
> >>> what exact sequences are supposed to be used in drivers?  A quick
> >>> browse through drivers that implement runtime pm seems to show a lot
> >>> of variation.  This sequence works.  I'm not sure if it's optimal or
> >>> not.
> >>
> >> We based our sequence on the comments in drivers/pci/pci-driver.c
> >>
> >> /*
> >>    * Unbound PCI devices are always put in D0, regardless of
> >>    * runtime PM status.  During probe, the device is set to
> >>    * active and the usage count is incremented.  If the driver
> >>    * supports runtime PM, it should call pm_runtime_put_noidle(),
> >>    * or any other runtime PM helper function decrementing the usage
> >>    * count, in its probe routine and pm_runtime_get_noresume() in
> >>    * its remove routine.
> >>    */
> >
> > If I understood correctly, below should be  the correct sequence rite ?
> >
> > acp pci driver probe sequence:
> >
> > pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
> > pm_runtime_use_autosuspend(&pci->dev);
> > pm_runtime_put_noidle(&pci->dev);
> > pm_runtime_allow(&pci->dev);
> 
> sounds about right. We added an extra pm_runtime_mark_last_busy() to
> make sure the information is updated, but that's probably on the
> paranoid side.
> >
> > acp pci driver remove sequence:
> >
> > pm_runtime_get_noresume(&pci->dev);
> > pm_runtime_disable(&pci->dev);
> >
> > I have still have a doubt.
> > Do we need to call pm_runtime_disable() explicitly  in this case ?
> 
> we don't call pm_runtime_disable().

I see in one of the PCI driver implementation, in driver remove sequence
pm_runtime_forbid( ) API is called before pm_runtime_get_noresume () call.

I believe , It's safe to call pm_runtime_forbid() which will prevent device to 
be power managed  at runtime in remove sequence.

Correct me, if my understanding is wrong .
diff mbox series

Patch

diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c
index 362409ef0d85..14651df9b5c8 100644
--- a/sound/soc/amd/renoir/rn-pci-acp3x.c
+++ b/sound/soc/amd/renoir/rn-pci-acp3x.c
@@ -10,6 +10,7 @@ 
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
 
 #include "rn_acp3x.h"
 
@@ -233,6 +234,11 @@  static int snd_rn_acp_probe(struct pci_dev *pci,
 		ret = PTR_ERR(adata->pdev);
 		goto unregister_devs;
 	}
+	pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&pci->dev);
+	pm_runtime_allow(&pci->dev);
+	pm_runtime_mark_last_busy(&pci->dev);
+	pm_runtime_put_autosuspend(&pci->dev);
 	return 0;
 
 unregister_devs:
@@ -250,6 +256,42 @@  static int snd_rn_acp_probe(struct pci_dev *pci,
 	return ret;
 }
 
+static int snd_rn_acp_suspend(struct device *dev)
+{
+	int ret;
+	struct acp_dev_data *adata;
+
+	adata = dev_get_drvdata(dev);
+	ret = rn_acp_deinit(adata->acp_base);
+	if (ret)
+		dev_err(dev, "ACP de-init failed\n");
+	else
+		dev_dbg(dev, "ACP de-initialized\n");
+
+	return 0;
+}
+
+static int snd_rn_acp_resume(struct device *dev)
+{
+	int ret;
+	struct acp_dev_data *adata;
+
+	adata = dev_get_drvdata(dev);
+	ret = rn_acp_init(adata->acp_base);
+	if (ret) {
+		dev_err(dev, "ACP init failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+static const struct dev_pm_ops rn_acp_pm = {
+	.runtime_suspend = snd_rn_acp_suspend,
+	.runtime_resume =  snd_rn_acp_resume,
+	.suspend = snd_rn_acp_suspend,
+	.resume =	snd_rn_acp_resume,
+};
+
 static void snd_rn_acp_remove(struct pci_dev *pci)
 {
 	struct acp_dev_data *adata;
@@ -260,6 +302,9 @@  static void snd_rn_acp_remove(struct pci_dev *pci)
 	ret = rn_acp_deinit(adata->acp_base);
 	if (ret)
 		dev_err(&pci->dev, "ACP de-init failed\n");
+	pm_runtime_put_noidle(&pci->dev);
+	pm_runtime_get_sync(&pci->dev);
+	pm_runtime_forbid(&pci->dev);
 	pci_disable_msi(pci);
 	pci_release_regions(pci);
 	pci_disable_device(pci);
@@ -278,6 +323,9 @@  static struct pci_driver rn_acp_driver  = {
 	.id_table = snd_rn_acp_ids,
 	.probe = snd_rn_acp_probe,
 	.remove = snd_rn_acp_remove,
+	.driver = {
+		.pm = &rn_acp_pm,
+	}
 };
 
 module_pci_driver(rn_acp_driver);
diff --git a/sound/soc/amd/renoir/rn_acp3x.h b/sound/soc/amd/renoir/rn_acp3x.h
index a4f654cf2df0..6e1888167fb3 100644
--- a/sound/soc/amd/renoir/rn_acp3x.h
+++ b/sound/soc/amd/renoir/rn_acp3x.h
@@ -40,6 +40,8 @@ 
 #define TWO_CH 0x02
 #define DELAY_US 5
 #define ACP_COUNTER 20000
+/* time in ms for runtime suspend delay */
+#define ACP_SUSPEND_DELAY_MS	2000
 
 #define ACP_SRAM_PTE_OFFSET	0x02050000
 #define PAGE_SIZE_4K_ENABLE     0x2