On Thu, Dec 5, 2024 at 11:35 PM Daniel Henrique Barboza <dbarb...@ventanamicro.com> wrote: > > From: Tomasz Jeznach <tjezn...@rivosinc.com> > > The next HPM related changes requires the HPM overflow timer to be > initialized by the riscv-iommu base emulation. > > Signed-off-by: Tomasz Jeznach <tjezn...@rivosinc.com> > Signed-off-by: Daniel Henrique Barboza <dbarb...@ventanamicro.com>
Acked-by: Alistair Francis <alistair.fran...@wdc.com> Alistair > --- > hw/riscv/riscv-iommu-hpm.c | 36 ++++++++++++++++++++++++++++++++++++ > hw/riscv/riscv-iommu-hpm.h | 1 + > hw/riscv/riscv-iommu.c | 3 +++ > hw/riscv/riscv-iommu.h | 2 ++ > 4 files changed, 42 insertions(+) > > diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c > index 8eca5ee17e..325088333e 100644 > --- a/hw/riscv/riscv-iommu-hpm.c > +++ b/hw/riscv/riscv-iommu-hpm.c > @@ -166,3 +166,39 @@ void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, > RISCVIOMMUContext *ctx, > hpm_incr_ctr(s, ctr_idx); > } > } > + > +/* Timer callback for cycle counter overflow. */ > +void riscv_iommu_hpm_timer_cb(void *priv) > +{ > + RISCVIOMMUState *s = priv; > + const uint32_t inhibit = riscv_iommu_reg_get32( > + s, RISCV_IOMMU_REG_IOCOUNTINH); > + uint32_t ovf; > + > + if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) { > + return; > + } > + > + if (s->irq_overflow_left > 0) { > + uint64_t irq_trigger_at = > + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->irq_overflow_left; > + timer_mod_anticipate_ns(s->hpm_timer, irq_trigger_at); > + s->irq_overflow_left = 0; > + return; > + } > + > + ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF); > + if (!get_field(ovf, RISCV_IOMMU_IOCOUNTOVF_CY)) { > + /* > + * We don't need to set hpmcycle_val to zero and update > hpmcycle_prev to > + * current clock value. The way we calculate iohpmcycs will overflow > + * and return the correct value. This avoids the need to synchronize > + * timer callback and write callback. > + */ > + riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF, > + RISCV_IOMMU_IOCOUNTOVF_CY, 0); > + riscv_iommu_reg_mod64(s, RISCV_IOMMU_REG_IOHPMCYCLES, > + RISCV_IOMMU_IOHPMCYCLES_OVF, 0); > + riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM); > + } > +} > diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h > index 411d869dce..cd896d3b7c 100644 > --- a/hw/riscv/riscv-iommu-hpm.h > +++ b/hw/riscv/riscv-iommu-hpm.h > @@ -25,5 +25,6 @@ > uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s); > void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, > unsigned event_id); > +void riscv_iommu_hpm_timer_cb(void *priv); > > #endif > diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c > index 5ce0d24359..2ec388ff3d 100644 > --- a/hw/riscv/riscv-iommu.c > +++ b/hw/riscv/riscv-iommu.c > @@ -2281,6 +2281,8 @@ static void riscv_iommu_realize(DeviceState *dev, Error > **errp) > address_space_init(&s->trap_as, &s->trap_mr, "riscv-iommu-trap-as"); > > if (s->cap & RISCV_IOMMU_CAP_HPM) { > + s->hpm_timer = > + timer_new_ns(QEMU_CLOCK_VIRTUAL, riscv_iommu_hpm_timer_cb, s); > s->hpm_event_ctr_map = g_hash_table_new(g_direct_hash, > g_direct_equal); > } > } > @@ -2294,6 +2296,7 @@ static void riscv_iommu_unrealize(DeviceState *dev) > > if (s->cap & RISCV_IOMMU_CAP_HPM) { > g_hash_table_unref(s->hpm_event_ctr_map); > + timer_free(s->hpm_timer); > } > } > > diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h > index a21ab51491..6ddc59f474 100644 > --- a/hw/riscv/riscv-iommu.h > +++ b/hw/riscv/riscv-iommu.h > @@ -88,8 +88,10 @@ struct RISCVIOMMUState { > QLIST_HEAD(, RISCVIOMMUSpace) spaces; > > /* HPM cycle counter */ > + QEMUTimer *hpm_timer; > uint64_t hpmcycle_val; /* Current value of cycle register */ > uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */ > + uint64_t irq_overflow_left; /* Value beyond INT64_MAX after overflow */ > > /* HPM event counters */ > GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */ > -- > 2.47.1 > >