Add the register_time_change_notifier method to the RISCVCPUTimeSrcIf interface. This method allows the time source user to register a notifier on tick counter asynchronous modification (i.e., a modification that is not due to the monotonic nature of the counter). This can happen if the time source counter is writable, which is the case of the `time' register of the ACLINT.
Use this mechanism in time_helper.c to recompute the sstc timers deadlines. Signed-off-by: Luc Michel <[email protected]> --- target/riscv/cpu-qom.h | 7 +++++++ target/riscv/cpu.h | 1 + target/riscv/time_helper.h | 11 +++++++++++ target/riscv/time_helper.c | 13 +++++++++++++ 4 files changed, 32 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index e5bc23b2ef5..29cb30d23a9 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -90,8 +90,15 @@ struct RISCVCPUTimeSrcIfClass { /** * get_tick_freq: get the tick frequency of this time source. */ uint32_t (*get_tick_freq)(RISCVCPUTimeSrcIf *); + + /* + * register_time_change_notifier: register a notifier which get notified + * when the value of the free running counter observes a discontinuity + * (e.g., the counter value gets reset to 0). + */ + void (*register_time_change_notifier)(RISCVCPUTimeSrcIf *, Notifier *); }; #endif /* RISCV_CPU_QOM_H */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 368b9e2532d..40b198d8d4a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -460,10 +460,11 @@ struct CPUArchState { int64_t last_icount; bool itrigger_enabled; /* machine specific time source interface */ RISCVCPUTimeSrcIf *time_src; + Notifier time_change_notifier; /* machine specific AIA ireg read-modify-write callback */ #define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \ ((((__xlen) & 0xff) << 24) | \ (((__vgein) & 0x3f) << 20) | \ diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h index b51fdd96570..074b516f4ad 100644 --- a/target/riscv/time_helper.h +++ b/target/riscv/time_helper.h @@ -42,6 +42,17 @@ static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src) g_assert(rctsc->get_tick_freq != NULL); return rctsc->get_tick_freq(src); } +static inline void +riscv_cpu_time_src_register_time_change_notifier(RISCVCPUTimeSrcIf *src, + Notifier *notifier) +{ + RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src); + + if (rctsc->register_time_change_notifier) { + rctsc->register_time_change_notifier(src, notifier); + } +} + #endif diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index 7b493b7a233..b1d7bba1afe 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -181,10 +181,19 @@ void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable) riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP); } } } +static void time_src_ticks_change_cb(Notifier *notifier, void *opaque) +{ + CPURISCVState *env = container_of(notifier, CPURISCVState, time_change_notifier); + + riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP); + riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); +} + void riscv_timer_init(RISCVCPU *cpu) { CPURISCVState *env; if (!cpu) { @@ -200,10 +209,14 @@ void riscv_timer_init(RISCVCPU *cpu) } void riscv_cpu_set_time_src(CPURISCVState *env, RISCVCPUTimeSrcIf *src) { env->time_src = src; + env->time_change_notifier.notify = time_src_ticks_change_cb; + + riscv_cpu_time_src_register_time_change_notifier(src, + &env->time_change_notifier); } static const TypeInfo riscv_cpu_time_src_if_info = { .name = TYPE_RISCV_CPU_TIME_SRC_IF, .parent = TYPE_INTERFACE, -- 2.51.0
