diff mbox

[1/2] dmaengine: ep93xx: Always start from BASE0

Message ID 20170513221327.10114-2-alexander.sverdlin@gmail.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Alexander Sverdlin May 13, 2017, 10:13 p.m. UTC
The current buffer is being reset to zero on device_free_chan_resources()
but not on device_terminate_all(). It could happen that HW is restarted and
expects BASE0 to be used, but the driver is not synchronized and will start
from BASE1. Therefore, it's better to reset the buffer explicitly in
m2p_hw_setup(). While here, check that HW really starts from BASE0 and
warn otherwise.

Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/ep93xx_dma.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Vinod Koul May 14, 2017, 1:14 p.m. UTC | #1
On Sun, May 14, 2017 at 12:13:26AM +0200, Alexander Sverdlin wrote:
> The current buffer is being reset to zero on device_free_chan_resources()
> but not on device_terminate_all(). It could happen that HW is restarted and
> expects BASE0 to be used, but the driver is not synchronized and will start
> from BASE1. Therefore, it's better to reset the buffer explicitly in
> m2p_hw_setup(). While here, check that HW really starts from BASE0 and
> warn otherwise.
> 
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> Cc: stable@vger.kernel.org
> ---
>  drivers/dma/ep93xx_dma.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
> index d37e8dda8079..a3d946d2a8e1 100644
> --- a/drivers/dma/ep93xx_dma.c
> +++ b/drivers/dma/ep93xx_dma.c
> @@ -45,6 +45,7 @@
>  
>  #define M2P_PPALLOC			0x0008
>  #define M2P_STATUS			0x000c
> +#define M2P_STATUS_NEXTBUFFER		BIT(6)
>  
>  #define M2P_MAXCNT0			0x0020
>  #define M2P_BASE0			0x0024
> @@ -312,6 +313,13 @@ static void m2p_set_control(struct ep93xx_dma_chan *edmac, u32 control)
>  	readl(edmac->regs + M2P_CONTROL);
>  }
>  
> +static inline u32 m2p_channel_nextbuf(struct ep93xx_dma_chan *edmac)
> +{
> +	if (readl(edmac->regs + M2P_STATUS) & M2P_STATUS_NEXTBUFFER)
> +		return 1;
> +	return 0;
> +}
> +
>  static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
>  {
>  	struct ep93xx_dma_data *data = edmac->chan.private;
> @@ -323,6 +331,10 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
>  		| M2P_CONTROL_ENABLE;
>  	m2p_set_control(edmac, control);
>  
> +	if (m2p_channel_nextbuf(edmac) != 0)
> +		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");

But then you are actually not restarting from BASE1 as you reset, so the
warn is wrong.. Perhaps a more meaningful msg would be to say "expected 0
but found 1, so resetting"

> +	edmac->buffer = 0;
> +
>  	return 0;
>  }
>  
> -- 
> 2.12.2
>
Alexander Sverdlin May 14, 2017, 1:33 p.m. UTC | #2
Hello Vinod,

On 14/05/17 15:14, Vinod Koul wrote:
>> @@ -323,6 +331,10 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
>>  		| M2P_CONTROL_ENABLE;
>>  	m2p_set_control(edmac, control);
>>  
>> +	if (m2p_channel_nextbuf(edmac) != 0)
>> +		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");
> But then you are actually not restarting from BASE1 as you reset, so the
> warn is wrong.. Perhaps a more meaningful msg would be to say "expected 0
> but found 1, so resetting"

This is, maybe not so obvious, a warning, which should never fire. It just
proves, that I understand the HW correctly. As long as nobody sees the warning,
it's the case. And it proves that HW behaves according to user manual.
We can remove this warning completely.

Once again, the story is following:

- m2p_hw_setup() is always called after channel reset
- after reset channel expects to start from buffer 0
- therefore we must always start from buffer 0 <= this was not the case before
- we can read the expected "next buffer" from the controller => hence the warning
  maybe if there will be a bug somewhere and the channel will not be reset before
  next transfer, it will be triggered

Regards,
Alexander.
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexander Sverdlin May 14, 2017, 1:36 p.m. UTC | #3
Hello Vinod,

On 14/05/17 15:33, Alexander Sverdlin wrote:
>>> +	if (m2p_channel_nextbuf(edmac) != 0)
>>> +		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");
>> But then you are actually not restarting from BASE1 as you reset, so the
>> warn is wrong.. Perhaps a more meaningful msg would be to say "expected 0
>> but found 1, so resetting"

Should it be something like "M2P: Channel has not been reset properly!\n"?

> This is, maybe not so obvious, a warning, which should never fire. It just
> proves, that I understand the HW correctly. As long as nobody sees the warning,
> it's the case. And it proves that HW behaves according to user manual.
> We can remove this warning completely.
> 
> Once again, the story is following:
> 
> - m2p_hw_setup() is always called after channel reset
> - after reset channel expects to start from buffer 0
> - therefore we must always start from buffer 0 <= this was not the case before
> - we can read the expected "next buffer" from the controller => hence the warning
>   maybe if there will be a bug somewhere and the channel will not be reset before
>   next transfer, it will be triggered

--
Alexander.
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" 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 14, 2017, 3:17 p.m. UTC | #4
On Sun, May 14, 2017 at 03:36:56PM +0200, Alexander Sverdlin wrote:
> Hello Vinod,
> 
> On 14/05/17 15:33, Alexander Sverdlin wrote:
> >>> +	if (m2p_channel_nextbuf(edmac) != 0)
> >>> +		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");
> >> But then you are actually not restarting from BASE1 as you reset, so the
> >> warn is wrong.. Perhaps a more meaningful msg would be to say "expected 0
> >> but found 1, so resetting"
> 
> Should it be something like "M2P: Channel has not been reset properly!\n"?

Better and with a word that you recovered and did reset of the state

> > This is, maybe not so obvious, a warning, which should never fire. It just
> > proves, that I understand the HW correctly. As long as nobody sees the warning,
> > it's the case. And it proves that HW behaves according to user manual.
> > We can remove this warning completely.
> > 
> > Once again, the story is following:
> > 
> > - m2p_hw_setup() is always called after channel reset
> > - after reset channel expects to start from buffer 0
> > - therefore we must always start from buffer 0 <= this was not the case before
> > - we can read the expected "next buffer" from the controller => hence the warning
> >   maybe if there will be a bug somewhere and the channel will not be reset before
> >   next transfer, it will be triggered
> 
> --
> Alexander.
Alexander Sverdlin May 14, 2017, 3:22 p.m. UTC | #5
Hi!

On 14/05/17 17:17, Vinod Koul wrote:
> On Sun, May 14, 2017 at 03:36:56PM +0200, Alexander Sverdlin wrote:
>> Hello Vinod,
>>
>> On 14/05/17 15:33, Alexander Sverdlin wrote:
>>>>> +	if (m2p_channel_nextbuf(edmac) != 0)
>>>>> +		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");
>>>> But then you are actually not restarting from BASE1 as you reset, so the
>>>> warn is wrong.. Perhaps a more meaningful msg would be to say "expected 0
>>>> but found 1, so resetting"
>> Should it be something like "M2P: Channel has not been reset properly!\n"?
> Better and with a word that you recovered and did reset of the state

No, no, I do not touch HW at all, I make the driver state consistent.
So the condition for warning is not expected at all. It could be even BUG_ON();
Only in case someone brakes the driver or changes the dmaengine core.

The problem was: we are maintaining the shadow of the controller state in the
driver. This "->buffer" member. It was not properly reset when the controller
was.

Alexander.

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

Patch

diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index d37e8dda8079..a3d946d2a8e1 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -45,6 +45,7 @@ 
 
 #define M2P_PPALLOC			0x0008
 #define M2P_STATUS			0x000c
+#define M2P_STATUS_NEXTBUFFER		BIT(6)
 
 #define M2P_MAXCNT0			0x0020
 #define M2P_BASE0			0x0024
@@ -312,6 +313,13 @@  static void m2p_set_control(struct ep93xx_dma_chan *edmac, u32 control)
 	readl(edmac->regs + M2P_CONTROL);
 }
 
+static inline u32 m2p_channel_nextbuf(struct ep93xx_dma_chan *edmac)
+{
+	if (readl(edmac->regs + M2P_STATUS) & M2P_STATUS_NEXTBUFFER)
+		return 1;
+	return 0;
+}
+
 static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
 {
 	struct ep93xx_dma_data *data = edmac->chan.private;
@@ -323,6 +331,10 @@  static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
 		| M2P_CONTROL_ENABLE;
 	m2p_set_control(edmac, control);
 
+	if (m2p_channel_nextbuf(edmac) != 0)
+		dev_warn(chan2dev(edmac), "M2P: Starting from BASE1\n");
+	edmac->buffer = 0;
+
 	return 0;
 }