* [PATCH v2 0/4] Timer events for OpenSBI
@ 2026-04-25 10:40 Anup Patel
2026-04-25 10:40 ` [PATCH v2 1/4] include: sbi: Add sbi_scratch_hartindex() macro Anup Patel
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Anup Patel @ 2026-04-25 10:40 UTC (permalink / raw)
To: Atish Patra; +Cc: Andrew Jones, Samuel Holland, Anup Patel, opensbi, Anup Patel
This series extends the sbi_timer framework to support
timer events usable from any part of OpenSBI. The platform
drivers in OpenSBI can use timer events for timeouts or
periodic checks.
These patches can also be found in sbi_timer_imp_v2 branch
at: https://github.com/avpatel/opensbi.git
Changes since v1:
- New PATCH4 adding sbi_timer_compute_delta() and friends
- Fix typo on cleanup() comments of struct sbi_timer_event
- Remove the spin_unlock()/lock() dance from sbi_timer_event_start()
and sbi_timer_exit()
- Update timer device in sbi_timer_event_stop() only when
required (i.e. ev->hart_index != current_hartindex())
- Break the loop in sbi_timer_process() when
ev->time_stamp > sbi_timer_value())
- Allow callback() function in struct sbi_timer_event to
optionally provide event re-start details
Anup Patel (4):
include: sbi: Add sbi_scratch_hartindex() macro
lib: sbi_timer: Introduce per-HART timer state
lib: sbi_timer: Add support for timer events
lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends
include/sbi/sbi_scratch.h | 6 +-
include/sbi/sbi_timer.h | 92 ++++++++++++-
lib/sbi/sbi_ecall_legacy.c | 4 +-
lib/sbi/sbi_ecall_time.c | 4 +-
lib/sbi/sbi_timer.c | 256 +++++++++++++++++++++++++++++++------
5 files changed, 314 insertions(+), 48 deletions(-)
--
2.43.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/4] include: sbi: Add sbi_scratch_hartindex() macro
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
@ 2026-04-25 10:40 ` Anup Patel
2026-04-25 10:40 ` [PATCH v2 2/4] lib: sbi_timer: Introduce per-HART timer state Anup Patel
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Anup Patel @ 2026-04-25 10:40 UTC (permalink / raw)
To: Atish Patra
Cc: Andrew Jones, Samuel Holland, Anup Patel, opensbi, Anup Patel,
Nicholas Piggin
Add helper macro to extract hart index from scratch pointer. This
can be used to check whether scratch pointer belongs to a particular
hart or not.
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
include/sbi/sbi_scratch.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h
index 58d54628..c12aa796 100644
--- a/include/sbi/sbi_scratch.h
+++ b/include/sbi/sbi_scratch.h
@@ -166,9 +166,11 @@ do { \
= (__type)(__ptr); \
} while (0)
+/** Get the hart index of a particular sbi_scratch */
+#define sbi_scratch_hartindex(__scratch) ((__scratch)->hartindex)
+
/** Get the hart index of the current hart */
-#define current_hartindex() \
- (sbi_scratch_thishart_ptr()->hartindex)
+#define current_hartindex() sbi_scratch_hartindex(sbi_scratch_thishart_ptr())
/** Number of harts managed by this OpenSBI instance */
extern u32 sbi_scratch_hart_count;
--
2.43.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/4] lib: sbi_timer: Introduce per-HART timer state
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
2026-04-25 10:40 ` [PATCH v2 1/4] include: sbi: Add sbi_scratch_hartindex() macro Anup Patel
@ 2026-04-25 10:40 ` Anup Patel
2026-04-25 10:40 ` [PATCH v2 3/4] lib: sbi_timer: Add support for timer events Anup Patel
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Anup Patel @ 2026-04-25 10:40 UTC (permalink / raw)
To: Atish Patra
Cc: Andrew Jones, Samuel Holland, Anup Patel, opensbi, Anup Patel,
Nicholas Piggin
Currently, only time_delta is per-HART so introduce per-HART timer
state for having more per-HART timer information.
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
---
lib/sbi/sbi_timer.c | 44 +++++++++++++++++++++++++-------------------
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 4088a597..9806c033 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -18,7 +18,11 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
-static unsigned long time_delta_off;
+struct timer_state {
+ u64 time_delta;
+};
+
+static unsigned long timer_state_off;
static u64 (*get_time_val)(void);
static const struct sbi_timer_device *timer_dev = NULL;
@@ -98,35 +102,37 @@ u64 sbi_timer_value(void)
u64 sbi_timer_virt_value(void)
{
- u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
- time_delta_off);
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
- return sbi_timer_value() + *time_delta;
+ return sbi_timer_value() + tstate->time_delta;
}
u64 sbi_timer_get_delta(void)
{
- u64 *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
- time_delta_off);
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
- return *time_delta;
+ return tstate->time_delta;
}
void sbi_timer_set_delta(ulong delta)
{
- ulong *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
- time_delta_off);
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
- *time_delta = delta;
+#if __riscv_xlen == 32
+ tstate->time_delta &= ~0xffffffffUL;
+ tstate->time_delta |= (u32)delta;
+#else
+ tstate->time_delta = delta;
+#endif
}
#if __riscv_xlen == 32
void sbi_timer_set_delta_upper(ulong delta_upper)
{
- ulong *time_delta = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
- time_delta_off);
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
- *(time_delta + 1) = delta_upper;
+ tstate->time_delta &= 0xffffffffUL;
+ tstate->time_delta |= (u64)delta << 32;
}
#endif
@@ -176,13 +182,13 @@ void sbi_timer_set_device(const struct sbi_timer_device *dev)
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
- u64 *time_delta;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
+ struct timer_state *tstate;
int ret;
if (cold_boot) {
- time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta));
- if (!time_delta_off)
+ timer_state_off = sbi_scratch_alloc_offset(sizeof(*tstate));
+ if (!timer_state_off)
return SBI_ENOMEM;
if (sbi_hart_has_csr(scratch, SBI_HART_CSR_TIME))
@@ -192,12 +198,12 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
if (ret)
return ret;
} else {
- if (!time_delta_off)
+ if (!timer_state_off)
return SBI_ENOMEM;
}
- time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
- *time_delta = 0;
+ tstate = sbi_scratch_offset_ptr(scratch, timer_state_off);
+ tstate->time_delta = 0;
if (timer_dev && timer_dev->warm_init) {
ret = timer_dev->warm_init();
--
2.43.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/4] lib: sbi_timer: Add support for timer events
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
2026-04-25 10:40 ` [PATCH v2 1/4] include: sbi: Add sbi_scratch_hartindex() macro Anup Patel
2026-04-25 10:40 ` [PATCH v2 2/4] lib: sbi_timer: Introduce per-HART timer state Anup Patel
@ 2026-04-25 10:40 ` Anup Patel
2026-04-29 8:18 ` Nicholas Piggin
2026-04-25 10:40 ` [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends Anup Patel
2026-05-09 7:46 ` [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
4 siblings, 1 reply; 8+ messages in thread
From: Anup Patel @ 2026-04-25 10:40 UTC (permalink / raw)
To: Atish Patra; +Cc: Andrew Jones, Samuel Holland, Anup Patel, opensbi, Anup Patel
Currently, the sbi_timer only supports timer events configured via
SBI calls. Introduce struct sbi_timer_event and related functions
to allow configuring timer events from any part of OpenSBI.
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
include/sbi/sbi_timer.h | 65 +++++++++++-
lib/sbi/sbi_ecall_legacy.c | 4 +-
lib/sbi/sbi_ecall_time.c | 4 +-
lib/sbi/sbi_timer.c | 198 ++++++++++++++++++++++++++++++++++---
4 files changed, 248 insertions(+), 23 deletions(-)
diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
index 2e1a7879..914a5f12 100644
--- a/include/sbi/sbi_timer.h
+++ b/include/sbi/sbi_timer.h
@@ -10,7 +10,60 @@
#ifndef __SBI_TIMER_H__
#define __SBI_TIMER_H__
-#include <sbi/sbi_types.h>
+#include <sbi/sbi_list.h>
+
+/** Timer event re-start details */
+struct sbi_timer_event_restart {
+ /** Flag indicating whether event re-start is required */
+ bool required;
+ /** Next time stamp for event if re-start is required */
+ u64 next_event;
+};
+
+/** Timer event abstraction */
+struct sbi_timer_event {
+ /** List head for per-HART event list (Internal) */
+ struct sbi_dlist head;
+
+ /** Hart on which the event is started / running (Internal) */
+ int hart_index;
+
+ /** Time stamp when the event expires (Internal) */
+ u64 time_stamp;
+
+ /**
+ * Event callback to be called upon expiry.
+ *
+ * If the callback wants to re-start the event then
+ * it must update the event re-start details.
+ *
+ * NOTE: This will be called with the per-HART timer
+ * event list lock held.
+ */
+ void (*callback)(struct sbi_timer_event *ev,
+ struct sbi_timer_event_restart *restart);
+
+ /**
+ * Event cleanup to be called upon sbi_timer_exit()
+ *
+ * NOTE: This will be called with per-HART timer
+ * event list lock held.
+ */
+ void (*cleanup)(struct sbi_timer_event *ev);
+
+ /** Event specific private data */
+ void *priv;
+};
+
+#define SBI_INIT_TIMER_EVENT(__ptr, __callback, __cleanup, __priv) \
+do { \
+ SBI_INIT_LIST_HEAD(&(__ptr)->head); \
+ (__ptr)->hart_index = -1; \
+ (__ptr)->time_stamp = 0; \
+ (__ptr)->callback = (__callback); \
+ (__ptr)->cleanup = (__cleanup); \
+ (__ptr)->priv = (__priv); \
+} while (0)
/** Timer hardware device */
struct sbi_timer_device {
@@ -86,8 +139,14 @@ void sbi_timer_set_delta(ulong delta);
void sbi_timer_set_delta_upper(ulong delta_upper);
#endif
-/** Start timer event for current HART */
-void sbi_timer_event_start(u64 next_event);
+/** Start timer event on current HART */
+void sbi_timer_event_start(struct sbi_timer_event *ev, u64 next_event);
+
+/** Stop timer event on current HART */
+void sbi_timer_event_stop(struct sbi_timer_event *ev);
+
+/** Start supervisor timer event on current HART */
+void sbi_timer_smode_event_start(u64 next_event);
/** Process timer event for current HART */
void sbi_timer_process(void);
diff --git a/lib/sbi/sbi_ecall_legacy.c b/lib/sbi/sbi_ecall_legacy.c
index 50a7660d..4501c4ad 100644
--- a/lib/sbi/sbi_ecall_legacy.c
+++ b/lib/sbi/sbi_ecall_legacy.c
@@ -54,9 +54,9 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
- sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
+ sbi_timer_smode_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
- sbi_timer_event_start((u64)regs->a0);
+ sbi_timer_smode_event_start((u64)regs->a0);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
diff --git a/lib/sbi/sbi_ecall_time.c b/lib/sbi/sbi_ecall_time.c
index 6ea6f054..a0aa580d 100644
--- a/lib/sbi/sbi_ecall_time.c
+++ b/lib/sbi/sbi_ecall_time.c
@@ -22,9 +22,9 @@ static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
if (funcid == SBI_EXT_TIME_SET_TIMER) {
#if __riscv_xlen == 32
- sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
+ sbi_timer_smode_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
#else
- sbi_timer_event_start((u64)regs->a0);
+ sbi_timer_smode_event_start((u64)regs->a0);
#endif
} else
ret = SBI_ENOTSUPP;
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 9806c033..4b16dbb2 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -10,9 +10,11 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
+#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -20,6 +22,9 @@
struct timer_state {
u64 time_delta;
+ spinlock_t event_list_lock;
+ struct sbi_dlist event_list;
+ struct sbi_timer_event smode_ev;
};
static unsigned long timer_state_off;
@@ -136,8 +141,130 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
}
#endif
-void sbi_timer_event_start(u64 next_event)
+static void __sbi_timer_update_device(struct timer_state *tstate)
{
+ struct sbi_timer_event *ev;
+
+ if (!timer_dev)
+ return;
+
+ if (sbi_list_empty(&tstate->event_list)) {
+ if (timer_dev->timer_event_stop)
+ timer_dev->timer_event_stop();
+ csr_clear(CSR_MIE, MIP_MTIP);
+ } else {
+ ev = sbi_list_first_entry(&tstate->event_list, struct sbi_timer_event, head);
+ if (timer_dev->timer_event_start)
+ timer_dev->timer_event_start(ev->time_stamp);
+ csr_set(CSR_MIE, MIP_MTIP);
+ }
+}
+
+static void __sbi_timer_event_stop(struct sbi_timer_event *ev)
+{
+ if (ev->hart_index > -1) {
+ sbi_list_del(&ev->head);
+ ev->hart_index = -1;
+ }
+}
+
+static void __sbi_timer_event_start(struct timer_state *tstate,
+ struct sbi_timer_event *ev, u64 next_event)
+{
+ struct sbi_timer_event *tev, *next_ev = NULL;
+
+ /* Find where to insert the event in per-HART event list */
+ sbi_list_for_each_entry(tev, &tstate->event_list, head) {
+ if (next_event < tev->time_stamp) {
+ next_ev = tev;
+ break;
+ }
+ }
+
+ /* Insert the event in per-HART event list */
+ ev->hart_index = current_hartindex();
+ ev->time_stamp = next_event;
+ if (next_ev)
+ sbi_list_add(&ev->head, &next_ev->head);
+ else
+ sbi_list_add_tail(&ev->head, &tstate->event_list);
+}
+
+void sbi_timer_event_start(struct sbi_timer_event *ev, u64 next_event)
+{
+ struct timer_state *tstate;
+
+ if (!ev)
+ return;
+
+ /* Ensure that event is not on the per-HART event list */
+ if (ev->hart_index > -1) {
+ tstate = sbi_scratch_offset_ptr(sbi_hartindex_to_scratch(ev->hart_index),
+ timer_state_off);
+ spin_lock(&tstate->event_list_lock);
+ __sbi_timer_event_stop(ev);
+ spin_unlock(&tstate->event_list_lock);
+ }
+
+ tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
+ spin_lock(&tstate->event_list_lock);
+
+ __sbi_timer_event_start(tstate, ev, next_event);
+ __sbi_timer_update_device(tstate);
+
+ spin_unlock(&tstate->event_list_lock);
+}
+
+void sbi_timer_event_stop(struct sbi_timer_event *ev)
+{
+ struct timer_state *tstate;
+ int ev_hart_index;
+
+ if (!ev)
+ return;
+
+ /* Ensure that event is not on the per-HART event list */
+ ev_hart_index = ev->hart_index;
+ if (ev->hart_index > -1) {
+ tstate = sbi_scratch_offset_ptr(sbi_hartindex_to_scratch(ev->hart_index),
+ timer_state_off);
+ spin_lock(&tstate->event_list_lock);
+ __sbi_timer_event_stop(ev);
+ spin_unlock(&tstate->event_list_lock);
+ }
+
+ /* Re-program timer device on the current HART */
+ if (ev_hart_index == current_hartindex()) {
+ tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
+ spin_lock(&tstate->event_list_lock);
+ __sbi_timer_update_device(tstate);
+ spin_unlock(&tstate->event_list_lock);
+ }
+}
+
+static void sbi_timer_smode_event_callback(struct sbi_timer_event *ev,
+ struct sbi_timer_event_restart *restart)
+{
+ /*
+ * If sstc extension is available, supervisor can receive the timer
+ * directly without M-mode come in between. This function should
+ * only invoked if M-mode programs the timer for its own purpose.
+ */
+ if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
+ csr_set(CSR_MIP, MIP_STIP);
+}
+
+static void sbi_timer_smode_event_cleanup(struct sbi_timer_event *ev)
+{
+ if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
+ csr_clear(CSR_MIP, MIP_STIP);
+}
+
+void sbi_timer_smode_event_start(u64 next_event)
+{
+ struct timer_state *tstate = sbi_scratch_offset_ptr(sbi_scratch_thishart_ptr(),
+ timer_state_off);
+
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
/**
@@ -146,23 +273,47 @@ void sbi_timer_event_start(u64 next_event)
*/
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
csr_write64(CSR_STIMECMP, next_event);
- } else if (timer_dev && timer_dev->timer_event_start) {
- timer_dev->timer_event_start(next_event);
+ } else {
csr_clear(CSR_MIP, MIP_STIP);
+ sbi_timer_event_start(&tstate->smode_ev, next_event);
}
- csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
- csr_clear(CSR_MIE, MIP_MTIP);
- /*
- * If sstc extension is available, supervisor can receive the timer
- * directly without M-mode come in between. This function should
- * only invoked if M-mode programs the timer for its own purpose.
- */
- if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
- csr_set(CSR_MIP, MIP_STIP);
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
+ struct sbi_timer_event_restart restart;
+ SBI_LIST_HEAD(restart_list);
+ struct sbi_timer_event *ev;
+
+ spin_lock(&tstate->event_list_lock);
+
+ while (!sbi_list_empty(&tstate->event_list)) {
+ ev = sbi_list_first_entry(&tstate->event_list, struct sbi_timer_event, head);
+ if (ev->time_stamp > sbi_timer_value())
+ break;
+
+ __sbi_timer_event_stop(ev);
+ if (ev->callback) {
+ restart.required = false;
+ restart.next_event = 0;
+ ev->callback(ev, &restart);
+ if (restart.required) {
+ ev->time_stamp = restart.next_event;
+ sbi_list_add_tail(&ev->head, &restart_list);
+ }
+ }
+ }
+
+ while (!sbi_list_empty(&restart_list)) {
+ ev = sbi_list_first_entry(&tstate->event_list, struct sbi_timer_event, head);
+ sbi_list_del(&ev->head);
+ __sbi_timer_event_start(tstate, ev, ev->time_stamp);
+ }
+
+ __sbi_timer_update_device(tstate);
+
+ spin_unlock(&tstate->event_list_lock);
}
const struct sbi_timer_device *sbi_timer_get_device(void)
@@ -204,6 +355,11 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
tstate = sbi_scratch_offset_ptr(scratch, timer_state_off);
tstate->time_delta = 0;
+ SPIN_LOCK_INIT(tstate->event_list_lock);
+ SBI_INIT_LIST_HEAD(&tstate->event_list);
+ SBI_INIT_TIMER_EVENT(&tstate->smode_ev,
+ sbi_timer_smode_event_callback,
+ sbi_timer_smode_event_cleanup, NULL);
if (timer_dev && timer_dev->warm_init) {
ret = timer_dev->warm_init();
@@ -216,9 +372,19 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
void sbi_timer_exit(struct sbi_scratch *scratch)
{
- if (timer_dev && timer_dev->timer_event_stop)
- timer_dev->timer_event_stop();
+ struct timer_state *tstate = sbi_scratch_thishart_offset_ptr(timer_state_off);
+ struct sbi_timer_event *ev;
+
+ spin_lock(&tstate->event_list_lock);
+
+ while (!sbi_list_empty(&tstate->event_list)) {
+ ev = sbi_list_first_entry(&tstate->event_list, struct sbi_timer_event, head);
+ __sbi_timer_event_stop(ev);
+ if (ev->cleanup)
+ ev->cleanup(ev);
+ }
+
+ __sbi_timer_update_device(tstate);
- csr_clear(CSR_MIP, MIP_STIP);
- csr_clear(CSR_MIE, MIP_MTIP);
+ spin_unlock(&tstate->event_list_lock);
}
--
2.43.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
` (2 preceding siblings ...)
2026-04-25 10:40 ` [PATCH v2 3/4] lib: sbi_timer: Add support for timer events Anup Patel
@ 2026-04-25 10:40 ` Anup Patel
2026-04-29 8:20 ` Nicholas Piggin
2026-05-09 7:46 ` [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
4 siblings, 1 reply; 8+ messages in thread
From: Anup Patel @ 2026-04-25 10:40 UTC (permalink / raw)
To: Atish Patra; +Cc: Andrew Jones, Samuel Holland, Anup Patel, opensbi, Anup Patel
The users of timer event have to compute next_event (aka timer value
in the future) based on desired units and unit frequency. Introduce
sbi_timer_compute_delta() and friends to simplify computing next_event
for timer event users.
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
include/sbi/sbi_timer.h | 27 +++++++++++++++++++++++++++
lib/sbi/sbi_timer.c | 14 ++++++++++----
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/include/sbi/sbi_timer.h b/include/sbi/sbi_timer.h
index 914a5f12..2a040927 100644
--- a/include/sbi/sbi_timer.h
+++ b/include/sbi/sbi_timer.h
@@ -88,6 +88,21 @@ struct sbi_timer_device {
struct sbi_scratch;
+/** Compute timer value delta based on arbitary units */
+u64 sbi_timer_compute_delta(ulong units, u64 unit_freq);
+
+/** Compute timer value delta from milliseconds */
+static inline u64 sbi_timer_compute_mdelta(ulong msecs)
+{
+ return sbi_timer_compute_delta(msecs, 1000);
+}
+
+/** Compute timer value delta from microseconds */
+static inline u64 sbi_timer_compute_udelta(ulong usecs)
+{
+ return sbi_timer_compute_delta(usecs, 1000000);
+}
+
/** Generic delay loop of desired granularity */
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
void (*delay_fn)(void *), void *opaque);
@@ -125,6 +140,18 @@ bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
/** Get timer value for current HART */
u64 sbi_timer_value(void);
+/** Compute timer value after specified milliseconds */
+static inline u64 sbi_timer_value_after_msecs(ulong msecs)
+{
+ return sbi_timer_value() + sbi_timer_compute_mdelta(msecs);
+}
+
+/** Compute timer value after specified microseconds */
+static inline u64 sbi_timer_value_after_usecs(ulong usecs)
+{
+ return sbi_timer_value() + sbi_timer_compute_udelta(usecs);
+}
+
/** Get virtualized timer value for current HART */
u64 sbi_timer_virt_value(void);
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index 4b16dbb2..ec25e5ce 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -58,6 +58,15 @@ static void nop_delay_fn(void *opaque)
cpu_relax();
}
+u64 sbi_timer_compute_delta(ulong units, u64 unit_freq)
+{
+ u64 delta;
+
+ delta = ((u64)timer_dev->timer_freq * (u64)units);
+ delta = delta / unit_freq;
+ return delta;
+}
+
void sbi_timer_delay_loop(ulong units, u64 unit_freq,
void (*delay_fn)(void *), void *opaque)
{
@@ -72,15 +81,12 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
/* Save starting timer value */
start_val = get_time_val();
- /* Compute desired timer value delta */
- delta = ((u64)timer_dev->timer_freq * (u64)units);
- delta = delta / unit_freq;
-
/* Use NOP delay function if delay function not available */
if (!delay_fn)
delay_fn = nop_delay_fn;
/* Busy loop until desired timer value delta reached */
+ delta = sbi_timer_compute_delta(units, unit_freq);
while ((get_time_val() - start_val) < delta)
delay_fn(opaque);
}
--
2.43.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 3/4] lib: sbi_timer: Add support for timer events
2026-04-25 10:40 ` [PATCH v2 3/4] lib: sbi_timer: Add support for timer events Anup Patel
@ 2026-04-29 8:18 ` Nicholas Piggin
0 siblings, 0 replies; 8+ messages in thread
From: Nicholas Piggin @ 2026-04-29 8:18 UTC (permalink / raw)
To: Anup Patel; +Cc: Atish Patra, Andrew Jones, Samuel Holland, Anup Patel, opensbi
On Sat, Apr 25, 2026 at 04:10:47PM +0530, Anup Patel wrote:
> Currently, the sbi_timer only supports timer events configured via
> SBI calls. Introduce struct sbi_timer_event and related functions
> to allow configuring timer events from any part of OpenSBI.
>
> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends
2026-04-25 10:40 ` [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends Anup Patel
@ 2026-04-29 8:20 ` Nicholas Piggin
0 siblings, 0 replies; 8+ messages in thread
From: Nicholas Piggin @ 2026-04-29 8:20 UTC (permalink / raw)
To: Anup Patel; +Cc: Atish Patra, Andrew Jones, Samuel Holland, Anup Patel, opensbi
On Sat, Apr 25, 2026 at 04:10:48PM +0530, Anup Patel wrote:
> The users of timer event have to compute next_event (aka timer value
> in the future) based on desired units and unit frequency. Introduce
> sbi_timer_compute_delta() and friends to simplify computing next_event
> for timer event users.
>
> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/4] Timer events for OpenSBI
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
` (3 preceding siblings ...)
2026-04-25 10:40 ` [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends Anup Patel
@ 2026-05-09 7:46 ` Anup Patel
4 siblings, 0 replies; 8+ messages in thread
From: Anup Patel @ 2026-05-09 7:46 UTC (permalink / raw)
To: Anup Patel; +Cc: Atish Patra, Andrew Jones, Samuel Holland, opensbi
On Sat, Apr 25, 2026 at 4:10 PM Anup Patel <anup.patel@oss.qualcomm.com> wrote:
>
> This series extends the sbi_timer framework to support
> timer events usable from any part of OpenSBI. The platform
> drivers in OpenSBI can use timer events for timeouts or
> periodic checks.
>
> These patches can also be found in sbi_timer_imp_v2 branch
> at: https://github.com/avpatel/opensbi.git
>
> Changes since v1:
> - New PATCH4 adding sbi_timer_compute_delta() and friends
> - Fix typo on cleanup() comments of struct sbi_timer_event
> - Remove the spin_unlock()/lock() dance from sbi_timer_event_start()
> and sbi_timer_exit()
> - Update timer device in sbi_timer_event_stop() only when
> required (i.e. ev->hart_index != current_hartindex())
> - Break the loop in sbi_timer_process() when
> ev->time_stamp > sbi_timer_value())
> - Allow callback() function in struct sbi_timer_event to
> optionally provide event re-start details
>
> Anup Patel (4):
> include: sbi: Add sbi_scratch_hartindex() macro
> lib: sbi_timer: Introduce per-HART timer state
> lib: sbi_timer: Add support for timer events
> lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends
>
> include/sbi/sbi_scratch.h | 6 +-
> include/sbi/sbi_timer.h | 92 ++++++++++++-
> lib/sbi/sbi_ecall_legacy.c | 4 +-
> lib/sbi/sbi_ecall_time.c | 4 +-
> lib/sbi/sbi_timer.c | 256 +++++++++++++++++++++++++++++++------
> 5 files changed, 314 insertions(+), 48 deletions(-)
>
> --
> 2.43.0
>
Applied this series to the riscv/opensbi repo.
Thanks,
Anup
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-05-09 7:47 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-25 10:40 [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
2026-04-25 10:40 ` [PATCH v2 1/4] include: sbi: Add sbi_scratch_hartindex() macro Anup Patel
2026-04-25 10:40 ` [PATCH v2 2/4] lib: sbi_timer: Introduce per-HART timer state Anup Patel
2026-04-25 10:40 ` [PATCH v2 3/4] lib: sbi_timer: Add support for timer events Anup Patel
2026-04-29 8:18 ` Nicholas Piggin
2026-04-25 10:40 ` [PATCH v2 4/4] lib: sbi_timer: Introduce sbi_timer_compute_delta() and friends Anup Patel
2026-04-29 8:20 ` Nicholas Piggin
2026-05-09 7:46 ` [PATCH v2 0/4] Timer events for OpenSBI Anup Patel
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.