[PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier

Luc Michel posted 9 patches 3 months ago
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
[PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
Posted by Luc Michel 3 months ago
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 <luc.michel@amd.com>
---
 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
Re: [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
Posted by Philippe Mathieu-Daudé 2 months, 2 weeks ago
On 7/11/25 11:23, Luc Michel wrote:
> 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 <luc.michel@amd.com>
> ---
>   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/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);
> +    }

What about some trace event to help developers? I.e.:

    if (!rctsc->register_time_change_notifier) {
        trace_riscv_cpu_time_src_register_time_change_without_notifier();
        return;
    }
    rctsc->register_time_change_notifier(src, notifier);

> +}

Anyhow:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>


Re: [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
Posted by Luc Michel 2 months, 2 weeks ago
Hi Phil,

On 18:20 Thu 20 Nov     , Philippe Mathieu-Daudé wrote:
> On 7/11/25 11:23, Luc Michel wrote:
> > 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 <luc.michel@amd.com>
> > ---
> >   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/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);
> > +    }
> 
> What about some trace event to help developers? I.e.:

I made this method optional in case the time source is read-only. In
this case there is no need for a notifier as it cannot change
asynchronously.

-- 
Luc

> 
>    if (!rctsc->register_time_change_notifier) {
>        trace_riscv_cpu_time_src_register_time_change_without_notifier();
>        return;
>    }
>    rctsc->register_time_change_notifier(src, notifier);
> 
> > +}
> 
> Anyhow:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> 

--