qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] hw/timer/nrf51_timer: Don't lose time when timer is queried


From: Joel Stanley
Subject: Re: [PATCH] hw/timer/nrf51_timer: Don't lose time when timer is queried in tight loop
Date: Wed, 7 Jun 2023 11:26:38 +0000

On Tue, 6 Jun 2023 at 13:49, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> The nrf51_timer has a free-running counter which we implement using
> the pattern of using two fields (update_counter_ns, counter) to track
> the last point at which we calculated the counter value, and the
> counter value at that time.  Then we can find the current counter
> value by converting the difference in wall-clock time between then
> and now to a tick count that we need to add to the counter value.
>
> Unfortunately the nrf51_timer's implementation of this has a bug
> which means it loses time every time update_counter() is called.
> After updating s->counter it always sets s->update_counter_ns to
> 'now', even though the actual point when s->counter hit the new value
> will be some point in the past (half a tick, say).  In the worst case
> (guest code in a tight loop reading the counter, icount mode) the
> counter is continually queried less than a tick after it was last
> read, so s->counter never advances but s->update_counter_ns does, and
> the guest never makes forward progress.
>
> The fix for this is to only advance update_counter_ns to the
> timestamp of the last tick, not all the way to 'now'.  (This is the
> pattern used in hw/misc/mps2-fpgaio.c's counter.)
>
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> The hang in icount mode was discovered by the Zephyr folks as part
> of their investigation into
> https://github.com/zephyrproject-rtos/zephyr/issues/57512

Did you get an image to test with?

Reviewed-by: Joel Stanley <joel@jms.id.au>

>
>  hw/timer/nrf51_timer.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
> index 42be79c7363..50c6772383e 100644
> --- a/hw/timer/nrf51_timer.c
> +++ b/hw/timer/nrf51_timer.c
> @@ -45,7 +45,12 @@ static uint32_t update_counter(NRF51TimerState *s, int64_t 
> now)
>      uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
>
>      s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
> -    s->update_counter_ns = now;
> +    /*
> +     * Only advance the sync time to the timestamp of the last tick,
> +     * not all the way to 'now', so we don't lose time if we do
> +     * multiple resyncs in a single tick.
> +     */
> +    s->update_counter_ns += ticks_to_ns(s, ticks);
>      return ticks;

We're still returning the number of ticks up to 'now'. Should we
instead return the elapsed ticks? If not, we will expire the timer
early.

Cheers,

Joel



reply via email to

[Prev in Thread] Current Thread [Next in Thread]