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


Reply via email to