Skip to content

Commit

Permalink
arch/risc-v/src/common/riscv_mtimer.c: Add risc-v tick timer operations
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jlaitine committed Mar 7, 2025
1 parent e15f7b1 commit 695a987
Showing 1 changed file with 175 additions and 4 deletions.
179 changes: 175 additions & 4 deletions arch/risc-v/src/common/riscv_mtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

/****************************************************************************
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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, mtime + 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
*
Expand Down Expand Up @@ -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
****************************************************************************/
Expand Down

0 comments on commit 695a987

Please sign in to comment.