diff mbox

[v11,5/6] dmaengine: pl330: Add PM sleep support

Message ID 1415802748-30530-6-git-send-email-k.kozlowski@samsung.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Krzysztof Kozlowski Nov. 12, 2014, 2:32 p.m. UTC
Add system suspend/resume capabilities to the pl330 driver so the amba
bus clock could be also unprepared to conserve energy.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

Comments

Ulf Hansson Nov. 12, 2014, 3:28 p.m. UTC | #1
On 12 November 2014 15:32, Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> Add system suspend/resume capabilities to the pl330 driver so the amba
> bus clock could be also unprepared to conserve energy.
>
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index c3bd3584f261..fd71777fc565 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -2627,6 +2627,42 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
>         return 0;
>  }
>
> +/*
> + * Runtime PM callbacks are provided by amba/bus.c driver.
> + *
> + * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> + * bus driver will only disable/enable the clock in runtime PM callbacks.
> + */
> +static int __maybe_unused pl330_suspend(struct device *dev)
> +{
> +       struct amba_device *pcdev = to_amba_device(dev);
> +
> +       if (!pm_runtime_status_suspended(dev)) {

No, this wont work. Consider this scenario:

pm_runtime_status_suspended() returns "true", which means you consider
the device to be runtime PM suspended, thus you will unprepare the
clock below.

Later, a call to pm_runtime_get_sync() is invoked from "somewhere" and
before this driver's system PM resume callback has been invoked. That
will trigger the runtime PM resume callback to be invoked, causing
clock unbalance issues.

You need a pm_runtime_disable() prior checking the runtime PM status
using pm_runtime_status_suspended(). That will prevent this from
happen.

I guess you may see where this is leading. I think
pm_runtime_force_suspend|resume() is well suited for this situation.

> +               /* amba did not disable the clock */
> +               amba_pclk_disable(pcdev);
> +       }
> +       amba_pclk_unprepare(pcdev);
> +
> +       return 0;
> +}
> +
> +static int __maybe_unused pl330_resume(struct device *dev)
> +{
> +       struct amba_device *pcdev = to_amba_device(dev);
> +       int ret;
> +
> +       ret = amba_pclk_prepare(pcdev);
> +       if (ret)
> +               return ret;
> +
> +       if (!pm_runtime_status_suspended(dev))
> +               ret = amba_pclk_enable(pcdev);
> +
> +       return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
> +
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
>  {
> @@ -2853,6 +2889,7 @@ static struct amba_driver pl330_driver = {
>         .drv = {
>                 .owner = THIS_MODULE,
>                 .name = "dma-pl330",
> +               .pm = &pl330_pm,
>         },
>         .id_table = pl330_ids,
>         .probe = pl330_probe,
> --
> 1.9.1
>

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Krzysztof Kozlowski Nov. 12, 2014, 3:53 p.m. UTC | #2
On ?ro, 2014-11-12 at 16:28 +0100, Ulf Hansson wrote:
> On 12 November 2014 15:32, Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> > Add system suspend/resume capabilities to the pl330 driver so the amba
> > bus clock could be also unprepared to conserve energy.
> >
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
> >  1 file changed, 37 insertions(+)
> >
> > diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> > index c3bd3584f261..fd71777fc565 100644
> > --- a/drivers/dma/pl330.c
> > +++ b/drivers/dma/pl330.c
> > @@ -2627,6 +2627,42 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
> >         return 0;
> >  }
> >
> > +/*
> > + * Runtime PM callbacks are provided by amba/bus.c driver.
> > + *
> > + * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> > + * bus driver will only disable/enable the clock in runtime PM callbacks.
> > + */
> > +static int __maybe_unused pl330_suspend(struct device *dev)
> > +{
> > +       struct amba_device *pcdev = to_amba_device(dev);
> > +
> > +       if (!pm_runtime_status_suspended(dev)) {
> 
> No, this wont work. Consider this scenario:
> 
> pm_runtime_status_suspended() returns "true", which means you consider
> the device to be runtime PM suspended, thus you will unprepare the
> clock below.
> 
> Later, a call to pm_runtime_get_sync() is invoked from "somewhere" and
> before this driver's system PM resume callback has been invoked. That
> will trigger the runtime PM resume callback to be invoked, causing
> clock unbalance issues.

If during system resume the device runtime resume is called BEFORE
normal resume of device, then you're right: clock will be unbalanced. 

But such case does not make sense. pm_runtime_get_sync() is called when
someone wants to use the dmaengine/pl330... but the pl330 driver is
still suspended in that time!

If runtime resume is called AFTER normal resume of device - then it is
fine with my code.

> You need a pm_runtime_disable() prior checking the runtime PM status
> using pm_runtime_status_suspended(). That will prevent this from
> happen.
> 
> I guess you may see where this is leading. I think
> pm_runtime_force_suspend|resume() is well suited for this situation.

I've been there... :)



--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki Nov. 13, 2014, 1:37 a.m. UTC | #3
On Wednesday, November 12, 2014 03:32:27 PM Krzysztof Kozlowski wrote:
> Add system suspend/resume capabilities to the pl330 driver so the amba
> bus clock could be also unprepared to conserve energy.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
> 
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index c3bd3584f261..fd71777fc565 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -2627,6 +2627,42 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
>  	return 0;
>  }
>  
> +/*
> + * Runtime PM callbacks are provided by amba/bus.c driver.
> + *
> + * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> + * bus driver will only disable/enable the clock in runtime PM callbacks.
> + */
> +static int __maybe_unused pl330_suspend(struct device *dev)
> +{
> +	struct amba_device *pcdev = to_amba_device(dev);
> +
> +	if (!pm_runtime_status_suspended(dev)) {

It generally isn't safe to call that in .suspend(), because the status may still
change in theory.  On the other hand, if you do that in .suspend_late(), you'll
be safe from that.

> +		/* amba did not disable the clock */
> +		amba_pclk_disable(pcdev);
> +	}
> +	amba_pclk_unprepare(pcdev);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused pl330_resume(struct device *dev)
> +{
> +	struct amba_device *pcdev = to_amba_device(dev);
> +	int ret;
> +
> +	ret = amba_pclk_prepare(pcdev);
> +	if (ret)
> +		return ret;
> +
> +	if (!pm_runtime_status_suspended(dev))
> +		ret = amba_pclk_enable(pcdev);
> +
> +	return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
> +
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
>  {
> @@ -2853,6 +2889,7 @@ static struct amba_driver pl330_driver = {
>  	.drv = {
>  		.owner = THIS_MODULE,
>  		.name = "dma-pl330",
> +		.pm = &pl330_pm,
>  	},
>  	.id_table = pl330_ids,
>  	.probe = pl330_probe,
>
Ulf Hansson Nov. 13, 2014, 9:03 a.m. UTC | #4
On 13 November 2014 02:37, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Wednesday, November 12, 2014 03:32:27 PM Krzysztof Kozlowski wrote:
>> Add system suspend/resume capabilities to the pl330 driver so the amba
>> bus clock could be also unprepared to conserve energy.
>>
>> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
>> ---
>>  drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
>>  1 file changed, 37 insertions(+)
>>
>> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
>> index c3bd3584f261..fd71777fc565 100644
>> --- a/drivers/dma/pl330.c
>> +++ b/drivers/dma/pl330.c
>> @@ -2627,6 +2627,42 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
>>       return 0;
>>  }
>>
>> +/*
>> + * Runtime PM callbacks are provided by amba/bus.c driver.
>> + *
>> + * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
>> + * bus driver will only disable/enable the clock in runtime PM callbacks.
>> + */
>> +static int __maybe_unused pl330_suspend(struct device *dev)
>> +{
>> +     struct amba_device *pcdev = to_amba_device(dev);
>> +
>> +     if (!pm_runtime_status_suspended(dev)) {
>
> It generally isn't safe to call that in .suspend(), because the status may still
> change in theory.  On the other hand, if you do that in .suspend_late(), you'll
> be safe from that.
>

Just to clarify that statement; it's safe in a ->suspend_late()
callback, because runtime PM has been disabled by the PM core.

That's also the reason why the pm_runtime_force_suspend() helper is
disabling runtime PM, such it may be used in some of the earlier
phases of the system PM callbacks.

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Krzysztof Kozlowski Nov. 14, 2014, 8:13 a.m. UTC | #5
On czw, 2014-11-13 at 10:03 +0100, Ulf Hansson wrote:
> On 13 November 2014 02:37, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> > On Wednesday, November 12, 2014 03:32:27 PM Krzysztof Kozlowski wrote:
> >> Add system suspend/resume capabilities to the pl330 driver so the amba
> >> bus clock could be also unprepared to conserve energy.
> >>
> >> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> >> ---
> >>  drivers/dma/pl330.c | 37 +++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 37 insertions(+)
> >>
> >> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> >> index c3bd3584f261..fd71777fc565 100644
> >> --- a/drivers/dma/pl330.c
> >> +++ b/drivers/dma/pl330.c
> >> @@ -2627,6 +2627,42 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
> >>       return 0;
> >>  }
> >>
> >> +/*
> >> + * Runtime PM callbacks are provided by amba/bus.c driver.
> >> + *
> >> + * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> >> + * bus driver will only disable/enable the clock in runtime PM callbacks.
> >> + */
> >> +static int __maybe_unused pl330_suspend(struct device *dev)
> >> +{
> >> +     struct amba_device *pcdev = to_amba_device(dev);
> >> +
> >> +     if (!pm_runtime_status_suspended(dev)) {
> >
> > It generally isn't safe to call that in .suspend(), because the status may still
> > change in theory.  On the other hand, if you do that in .suspend_late(), you'll
> > be safe from that.
> >
> 
> Just to clarify that statement; it's safe in a ->suspend_late()
> callback, because runtime PM has been disabled by the PM core.
> 
> That's also the reason why the pm_runtime_force_suspend() helper is
> disabling runtime PM, such it may be used in some of the earlier
> phases of the system PM callbacks.

So actually only pm_runtime_disable() is missing here (as you mentioned
earlier)?

Best regards,
Krzysztof


--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index c3bd3584f261..fd71777fc565 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2627,6 +2627,42 @@  static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
 	return 0;
 }
 
+/*
+ * Runtime PM callbacks are provided by amba/bus.c driver.
+ *
+ * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
+ * bus driver will only disable/enable the clock in runtime PM callbacks.
+ */
+static int __maybe_unused pl330_suspend(struct device *dev)
+{
+	struct amba_device *pcdev = to_amba_device(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		/* amba did not disable the clock */
+		amba_pclk_disable(pcdev);
+	}
+	amba_pclk_unprepare(pcdev);
+
+	return 0;
+}
+
+static int __maybe_unused pl330_resume(struct device *dev)
+{
+	struct amba_device *pcdev = to_amba_device(dev);
+	int ret;
+
+	ret = amba_pclk_prepare(pcdev);
+	if (ret)
+		return ret;
+
+	if (!pm_runtime_status_suspended(dev))
+		ret = amba_pclk_enable(pcdev);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
+
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
@@ -2853,6 +2889,7 @@  static struct amba_driver pl330_driver = {
 	.drv = {
 		.owner = THIS_MODULE,
 		.name = "dma-pl330",
+		.pm = &pl330_pm,
 	},
 	.id_table = pl330_ids,
 	.probe = pl330_probe,