2021-03-04 15:20:39

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 1/3] clocksource/drivers/timer-ti-dm: Fix posted mode status check order

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 <[email protected]>
---
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);

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;
}
--
2.30.1


2021-03-05 00:58:33

by Grygorii Strashko

[permalink] [raw]
Subject: Re: [PATCH 1/3] clocksource/drivers/timer-ti-dm: Fix posted mode status check order



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 <[email protected]>
> ---
> 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;
> }
>

--
Best regards,
grygorii

2021-03-05 07:54:41

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 1/3] clocksource/drivers/timer-ti-dm: Fix posted mode status check order

* Grygorii Strashko <[email protected]> [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

2021-03-05 10:11:46

by Grygorii Strashko

[permalink] [raw]
Subject: Re: [PATCH 1/3] clocksource/drivers/timer-ti-dm: Fix posted mode status check order



On 05/03/2021 09:53, Tony Lindgren wrote:
> * Grygorii Strashko <[email protected]> [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.

--
Best regards,
grygorii

2021-04-09 10:30:28

by tip-bot2 for Jacob Pan

[permalink] [raw]
Subject: [tip: timers/core] clocksource/drivers/timer-ti-dm: Fix posted mode status check order

The following commit has been merged into the timers/core branch of tip:

Commit-ID: 212709926c5493a566ca4086ad4f4b0d4e66b553
Gitweb: https://git.kernel.org/tip/212709926c5493a566ca4086ad4f4b0d4e66b553
Author: Tony Lindgren <[email protected]>
AuthorDate: Thu, 04 Mar 2021 09:21:33 +02:00
Committer: Daniel Lezcano <[email protected]>
CommitterDate: Thu, 08 Apr 2021 13:23:41 +02:00

clocksource/drivers/timer-ti-dm: Fix posted mode status check order

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 <[email protected]>
Signed-off-by: Daniel Lezcano <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
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
index 614c838..3a65434 100644
--- 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;
}