lkml.org 
[lkml]   [2011]   [Jul]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH 2/3] dmaengine: at_hdmac: improve power management routines
    From
    Date
    On Mon, 2011-07-25 at 23:06 +0200, Nicolas Ferre wrote:
    > On 07/07/2011 04:20 AM, Vinod Koul wrote:
    > > On Tue, 2011-06-28 at 13:17 +0200, Nicolas Ferre wrote:
    > >> Save/restore dma controller state across a suspend-resume sequence.
    > >> The prepare() function will wait for the non-cyclic channels to become idle.
    > >> It also deals with cyclic operations with the start at next period while
    > >> resuming.
    > >>
    > >> Signed-off-by: Nicolas Ferre<nicolas.ferre@atmel.com>
    > >> Signed-off-by: Uwe Kleine-König<u.kleine-koenig@pengutronix.de>
    > >> ---
    > >> drivers/dma/at_hdmac.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
    > >> drivers/dma/at_hdmac_regs.h | 7 +++
    > >> 2 files changed, 94 insertions(+), 1 deletions(-)
    > >>
    > >> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
    > >> index fd87b96..7096adb 100644
    > >> --- a/drivers/dma/at_hdmac.c
    > >> +++ b/drivers/dma/at_hdmac.c
    > >> @@ -1385,27 +1385,113 @@ static void at_dma_shutdown(struct platform_device *pdev)
    > >> clk_disable(atdma->clk);
    > >> }
    > >>
    > >> +static int at_dma_prepare(struct device *dev)
    > >> +{
    > >> + struct platform_device *pdev = to_platform_device(dev);
    > >> + struct at_dma *atdma = platform_get_drvdata(pdev);
    > >> + struct dma_chan *chan, *_chan;
    > >> +
    > >> + list_for_each_entry_safe(chan, _chan,&atdma->dma_common.channels,
    > >> + device_node) {
    > >> + struct at_dma_chan *atchan = to_at_dma_chan(chan);
    > >> + /* wait for transaction completion (except in cyclic case) */
    > >> + if (atc_chan_is_enabled(atchan)&&
    > >> + !test_bit(ATC_IS_CYCLIC,&atchan->status))
    > >> + return -EAGAIN;
    > > pls fix indent here
    >
    > Fixed by replacement of test_bit() with a wrapper in a patch to come (as
    > you suggest hereafter).
    >
    > >> + }
    > >> + return 0;
    > >> +}
    > >> +
    > >> +static void atc_suspend_cyclic(struct at_dma_chan *atchan)
    > >> +{
    > >> + struct dma_chan *chan =&atchan->chan_common;
    > >> +
    > >> + /* Channel should be paused by user
    > >> + * do it anyway even if it is not done already */
    > >> + if (!test_bit(ATC_IS_PAUSED,&atchan->status)) {
    > >> + dev_warn(chan2dev(chan),
    > >> + "cyclic channel not paused, should be done by channel user\n");
    > >> + atc_control(chan, DMA_PAUSE, 0);
    > >> + }
    > >> +
    > >> + /* now preserve additional data for cyclic operations */
    > >> + /* next descriptor address in the cyclic list */
    > >> + atchan->save_dscr = channel_readl(atchan, DSCR);
    > >> +
    > >> + vdbg_dump_regs(atchan);
    > >> +}
    > >> +
    > >> static int at_dma_suspend_noirq(struct device *dev)
    > >> {
    > >> struct platform_device *pdev = to_platform_device(dev);
    > >> struct at_dma *atdma = platform_get_drvdata(pdev);
    > >> + struct dma_chan *chan, *_chan;
    > >>
    > >> - at_dma_off(platform_get_drvdata(pdev));
    > >> + /* preserve data */
    > >> + list_for_each_entry_safe(chan, _chan,&atdma->dma_common.channels,
    > >> + device_node) {
    > >> + struct at_dma_chan *atchan = to_at_dma_chan(chan);
    > >> +
    > >> + if (test_bit(ATC_IS_CYCLIC,&atchan->status))
    > >> + atc_suspend_cyclic(atchan);
    > >> + atchan->save_cfg = channel_readl(atchan, CFG);
    > >> + }
    > >> + atdma->save_imr = dma_readl(atdma, EBCIMR);
    > >> +
    > >> + /* disable DMA controller */
    > >> + at_dma_off(atdma);
    > >> clk_disable(atdma->clk);
    > >> return 0;
    > >> }
    > >>
    > >> +static void atc_resume_cyclic(struct at_dma_chan *atchan)
    > >> +{
    > >> + struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
    > >> +
    > >> + /* restore channel status for cyclic descriptors list:
    > >> + * next descriptor in the cyclic list at the time of suspend */
    > >> + channel_writel(atchan, SADDR, 0);
    > >> + channel_writel(atchan, DADDR, 0);
    > >> + channel_writel(atchan, CTRLA, 0);
    > >> + channel_writel(atchan, CTRLB, 0);
    > >> + channel_writel(atchan, DSCR, atchan->save_dscr);
    > >> + dma_writel(atdma, CHER, atchan->mask);
    > >> +
    > >> + /* channel pause status should be removed by channel user
    > >> + * We cannot take the initiative to do it here */
    > >> +
    > >> + vdbg_dump_regs(atchan);
    > >> +}
    > >> +
    > >> static int at_dma_resume_noirq(struct device *dev)
    > >> {
    > >> struct platform_device *pdev = to_platform_device(dev);
    > >> struct at_dma *atdma = platform_get_drvdata(pdev);
    > >> + struct dma_chan *chan, *_chan;
    > >>
    > >> + /* bring back DMA controller */
    > >> clk_enable(atdma->clk);
    > >> dma_writel(atdma, EN, AT_DMA_ENABLE);
    > >> +
    > >> + /* clear any pending interrupt */
    > >> + while (dma_readl(atdma, EBCISR))
    > >> + cpu_relax();
    > >> +
    > >> + /* restore saved data */
    > >> + dma_writel(atdma, EBCIER, atdma->save_imr);
    > >> + list_for_each_entry_safe(chan, _chan,&atdma->dma_common.channels,
    > >> + device_node) {
    > >> + struct at_dma_chan *atchan = to_at_dma_chan(chan);
    > >> +
    > >> + channel_writel(atchan, CFG, atchan->save_cfg);
    > >> + if (test_bit(ATC_IS_CYCLIC,&atchan->status))
    > >> + atc_resume_cyclic(atchan);
    > > This testing on bits seems to be reused few times how about wrapping it
    > > up in a routine?
    >
    > True: I write a little patch for this and the "PAUSE" state. I send a
    > patch for this now:
    > dmaengine: at_hdmac: add wrappers for testing channel state
    > So can you:
    > 1/ queue 1/3 and 2/3 of this patch series
    > 2/ queue the following patch named
    > "dmaengine: at_hdmac: add wrappers for testing channel state"
    > on top of that
    >
    > 3/ drop the patch 3/3 of this series: it certainly have to be reworked
    > with all slave config infrastructure implementation in the at_hdmac driver.
    The indent needs to be fixed before I can apply this one, sorry but
    error introduced in one patch cannot be fixed in next, it is not
    supposed to work that way

    --
    ~Vinod Koul
    Intel Corp.

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2011-07-26 15:51    [W:0.035 / U:0.292 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site