Re: [PATCH] dmaengine: pl330: get rid of pm_runtime_irq_safe()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2015-04-10 8:57 GMT+02:00 Robert Baldyga <r.baldyga@xxxxxxxxxxx>:
> As using pm_runtime_irq_safe() causes power domain is always enabled,
> we want to get rid of it to reach better power efficiency. For this purpose
> we call pm_runtime_get()/pm_runtime_put() only in DMA channel allocate/free
> code. DMA channels are always requested and freed in non-atomic context,
> so we don't need pm_runtime_irq_safe().
>
> With pm_runtime_irq_safe() enabled the only action performed by
> pm_runtime_get()/pm_runtime_put() functions was enabling and disabling
> AHB clock, so now we do that manually to avoid using pm_runtime functions
> in atomic context.
>
> In result we manage AHB clock as we did before, plus we can disable power
> domain when nobody uses DMA controller.
>
> Signed-off-by: Robert Baldyga <r.baldyga@xxxxxxxxxxx>

Great job! Some comments below.

> ---
>  drivers/dma/pl330.c | 57 ++++++++++++++++++++++++++++++++---------------------
>  1 file changed, 34 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 0e1f567..5348ab9 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -1969,6 +1969,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
>  static void pl330_tasklet(unsigned long data)
>  {
>         struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> +       struct amba_device *pcdev = to_amba_device(pch->dmac->ddma.dev);
>         struct dma_pl330_desc *desc, *_dt;
>         unsigned long flags;
>         bool power_down = false;
> @@ -2032,11 +2033,9 @@ static void pl330_tasklet(unsigned long data)
>         }
>         spin_unlock_irqrestore(&pch->lock, flags);
>
> -       /* If work list empty, power down */
> -       if (power_down) {
> -               pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -               pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
> -       }
> +       /* If work list empty, disable clock */
> +       if (power_down)
> +               amba_pclk_disable(pcdev);
>  }
>
>  bool pl330_filter(struct dma_chan *chan, void *param)
> @@ -2077,6 +2076,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
>
> +       pm_runtime_get_sync(pch->dmac->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>
>         dma_cookie_init(chan);
> @@ -2165,10 +2165,15 @@ static int pl330_terminate_all(struct dma_chan *chan)
>  int pl330_pause(struct dma_chan *chan)
>  {
>         struct dma_pl330_chan *pch = to_pchan(chan);
> +       struct amba_device *pcdev = to_amba_device(pch->dmac->ddma.dev);
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
> +       int ret;
> +
> +       ret = amba_pclk_enable(pcdev);
> +       if (ret < 0)
> +               return ret;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>
>         spin_lock(&pl330->lock);
> @@ -2176,8 +2181,7 @@ int pl330_pause(struct dma_chan *chan)
>         spin_unlock(&pl330->lock);
>
>         spin_unlock_irqrestore(&pch->lock, flags);
> -       pm_runtime_mark_last_busy(pl330->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
> +       amba_pclk_disable(pcdev);
>
>         return 0;
>  }
> @@ -2185,11 +2189,16 @@ int pl330_pause(struct dma_chan *chan)
>  static void pl330_free_chan_resources(struct dma_chan *chan)
>  {
>         struct dma_pl330_chan *pch = to_pchan(chan);
> +       struct amba_device *pcdev = to_amba_device(pch->dmac->ddma.dev);
>         unsigned long flags;
> +       int ret;
>
>         tasklet_kill(&pch->task);
>
> -       pm_runtime_get_sync(pch->dmac->ddma.dev);
> +       ret = amba_pclk_enable(pcdev);
> +       if (ret < 0)
> +               return;
> +
>         spin_lock_irqsave(&pch->lock, flags);
>
>         pl330_release_channel(pch->thread);
> @@ -2199,6 +2208,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>                 list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
>
>         spin_unlock_irqrestore(&pch->lock, flags);
> +       amba_pclk_disable(pcdev);
>         pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
>         pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
>  }
> @@ -2206,12 +2216,17 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>  int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                 struct dma_pl330_desc *desc)
>  {
> +       struct amba_device *pcdev = to_amba_device(pch->dmac->ddma.dev);
>         struct pl330_thread *thrd = pch->thread;
>         struct pl330_dmac *pl330 = pch->dmac;
>         void __iomem *regs = thrd->dmac->base;
>         u32 val, addr;
> +       int ret;
> +
> +       ret = amba_pclk_enable(pcdev);
> +       if (ret < 0)
> +               return ret;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         val = addr = 0;
>         if (desc->rqcfg.src_inc) {
>                 val = readl(regs + SA(thrd->id));
> @@ -2220,8 +2235,8 @@ int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                 val = readl(regs + DA(thrd->id));
>                 addr = desc->px.dst_addr;
>         }
> -       pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
> +
> +       amba_pclk_disable(pcdev);
>         return val - addr;
>  }
>
> @@ -2276,17 +2291,21 @@ out:
>  static void pl330_issue_pending(struct dma_chan *chan)
>  {
>         struct dma_pl330_chan *pch = to_pchan(chan);
> +       struct amba_device *pcdev = to_amba_device(pch->dmac->ddma.dev);
>         unsigned long flags;
> +       int ret;
>
>         spin_lock_irqsave(&pch->lock, flags);
>         if (list_empty(&pch->work_list)) {
>                 /*
>                  * Warn on nothing pending. Empty submitted_list may
> -                * break our pm_runtime usage counter as it is
> -                * updated on work_list emptiness status.
> +                * break our clock usage counter as it is updated on
> +                * work_list emptiness status.
>                  */
>                 WARN_ON(list_empty(&pch->submitted_list));
> -               pm_runtime_get_sync(pch->dmac->ddma.dev);
> +               ret = amba_pclk_enable(pcdev);
> +               if (ret < 0)
> +                       return;
>         }
>         list_splice_tail_init(&pch->submitted_list, &pch->work_list);
>         spin_unlock_irqrestore(&pch->lock, flags);
> @@ -2723,10 +2742,6 @@ static int __maybe_unused pl330_suspend(struct device *dev)
>
>         pm_runtime_disable(dev);
>
> -       if (!pm_runtime_status_suspended(dev)) {
> -               /* amba did not disable the clock */
> -               amba_pclk_disable(pcdev);
> -       }

What if system suspend happens when clock is enabled? I think it may
happen between issue_pending and tasklet execution. In such (rare)
case the clock won't be disabled but will be unprepared.

>         amba_pclk_unprepare(pcdev);
>
>         return 0;
> @@ -2741,9 +2756,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         if (ret)
>                 return ret;
>
> -       if (!pm_runtime_status_suspended(dev))
> -               ret = amba_pclk_enable(pcdev);
> -
>         pm_runtime_enable(dev);
>
>         return ret;
> @@ -2910,7 +2922,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
>                 pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
>                 pcfg->num_peri, pcfg->num_events);
>
> -       pm_runtime_irq_safe(&adev->dev);
>         pm_runtime_use_autosuspend(&adev->dev);
>         pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);

Any needs for updating also PL330_AUTOSUSPEND_DELAY? I set it to 20ms
to avoid too frequent suspend/resume. In your solution suspend happens
in different cases so maybe the time should longer?

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




[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux