On Thu, Dec 5, 2024 at 11:34 PM Daniel Henrique Barboza <dbarb...@ventanamicro.com> wrote: > > From: Tomasz Jeznach <tjezn...@rivosinc.com> > > To support hpm events mmio writes, done via > riscv_iommu_process_hpmevt_write(), we're also adding the 'hpm-counters' > IOMMU property that are used to determine the amount of counters > available in the IOMMU. > > Note that everything we did so far didn't change any IOMMU behavior > because we're still not advertising HPM capability to software. This > will be done in the next patch. > > 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 | 88 ++++++++++++++++++++++++++++++++++++++ > hw/riscv/riscv-iommu-hpm.h | 1 + > hw/riscv/riscv-iommu.c | 4 +- > hw/riscv/riscv-iommu.h | 1 + > 4 files changed, 93 insertions(+), 1 deletion(-) > > diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c > index 1cea6b1df1..5518c287a5 100644 > --- a/hw/riscv/riscv-iommu-hpm.c > +++ b/hw/riscv/riscv-iommu-hpm.c > @@ -281,3 +281,91 @@ void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState > *s) > s->hpmcycle_prev = get_cycles(); > hpm_setup_timer(s, s->hpmcycle_val); > } > + > +static inline bool check_valid_event_id(unsigned event_id) > +{ > + return event_id > RISCV_IOMMU_HPMEVENT_INVALID && > + event_id < RISCV_IOMMU_HPMEVENT_MAX; > +} > + > +static gboolean hpm_event_equal(gpointer key, gpointer value, gpointer udata) > +{ > + uint32_t *pair = udata; > + > + if (GPOINTER_TO_UINT(value) & (1 << pair[0])) { > + pair[1] = GPOINTER_TO_UINT(key); > + return true; > + } > + > + return false; > +} > + > +/* Caller must check ctr_idx against hpm_ctrs to see if its supported or > not. */ > +static void update_event_map(RISCVIOMMUState *s, uint64_t value, > + uint32_t ctr_idx) > +{ > + unsigned event_id = get_field(value, RISCV_IOMMU_IOHPMEVT_EVENT_ID); > + uint32_t pair[2] = { ctr_idx, RISCV_IOMMU_HPMEVENT_INVALID }; > + uint32_t new_value = 1 << ctr_idx; > + gpointer data; > + > + /* > + * If EventID field is RISCV_IOMMU_HPMEVENT_INVALID > + * remove the current mapping. > + */ > + if (event_id == RISCV_IOMMU_HPMEVENT_INVALID) { > + data = g_hash_table_find(s->hpm_event_ctr_map, hpm_event_equal, > pair); > + > + new_value = GPOINTER_TO_UINT(data) & ~(new_value); > + if (new_value != 0) { > + g_hash_table_replace(s->hpm_event_ctr_map, > + GUINT_TO_POINTER(pair[1]), > + GUINT_TO_POINTER(new_value)); > + } else { > + g_hash_table_remove(s->hpm_event_ctr_map, > + GUINT_TO_POINTER(pair[1])); > + } > + > + return; > + } > + > + /* Update the counter mask if the event is already enabled. */ > + if (g_hash_table_lookup_extended(s->hpm_event_ctr_map, > + GUINT_TO_POINTER(event_id), > + NULL, > + &data)) { > + new_value |= GPOINTER_TO_UINT(data); > + } > + > + g_hash_table_insert(s->hpm_event_ctr_map, > + GUINT_TO_POINTER(event_id), > + GUINT_TO_POINTER(new_value)); > +} > + > +void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg) > +{ > + const uint32_t ctr_idx = (evt_reg - RISCV_IOMMU_REG_IOHPMEVT_BASE) >> 3; > + const uint32_t ovf = riscv_iommu_reg_get32(s, > RISCV_IOMMU_REG_IOCOUNTOVF); > + uint64_t val = riscv_iommu_reg_get64(s, evt_reg); > + > + if (ctr_idx >= s->hpm_cntrs) { > + return; > + } > + > + /* Clear OF bit in IOCNTOVF if it's being cleared in IOHPMEVT register. > */ > + if (get_field(ovf, BIT(ctr_idx + 1)) && > + !get_field(val, RISCV_IOMMU_IOHPMEVT_OF)) { > + /* +1 to offset CYCLE register OF bit. */ > + riscv_iommu_reg_mod32( > + s, RISCV_IOMMU_REG_IOCOUNTOVF, 0, BIT(ctr_idx + 1)); > + } > + > + if (!check_valid_event_id(get_field(val, > RISCV_IOMMU_IOHPMEVT_EVENT_ID))) { > + /* Reset EventID (WARL) field to invalid. */ > + val = set_field(val, RISCV_IOMMU_IOHPMEVT_EVENT_ID, > + RISCV_IOMMU_HPMEVENT_INVALID); > + riscv_iommu_reg_set64(s, evt_reg, val); > + } > + > + update_event_map(s, val, ctr_idx); > +} > diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h > index 0cd550975d..5fc4ef2e8b 100644 > --- a/hw/riscv/riscv-iommu-hpm.h > +++ b/hw/riscv/riscv-iommu-hpm.h > @@ -28,5 +28,6 @@ void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, > RISCVIOMMUContext *ctx, > void riscv_iommu_hpm_timer_cb(void *priv); > void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh); > void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s); > +void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg); > > #endif > diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c > index 3bdd88df4a..83cd529844 100644 > --- a/hw/riscv/riscv-iommu.c > +++ b/hw/riscv/riscv-iommu.c > @@ -1939,7 +1939,7 @@ static void > riscv_iommu_process_hpm_writes(RISCVIOMMUState *s, > > case RISCV_IOMMU_REG_IOHPMEVT_BASE ... > RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4: > - /* not yet implemented */ > + riscv_iommu_process_hpmevt_write(s, regb & ~7); > break; > } > } > @@ -2386,6 +2386,8 @@ static Property riscv_iommu_properties[] = { > DEFINE_PROP_BOOL("g-stage", RISCVIOMMUState, enable_g_stage, TRUE), > DEFINE_PROP_LINK("downstream-mr", RISCVIOMMUState, target_mr, > TYPE_MEMORY_REGION, MemoryRegion *), > + DEFINE_PROP_UINT8("hpm-counters", RISCVIOMMUState, hpm_cntrs, > + RISCV_IOMMU_IOCOUNT_NUM), > DEFINE_PROP_END_OF_LIST(), > }; > > diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h > index 6ddc59f474..5aaa66fae5 100644 > --- a/hw/riscv/riscv-iommu.h > +++ b/hw/riscv/riscv-iommu.h > @@ -95,6 +95,7 @@ struct RISCVIOMMUState { > > /* HPM event counters */ > GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */ > + uint8_t hpm_cntrs; > }; > > void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus, > -- > 2.47.1 > >