aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Jeznach <tjeznach@rivosinc.com>2025-02-24 16:08:20 -0300
committerAlistair Francis <alistair.francis@wdc.com>2025-03-04 15:42:54 +1000
commitffb37df056490b34cecc7958bf5f83fe5497b2d4 (patch)
treeb0feb2ce68a5eccaef9dca2f87d41e0b4d5a6591
parent11ecf24c7eda83bb92e24a81425ac6d33a63378e (diff)
downloadqemu-ffb37df056490b34cecc7958bf5f83fe5497b2d4.zip
qemu-ffb37df056490b34cecc7958bf5f83fe5497b2d4.tar.gz
qemu-ffb37df056490b34cecc7958bf5f83fe5497b2d4.tar.bz2
hw/riscv/riscv-iommu: instantiate hpm_timer
The next HPM related changes requires the HPM overflow timer to be initialized by the riscv-iommu base emulation. Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20250224190826.1858473-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
-rw-r--r--hw/riscv/riscv-iommu-hpm.c36
-rw-r--r--hw/riscv/riscv-iommu-hpm.h1
-rw-r--r--hw/riscv/riscv-iommu.c3
-rw-r--r--hw/riscv/riscv-iommu.h2
4 files changed, 42 insertions, 0 deletions
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 8eca5ee..3250883 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 411d869..cd896d3 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 0b15acf..f26aa15 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -2382,6 +2382,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);
}
}
@@ -2395,6 +2397,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 4384f39..2fef6ee 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -83,8 +83,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 */