From e398e4a4ffec898bcd74f509df27e398b7c1df08 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 3 Mar 2025 11:06:04 +0200 Subject: [PATCH] arch/risc-v/src/common/riscv_mtimer.c: Add risc-v tick timer operations Add the mtimer _tick operations for use when tickless mode is not used. This corrects the tick-based timing calculations, removing tick timer drift and rounding errors causing early wdog expirations. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/common/riscv_mtimer.c | 179 +++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/common/riscv_mtimer.c b/arch/risc-v/src/common/riscv_mtimer.c index 74fd062ed2..cc04169d18 100644 --- a/arch/risc-v/src/common/riscv_mtimer.c +++ b/arch/risc-v/src/common/riscv_mtimer.c @@ -68,16 +68,30 @@ static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower, static int riscv_mtimer_current(struct oneshot_lowerhalf_s *lower, struct timespec *ts); +static int riscv_mtimer_tick_max_delay(struct oneshot_lowerhalf_s *lower, + clock_t *ticks); +static int riscv_mtimer_tick_start(struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, void *arg, + clock_t ticks); +static int riscv_mtimer_tick_cancel(struct oneshot_lowerhalf_s *lower, + clock_t *ticks); +static int riscv_mtimer_tick_current(struct oneshot_lowerhalf_s *lower, + clock_t *ticks); + /**************************************************************************** * Private Data ****************************************************************************/ static const struct oneshot_operations_s g_riscv_mtimer_ops = { - .max_delay = riscv_mtimer_max_delay, - .start = riscv_mtimer_start, - .cancel = riscv_mtimer_cancel, - .current = riscv_mtimer_current, + .max_delay = riscv_mtimer_max_delay, + .start = riscv_mtimer_start, + .cancel = riscv_mtimer_cancel, + .current = riscv_mtimer_current, + .tick_start = riscv_mtimer_tick_start, + .tick_current = riscv_mtimer_tick_current, + .tick_max_delay = riscv_mtimer_tick_max_delay, + .tick_cancel = riscv_mtimer_tick_cancel, }; /**************************************************************************** @@ -189,6 +203,32 @@ static int riscv_mtimer_max_delay(struct oneshot_lowerhalf_s *lower, return 0; } +/**************************************************************************** + * Name: riscv_mtimer_tick_max_delay + * + * Description: + * Determine the maximum delay of the one-shot timer + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the maximum delay. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int riscv_mtimer_tick_max_delay(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + *ticks = (clock_t)UINT64_MAX; + + return 0; +} + /**************************************************************************** * Name: riscv_mtimer_start * @@ -235,6 +275,53 @@ static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower, return 0; } +/**************************************************************************** + * Name: riscv_mtimer_tick_start + * + * Description: + * Start the oneshot timer + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * handler The function to call when when the oneshot timer expires. + * arg An opaque argument that will accompany the callback. + * ticks Provides the duration of the one shot timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int riscv_mtimer_tick_start(struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, void *arg, + clock_t ticks) +{ + struct riscv_mtimer_lowerhalf_s *priv = + (struct riscv_mtimer_lowerhalf_s *)lower; + irqstate_t flags; + uint64_t mtime; + clock_t current; + uint64_t alarm; + + flags = up_irq_save(); + + mtime = riscv_mtimer_get_mtime(priv); + current = mtime * TICK_PER_SEC / priv->freq; + alarm = (current + ticks) * priv->freq / TICK_PER_SEC; + + priv->alarm = alarm; + priv->callback = callback; + priv->arg = arg; + + riscv_mtimer_set_mtimecmp(priv, priv->alarm); + + up_irq_restore(flags); + return 0; +} + /**************************************************************************** * Name: riscv_mtimer_cancel * @@ -290,6 +377,59 @@ static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower, return 0; } +/**************************************************************************** + * Name: riscv_mtimer_tick_cancel + * + * Description: + * Cancel the oneshot timer and return the time remaining on the timer. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the time remaining on the + * oneshot timer. A time of zero is returned if the timer is + * not running. + * + * Returned Value: + * Zero (OK) is returned on success. A call to up_timer_cancel() when + * the timer is not active should also return success; a negated errno + * value is returned on any failure. + * + ****************************************************************************/ + +static int riscv_mtimer_tick_cancel(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + struct riscv_mtimer_lowerhalf_s *priv = + (struct riscv_mtimer_lowerhalf_s *)lower; + uint64_t mtime; + uint64_t alarm; + irqstate_t flags; + + flags = up_irq_save(); + + alarm = priv->alarm; + + mtime = riscv_mtimer_get_mtime(priv); + + riscv_mtimer_set_mtimecmp(priv, UINT64_MAX); + + *ticks = alarm * TICK_PER_SEC / priv->freq - + mtime * TICK_PER_SEC / priv->freq; + + priv->alarm = 0; + priv->callback = NULL; + priv->arg = NULL; + + up_irq_restore(flags); + + return 0; +} + /**************************************************************************** * Name: riscv_mtimer_current * @@ -336,6 +476,37 @@ static int riscv_mtimer_interrupt(int irq, void *context, void *arg) return 0; } +/**************************************************************************** + * Name: riscv_mtimer_tick_current + * + * Description: + * Get the current time. + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ticks The location in which to return the current time. A time of zero + * is returned for the initialization moment. + * + * Returned Value: + * Zero (OK) is returned on success, a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int riscv_mtimer_tick_current(struct oneshot_lowerhalf_s *lower, + clock_t *ticks) +{ + struct riscv_mtimer_lowerhalf_s *priv = + (struct riscv_mtimer_lowerhalf_s *)lower; + uint64_t mtime = riscv_mtimer_get_mtime(priv); + + *ticks = mtime * TICK_PER_SEC / priv->freq; + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/