[1/3] clocksource/drivers/timer-ti-dm: Fix posted mode status check order
diff mbox series

Message ID 20210304072135.52712-2-tony@atomide.com
State New, archived
Headers show
Series
  • Fixes for timer-ti-dm systimer posted mode
Related show

Commit Message

Tony Lindgren March 4, 2021, 7:21 a.m. UTC
When the timer is configured in posted mode, we need to check the write-
posted status register (TWPS) before writing to the register.

We now check TWPS after the write starting with commit 52762fbd1c47
("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource
support").

For example, in the TRM for am571x the following is documented in chapter
"22.2.4.13.1.1 Write Posting Synchronization Mode":

"For each register, a status bit is provided in the timer write-posted
 status (TWPS) register. In this mode, it is mandatory that software check
 this status bit before any write access. If a write is attempted to a
 register with a previous access pending, the previous access is discarded
 without notice."

The regression happened when I updated the code to use standard read/write
accessors for the driver instead of using __omap_dm_timer_load_start().
We have__omap_dm_timer_load_start() check the TWPS status correctly using
__omap_dm_timer_write().

Fixes: 52762fbd1c47 ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support")
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/clocksource/timer-ti-dm-systimer.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Comments

Grygorii Strashko March 4, 2021, 8:57 p.m. UTC | #1
On 04/03/2021 09:21, Tony Lindgren wrote:
> When the timer is configured in posted mode, we need to check the write-
> posted status register (TWPS) before writing to the register.
> 
> We now check TWPS after the write starting with commit 52762fbd1c47
> ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource
> support").
> 
> For example, in the TRM for am571x the following is documented in chapter
> "22.2.4.13.1.1 Write Posting Synchronization Mode":
> 
> "For each register, a status bit is provided in the timer write-posted
>   status (TWPS) register. In this mode, it is mandatory that software check
>   this status bit before any write access. If a write is attempted to a
>   register with a previous access pending, the previous access is discarded
>   without notice."
> 
> The regression happened when I updated the code to use standard read/write
> accessors for the driver instead of using __omap_dm_timer_load_start().
> We have__omap_dm_timer_load_start() check the TWPS status correctly using
> __omap_dm_timer_write().
> 
> Fixes: 52762fbd1c47 ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support")
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
>   drivers/clocksource/timer-ti-dm-systimer.c | 12 ++++++------
>   1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
> --- a/drivers/clocksource/timer-ti-dm-systimer.c
> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> @@ -449,13 +449,13 @@ static int dmtimer_set_next_event(unsigned long cycles,
>   	struct dmtimer_systimer *t = &clkevt->t;
>   	void __iomem *pend = t->base + t->pend;
>   
> -	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
>   	while (readl_relaxed(pend) & WP_TCRR)
>   		cpu_relax();
> +	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
>   
> -	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
>   	while (readl_relaxed(pend) & WP_TCLR)
>   		cpu_relax();
> +	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);

It seems static [and inline] helper here could be better solution. no?

>   
>   	return 0;
>   }
> @@ -490,18 +490,18 @@ static int dmtimer_set_periodic(struct clock_event_device *evt)
>   	dmtimer_clockevent_shutdown(evt);
>   
>   	/* Looks like we need to first set the load value separately */
> -	writel_relaxed(clkevt->period, t->base + t->load);
>   	while (readl_relaxed(pend) & WP_TLDR)
>   		cpu_relax();
> +	writel_relaxed(clkevt->period, t->base + t->load);
>   
> -	writel_relaxed(clkevt->period, t->base + t->counter);
>   	while (readl_relaxed(pend) & WP_TCRR)
>   		cpu_relax();
> +	writel_relaxed(clkevt->period, t->base + t->counter);
>   
> -	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
> -		       t->base + t->ctrl);
>   	while (readl_relaxed(pend) & WP_TCLR)
>   		cpu_relax();
> +	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
> +		       t->base + t->ctrl);
>   
>   	return 0;
>   }
>
Tony Lindgren March 5, 2021, 7:53 a.m. UTC | #2
* Grygorii Strashko <grygorii.strashko@ti.com> [210304 20:58]:
> On 04/03/2021 09:21, Tony Lindgren wrote:
> > When the timer is configured in posted mode, we need to check the write-
> > posted status register (TWPS) before writing to the register.
...

> > --- a/drivers/clocksource/timer-ti-dm-systimer.c
> > +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> > @@ -449,13 +449,13 @@ static int dmtimer_set_next_event(unsigned long cycles,
> >   	struct dmtimer_systimer *t = &clkevt->t;
> >   	void __iomem *pend = t->base + t->pend;
> > -	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
> >   	while (readl_relaxed(pend) & WP_TCRR)
> >   		cpu_relax();
> > +	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
> > -	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
> >   	while (readl_relaxed(pend) & WP_TCLR)
> >   		cpu_relax();
> > +	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
> 
> It seems static [and inline] helper here could be better solution. no?

Well we wanted to get rid of the confusing macros. And in this case I
suspect we can eventually do just one read of the pending register for
the registers used mask rather than check the status separately multiple
times. But that needs to be carefully tested and is not a fix :)

Regards,

Tony
Grygorii Strashko March 5, 2021, 10:09 a.m. UTC | #3
On 05/03/2021 09:53, Tony Lindgren wrote:
> * Grygorii Strashko <grygorii.strashko@ti.com> [210304 20:58]:
>> On 04/03/2021 09:21, Tony Lindgren wrote:
>>> When the timer is configured in posted mode, we need to check the write-
>>> posted status register (TWPS) before writing to the register.
> ...
> 
>>> --- a/drivers/clocksource/timer-ti-dm-systimer.c
>>> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
>>> @@ -449,13 +449,13 @@ static int dmtimer_set_next_event(unsigned long cycles,
>>>    	struct dmtimer_systimer *t = &clkevt->t;
>>>    	void __iomem *pend = t->base + t->pend;
>>> -	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
>>>    	while (readl_relaxed(pend) & WP_TCRR)
>>>    		cpu_relax();
>>> +	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
>>> -	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
>>>    	while (readl_relaxed(pend) & WP_TCLR)
>>>    		cpu_relax();
>>> +	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
>>
>> It seems static [and inline] helper here could be better solution. no?
> 
> Well we wanted to get rid of the confusing macros. And in this case I
> suspect we can eventually do just one read of the pending register for
> the registers used mask rather than check the status separately multiple
> times. But that needs to be carefully tested and is not a fix :)

Might work.

Patch
diff mbox series

diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
--- a/drivers/clocksource/timer-ti-dm-systimer.c
+++ b/drivers/clocksource/timer-ti-dm-systimer.c
@@ -449,13 +449,13 @@  static int dmtimer_set_next_event(unsigned long cycles,
 	struct dmtimer_systimer *t = &clkevt->t;
 	void __iomem *pend = t->base + t->pend;
 
-	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
 	while (readl_relaxed(pend) & WP_TCRR)
 		cpu_relax();
+	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
 
-	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
 	while (readl_relaxed(pend) & WP_TCLR)
 		cpu_relax();
+	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
 
 	return 0;
 }
@@ -490,18 +490,18 @@  static int dmtimer_set_periodic(struct clock_event_device *evt)
 	dmtimer_clockevent_shutdown(evt);
 
 	/* Looks like we need to first set the load value separately */
-	writel_relaxed(clkevt->period, t->base + t->load);
 	while (readl_relaxed(pend) & WP_TLDR)
 		cpu_relax();
+	writel_relaxed(clkevt->period, t->base + t->load);
 
-	writel_relaxed(clkevt->period, t->base + t->counter);
 	while (readl_relaxed(pend) & WP_TCRR)
 		cpu_relax();
+	writel_relaxed(clkevt->period, t->base + t->counter);
 
-	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
-		       t->base + t->ctrl);
 	while (readl_relaxed(pend) & WP_TCLR)
 		cpu_relax();
+	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
+		       t->base + t->ctrl);
 
 	return 0;
 }