arch/riscv: Fixed hardware timer warps-around issue

This commit fixed the issue where the hardware timer wraps around and causes the system to halt.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
ouyangxiangzhen
2024-09-04 18:57:33 +08:00
committed by Xiang Xiao
parent 908df725ad
commit 733a68002c
+28 -39
View File
@@ -211,28 +211,23 @@ static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower,
{ {
struct riscv_mtimer_lowerhalf_s *priv = struct riscv_mtimer_lowerhalf_s *priv =
(struct riscv_mtimer_lowerhalf_s *)lower; (struct riscv_mtimer_lowerhalf_s *)lower;
uint64_t mtime = riscv_mtimer_get_mtime(priv); irqstate_t flags;
uint64_t alarm = mtime + ts->tv_sec * priv->freq + uint64_t mtime;
ts->tv_nsec * priv->freq / NSEC_PER_SEC; uint64_t alarm;
if (alarm < mtime) flags = up_irq_save();
{
priv->alarm = UINT64_MAX;
priv->callback = NULL;
priv->arg = NULL;
}
else
{
priv->alarm = alarm;
priv->callback = callback;
priv->arg = arg;
}
if (!up_interrupt_context()) mtime = riscv_mtimer_get_mtime(priv);
{ alarm = mtime + ts->tv_sec * priv->freq +
riscv_mtimer_set_mtimecmp(priv, priv->alarm); ts->tv_nsec * priv->freq / NSEC_PER_SEC;
}
priv->alarm = alarm;
priv->callback = callback;
priv->arg = arg;
riscv_mtimer_set_mtimecmp(priv, priv->alarm);
up_irq_restore(flags);
return 0; return 0;
} }
@@ -266,31 +261,28 @@ static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower,
struct riscv_mtimer_lowerhalf_s *priv = struct riscv_mtimer_lowerhalf_s *priv =
(struct riscv_mtimer_lowerhalf_s *)lower; (struct riscv_mtimer_lowerhalf_s *)lower;
uint64_t mtime; uint64_t mtime;
uint64_t alarm = priv->alarm; uint64_t alarm;
uint64_t nsec;
irqstate_t flags;
priv->alarm = UINT64_MAX; flags = up_irq_save();
if (!up_interrupt_context())
{ alarm = priv->alarm;
riscv_mtimer_set_mtimecmp(priv, priv->alarm);
}
mtime = riscv_mtimer_get_mtime(priv); mtime = riscv_mtimer_get_mtime(priv);
if (alarm > mtime)
{ riscv_mtimer_set_mtimecmp(priv, mtime + UINT64_MAX);
uint64_t nsec = (alarm - mtime) * NSEC_PER_SEC / priv->freq;
ts->tv_sec = nsec / NSEC_PER_SEC; nsec = (alarm - mtime) * NSEC_PER_SEC / priv->freq;
ts->tv_nsec = nsec % NSEC_PER_SEC; ts->tv_sec = nsec / NSEC_PER_SEC;
} ts->tv_nsec = nsec % NSEC_PER_SEC;
else
{
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
priv->alarm = 0; priv->alarm = 0;
priv->callback = NULL; priv->callback = NULL;
priv->arg = NULL; priv->arg = NULL;
up_irq_restore(flags);
return 0; return 0;
} }
@@ -332,14 +324,11 @@ static int riscv_mtimer_interrupt(int irq, void *context, void *arg)
{ {
struct riscv_mtimer_lowerhalf_s *priv = arg; struct riscv_mtimer_lowerhalf_s *priv = arg;
priv->alarm = UINT64_MAX;
if (priv->callback != NULL) if (priv->callback != NULL)
{ {
priv->callback(&priv->lower, priv->arg); priv->callback(&priv->lower, priv->arg);
} }
riscv_mtimer_set_mtimecmp(priv, priv->alarm);
return 0; return 0;
} }