* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
@ 2013-07-30 9:44 Barry Song
2013-08-12 5:29 ` Barry Song
2013-08-13 11:32 ` Vinod Koul
0 siblings, 2 replies; 6+ messages in thread
From: Barry Song @ 2013-07-30 9:44 UTC (permalink / raw)
To: linux-arm-kernel
this patch adds PM ops entries in sirf-dma drivers, so that this
driver can support suspend/resume, hibernation and runtime PM.
while suspending, sirf-dma will lose all registers, so we save
them at suspend and restore in resume for active channels.
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
-v2: add comments for PM state machine;
don't always put dma to suspended after resuming from sleep as it
depends on the runtime pm status;
drivers/dma/sirf-dma.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 129 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 716b23e..ff3cdd2 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -73,6 +74,11 @@ struct sirfsoc_dma_chan {
int mode;
};
+struct sirfsoc_dma_regs {
+ u32 ctrl[SIRFSOC_DMA_CHANNELS];
+ u32 interrupt_en;
+};
+
struct sirfsoc_dma {
struct dma_device dma;
struct tasklet_struct tasklet;
@@ -81,10 +87,13 @@ struct sirfsoc_dma {
int irq;
struct clk *clk;
bool is_marco;
+ struct sirfsoc_dma_regs regs_save;
};
#define DRV_NAME "sirfsoc_dma"
+static int sirfsoc_dma_runtime_suspend(struct device *dev);
+
/* Convert struct dma_chan to struct sirfsoc_dma_chan */
static inline
struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c)
@@ -393,6 +402,8 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
LIST_HEAD(descs);
int i;
+ pm_runtime_get_sync(sdma->dma.dev);
+
/* Alloc descriptors for this channel */
for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) {
sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL);
@@ -425,6 +436,7 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
{
struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+ struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
struct sirfsoc_dma_desc *sdesc, *tmp;
unsigned long flags;
LIST_HEAD(descs);
@@ -445,6 +457,8 @@ static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
/* Free descriptors */
list_for_each_entry_safe(sdesc, tmp, &descs, node)
kfree(sdesc);
+
+ pm_runtime_put(sdma->dma.dev);
}
/* Send pending descriptor to hardware */
@@ -723,14 +737,14 @@ static int sirfsoc_dma_probe(struct platform_device *op)
tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma);
- clk_prepare_enable(sdma->clk);
-
/* Register DMA engine */
dev_set_drvdata(dev, sdma);
+
ret = dma_async_device_register(dma);
if (ret)
goto free_irq;
+ pm_runtime_enable(&op->dev);
dev_info(dev, "initialized SIRFSOC DMAC driver\n");
return 0;
@@ -747,13 +761,124 @@ static int sirfsoc_dma_remove(struct platform_device *op)
struct device *dev = &op->dev;
struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
- clk_disable_unprepare(sdma->clk);
dma_async_device_unregister(&sdma->dma);
free_irq(sdma->irq, sdma);
irq_dispose_mapping(sdma->irq);
+ pm_runtime_disable(&op->dev);
+ if (!pm_runtime_status_suspended(&op->dev))
+ sirfsoc_dma_runtime_suspend(&op->dev);
+
+ return 0;
+}
+
+static int sirfsoc_dma_runtime_suspend(struct device *dev)
+{
+ struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(sdma->clk);
+ return 0;
+}
+
+static int sirfsoc_dma_runtime_resume(struct device *dev)
+{
+ struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(sdma->clk);
+ if (ret < 0) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int sirfsoc_dma_pm_suspend(struct device *dev)
+{
+ struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+ struct sirfsoc_dma_regs *save = &sdma->regs_save;
+ struct sirfsoc_dma_desc *sdesc;
+ struct sirfsoc_dma_chan *schan;
+ int ch;
+ int ret;
+
+ /*
+ * if we were runtime-suspended before, resume to enable clock
+ * before accessing register
+ */
+ if (pm_runtime_status_suspended(dev)) {
+ ret = sirfsoc_dma_runtime_resume(dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * DMA controller will lose all registers while suspending
+ * so we need to save registers for active channels
+ */
+ for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
+ schan = &sdma->channels[ch];
+ if (list_empty(&schan->active))
+ continue;
+ sdesc = list_first_entry(&schan->active,
+ struct sirfsoc_dma_desc,
+ node);
+ save->ctrl[ch] = readl_relaxed(sdma->base +
+ ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
+ }
+ save->interrupt_en = readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN);
+
+ /* Disable clock */
+ sirfsoc_dma_runtime_suspend(dev);
+
+ return 0;
+}
+
+static int sirfsoc_dma_pm_resume(struct device *dev)
+{
+ struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+ struct sirfsoc_dma_regs *save = &sdma->regs_save;
+ struct sirfsoc_dma_desc *sdesc;
+ struct sirfsoc_dma_chan *schan;
+ int ch;
+ int ret;
+
+ /* Enable clock before accessing register */
+ ret = sirfsoc_dma_runtime_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ writel_relaxed(save->interrupt_en, sdma->base + SIRFSOC_DMA_INT_EN);
+ for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
+ schan = &sdma->channels[ch];
+ if (list_empty(&schan->active))
+ continue;
+ sdesc = list_first_entry(&schan->active,
+ struct sirfsoc_dma_desc,
+ node);
+ writel_relaxed(sdesc->width,
+ sdma->base + SIRFSOC_DMA_WIDTH_0 + ch * 4);
+ writel_relaxed(sdesc->xlen,
+ sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_XLEN);
+ writel_relaxed(sdesc->ylen,
+ sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_YLEN);
+ writel_relaxed(save->ctrl[ch],
+ sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
+ writel_relaxed(sdesc->addr >> 2,
+ sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_ADDR);
+ }
+
+ /* if we were runtime-suspended before, suspend again */
+ if (pm_runtime_status_suspended(dev))
+ sirfsoc_dma_runtime_suspend(dev);
+
return 0;
}
+static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
+ SET_RUNTIME_PM_OPS(sirfsoc_dma_runtime_suspend, sirfsoc_dma_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
+};
+
static struct of_device_id sirfsoc_dma_match[] = {
{ .compatible = "sirf,prima2-dmac", },
{ .compatible = "sirf,marco-dmac", },
@@ -766,6 +891,7 @@ static struct platform_driver sirfsoc_dma_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &sirfsoc_dma_pm_ops,
.of_match_table = sirfsoc_dma_match,
},
};
--
1.8.2.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
2013-07-30 9:44 [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime Barry Song
@ 2013-08-12 5:29 ` Barry Song
2013-08-13 11:32 ` Vinod Koul
1 sibling, 0 replies; 6+ messages in thread
From: Barry Song @ 2013-08-12 5:29 UTC (permalink / raw)
To: linux-arm-kernel
2013/7/30 Barry Song <21cnbao@gmail.com>:
> this patch adds PM ops entries in sirf-dma drivers, so that this
> driver can support suspend/resume, hibernation and runtime PM.
>
> while suspending, sirf-dma will lose all registers, so we save
> them at suspend and restore in resume for active channels.
>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
ping Vinod.
-barry
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
2013-07-30 9:44 [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime Barry Song
2013-08-12 5:29 ` Barry Song
@ 2013-08-13 11:32 ` Vinod Koul
2013-08-13 12:18 ` Russell King - ARM Linux
[not found] ` <CAGsJ_4yPgXhUO65tAyU4ngMRUzqa6uZWqEM2NoD-HWy9DL-rnQ@mail.gmail.com>
1 sibling, 2 replies; 6+ messages in thread
From: Vinod Koul @ 2013-08-13 11:32 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jul 30, 2013 at 05:44:34PM +0800, Barry Song wrote:
> this patch adds PM ops entries in sirf-dma drivers, so that this
> driver can support suspend/resume, hibernation and runtime PM.
>
> while suspending, sirf-dma will lose all registers, so we save
> them at suspend and restore in resume for active channels.
>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
Applied, thanks
Although putting runtime_get/put in submit and callback would be much more
better than alloc/free implementation
~Vinod
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
2013-08-13 12:18 ` Russell King - ARM Linux
@ 2013-08-13 11:53 ` Vinod Koul
0 siblings, 0 replies; 6+ messages in thread
From: Vinod Koul @ 2013-08-13 11:53 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 13, 2013 at 01:18:13PM +0100, Russell King - ARM Linux wrote:
> On Tue, Aug 13, 2013 at 05:02:00PM +0530, Vinod Koul wrote:
> > On Tue, Jul 30, 2013 at 05:44:34PM +0800, Barry Song wrote:
> > Although putting runtime_get/put in submit and callback would be much more
> > better than alloc/free implementation
>
> When the prepare/submit is called from non-process context, the runtime
> API tends to complain, so it's not that easy.
only the pm_runtime_get_sync() is the problem here. you can do pm_runtime_get() and
submit the descriptor
Then on .runtime_resume you can start the pending transaction.
I found it very useful when working with serial dma's where the serial driver
would like to keep the dma channel and not free it.
> Also you can end up in situations which cause lockdep to complain,
> especially when some of the runtime stuff calls out to an i2c controller
> which then uses the dmaengine, but the dma engine also calls out to the
> runtime api. (I don't rememeber the exact details, I just remember having
> to drop the runtime API from such places in the past.)
hmmm, i havent seen such dependency. Can you recall what were you testing in
that scenario
~Vinod
--
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
2013-08-13 11:32 ` Vinod Koul
@ 2013-08-13 12:18 ` Russell King - ARM Linux
2013-08-13 11:53 ` Vinod Koul
[not found] ` <CAGsJ_4yPgXhUO65tAyU4ngMRUzqa6uZWqEM2NoD-HWy9DL-rnQ@mail.gmail.com>
1 sibling, 1 reply; 6+ messages in thread
From: Russell King - ARM Linux @ 2013-08-13 12:18 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 13, 2013 at 05:02:00PM +0530, Vinod Koul wrote:
> On Tue, Jul 30, 2013 at 05:44:34PM +0800, Barry Song wrote:
> > this patch adds PM ops entries in sirf-dma drivers, so that this
> > driver can support suspend/resume, hibernation and runtime PM.
> >
> > while suspending, sirf-dma will lose all registers, so we save
> > them at suspend and restore in resume for active channels.
> >
> > Signed-off-by: Barry Song <Baohua.Song@csr.com>
> > Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
> Applied, thanks
>
> Although putting runtime_get/put in submit and callback would be much more
> better than alloc/free implementation
When the prepare/submit is called from non-process context, the runtime
API tends to complain, so it's not that easy.
Also you can end up in situations which cause lockdep to complain,
especially when some of the runtime stuff calls out to an i2c controller
which then uses the dmaengine, but the dma engine also calls out to the
runtime api. (I don't rememeber the exact details, I just remember having
to drop the runtime API from such places in the past.)
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime
[not found] ` <CAGsJ_4yPgXhUO65tAyU4ngMRUzqa6uZWqEM2NoD-HWy9DL-rnQ@mail.gmail.com>
@ 2013-08-14 2:53 ` Vinod Koul
0 siblings, 0 replies; 6+ messages in thread
From: Vinod Koul @ 2013-08-14 2:53 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Aug 14, 2013 at 10:22:15AM +0800, Barry Song wrote:
> 2013/8/13 Vinod Koul <vinod.koul@intel.com>
>
> > On Tue, Jul 30, 2013 at 05:44:34PM +0800, Barry Song wrote:
> > > this patch adds PM ops entries in sirf-dma drivers, so that this
> > > driver can support suspend/resume, hibernation and runtime PM.
> > >
> > > while suspending, sirf-dma will lose all registers, so we save
> > > them at suspend and restore in resume for active channels.
> > >
> > > Signed-off-by: Barry Song <Baohua.Song@csr.com>
> > > Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
> > Applied, thanks
> >
> > Although putting runtime_get/put in submit and callback would be much more
> > better than alloc/free implementation
> >
> > i do agree. i did want to make the runtime pm happen in submit and finish
> callback. then i found it was buggy. and we need more work to make it
> really stable, then i moved to runtime PM with more coarse accuracy. that
> will lose some power saving. but i think we can have increased patches for
> that if we measure and find dma power consumption is large.
> BTW, where is the active dmaengine tree located in now? it seems that
> https://git.kernel.org/cgit/linux/kernel/git/djbw/dmaengine.git/ is not
> active for a long time.
mine is at git.infradead.org/users/vkoul/slave-dma.git
Dan seem busy so he acks patches and I carry them
~Vinod
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-08-14 2:53 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-30 9:44 [PATCH v2] dmaengine: sirf: add PM entries for sleep and runtime Barry Song
2013-08-12 5:29 ` Barry Song
2013-08-13 11:32 ` Vinod Koul
2013-08-13 12:18 ` Russell King - ARM Linux
2013-08-13 11:53 ` Vinod Koul
[not found] ` <CAGsJ_4yPgXhUO65tAyU4ngMRUzqa6uZWqEM2NoD-HWy9DL-rnQ@mail.gmail.com>
2013-08-14 2:53 ` Vinod Koul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).