diff mbox

[v1,1/1] dmaengine: dw: make busyloops limited by counter

Message ID 1425983107-20612-1-git-send-email-andriy.shevchenko@linux.intel.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Andy Shevchenko March 10, 2015, 10:25 a.m. UTC
In some cases we might have DMA powered off and therefore get 0xffffffff from
the register. This patch introduces a counter to prevent a hang.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/core.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

Vinod Koul March 16, 2015, 4:48 p.m. UTC | #1
On Tue, Mar 10, 2015 at 12:25:07PM +0200, Andy Shevchenko wrote:
> In some cases we might have DMA powered off and therefore get 0xffffffff from
> the register. This patch introduces a counter to prevent a hang.
> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw/core.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> index a8ad052..3f514d6 100644
> --- a/drivers/dma/dw/core.c
> +++ b/drivers/dma/dw/core.c
> @@ -191,8 +191,10 @@ static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
>  
>  static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  {
> +	unsigned int count = 20;
> +
>  	channel_clear_bit(dw, CH_EN, dwc->mask);
> -	while (dma_readl(dw, CH_EN) & dwc->mask)
> +	while (dma_readl(dw, CH_EN) & dwc->mask && count--)
you have a write instructions before this, so how is that write is not
impacted and read is. Why would DMA be powered off?
Andy Shevchenko March 17, 2015, 10:32 a.m. UTC | #2
On Mon, 2015-03-16 at 22:18 +0530, Vinod Koul wrote:
> On Tue, Mar 10, 2015 at 12:25:07PM +0200, Andy Shevchenko wrote:
> > In some cases we might have DMA powered off and therefore get 0xffffffff from
> > the register. This patch introduces a counter to prevent a hang.
> > 
> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > ---
> >  drivers/dma/dw/core.c | 7 +++++--
> >  1 file changed, 5 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> > index a8ad052..3f514d6 100644
> > --- a/drivers/dma/dw/core.c
> > +++ b/drivers/dma/dw/core.c
> > @@ -191,8 +191,10 @@ static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
> >  
> >  static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
> >  {
> > +	unsigned int count = 20;
> > +
> >  	channel_clear_bit(dw, CH_EN, dwc->mask);
> > -	while (dma_readl(dw, CH_EN) & dwc->mask)
> > +	while (dma_readl(dw, CH_EN) & dwc->mask && count--)
> you have a write instructions before this, so how is that write is not
> impacted and read is.

The write rather can be impacted, but we can't know this for sure (needs
some probe on the interconnect / IOSF to see that).

>  Why would DMA be powered off?

In our case DMA is a private IP to the host controllers (SPI, for
example), So, the power rail is shared for SPI and DMA. SPI uses runtime
PM and can be switched off.

The actual issue we have is happened at dw_dma_off(). I decided to add
an extra to dwc_chan_disable().

Give another thought I'm okay to fix just dw_dma_off() case.
Maxime Ripard March 17, 2015, 2:13 p.m. UTC | #3
Hi Andy,

On Tue, Mar 10, 2015 at 12:25:07PM +0200, Andy Shevchenko wrote:
> In some cases we might have DMA powered off and therefore get 0xffffffff from
> the register. This patch introduces a counter to prevent a hang.
> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw/core.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> index a8ad052..3f514d6 100644
> --- a/drivers/dma/dw/core.c
> +++ b/drivers/dma/dw/core.c
> @@ -191,8 +191,10 @@ static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
>  
>  static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  {
> +	unsigned int count = 20;
> +
>  	channel_clear_bit(dw, CH_EN, dwc->mask);
> -	while (dma_readl(dw, CH_EN) & dwc->mask)
> +	while (dma_readl(dw, CH_EN) & dwc->mask && count--)

It looks like a good case for the new readl_poll_timeout_* functions.

Maxime
Andy Shevchenko March 17, 2015, 2:57 p.m. UTC | #4
On Tue, 2015-03-17 at 15:13 +0100, Maxime Ripard wrote:
> Hi Andy,
> 
> On Tue, Mar 10, 2015 at 12:25:07PM +0200, Andy Shevchenko wrote:
> > In some cases we might have DMA powered off and therefore get 0xffffffff from
> > the register. This patch introduces a counter to prevent a hang.
> > 
> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > ---
> >  drivers/dma/dw/core.c | 7 +++++--
> >  1 file changed, 5 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> > index a8ad052..3f514d6 100644
> > --- a/drivers/dma/dw/core.c
> > +++ b/drivers/dma/dw/core.c
> > @@ -191,8 +191,10 @@ static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
> >  
> >  static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
> >  {
> > +	unsigned int count = 20;
> > +
> >  	channel_clear_bit(dw, CH_EN, dwc->mask);
> > -	while (dma_readl(dw, CH_EN) & dwc->mask)
> > +	while (dma_readl(dw, CH_EN) & dwc->mask && count--)
> 
> It looks like a good case for the new readl_poll_timeout_* functions.

I like the idea, but it is not a good case unfortunately. There are not
endianess-aware. And I don't have time to implement the generic support
of that.
Maxime Ripard March 17, 2015, 4:57 p.m. UTC | #5
On Tue, Mar 17, 2015 at 04:57:46PM +0200, Andy Shevchenko wrote:
> On Tue, 2015-03-17 at 15:13 +0100, Maxime Ripard wrote:
> > Hi Andy,
> > 
> > On Tue, Mar 10, 2015 at 12:25:07PM +0200, Andy Shevchenko wrote:
> > > In some cases we might have DMA powered off and therefore get 0xffffffff from
> > > the register. This patch introduces a counter to prevent a hang.
> > > 
> > > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > > ---
> > >  drivers/dma/dw/core.c | 7 +++++--
> > >  1 file changed, 5 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> > > index a8ad052..3f514d6 100644
> > > --- a/drivers/dma/dw/core.c
> > > +++ b/drivers/dma/dw/core.c
> > > @@ -191,8 +191,10 @@ static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
> > >  
> > >  static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
> > >  {
> > > +	unsigned int count = 20;
> > > +
> > >  	channel_clear_bit(dw, CH_EN, dwc->mask);
> > > -	while (dma_readl(dw, CH_EN) & dwc->mask)
> > > +	while (dma_readl(dw, CH_EN) & dwc->mask && count--)
> > 
> > It looks like a good case for the new readl_poll_timeout_* functions.
> 
> I like the idea, but it is not a good case unfortunately. There are not
> endianess-aware. And I don't have time to implement the generic support
> of that.

Ok, nevermind then :)

Maxime
diff mbox

Patch

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index a8ad052..3f514d6 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -191,8 +191,10 @@  static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
 
 static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
 {
+	unsigned int count = 20;
+
 	channel_clear_bit(dw, CH_EN, dwc->mask);
-	while (dma_readl(dw, CH_EN) & dwc->mask)
+	while (dma_readl(dw, CH_EN) & dwc->mask && count--)
 		cpu_relax();
 }
 
@@ -1109,6 +1111,7 @@  static void dwc_issue_pending(struct dma_chan *chan)
 
 static void dw_dma_off(struct dw_dma *dw)
 {
+	unsigned int count = 20;
 	int i;
 
 	dma_writel(dw, CFG, 0);
@@ -1118,7 +1121,7 @@  static void dw_dma_off(struct dw_dma *dw)
 	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
 	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
 
-	while (dma_readl(dw, CFG) & DW_CFG_DMA_EN)
+	while (dma_readl(dw, CFG) & DW_CFG_DMA_EN && count--)
 		cpu_relax();
 
 	for (i = 0; i < dw->dma.chancnt; i++)