diff mbox

[2/2] dmaengine: shdma: add runtime- and system-level power management

Message ID Pine.LNX.4.64.1104291908090.17813@axis700.grange (mailing list archive)
State Accepted
Headers show

Commit Message

Guennadi Liakhovetski April 29, 2011, 5:09 p.m. UTC
This patch extends and fixes runtime power management in the shdma
driver to support powering down the DMA controller and adds support
for system-level suspend and resume.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/dma/shdma.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/dma/shdma.h |    1 +
 2 files changed, 69 insertions(+), 0 deletions(-)

Comments

Vinod Koul May 2, 2011, 8:03 a.m. UTC | #1
On Fri, 2011-04-29 at 19:09 +0200, Guennadi Liakhovetski wrote:
> This patch extends and fixes runtime power management in the shdma
> driver to support powering down the DMA controller and adds support
> for system-level suspend and resume.
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>  drivers/dma/shdma.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/dma/shdma.h |    1 +
>  2 files changed, 69 insertions(+), 0 deletions(-)
> 

>  
> +static int sh_dmae_runtime_suspend(struct device *dev)
> +{
> +	return 0;
> +}
Don't you need to initialize you device on resume...????


> +
> +static int sh_dmae_runtime_resume(struct device *dev)
> +{
> +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> +
> +	return sh_dmae_rst(shdev);
> +}
> +
> +#ifdef CONFIG_PM
This should be removed...
> +static int sh_dmae_suspend(struct device *dev)
> +{
> +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> +	int i;
> +
> +	for (i = 0; i < shdev->pdata->channel_num; i++) {
> +		struct sh_dmae_chan *sh_chan = shdev->chan[i];
> +		if (sh_chan->descs_allocated)
> +			sh_chan->pm_error = pm_runtime_put_sync(dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sh_dmae_resume(struct device *dev)
> +{
> +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> +	int i;
> +
> +	for (i = 0; i < shdev->pdata->channel_num; i++) {
> +		struct sh_dmae_chan *sh_chan = shdev->chan[i];
> +		struct sh_dmae_slave *param = sh_chan->common.private;
> +
> +		if (!sh_chan->descs_allocated)
> +			continue;
> +
> +		if (!sh_chan->pm_error)
> +			pm_runtime_get_sync(dev);
> +
> +		if (param) {
> +			const struct sh_dmae_slave_config *cfg = param->config;
> +			dmae_set_dmars(sh_chan, cfg->mid_rid);
> +			dmae_set_chcr(sh_chan, cfg->chcr);
> +		} else {
> +			dmae_init(sh_chan);
> +		}
> +	}
> +
> +	return 0;
> +}
> +#else
> +#define sh_dmae_suspend NULL
> +#define sh_dmae_resume NULL
> +#endif
> +
> +const struct dev_pm_ops sh_dmae_pm = {
> +	.suspend		= sh_dmae_suspend,
> +	.resume			= sh_dmae_resume,
> +	.runtime_suspend	= sh_dmae_runtime_suspend,
> +	.runtime_resume		= sh_dmae_runtime_resume,
> +};
> +
>  static struct platform_driver sh_dmae_driver = {
>  	.remove		= __exit_p(sh_dmae_remove),
>  	.shutdown	= sh_dmae_shutdown,
>  	.driver = {
>  		.owner	= THIS_MODULE,
>  		.name	= "sh-dma-engine",
> +		.pm	= &sh_dmae_pm,
>  	},
>  };
>  
> diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> index 52e4fb1..3f9d3cd 100644
> --- a/drivers/dma/shdma.h
> +++ b/drivers/dma/shdma.h
> @@ -37,6 +37,7 @@ struct sh_dmae_chan {
>  	int id;				/* Raw id of this channel */
>  	u32 __iomem *base;
>  	char dev_id[16];		/* unique name per DMAC of channel */
> +	int pm_error;
>  };
>  
>  struct sh_dmae_device {

And please remember to CC maintainers...
Vinod Koul May 2, 2011, 8:38 a.m. UTC | #2
On Mon, 2011-05-02 at 11:04 +0200, Guennadi Liakhovetski wrote:
> On Mon, 2 May 2011, Koul, Vinod wrote:
> 
> > On Fri, 2011-04-29 at 19:09 +0200, Guennadi Liakhovetski wrote:
> > > This patch extends and fixes runtime power management in the shdma
> > > driver to support powering down the DMA controller and adds support
> > > for system-level suspend and resume.
> > > 
> > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > ---
> > >  drivers/dma/shdma.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/dma/shdma.h |    1 +
> > >  2 files changed, 69 insertions(+), 0 deletions(-)
> > > 
> > 
> > >  
> > > +static int sh_dmae_runtime_suspend(struct device *dev)
> > > +{
> > > +	return 0;
> > > +}
> > Don't you need to initialize you device on resume...????
> 
> Hm, yes, but this is suspend... Resume is below. Sorry, I probably don't 
> understand your question.
Opps, my question was for empty suspend. Dont you need to power off you
device.
> 
> > > +
> > > +static int sh_dmae_runtime_resume(struct device *dev)
> > > +{
> > > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > > +
> > > +	return sh_dmae_rst(shdev);
> > > +}
> > > +
> > > +#ifdef CONFIG_PM
> > This should be removed...
> 
> You mean, these functions just won't be called, but this way we save a 
> couple of bytes if PM is not set, don't we?
I meant you dont need to have this, PM is usually part of core options
which ppl enable nowadays. Do you run with PM disabled?
Guennadi Liakhovetski May 2, 2011, 9:04 a.m. UTC | #3
On Mon, 2 May 2011, Koul, Vinod wrote:

> On Fri, 2011-04-29 at 19:09 +0200, Guennadi Liakhovetski wrote:
> > This patch extends and fixes runtime power management in the shdma
> > driver to support powering down the DMA controller and adds support
> > for system-level suspend and resume.
> > 
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> >  drivers/dma/shdma.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/dma/shdma.h |    1 +
> >  2 files changed, 69 insertions(+), 0 deletions(-)
> > 
> 
> >  
> > +static int sh_dmae_runtime_suspend(struct device *dev)
> > +{
> > +	return 0;
> > +}
> Don't you need to initialize you device on resume...????

Hm, yes, but this is suspend... Resume is below. Sorry, I probably don't 
understand your question.

> > +
> > +static int sh_dmae_runtime_resume(struct device *dev)
> > +{
> > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > +
> > +	return sh_dmae_rst(shdev);
> > +}
> > +
> > +#ifdef CONFIG_PM
> This should be removed...

You mean, these functions just won't be called, but this way we save a 
couple of bytes if PM is not set, don't we?

> > +static int sh_dmae_suspend(struct device *dev)
> > +{
> > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > +	int i;
> > +
> > +	for (i = 0; i < shdev->pdata->channel_num; i++) {
> > +		struct sh_dmae_chan *sh_chan = shdev->chan[i];
> > +		if (sh_chan->descs_allocated)
> > +			sh_chan->pm_error = pm_runtime_put_sync(dev);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int sh_dmae_resume(struct device *dev)
> > +{
> > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > +	int i;
> > +
> > +	for (i = 0; i < shdev->pdata->channel_num; i++) {
> > +		struct sh_dmae_chan *sh_chan = shdev->chan[i];
> > +		struct sh_dmae_slave *param = sh_chan->common.private;
> > +
> > +		if (!sh_chan->descs_allocated)
> > +			continue;
> > +
> > +		if (!sh_chan->pm_error)
> > +			pm_runtime_get_sync(dev);
> > +
> > +		if (param) {
> > +			const struct sh_dmae_slave_config *cfg = param->config;
> > +			dmae_set_dmars(sh_chan, cfg->mid_rid);
> > +			dmae_set_chcr(sh_chan, cfg->chcr);
> > +		} else {
> > +			dmae_init(sh_chan);
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +#else
> > +#define sh_dmae_suspend NULL
> > +#define sh_dmae_resume NULL
> > +#endif
> > +
> > +const struct dev_pm_ops sh_dmae_pm = {
> > +	.suspend		= sh_dmae_suspend,
> > +	.resume			= sh_dmae_resume,
> > +	.runtime_suspend	= sh_dmae_runtime_suspend,
> > +	.runtime_resume		= sh_dmae_runtime_resume,
> > +};
> > +
> >  static struct platform_driver sh_dmae_driver = {
> >  	.remove		= __exit_p(sh_dmae_remove),
> >  	.shutdown	= sh_dmae_shutdown,
> >  	.driver = {
> >  		.owner	= THIS_MODULE,
> >  		.name	= "sh-dma-engine",
> > +		.pm	= &sh_dmae_pm,
> >  	},
> >  };
> >  
> > diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
> > index 52e4fb1..3f9d3cd 100644
> > --- a/drivers/dma/shdma.h
> > +++ b/drivers/dma/shdma.h
> > @@ -37,6 +37,7 @@ struct sh_dmae_chan {
> >  	int id;				/* Raw id of this channel */
> >  	u32 __iomem *base;
> >  	char dev_id[16];		/* unique name per DMAC of channel */
> > +	int pm_error;
> >  };
> >  
> >  struct sh_dmae_device {
> 
> And please remember to CC maintainers...

Sorry, will try to remember.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski May 2, 2011, 9:53 a.m. UTC | #4
On Mon, 2 May 2011, Koul, Vinod wrote:

> On Mon, 2011-05-02 at 11:04 +0200, Guennadi Liakhovetski wrote:
> > On Mon, 2 May 2011, Koul, Vinod wrote:
> > 
> > > On Fri, 2011-04-29 at 19:09 +0200, Guennadi Liakhovetski wrote:
> > > > This patch extends and fixes runtime power management in the shdma
> > > > driver to support powering down the DMA controller and adds support
> > > > for system-level suspend and resume.
> > > > 
> > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > ---
> > > >  drivers/dma/shdma.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > > >  drivers/dma/shdma.h |    1 +
> > > >  2 files changed, 69 insertions(+), 0 deletions(-)
> > > > 
> > > 
> > > >  
> > > > +static int sh_dmae_runtime_suspend(struct device *dev)
> > > > +{
> > > > +	return 0;
> > > > +}
> > > Don't you need to initialize you device on resume...????
> > 
> > Hm, yes, but this is suspend... Resume is below. Sorry, I probably don't 
> > understand your question.
> Opps, my question was for empty suspend. Dont you need to power off you
> device.

Powering down and up is performed by platform / domain hooks. I only need 
to reset the hardware on wakeup. An empty .runtime_suspend() is needed by 
the sh-mobile specific rtpm, at least by the version, that I have, because 
otherwise the device status will not be changed and the resume will not be 
called.

> > > > +
> > > > +static int sh_dmae_runtime_resume(struct device *dev)
> > > > +{
> > > > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > > > +
> > > > +	return sh_dmae_rst(shdev);
> > > > +}
> > > > +
> > > > +#ifdef CONFIG_PM
> > > This should be removed...
> > 
> > You mean, these functions just won't be called, but this way we save a 
> > couple of bytes if PM is not set, don't we?
> I meant you dont need to have this, PM is usually part of core options
> which ppl enable nowadays. Do you run with PM disabled?

I actually do, but maybe that's not a very important argument. So, if the 
only difference is a couple of kilobytes in the kernel size, then maybe we 
can just keep it always enabled. There are no other side-efects to it, 
right?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vinod Koul May 2, 2011, 10:05 a.m. UTC | #5
On Mon, 2011-05-02 at 11:53 +0200, Guennadi Liakhovetski wrote:
> On Mon, 2 May 2011, Koul, Vinod wrote:
> 
> > On Mon, 2011-05-02 at 11:04 +0200, Guennadi Liakhovetski wrote:
> > > On Mon, 2 May 2011, Koul, Vinod wrote:
> > > 
> > > > On Fri, 2011-04-29 at 19:09 +0200, Guennadi Liakhovetski wrote:
> > > > > This patch extends and fixes runtime power management in the shdma
> > > > > driver to support powering down the DMA controller and adds support
> > > > > for system-level suspend and resume.
> > > > > 
> > > > > +
> > > > > +static int sh_dmae_runtime_resume(struct device *dev)
> > > > > +{
> > > > > +	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
> > > > > +
> > > > > +	return sh_dmae_rst(shdev);
> > > > > +}
> > > > > +
> > > > > +#ifdef CONFIG_PM
> > > > This should be removed...
> > > 
> > > You mean, these functions just won't be called, but this way we save a 
> > > couple of bytes if PM is not set, don't we?
> > I meant you dont need to have this, PM is usually part of core options
> > which ppl enable nowadays. Do you run with PM disabled?
> 
> I actually do, but maybe that's not a very important argument. So, if the 
> only difference is a couple of kilobytes in the kernel size, then maybe we 
> can just keep it always enabled. There are no other side-efects to it, 
> right?
Yes, other driver currently do this...
diff mbox

Patch

diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index d0f402b..dcc1b21 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -1254,6 +1254,8 @@  rst_err:
 	spin_unlock_irq(&sh_dmae_lock);
 
 	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	if (dmars)
 		iounmap(shdev->dmars);
 emapdmars:
@@ -1313,12 +1315,78 @@  static void sh_dmae_shutdown(struct platform_device *pdev)
 	sh_dmae_ctl_stop(shdev);
 }
 
+static int sh_dmae_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int sh_dmae_runtime_resume(struct device *dev)
+{
+	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+	return sh_dmae_rst(shdev);
+}
+
+#ifdef CONFIG_PM
+static int sh_dmae_suspend(struct device *dev)
+{
+	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < shdev->pdata->channel_num; i++) {
+		struct sh_dmae_chan *sh_chan = shdev->chan[i];
+		if (sh_chan->descs_allocated)
+			sh_chan->pm_error = pm_runtime_put_sync(dev);
+	}
+
+	return 0;
+}
+
+static int sh_dmae_resume(struct device *dev)
+{
+	struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < shdev->pdata->channel_num; i++) {
+		struct sh_dmae_chan *sh_chan = shdev->chan[i];
+		struct sh_dmae_slave *param = sh_chan->common.private;
+
+		if (!sh_chan->descs_allocated)
+			continue;
+
+		if (!sh_chan->pm_error)
+			pm_runtime_get_sync(dev);
+
+		if (param) {
+			const struct sh_dmae_slave_config *cfg = param->config;
+			dmae_set_dmars(sh_chan, cfg->mid_rid);
+			dmae_set_chcr(sh_chan, cfg->chcr);
+		} else {
+			dmae_init(sh_chan);
+		}
+	}
+
+	return 0;
+}
+#else
+#define sh_dmae_suspend NULL
+#define sh_dmae_resume NULL
+#endif
+
+const struct dev_pm_ops sh_dmae_pm = {
+	.suspend		= sh_dmae_suspend,
+	.resume			= sh_dmae_resume,
+	.runtime_suspend	= sh_dmae_runtime_suspend,
+	.runtime_resume		= sh_dmae_runtime_resume,
+};
+
 static struct platform_driver sh_dmae_driver = {
 	.remove		= __exit_p(sh_dmae_remove),
 	.shutdown	= sh_dmae_shutdown,
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "sh-dma-engine",
+		.pm	= &sh_dmae_pm,
 	},
 };
 
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 52e4fb1..3f9d3cd 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -37,6 +37,7 @@  struct sh_dmae_chan {
 	int id;				/* Raw id of this channel */
 	u32 __iomem *base;
 	char dev_id[16];		/* unique name per DMAC of channel */
+	int pm_error;
 };
 
 struct sh_dmae_device {