diff mbox

[U-Boot] Revert "imx: wdog: correct wcr register settings"

Message ID 1443727970-10347-1-git-send-email-festevam@gmail.com
State Changes Requested
Headers show

Commit Message

Fabio Estevam Oct. 1, 2015, 7:32 p.m. UTC
From: Fabio Estevam <fabio.estevam@freescale.com>

This reverts commit 623d96e89aca64c2762150087f4e872c55481f13.

commit 623d96e89aca6("imx: wdog: correct wcr register settings")
introduced the usage of clrsetbits_le16(), which causes a regression
on LS1021 systems.

Unlike i.MX, LS1021 uses big-endian ordering for the watchdog
controller, which means we cannot use the little endian accessors.

Reported-by: Sinan Akman <sinan@writeme.com>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
 drivers/watchdog/imx_watchdog.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

Comments

Sinan Akman Oct. 1, 2015, 7:39 p.m. UTC | #1
On 01/10/15 03:32 PM, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
>
> This reverts commit 623d96e89aca64c2762150087f4e872c55481f13.
>
> commit 623d96e89aca6("imx: wdog: correct wcr register settings")
> introduced the usage of clrsetbits_le16(), which causes a regression
> on LS1021 systems.
>
> Unlike i.MX, LS1021 uses big-endian ordering for the watchdog
> controller, which means we cannot use the little endian accessors.
>
> Reported-by: Sinan Akman <sinan@writeme.com>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
>   drivers/watchdog/imx_watchdog.c | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
> index 9a77a54..1d18d4b 100644
> --- a/drivers/watchdog/imx_watchdog.c
> +++ b/drivers/watchdog/imx_watchdog.c
> @@ -55,8 +55,7 @@ void reset_cpu(ulong addr)
>   {
>   	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
>   
> -	clrsetbits_le16(&wdog->wcr, 0, WCR_WDE);
> -
> +	writew(WCR_WDE, &wdog->wcr);
>   	writew(0x5555, &wdog->wsr);
>   	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
>   	while (1) {

   Hi Fabio, I just wanted to point out that with this revert we don't 
only break imx again
(whatever the initial bug was for this commit) but also we are having 
ls1021atwr
working accidentally, just because  writew(WCR_WDE, &wdog->wcr) clears SRS
bit which is the only requirement for reset if watchdog is not running.

   I don't have any strong opinion on this but i just wanted to make it 
clear that
we are leaving both imx6 and ls1021atwr not properly implemented.

   Regards
   Sinan Akman
Fabio Estevam Oct. 1, 2015, 7:45 p.m. UTC | #2
Hi Sinan,

On Thu, Oct 1, 2015 at 4:39 PM, Sinan Akman <sinan@writeme.com> wrote:

>   Hi Fabio, I just wanted to point out that with this revert we don't only
> break imx again

We are not breaking imx by doing the revert. The reset still works.
623d96e89aca64c2 appeared only  in 2015.10-rc4.

> (whatever the initial bug was for this commit) but also we are having
> ls1021atwr
> working accidentally, just because  writew(WCR_WDE, &wdog->wcr) clears SRS
> bit which is the only requirement for reset if watchdog is not running.
>
>   I don't have any strong opinion on this but i just wanted to make it clear
> that
> we are leaving both imx6 and ls1021atwr not properly implemented.

I think it is the best/safest we can do at -rc4 to avoid the reset
regression on ls1021.

Then a proper implementation can be done for 2016.01.

Do you agree?

Regards,

Fabio Estevam
Sinan Akman Oct. 1, 2015, 7:50 p.m. UTC | #3
On 01/10/15 03:45 PM, Fabio Estevam wrote:
> Hi Sinan,
>
> On Thu, Oct 1, 2015 at 4:39 PM, Sinan Akman <sinan@writeme.com> wrote:
>
>>    Hi Fabio, I just wanted to point out that with this revert we don't only
>> break imx again
> We are not breaking imx by doing the revert. The reset still works.
> 623d96e89aca64c2 appeared only  in 2015.10-rc4.
>
>> (whatever the initial bug was for this commit) but also we are having
>> ls1021atwr
>> working accidentally, just because  writew(WCR_WDE, &wdog->wcr) clears SRS
>> bit which is the only requirement for reset if watchdog is not running.
>>
>>    I don't have any strong opinion on this but i just wanted to make it clear
>> that
>> we are leaving both imx6 and ls1021atwr not properly implemented.
> I think it is the best/safest we can do at -rc4 to avoid the reset
> regression on ls1021.
>
> Then a proper implementation can be done for 2016.01.
>
> Do you agree?

   Hi Fabio, yes this seems to be the best thing to do for now.
Let's implement then this thing properly soon after.

   Thanks
   Sinan Akman
Fabio Estevam Oct. 1, 2015, 7:52 p.m. UTC | #4
On Thu, Oct 1, 2015 at 4:50 PM, Sinan Akman <sinan@writeme.com> wrote:

>   Hi Fabio, yes this seems to be the best thing to do for now.
> Let's implement then this thing properly soon after.

Could you please reply with a Tested-by tag?

Thanks
Wolfgang Denk Oct. 1, 2015, 8:11 p.m. UTC | #5
Dear Fabio,

In message <1443727970-10347-1-git-send-email-festevam@gmail.com> you wrote:
> 
> Unlike i.MX, LS1021 uses big-endian ordering for the watchdog
> controller, which means we cannot use the little endian accessors.
...
> -	clrsetbits_le16(&wdog->wcr, 0, WCR_WDE);
> -
> +	writew(WCR_WDE, &wdog->wcr);

I'm sorry, but I fail to understand how writew() can be better than
another I/O accessor.  Neither of these has the capability to detect
the endianess of this specific register interface ?

Best regards,

Wolfgang Denk
Fabio Estevam Oct. 1, 2015, 8:19 p.m. UTC | #6
Hi Wolfgang,

On Thu, Oct 1, 2015 at 5:11 PM, Wolfgang Denk <wd@denx.de> wrote:

> I'm sorry, but I fail to understand how writew() can be better than
> another I/O accessor.  Neither of these has the capability to detect
> the endianess of this specific register interface ?

It's not that writew() is better. The problem is that we cannot use
clrsetbits_le16() for a big endian controller.

Regards,

Fabio Estevam
Wolfgang Denk Oct. 1, 2015, 8:50 p.m. UTC | #7
Dear Fabio,

In message <CAOMZO5BEfS10XVztnigMejMVJYLvv+jqDLZYom9K8-G+Zi1TXA@mail.gmail.com> you wrote:
> 
> > I'm sorry, but I fail to understand how writew() can be better than
> > another I/O accessor.  Neither of these has the capability to detect
> > the endianess of this specific register interface ?
> 
> It's not that writew() is better. The problem is that we cannot use
> clrsetbits_le16() for a big endian controller.

On ARM (a LE architecture), clrsetbits_le16() maps down into:

	clrsetbits_le16 ->
	out_le16 / in_le16 ->
	out_arch, w,le16 / in_arch, w,le16 ->
	__raw_writew(cpu_to_le16()) / le16__to_cpu(__raw_readw()) ->
	__raw_writew() / __raw_readw()

while

	writew() ->
	__raw_writew(cpu_to_le16(v),__mem_pci(c))
	__raw_writew()

Both map into __raw_writew() [which then boild down into
__arch_putw() which is just a volatile unsigned short write access.

So both clrsetbits_le16() and writew() are little endian accessors.
In which way would one write other data to the device than the other?

Best regards,

Wolfgang Denk
Fabio Estevam Oct. 1, 2015, 11:11 p.m. UTC | #8
On Thu, Oct 1, 2015 at 5:50 PM, Wolfgang Denk <wd@denx.de> wrote:

> On ARM (a LE architecture), clrsetbits_le16() maps down into:
>
>         clrsetbits_le16 ->
>         out_le16 / in_le16 ->
>         out_arch, w,le16 / in_arch, w,le16 ->
>         __raw_writew(cpu_to_le16()) / le16__to_cpu(__raw_readw()) ->
>         __raw_writew() / __raw_readw()
>
> while
>
>         writew() ->
>         __raw_writew(cpu_to_le16(v),__mem_pci(c))
>         __raw_writew()
>
> Both map into __raw_writew() [which then boild down into
> __arch_putw() which is just a volatile unsigned short write access.
>
> So both clrsetbits_le16() and writew() are little endian accessors.
> In which way would one write other data to the device than the other?

Yes, you are right.

The issue seems to be related to the effect of writing doing
'writew(WCR_WDE, &wdog->wcr)', which writes 0x40 to the register WCR
versus 'clrsetbits_le16(&wdog->wcr, 0, WCR_WDE)' which only enables
the WDE bit.

The kernel driver also does the full write to the WCR register(like we
used to have prior to 623d96e89aca6)
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/watchdog/imx2_wdt.c?id=refs/tags/v4.2.2#n86

This has also the effect of clearing the SRS bit.

By the way we need to implement erratum ERR004346 (WDOG: WDOG SRS bit
requires to be
written twice) in U-boot, but this is an unrelated issue.

So the revert seems to be appropriate. The commit log should be adjusted though.

Regards,

Fabio Estevam
Sinan Akman Oct. 2, 2015, 1:48 a.m. UTC | #9
On 01/10/15 07:11 PM, Fabio Estevam wrote:
> On Thu, Oct 1, 2015 at 5:50 PM, Wolfgang Denk <wd@denx.de> wrote:
>
>> On ARM (a LE architecture), clrsetbits_le16() maps down into:
>>
>>          clrsetbits_le16 ->
>>          out_le16 / in_le16 ->
>>          out_arch, w,le16 / in_arch, w,le16 ->
>>          __raw_writew(cpu_to_le16()) / le16__to_cpu(__raw_readw()) ->
>>          __raw_writew() / __raw_readw()
>>
>> while
>>
>>          writew() ->
>>          __raw_writew(cpu_to_le16(v),__mem_pci(c))
>>          __raw_writew()
>>
>> Both map into __raw_writew() [which then boild down into
>> __arch_putw() which is just a volatile unsigned short write access.
>>
>> So both clrsetbits_le16() and writew() are little endian accessors.
>> In which way would one write other data to the device than the other?
> Yes, you are right.
>
> The issue seems to be related to the effect of writing doing
> 'writew(WCR_WDE, &wdog->wcr)', which writes 0x40 to the register WCR
> versus 'clrsetbits_le16(&wdog->wcr, 0, WCR_WDE)' which only enables
> the WDE bit.


   Unfortunately, I believe this is not exactly true. After the
revert with writew(WCR_WDE, &wdog->wcr) we are
not really writing 0x4 or setting WDE but we are writing
0x0400 and setting the WT bits (wcr[8:15] to 0x04 and
this is accidentally also clearing the SRS bit. In addition,
even if  it was setting the WDE correctly it wouldn't be
relevant to ls1021atwr as we are not setting the timeout.

   Bottom line is the code is broken for ls1021 both
before and after the revert and it just happens that
the broken code after the revert (with writew) clears
a bit we didn't intend to and that generates a
wdog_rst so it hides the real bug. The correct
implementation would be clearing the SRS bit
via an _be16 operation.

   Anyhow, let's move on with this revert if you all agree with
this.

   Fabio, I will send you the test-by to your commit
but we will have to clean up this mini mess soon after :)

   Thanks
   Sinan Akman

>
> The kernel driver also does the full write to the WCR register(like we
> used to have prior to 623d96e89aca6)
> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/watchdog/imx2_wdt.c?id=refs/tags/v4.2.2#n86
>
> This has also the effect of clearing the SRS bit.
>
> By the way we need to implement erratum ERR004346 (WDOG: WDOG SRS bit
> requires to be
> written twice) in U-boot, but this is an unrelated issue.
>
> So the revert seems to be appropriate. The commit log should be adjusted though.
>
> Regards,
>
> Fabio Estevam
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Wolfgang Denk Oct. 2, 2015, 4:30 a.m. UTC | #10
Dear Fabio,

In message <CAOMZO5CAQXVzpX9mW7uHKB98JnMBeuT3ZjiUe4-V4=adjRk0zg@mail.gmail.com> you wrote:
> 
> > So both clrsetbits_le16() and writew() are little endian accessors.
> > In which way would one write other data to the device than the other?
> 
> Yes, you are right.
> 
> The issue seems to be related to the effect of writing doing
> 'writew(WCR_WDE, &wdog->wcr)', which writes 0x40 to the register WCR
> versus 'clrsetbits_le16(&wdog->wcr, 0, WCR_WDE)' which only enables
> the WDE bit.

But if we agree that both are LE accessors, and that the register is
BE, then how does it work at all - we would be writing the wrong bit?

Best regards,

Wolfgang Denk
Fabio Estevam Oct. 2, 2015, 11:10 a.m. UTC | #11
On Fri, Oct 2, 2015 at 1:30 AM, Wolfgang Denk <wd@denx.de> wrote:

> In message <CAOMZO5CAQXVzpX9mW7uHKB98JnMBeuT3ZjiUe4-V4=adjRk0zg@mail.gmail.com> you
> But if we agree that both are LE accessors, and that the register is
> BE, then how does it work at all - we would be writing the wrong bit?

Watchdog on LS1021 works by accident rather than by design.

What we are trying to do is to avoid the regression on LS1021 for the
2015.10 release.

Then a proper watchdog driver implementation is needed for 2016.01 so
that it takes care of the endianness.

Is this approach acceptable?

Regards,

Fabio Estevam
diff mbox

Patch

diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 9a77a54..1d18d4b 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -55,8 +55,7 @@  void reset_cpu(ulong addr)
 {
 	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
 
-	clrsetbits_le16(&wdog->wcr, 0, WCR_WDE);
-
+	writew(WCR_WDE, &wdog->wcr);
 	writew(0x5555, &wdog->wsr);
 	writew(0xaaaa, &wdog->wsr);	/* load minimum 1/2 second timeout */
 	while (1) {