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 <jukka.laitinen@tii.ae>
This commit is contained in:
parent
2e57ed24a7
commit
e398e4a4ff
1 changed files with 175 additions and 4 deletions
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue