* [PATCH for-10.0 00/11] riscv: IOMMU HPM support
@ 2024-12-05 13:29 Daniel Henrique Barboza
2024-12-05 13:29 ` [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers Daniel Henrique Barboza
` (11 more replies)
0 siblings, 12 replies; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Daniel Henrique Barboza, Tomasz Jeznach
Hi,
This is a re-submission of the original Hardware Performance Monitor
IOMMU support sent by Tomasz back in July 2023 [1] in the first version
of the IOMMU emulation. In the second version of that work [2] sent in
February 2024 I said:
----
- I'm not contributing the HPM support that was present in v1. It shaved
off 600 lines of code from the series, which is already large enough
as is. We'll introduce HPM in later versions or as a follow-up;
-----
So here I am keeping my end of the deal. The code is basically the same that
Tomasz sent in v1 with some tweaks:
- Code was split across several patches for easier review;
- A separated file was created, riscv-iommu-hpm.c, to host all the HPM
related code. The base emulation will use HPM via public helpers. The
idea is to avoid clogging riscv-iommu.c;
- There was a lock in use to read/write the HPM registers in the
original posting. Based on the current design of the merged IOMMU
support, a lock-less design, I also removed the locks from HPM;
- Other minor tweaks such as not naming functions using "__name" and so
on.
Patch 1 is a header fix required to put the helpers in riscv-iommu-hpm.
Patches 10 and 11 are new. The original HPM code is split in patches
2-9.
Series based on alistair/riscv-to-apply.next.
[1] https://lore.kernel.org/qemu-riscv/cover.1689819031.git.tjeznach@rivosinc.com/
[2] https://lore.kernel.org/qemu-riscv/20240307160319.675044-1-dbarboza@ventanamicro.com/
Cc: Tomasz Jeznach <tjeznach@rivosinc.com>
Daniel Henrique Barboza (3):
hw/riscv/riscv-iommu.h: add missing headers
hw/riscv: add IOMMU HPM trace events
docs/specs/riscv-iommu.rst: add HPM support info
Tomasz Jeznach (8):
hw/riscv/riscv-iommu-bits.h: HPM bits
hw/riscv/riscv-iommu: add riscv-iommu-hpm file
hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr()
hw/riscv/riscv-iommu: instantiate hpm_timer
hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes
hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write
hw/riscv/riscv-iommu: add hpm events mmio write
hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap
docs/specs/riscv-iommu.rst | 2 +
hw/riscv/meson.build | 3 +-
hw/riscv/riscv-iommu-bits.h | 47 +++++
hw/riscv/riscv-iommu-hpm.c | 381 ++++++++++++++++++++++++++++++++++++
hw/riscv/riscv-iommu-hpm.h | 33 ++++
hw/riscv/riscv-iommu.c | 131 +++++++++++--
hw/riscv/riscv-iommu.h | 27 +++
hw/riscv/trace-events | 5 +
8 files changed, 612 insertions(+), 17 deletions(-)
create mode 100644 hw/riscv/riscv-iommu-hpm.c
create mode 100644 hw/riscv/riscv-iommu-hpm.h
--
2.47.1
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 2:08 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits Daniel Henrique Barboza
` (10 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Daniel Henrique Barboza
This header is incomplete, i.e. it is using definitions that are being
supplied by the .c files that are including it.
Adding this header into a fresh .c file will result in errors:
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:30:17: error: field ‘parent_obj’ has incomplete type
30 | DeviceState parent_obj;
| ^~~~~~~~~~
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:50:5: error: unknown type name ‘dma_addr_t’; did you mean ‘in_addr_t’?
50 | dma_addr_t cq_addr; /* Command queue base physical address */
| ^~~~~~~~~~
| in_addr_t
(...)
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:62:5: error: unknown type name ‘QemuThread’; did you mean ‘GThread’?
62 | QemuThread core_proc; /* Background processing thread */
| ^~~~~~~~~~
| GThread
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:63:5: error: unknown type name ‘QemuCond’
63 | QemuCond core_cond; /* Background processing wake up signal */
| ^~~~~~~~
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:71:18: error: field ‘trap_as’ has incomplete type
71 | AddressSpace trap_as;
| ^~~~~~~
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:72:18: error: field ‘trap_mr’ has incomplete type
72 | MemoryRegion trap_mr;
| ^~~~~~~
/home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:80:18: error: field ‘regs_mr’ has incomplete type
80 | MemoryRegion regs_mr;
| ^~~~~~~
Fix it by adding the missing headers for these definitions.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
index 9424989df4..2de0cdfc56 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -20,6 +20,8 @@
#define HW_RISCV_IOMMU_STATE_H
#include "qom/object.h"
+#include "hw/qdev-properties.h"
+#include "sysemu/dma.h"
#include "hw/riscv/iommu.h"
#include "hw/riscv/riscv-iommu-bits.h"
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
2024-12-05 13:29 ` [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 2:10 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file Daniel Henrique Barboza
` (9 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
Add the relevant HPM (High Performance Monitor) bits that we'll be using
in the next patches.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu-bits.h | 47 +++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
index 485f36b9c9..298a060085 100644
--- a/hw/riscv/riscv-iommu-bits.h
+++ b/hw/riscv/riscv-iommu-bits.h
@@ -82,6 +82,7 @@ struct riscv_iommu_pq_record {
#define RISCV_IOMMU_CAP_ATS BIT_ULL(25)
#define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
#define RISCV_IOMMU_CAP_IGS GENMASK_ULL(29, 28)
+#define RISCV_IOMMU_CAP_HPM BIT_ULL(30)
#define RISCV_IOMMU_CAP_DBG BIT_ULL(31)
#define RISCV_IOMMU_CAP_PAS GENMASK_ULL(37, 32)
#define RISCV_IOMMU_CAP_PD8 BIT_ULL(38)
@@ -191,6 +192,52 @@ enum {
RISCV_IOMMU_INTR_COUNT
};
+#define RISCV_IOMMU_IOCOUNT_NUM 31
+
+/* 5.19 Performance monitoring counter overflow status (32bits) */
+#define RISCV_IOMMU_REG_IOCOUNTOVF 0x0058
+#define RISCV_IOMMU_IOCOUNTOVF_CY BIT(0)
+
+/* 5.20 Performance monitoring counter inhibits (32bits) */
+#define RISCV_IOMMU_REG_IOCOUNTINH 0x005C
+#define RISCV_IOMMU_IOCOUNTINH_CY BIT(0)
+
+/* 5.21 Performance monitoring cycles counter (64bits) */
+#define RISCV_IOMMU_REG_IOHPMCYCLES 0x0060
+#define RISCV_IOMMU_IOHPMCYCLES_COUNTER GENMASK_ULL(62, 0)
+#define RISCV_IOMMU_IOHPMCYCLES_OVF BIT_ULL(63)
+
+/* 5.22 Performance monitoring event counters (31 * 64bits) */
+#define RISCV_IOMMU_REG_IOHPMCTR_BASE 0x0068
+#define RISCV_IOMMU_REG_IOHPMCTR(_n) \
+ (RISCV_IOMMU_REG_IOHPMCTR_BASE + (_n * 0x8))
+
+/* 5.23 Performance monitoring event selectors (31 * 64bits) */
+#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
+#define RISCV_IOMMU_REG_IOHPMEVT(_n) \
+ (RISCV_IOMMU_REG_IOHPMEVT_BASE + (_n * 0x8))
+#define RISCV_IOMMU_IOHPMEVT_EVENT_ID GENMASK_ULL(14, 0)
+#define RISCV_IOMMU_IOHPMEVT_DMASK BIT_ULL(15)
+#define RISCV_IOMMU_IOHPMEVT_PID_PSCID GENMASK_ULL(35, 16)
+#define RISCV_IOMMU_IOHPMEVT_DID_GSCID GENMASK_ULL(59, 36)
+#define RISCV_IOMMU_IOHPMEVT_PV_PSCV BIT_ULL(60)
+#define RISCV_IOMMU_IOHPMEVT_DV_GSCV BIT_ULL(61)
+#define RISCV_IOMMU_IOHPMEVT_IDT BIT_ULL(62)
+#define RISCV_IOMMU_IOHPMEVT_OF BIT_ULL(63)
+
+enum RISCV_IOMMU_HPMEVENT_id {
+ RISCV_IOMMU_HPMEVENT_INVALID = 0,
+ RISCV_IOMMU_HPMEVENT_URQ = 1,
+ RISCV_IOMMU_HPMEVENT_TRQ = 2,
+ RISCV_IOMMU_HPMEVENT_ATS_RQ = 3,
+ RISCV_IOMMU_HPMEVENT_TLB_MISS = 4,
+ RISCV_IOMMU_HPMEVENT_DD_WALK = 5,
+ RISCV_IOMMU_HPMEVENT_PD_WALK = 6,
+ RISCV_IOMMU_HPMEVENT_S_VS_WALKS = 7,
+ RISCV_IOMMU_HPMEVENT_G_WALKS = 8,
+ RISCV_IOMMU_HPMEVENT_MAX = 9
+};
+
/* 5.24 Translation request IOVA (64bits) */
#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
2024-12-05 13:29 ` [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers Daniel Henrique Barboza
2024-12-05 13:29 ` [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 2:16 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr() Daniel Henrique Barboza
` (8 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
The HPM (Hardware Performance Monitor) support consists of almost 7
hundred lines that would be put on top of the base riscv-iommu
emulation.
To avoid clogging riscv-iommu.c, add a separated riscv-iommu-hpm file
that will contain HPM specific code.
We'll start by adding riscv_iommu_hpmcycle_read(), a helper that will be
called during the riscv_iommu_mmio_read() callback.
This change will have no effect on the existing emulation since we're
not declaring HPM feature support.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/meson.build | 3 ++-
hw/riscv/riscv-iommu-hpm.c | 54 ++++++++++++++++++++++++++++++++++++++
hw/riscv/riscv-iommu-hpm.h | 27 +++++++++++++++++++
hw/riscv/riscv-iommu.c | 24 ++++++++++++++++-
hw/riscv/riscv-iommu.h | 4 +++
5 files changed, 110 insertions(+), 2 deletions(-)
create mode 100644 hw/riscv/riscv-iommu-hpm.c
create mode 100644 hw/riscv/riscv-iommu-hpm.h
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 3c7e083aca..c22f3a7216 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -10,7 +10,8 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
-riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files('riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c'))
+riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
+ 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
hw_arch += {'riscv': riscv_ss}
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
new file mode 100644
index 0000000000..5833ab8956
--- /dev/null
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -0,0 +1,54 @@
+/*
+ * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "cpu_bits.h"
+#include "riscv-iommu-hpm.h"
+#include "riscv-iommu.h"
+#include "riscv-iommu-bits.h"
+#include "trace.h"
+
+/* For now we assume IOMMU HPM frequency to be 1GHz so 1-cycle is of 1-ns. */
+static inline uint64_t get_cycles(void)
+{
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
+{
+ const uint64_t cycle = riscv_iommu_reg_get64(
+ s, RISCV_IOMMU_REG_IOHPMCYCLES);
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ const uint64_t ctr_prev = s->hpmcycle_prev;
+ const uint64_t ctr_val = s->hpmcycle_val;
+
+ if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
+ /*
+ * Counter should not increment if inhibit bit is set. We can't really
+ * stop the QEMU_CLOCK_VIRTUAL, so we just return the last updated
+ * counter value to indicate that counter was not incremented.
+ */
+ return (ctr_val & RISCV_IOMMU_IOHPMCYCLES_COUNTER) |
+ (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
+ }
+
+ return (ctr_val + get_cycles() - ctr_prev) |
+ (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
+}
diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
new file mode 100644
index 0000000000..231c110ff2
--- /dev/null
+++ b/hw/riscv/riscv-iommu-hpm.h
@@ -0,0 +1,27 @@
+/*
+ * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
+ *
+ * Copyright (C) 2022-2023 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_RISCV_IOMMU_HPM_H
+#define HW_RISCV_IOMMU_HPM_H
+
+#include "qom/object.h"
+#include "hw/riscv/riscv-iommu.h"
+
+uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s);
+
+#endif
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index e9a0775d6e..01df25418c 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -29,6 +29,7 @@
#include "cpu_bits.h"
#include "riscv-iommu.h"
#include "riscv-iommu-bits.h"
+#include "riscv-iommu-hpm.h"
#include "trace.h"
#define LIMIT_CACHE_CTX (1U << 7)
@@ -2052,7 +2053,28 @@ static MemTxResult riscv_iommu_mmio_read(void *opaque, hwaddr addr,
return MEMTX_ACCESS_ERROR;
}
- ptr = &s->regs_rw[addr];
+ /* Compute cycle register value. */
+ if ((addr & ~7) == RISCV_IOMMU_REG_IOHPMCYCLES) {
+ val = riscv_iommu_hpmcycle_read(s);
+ ptr = (uint8_t *)&val + (addr & 7);
+ } else if ((addr & ~3) == RISCV_IOMMU_REG_IOCOUNTOVF) {
+ /*
+ * Software can read RISCV_IOMMU_REG_IOCOUNTOVF before timer
+ * callback completes. In which case CY_OF bit in
+ * RISCV_IOMMU_IOHPMCYCLES_OVF would be 0. Here we take the
+ * CY_OF bit state from RISCV_IOMMU_REG_IOHPMCYCLES register as
+ * it's not dependent over the timer callback and is computed
+ * from cycle overflow.
+ */
+ val = ldq_le_p(&s->regs_rw[addr]);
+ val |= (riscv_iommu_hpmcycle_read(s) & RISCV_IOMMU_IOHPMCYCLES_OVF)
+ ? RISCV_IOMMU_IOCOUNTOVF_CY
+ : 0;
+ ptr = (uint8_t *)&val + (addr & 3);
+ } else {
+ ptr = &s->regs_rw[addr];
+ }
+
val = ldn_le_p(ptr, size);
*data = val;
diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
index 2de0cdfc56..380f7e81d1 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -86,6 +86,10 @@ struct RISCVIOMMUState {
QLIST_ENTRY(RISCVIOMMUState) iommus;
QLIST_HEAD(, RISCVIOMMUSpace) spaces;
+
+ /* HPM cycle counter */
+ uint64_t hpmcycle_val; /* Current value of cycle register */
+ uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */
};
void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr()
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (2 preceding siblings ...)
2024-12-05 13:29 ` [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 2:50 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer Daniel Henrique Barboza
` (7 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
This function will increment a specific counter, generating an interrupt
when an overflow occurs.
Some extra changes in riscv-iommu.c were required to add this new
helper in riscv-iommu-hpm.c:
- RISCVIOMMUContext was moved to riscv-iommu.h, making it visible in
riscv-iommu-hpm.c;
- riscv_iommu_notify() is now public.
No behavior change is made since HPM support is not being advertised
yet.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu-hpm.c | 114 +++++++++++++++++++++++++++++++++++++
hw/riscv/riscv-iommu-hpm.h | 2 +
hw/riscv/riscv-iommu.c | 43 +++++++++-----
hw/riscv/riscv-iommu.h | 18 ++++++
4 files changed, 162 insertions(+), 15 deletions(-)
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 5833ab8956..8eca5ee17e 100644
--- a/hw/riscv/riscv-iommu-hpm.c
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -52,3 +52,117 @@ uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
return (ctr_val + get_cycles() - ctr_prev) |
(cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
}
+
+static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
+{
+ const uint32_t off = ctr_idx << 3;
+ uint64_t cntr_val;
+
+ cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
+ stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
+
+ /* Handle the overflow scenario. */
+ if (cntr_val == UINT64_MAX) {
+ /*
+ * Generate interrupt only if OF bit is clear. +1 to offset the cycle
+ * register OF bit.
+ */
+ const uint32_t ovf =
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF,
+ BIT(ctr_idx + 1), 0);
+ if (!get_field(ovf, BIT(ctr_idx + 1))) {
+ riscv_iommu_reg_mod64(s,
+ RISCV_IOMMU_REG_IOHPMEVT_BASE + off,
+ RISCV_IOMMU_IOHPMEVT_OF,
+ 0);
+ riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
+ }
+ }
+}
+
+void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ unsigned event_id)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ uint32_t did_gscid;
+ uint32_t pid_pscid;
+ uint32_t ctr_idx;
+ gpointer value;
+ uint32_t ctrs;
+ uint64_t evt;
+
+ if (!(s->cap & RISCV_IOMMU_CAP_HPM)) {
+ return;
+ }
+
+ value = g_hash_table_lookup(s->hpm_event_ctr_map,
+ GUINT_TO_POINTER(event_id));
+ if (value == NULL) {
+ return;
+ }
+
+ for (ctrs = GPOINTER_TO_UINT(value); ctrs != 0; ctrs &= ctrs - 1) {
+ ctr_idx = ctz32(ctrs);
+ if (get_field(inhibit, BIT(ctr_idx + 1))) {
+ continue;
+ }
+
+ evt = riscv_iommu_reg_get64(s,
+ RISCV_IOMMU_REG_IOHPMEVT_BASE + (ctr_idx << 3));
+
+ /*
+ * It's quite possible that event ID has been changed in counter
+ * but hashtable hasn't been updated yet. We don't want to increment
+ * counter for the old event ID.
+ */
+ if (event_id != get_field(evt, RISCV_IOMMU_IOHPMEVT_EVENT_ID)) {
+ continue;
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_IDT)) {
+ did_gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID);
+ pid_pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID);
+ } else {
+ did_gscid = ctx->devid;
+ pid_pscid = ctx->process_id;
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_PV_PSCV)) {
+ /*
+ * If the transaction does not have a valid process_id, counter
+ * increments if device_id matches DID_GSCID. If the transaction
+ * has a valid process_id, counter increments if device_id
+ * matches DID_GSCID and process_id matches PID_PSCID. See
+ * IOMMU Specification, Chapter 5.23. Performance-monitoring
+ * event selector.
+ */
+ if (ctx->process_id &&
+ get_field(evt, RISCV_IOMMU_IOHPMEVT_PID_PSCID) != pid_pscid) {
+ continue;
+ }
+ }
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DV_GSCV)) {
+ uint32_t mask = ~0;
+
+ if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DMASK)) {
+ /*
+ * 1001 1011 mask = GSCID
+ * 0000 0111 mask = mask ^ (mask + 1)
+ * 1111 1000 mask = ~mask;
+ */
+ mask = get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID);
+ mask = mask ^ (mask + 1);
+ mask = ~mask;
+ }
+
+ if ((get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID) & mask) !=
+ (did_gscid & mask)) {
+ continue;
+ }
+ }
+
+ hpm_incr_ctr(s, ctr_idx);
+ }
+}
diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
index 231c110ff2..411d869dce 100644
--- a/hw/riscv/riscv-iommu-hpm.h
+++ b/hw/riscv/riscv-iommu-hpm.h
@@ -23,5 +23,7 @@
#include "hw/riscv/riscv-iommu.h"
uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s);
+void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
+ unsigned event_id);
#endif
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 01df25418c..5ce0d24359 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -39,7 +39,6 @@
#define PPN_PHYS(ppn) ((ppn) << TARGET_PAGE_BITS)
#define PPN_DOWN(phy) ((phy) >> TARGET_PAGE_BITS)
-typedef struct RISCVIOMMUContext RISCVIOMMUContext;
typedef struct RISCVIOMMUEntry RISCVIOMMUEntry;
/* Device assigned I/O address space */
@@ -52,19 +51,6 @@ struct RISCVIOMMUSpace {
QLIST_ENTRY(RISCVIOMMUSpace) list;
};
-/* Device translation context state. */
-struct RISCVIOMMUContext {
- uint64_t devid:24; /* Requester Id, AKA device_id */
- uint64_t process_id:20; /* Process ID. PASID for PCIe */
- uint64_t tc; /* Translation Control */
- uint64_t ta; /* Translation Attributes */
- uint64_t satp; /* S-Stage address translation and protection */
- uint64_t gatp; /* G-Stage address translation and protection */
- uint64_t msi_addr_mask; /* MSI filtering - address mask */
- uint64_t msi_addr_pattern; /* MSI filtering - address pattern */
- uint64_t msiptp; /* MSI redirection page table pointer */
-};
-
/* Address translation cache entry */
struct RISCVIOMMUEntry {
uint64_t iova:44; /* IOVA Page Number */
@@ -93,7 +79,7 @@ static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type)
}
}
-static void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
+void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
{
uint32_t ipsr, icvec, vector;
@@ -415,6 +401,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
}
}
+
+ if (pass == S_STAGE) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_S_VS_WALKS);
+ } else {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_G_WALKS);
+ }
+
/* Read page table entry */
if (sc[pass].ptesize == 4) {
uint32_t pte32 = 0;
@@ -933,6 +926,7 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
/* Device directory tree walk */
for (; depth-- > 0; ) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
/*
* Select device id index bits based on device directory tree level
* and device context format.
@@ -960,6 +954,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
addr = PPN_PHYS(get_field(de, RISCV_IOMMU_DDTE_PPN));
}
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
+
/* index into device context entry page */
addr |= (ctx->devid * dc_len) & ~TARGET_PAGE_MASK;
@@ -1025,6 +1021,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
}
for (depth = mode - RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8; depth-- > 0; ) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
+
/*
* Select process id index bits based on process directory tree
* level. See IOMMU Specification, 2.2. Process-Directory-Table.
@@ -1042,6 +1040,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
addr = PPN_PHYS(get_field(de, RISCV_IOMMU_PC_FSC_PPN));
}
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
+
/* Leaf entry in PDT */
addr |= (ctx->process_id << 4) & ~TARGET_PAGE_MASK;
if (dma_memory_read(s->target_as, addr, &dc.ta, sizeof(uint64_t) * 2,
@@ -1347,6 +1347,8 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
GHashTable *iot_cache;
int fault;
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ);
+
iot_cache = g_hash_table_ref(s->iot_cache);
/*
* TC[32] is reserved for custom extensions, used here to temporarily
@@ -1357,6 +1359,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
/* Check for ATS request. */
if (iotlb->perm == IOMMU_NONE) {
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_ATS_RQ);
/* Check if ATS is disabled. */
if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS)) {
enable_pri = false;
@@ -1375,6 +1378,8 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
goto done;
}
+ riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_TLB_MISS);
+
/* Translate using device directory / page table information. */
fault = riscv_iommu_spa_fetch(s, ctx, iotlb);
@@ -2274,6 +2279,10 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->trap_mr, OBJECT(dev), &riscv_iommu_trap_ops, s,
"riscv-iommu-trap", ~0ULL);
address_space_init(&s->trap_as, &s->trap_mr, "riscv-iommu-trap-as");
+
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ s->hpm_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
}
static void riscv_iommu_unrealize(DeviceState *dev)
@@ -2282,6 +2291,10 @@ static void riscv_iommu_unrealize(DeviceState *dev)
g_hash_table_unref(s->iot_cache);
g_hash_table_unref(s->ctx_cache);
+
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ g_hash_table_unref(s->hpm_event_ctr_map);
+ }
}
void riscv_iommu_reset(RISCVIOMMUState *s)
diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
index 380f7e81d1..a21ab51491 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -90,12 +90,30 @@ struct RISCVIOMMUState {
/* HPM cycle counter */
uint64_t hpmcycle_val; /* Current value of cycle register */
uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */
+
+ /* HPM event counters */
+ GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */
};
void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
Error **errp);
void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
void riscv_iommu_reset(RISCVIOMMUState *s);
+void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
+
+typedef struct RISCVIOMMUContext RISCVIOMMUContext;
+/* Device translation context state. */
+struct RISCVIOMMUContext {
+ uint64_t devid:24; /* Requester Id, AKA device_id */
+ uint64_t process_id:20; /* Process ID. PASID for PCIe */
+ uint64_t tc; /* Translation Control */
+ uint64_t ta; /* Translation Attributes */
+ uint64_t satp; /* S-Stage address translation and protection */
+ uint64_t gatp; /* G-Stage address translation and protection */
+ uint64_t msi_addr_mask; /* MSI filtering - address mask */
+ uint64_t msi_addr_pattern; /* MSI filtering - address pattern */
+ uint64_t msiptp; /* MSI redirection page table pointer */
+};
/* private helpers */
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (3 preceding siblings ...)
2024-12-05 13:29 ` [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr() Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 2:55 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes Daniel Henrique Barboza
` (6 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@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 <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
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
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (4 preceding siblings ...)
2024-12-05 13:29 ` [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 3:04 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write Daniel Henrique Barboza
` (5 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
RISCV_IOMMU_REG_IOCOUNTINH is done by riscv_iommu_process_iocntinh_cy(),
which is called during riscv_iommu_mmio_write() callback via a new
riscv_iommu_pricess_hpm_writes() helper.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu-hpm.c | 60 ++++++++++++++++++++++++++++++++++++++
hw/riscv/riscv-iommu-hpm.h | 1 +
hw/riscv/riscv-iommu.c | 38 ++++++++++++++++++++++++
3 files changed, 99 insertions(+)
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 325088333e..70814b942d 100644
--- a/hw/riscv/riscv-iommu-hpm.c
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -202,3 +202,63 @@ void riscv_iommu_hpm_timer_cb(void *priv)
riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
}
}
+
+static void hpm_setup_timer(RISCVIOMMUState *s, uint64_t value)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+ uint64_t overflow_at, overflow_ns;
+
+ if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
+ return;
+ }
+
+ /*
+ * We are using INT64_MAX here instead to UINT64_MAX because cycle counter
+ * has 63-bit precision and INT64_MAX is the maximum it can store.
+ */
+ if (value) {
+ overflow_ns = INT64_MAX - value + 1;
+ } else {
+ overflow_ns = INT64_MAX;
+ }
+
+ overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns;
+
+ if (overflow_at > INT64_MAX) {
+ s->irq_overflow_left = overflow_at - INT64_MAX;
+ overflow_at = INT64_MAX;
+ }
+
+ timer_mod_anticipate_ns(s->hpm_timer, overflow_at);
+}
+
+/* Updates the internal cycle counter state when iocntinh:CY is changed. */
+void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
+{
+ const uint32_t inhibit = riscv_iommu_reg_get32(
+ s, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ /* We only need to process CY bit toggle. */
+ if (!(inhibit ^ prev_cy_inh)) {
+ return;
+ }
+
+ if (!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY)) {
+ /*
+ * Cycle counter is enabled. Just start the timer again and update
+ * the clock snapshot value to point to the current time to make
+ * sure iohpmcycles read is correct.
+ */
+ s->hpmcycle_prev = get_cycles();
+ hpm_setup_timer(s, s->hpmcycle_val);
+ } else {
+ /*
+ * Cycle counter is disabled. Stop the timer and update the cycle
+ * counter to record the current value which is last programmed
+ * value + the cycles passed so far.
+ */
+ s->hpmcycle_val = s->hpmcycle_val + (get_cycles() - s->hpmcycle_prev);
+ timer_del(s->hpm_timer);
+ }
+}
diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
index cd896d3b7c..ee888650fb 100644
--- a/hw/riscv/riscv-iommu-hpm.h
+++ b/hw/riscv/riscv-iommu-hpm.h
@@ -26,5 +26,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);
+void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh);
#endif
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 2ec388ff3d..56ec2d6d42 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -1923,6 +1923,27 @@ static void riscv_iommu_update_ipsr(RISCVIOMMUState *s, uint64_t data)
riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IPSR, ipsr_set, ipsr_clr);
}
+static void riscv_iommu_process_hpm_writes(RISCVIOMMUState *s,
+ uint32_t regb,
+ bool prev_cy_inh)
+{
+ switch (regb) {
+ case RISCV_IOMMU_REG_IOCOUNTINH:
+ riscv_iommu_process_iocntinh_cy(s, prev_cy_inh);
+ break;
+
+ case RISCV_IOMMU_REG_IOHPMCYCLES:
+ case RISCV_IOMMU_REG_IOHPMCYCLES + 4:
+ /* not yet implemented */
+ break;
+
+ case RISCV_IOMMU_REG_IOHPMEVT_BASE ...
+ RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4:
+ /* not yet implemented */
+ break;
+ }
+}
+
/*
* Write the resulting value of 'data' for the reg specified
* by 'reg_addr', after considering read-only/read-write/write-clear
@@ -1950,6 +1971,7 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
uint32_t regb = addr & ~3;
uint32_t busy = 0;
uint64_t val = 0;
+ bool cy_inh = false;
if ((addr & (size - 1)) != 0) {
/* Unsupported MMIO alignment or access size */
@@ -2017,6 +2039,16 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
busy = RISCV_IOMMU_TR_REQ_CTL_GO_BUSY;
break;
+ case RISCV_IOMMU_REG_IOCOUNTINH:
+ if (addr != RISCV_IOMMU_REG_IOCOUNTINH) {
+ break;
+ }
+ /* Store previous value of CY bit. */
+ cy_inh = !!(riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTINH) &
+ RISCV_IOMMU_IOCOUNTINH_CY);
+ break;
+
+
default:
break;
}
@@ -2035,6 +2067,12 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
stl_le_p(&s->regs_rw[regb], rw | busy);
}
+ /* Process HPM writes and update any internal state if needed. */
+ if (regb >= RISCV_IOMMU_REG_IOCOUNTOVF &&
+ regb <= (RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4)) {
+ riscv_iommu_process_hpm_writes(s, regb, cy_inh);
+ }
+
if (process_fn) {
process_fn(s);
}
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (5 preceding siblings ...)
2024-12-05 13:29 ` [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes Daniel Henrique Barboza
@ 2024-12-05 13:29 ` Daniel Henrique Barboza
2025-02-24 3:06 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events " Daniel Henrique Barboza
` (4 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:29 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
RISCV_IOMMU_REG_IOHPMCYCLES writes are done by
riscv_iommu_process_hpmcycle_write(), called by the mmio write callback
via riscv_iommu_process_hpm_writes().
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu-hpm.c | 19 +++++++++++++++++++
hw/riscv/riscv-iommu-hpm.h | 1 +
hw/riscv/riscv-iommu.c | 2 +-
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 70814b942d..1cea6b1df1 100644
--- a/hw/riscv/riscv-iommu-hpm.c
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -262,3 +262,22 @@ void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
timer_del(s->hpm_timer);
}
}
+
+void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s)
+{
+ const uint64_t val = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_IOHPMCYCLES);
+ const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
+
+ /*
+ * Clear OF bit in IOCNTOVF if it's being cleared in IOHPMCYCLES register.
+ */
+ if (get_field(ovf, RISCV_IOMMU_IOCOUNTOVF_CY) &&
+ !get_field(val, RISCV_IOMMU_IOHPMCYCLES_OVF)) {
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF, 0,
+ RISCV_IOMMU_IOCOUNTOVF_CY);
+ }
+
+ s->hpmcycle_val = val & ~RISCV_IOMMU_IOHPMCYCLES_OVF;
+ s->hpmcycle_prev = get_cycles();
+ hpm_setup_timer(s, s->hpmcycle_val);
+}
diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
index ee888650fb..0cd550975d 100644
--- a/hw/riscv/riscv-iommu-hpm.h
+++ b/hw/riscv/riscv-iommu-hpm.h
@@ -27,5 +27,6 @@ void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
unsigned event_id);
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);
#endif
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 56ec2d6d42..3bdd88df4a 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -1934,7 +1934,7 @@ static void riscv_iommu_process_hpm_writes(RISCVIOMMUState *s,
case RISCV_IOMMU_REG_IOHPMCYCLES:
case RISCV_IOMMU_REG_IOHPMCYCLES + 4:
- /* not yet implemented */
+ riscv_iommu_process_hpmcycle_write(s);
break;
case RISCV_IOMMU_REG_IOHPMEVT_BASE ...
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events mmio write
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (6 preceding siblings ...)
2024-12-05 13:29 ` [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write Daniel Henrique Barboza
@ 2024-12-05 13:30 ` Daniel Henrique Barboza
2025-02-24 3:31 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap Daniel Henrique Barboza
` (3 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:30 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@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 <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
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
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (7 preceding siblings ...)
2024-12-05 13:30 ` [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events " Daniel Henrique Barboza
@ 2024-12-05 13:30 ` Daniel Henrique Barboza
2025-02-24 3:32 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events Daniel Henrique Barboza
` (2 subsequent siblings)
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:30 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Tomasz Jeznach, Daniel Henrique Barboza
From: Tomasz Jeznach <tjeznach@rivosinc.com>
Now that we have every piece in place we can advertise CAP_HTM to
software, allowing any HPM aware driver to make use of the counters.
HPM is enabled/disabled via the 'hpm-counters' attribute. Default value
is 31, max value is also 31. Setting it to zero will disable HPM
support.
Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 83cd529844..7df40900b0 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -2256,6 +2256,15 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4;
}
+ if (s->hpm_cntrs > 0) {
+ /* Clip number of HPM counters to maximum supported (31). */
+ if (s->hpm_cntrs > RISCV_IOMMU_IOCOUNT_NUM) {
+ s->hpm_cntrs = RISCV_IOMMU_IOCOUNT_NUM;
+ }
+ /* Enable hardware performance monitor interface */
+ s->cap |= RISCV_IOMMU_CAP_HPM;
+ }
+
/* Out-of-reset translation mode: OFF (DMA disabled) BARE (passthrough) */
s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, s->enable_off ?
RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE);
@@ -2303,6 +2312,18 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
}
+ /* If HPM registers are enabled. */
+ if (s->cap & RISCV_IOMMU_CAP_HPM) {
+ /* +1 for cycle counter bit. */
+ stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOCOUNTINH],
+ ~((2 << s->hpm_cntrs) - 1));
+ stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCYCLES], 0);
+ memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCTR_BASE],
+ 0x00, s->hpm_cntrs * 8);
+ memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMEVT_BASE],
+ 0x00, s->hpm_cntrs * 8);
+ }
+
/* Memory region for downstream access, if specified. */
if (s->target_mr) {
s->target_as = g_new0(AddressSpace, 1);
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (8 preceding siblings ...)
2024-12-05 13:30 ` [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap Daniel Henrique Barboza
@ 2024-12-05 13:30 ` Daniel Henrique Barboza
2025-02-24 3:33 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info Daniel Henrique Barboza
2025-02-24 3:59 ` [PATCH for-10.0 00/11] riscv: IOMMU HPM support Alistair Francis
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:30 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Daniel Henrique Barboza
Add a handful of trace events to allow for an easier time debugging the
HPM feature.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/riscv-iommu-hpm.c | 10 ++++++++++
hw/riscv/trace-events | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 5518c287a5..c5034bff79 100644
--- a/hw/riscv/riscv-iommu-hpm.c
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -39,6 +39,8 @@ uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
const uint64_t ctr_prev = s->hpmcycle_prev;
const uint64_t ctr_val = s->hpmcycle_val;
+ trace_riscv_iommu_hpm_read(cycle, inhibit, ctr_prev, ctr_val);
+
if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
/*
* Counter should not increment if inhibit bit is set. We can't really
@@ -61,6 +63,8 @@ static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
+ trace_riscv_iommu_hpm_incr_ctr(cntr_val);
+
/* Handle the overflow scenario. */
if (cntr_val == UINT64_MAX) {
/*
@@ -244,6 +248,8 @@ void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
return;
}
+ trace_riscv_iommu_hpm_iocntinh_cy(prev_cy_inh);
+
if (!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY)) {
/*
* Cycle counter is enabled. Just start the timer again and update
@@ -268,6 +274,8 @@ void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s)
const uint64_t val = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_IOHPMCYCLES);
const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
+ trace_riscv_iommu_hpm_cycle_write(ovf, val);
+
/*
* Clear OF bit in IOCNTOVF if it's being cleared in IOHPMCYCLES register.
*/
@@ -352,6 +360,8 @@ void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg)
return;
}
+ trace_riscv_iommu_hpm_evt_write(ctr_idx, ovf, val);
+
/* 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)) {
diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
index aaa2c0eb94..846f5f19c7 100644
--- a/hw/riscv/trace-events
+++ b/hw/riscv/trace-events
@@ -19,3 +19,8 @@ riscv_iommu_sys_irq_sent(uint32_t vector) "IRQ sent to vector %u"
riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
riscv_iommu_sys_reset_hold(int reset_type) "reset type %d"
riscv_iommu_pci_reset_hold(int reset_type) "reset type %d"
+riscv_iommu_hpm_read(uint64_t cycle, uint32_t inhibit, uint64_t ctr_prev, uint64_t ctr_val) "cycle 0x%lx inhibit 0x%x ctr_prev 0x%lx ctr_val 0x%lx"
+riscv_iommu_hpm_incr_ctr(uint64_t cntr_val) "cntr_val 0x%lx"
+riscv_iommu_hpm_iocntinh_cy(bool prev_cy_inh) "prev_cy_inh %d"
+riscv_iommu_hpm_cycle_write(uint32_t ovf, uint64_t val) "ovf 0x%x val 0x%lx"
+riscv_iommu_hpm_evt_write(uint32_t ctr_idx, uint32_t ovf, uint64_t val) "ctr_idx 0x%x ovf 0x%x val 0x%lx"
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (9 preceding siblings ...)
2024-12-05 13:30 ` [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events Daniel Henrique Barboza
@ 2024-12-05 13:30 ` Daniel Henrique Barboza
2025-02-24 3:34 ` Alistair Francis
2025-02-24 3:59 ` [PATCH for-10.0 00/11] riscv: IOMMU HPM support Alistair Francis
11 siblings, 1 reply; 24+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-05 13:30 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, bmeng, liwei1518, zhiwei_liu,
palmer, Daniel Henrique Barboza
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
docs/specs/riscv-iommu.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/specs/riscv-iommu.rst b/docs/specs/riscv-iommu.rst
index b1538c9ead..000c7e1f57 100644
--- a/docs/specs/riscv-iommu.rst
+++ b/docs/specs/riscv-iommu.rst
@@ -82,6 +82,8 @@ Several options are available to control the capabilities of the device, namely:
- "off" (Out-of-reset translation mode: 'on' for DMA disabled, 'off' for 'BARE' (passthrough))
- "s-stage": enable s-stage support
- "g-stage": enable g-stage support
+- "hpm-counters": number of hardware performance counters available. Maximum value is 31.
+ Default value is 31. Use 0 (zero) to disable HPM support
riscv-iommu-sys device
----------------------
--
2.47.1
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers
2024-12-05 13:29 ` [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers Daniel Henrique Barboza
@ 2025-02-24 2:08 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 2:08 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer
On Thu, Dec 5, 2024 at 11:32 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> This header is incomplete, i.e. it is using definitions that are being
> supplied by the .c files that are including it.
>
> Adding this header into a fresh .c file will result in errors:
>
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:30:17: error: field ‘parent_obj’ has incomplete type
> 30 | DeviceState parent_obj;
> | ^~~~~~~~~~
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:50:5: error: unknown type name ‘dma_addr_t’; did you mean ‘in_addr_t’?
> 50 | dma_addr_t cq_addr; /* Command queue base physical address */
> | ^~~~~~~~~~
> | in_addr_t
> (...)
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:62:5: error: unknown type name ‘QemuThread’; did you mean ‘GThread’?
> 62 | QemuThread core_proc; /* Background processing thread */
> | ^~~~~~~~~~
> | GThread
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:63:5: error: unknown type name ‘QemuCond’
> 63 | QemuCond core_cond; /* Background processing wake up signal */
> | ^~~~~~~~
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:71:18: error: field ‘trap_as’ has incomplete type
> 71 | AddressSpace trap_as;
> | ^~~~~~~
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:72:18: error: field ‘trap_mr’ has incomplete type
> 72 | MemoryRegion trap_mr;
> | ^~~~~~~
> /home/danielhb/work/qemu/hw/riscv/riscv-iommu.h:80:18: error: field ‘regs_mr’ has incomplete type
> 80 | MemoryRegion regs_mr;
> | ^~~~~~~
>
> Fix it by adding the missing headers for these definitions.
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/riscv-iommu.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index 9424989df4..2de0cdfc56 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -20,6 +20,8 @@
> #define HW_RISCV_IOMMU_STATE_H
>
> #include "qom/object.h"
> +#include "hw/qdev-properties.h"
> +#include "sysemu/dma.h"
> #include "hw/riscv/iommu.h"
> #include "hw/riscv/riscv-iommu-bits.h"
>
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits
2024-12-05 13:29 ` [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits Daniel Henrique Barboza
@ 2025-02-24 2:10 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 2:10 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:33 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> Add the relevant HPM (High Performance Monitor) bits that we'll be using
> in the next patches.
>
> 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>
Alistair
> ---
> hw/riscv/riscv-iommu-bits.h | 47 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
> index 485f36b9c9..298a060085 100644
> --- a/hw/riscv/riscv-iommu-bits.h
> +++ b/hw/riscv/riscv-iommu-bits.h
> @@ -82,6 +82,7 @@ struct riscv_iommu_pq_record {
> #define RISCV_IOMMU_CAP_ATS BIT_ULL(25)
> #define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
> #define RISCV_IOMMU_CAP_IGS GENMASK_ULL(29, 28)
> +#define RISCV_IOMMU_CAP_HPM BIT_ULL(30)
> #define RISCV_IOMMU_CAP_DBG BIT_ULL(31)
> #define RISCV_IOMMU_CAP_PAS GENMASK_ULL(37, 32)
> #define RISCV_IOMMU_CAP_PD8 BIT_ULL(38)
> @@ -191,6 +192,52 @@ enum {
> RISCV_IOMMU_INTR_COUNT
> };
>
> +#define RISCV_IOMMU_IOCOUNT_NUM 31
> +
> +/* 5.19 Performance monitoring counter overflow status (32bits) */
> +#define RISCV_IOMMU_REG_IOCOUNTOVF 0x0058
> +#define RISCV_IOMMU_IOCOUNTOVF_CY BIT(0)
> +
> +/* 5.20 Performance monitoring counter inhibits (32bits) */
> +#define RISCV_IOMMU_REG_IOCOUNTINH 0x005C
> +#define RISCV_IOMMU_IOCOUNTINH_CY BIT(0)
> +
> +/* 5.21 Performance monitoring cycles counter (64bits) */
> +#define RISCV_IOMMU_REG_IOHPMCYCLES 0x0060
> +#define RISCV_IOMMU_IOHPMCYCLES_COUNTER GENMASK_ULL(62, 0)
> +#define RISCV_IOMMU_IOHPMCYCLES_OVF BIT_ULL(63)
> +
> +/* 5.22 Performance monitoring event counters (31 * 64bits) */
> +#define RISCV_IOMMU_REG_IOHPMCTR_BASE 0x0068
> +#define RISCV_IOMMU_REG_IOHPMCTR(_n) \
> + (RISCV_IOMMU_REG_IOHPMCTR_BASE + (_n * 0x8))
> +
> +/* 5.23 Performance monitoring event selectors (31 * 64bits) */
> +#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
> +#define RISCV_IOMMU_REG_IOHPMEVT(_n) \
> + (RISCV_IOMMU_REG_IOHPMEVT_BASE + (_n * 0x8))
> +#define RISCV_IOMMU_IOHPMEVT_EVENT_ID GENMASK_ULL(14, 0)
> +#define RISCV_IOMMU_IOHPMEVT_DMASK BIT_ULL(15)
> +#define RISCV_IOMMU_IOHPMEVT_PID_PSCID GENMASK_ULL(35, 16)
> +#define RISCV_IOMMU_IOHPMEVT_DID_GSCID GENMASK_ULL(59, 36)
> +#define RISCV_IOMMU_IOHPMEVT_PV_PSCV BIT_ULL(60)
> +#define RISCV_IOMMU_IOHPMEVT_DV_GSCV BIT_ULL(61)
> +#define RISCV_IOMMU_IOHPMEVT_IDT BIT_ULL(62)
> +#define RISCV_IOMMU_IOHPMEVT_OF BIT_ULL(63)
> +
> +enum RISCV_IOMMU_HPMEVENT_id {
> + RISCV_IOMMU_HPMEVENT_INVALID = 0,
> + RISCV_IOMMU_HPMEVENT_URQ = 1,
> + RISCV_IOMMU_HPMEVENT_TRQ = 2,
> + RISCV_IOMMU_HPMEVENT_ATS_RQ = 3,
> + RISCV_IOMMU_HPMEVENT_TLB_MISS = 4,
> + RISCV_IOMMU_HPMEVENT_DD_WALK = 5,
> + RISCV_IOMMU_HPMEVENT_PD_WALK = 6,
> + RISCV_IOMMU_HPMEVENT_S_VS_WALKS = 7,
> + RISCV_IOMMU_HPMEVENT_G_WALKS = 8,
> + RISCV_IOMMU_HPMEVENT_MAX = 9
> +};
> +
> /* 5.24 Translation request IOVA (64bits) */
> #define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
>
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file
2024-12-05 13:29 ` [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file Daniel Henrique Barboza
@ 2025-02-24 2:16 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 2:16 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:35 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> The HPM (Hardware Performance Monitor) support consists of almost 7
> hundred lines that would be put on top of the base riscv-iommu
> emulation.
>
> To avoid clogging riscv-iommu.c, add a separated riscv-iommu-hpm file
> that will contain HPM specific code.
>
> We'll start by adding riscv_iommu_hpmcycle_read(), a helper that will be
> called during the riscv_iommu_mmio_read() callback.
>
> This change will have no effect on the existing emulation since we're
> not declaring HPM feature support.
>
> 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>
Alistair
> ---
> hw/riscv/meson.build | 3 ++-
> hw/riscv/riscv-iommu-hpm.c | 54 ++++++++++++++++++++++++++++++++++++++
> hw/riscv/riscv-iommu-hpm.h | 27 +++++++++++++++++++
> hw/riscv/riscv-iommu.c | 24 ++++++++++++++++-
> hw/riscv/riscv-iommu.h | 4 +++
> 5 files changed, 110 insertions(+), 2 deletions(-)
> create mode 100644 hw/riscv/riscv-iommu-hpm.c
> create mode 100644 hw/riscv/riscv-iommu-hpm.h
>
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 3c7e083aca..c22f3a7216 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -10,7 +10,8 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
> riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
> riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
> riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
> -riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files('riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c'))
> +riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
> + 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
> riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
>
> hw_arch += {'riscv': riscv_ss}
> diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
> new file mode 100644
> index 0000000000..5833ab8956
> --- /dev/null
> +++ b/hw/riscv/riscv-iommu-hpm.c
> @@ -0,0 +1,54 @@
> +/*
> + * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
> + *
> + * Copyright (C) 2022-2023 Rivos Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/timer.h"
> +#include "cpu_bits.h"
> +#include "riscv-iommu-hpm.h"
> +#include "riscv-iommu.h"
> +#include "riscv-iommu-bits.h"
> +#include "trace.h"
> +
> +/* For now we assume IOMMU HPM frequency to be 1GHz so 1-cycle is of 1-ns. */
> +static inline uint64_t get_cycles(void)
> +{
> + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +}
> +
> +uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
> +{
> + const uint64_t cycle = riscv_iommu_reg_get64(
> + s, RISCV_IOMMU_REG_IOHPMCYCLES);
> + const uint32_t inhibit = riscv_iommu_reg_get32(
> + s, RISCV_IOMMU_REG_IOCOUNTINH);
> + const uint64_t ctr_prev = s->hpmcycle_prev;
> + const uint64_t ctr_val = s->hpmcycle_val;
> +
> + if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
> + /*
> + * Counter should not increment if inhibit bit is set. We can't really
> + * stop the QEMU_CLOCK_VIRTUAL, so we just return the last updated
> + * counter value to indicate that counter was not incremented.
> + */
> + return (ctr_val & RISCV_IOMMU_IOHPMCYCLES_COUNTER) |
> + (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
> + }
> +
> + return (ctr_val + get_cycles() - ctr_prev) |
> + (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
> +}
> diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
> new file mode 100644
> index 0000000000..231c110ff2
> --- /dev/null
> +++ b/hw/riscv/riscv-iommu-hpm.h
> @@ -0,0 +1,27 @@
> +/*
> + * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers
> + *
> + * Copyright (C) 2022-2023 Rivos Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_IOMMU_HPM_H
> +#define HW_RISCV_IOMMU_HPM_H
> +
> +#include "qom/object.h"
> +#include "hw/riscv/riscv-iommu.h"
> +
> +uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s);
> +
> +#endif
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index e9a0775d6e..01df25418c 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -29,6 +29,7 @@
> #include "cpu_bits.h"
> #include "riscv-iommu.h"
> #include "riscv-iommu-bits.h"
> +#include "riscv-iommu-hpm.h"
> #include "trace.h"
>
> #define LIMIT_CACHE_CTX (1U << 7)
> @@ -2052,7 +2053,28 @@ static MemTxResult riscv_iommu_mmio_read(void *opaque, hwaddr addr,
> return MEMTX_ACCESS_ERROR;
> }
>
> - ptr = &s->regs_rw[addr];
> + /* Compute cycle register value. */
> + if ((addr & ~7) == RISCV_IOMMU_REG_IOHPMCYCLES) {
> + val = riscv_iommu_hpmcycle_read(s);
> + ptr = (uint8_t *)&val + (addr & 7);
> + } else if ((addr & ~3) == RISCV_IOMMU_REG_IOCOUNTOVF) {
> + /*
> + * Software can read RISCV_IOMMU_REG_IOCOUNTOVF before timer
> + * callback completes. In which case CY_OF bit in
> + * RISCV_IOMMU_IOHPMCYCLES_OVF would be 0. Here we take the
> + * CY_OF bit state from RISCV_IOMMU_REG_IOHPMCYCLES register as
> + * it's not dependent over the timer callback and is computed
> + * from cycle overflow.
> + */
> + val = ldq_le_p(&s->regs_rw[addr]);
> + val |= (riscv_iommu_hpmcycle_read(s) & RISCV_IOMMU_IOHPMCYCLES_OVF)
> + ? RISCV_IOMMU_IOCOUNTOVF_CY
> + : 0;
> + ptr = (uint8_t *)&val + (addr & 3);
> + } else {
> + ptr = &s->regs_rw[addr];
> + }
> +
> val = ldn_le_p(ptr, size);
>
> *data = val;
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index 2de0cdfc56..380f7e81d1 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -86,6 +86,10 @@ struct RISCVIOMMUState {
>
> QLIST_ENTRY(RISCVIOMMUState) iommus;
> QLIST_HEAD(, RISCVIOMMUSpace) spaces;
> +
> + /* HPM cycle counter */
> + uint64_t hpmcycle_val; /* Current value of cycle register */
> + uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */
> };
>
> void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr()
2024-12-05 13:29 ` [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr() Daniel Henrique Barboza
@ 2025-02-24 2:50 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 2:50 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:33 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> This function will increment a specific counter, generating an interrupt
> when an overflow occurs.
>
> Some extra changes in riscv-iommu.c were required to add this new
> helper in riscv-iommu-hpm.c:
>
> - RISCVIOMMUContext was moved to riscv-iommu.h, making it visible in
> riscv-iommu-hpm.c;
>
> - riscv_iommu_notify() is now public.
>
> No behavior change is made since HPM support is not being advertised
> yet.
>
> 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>
Alistair
> ---
> hw/riscv/riscv-iommu-hpm.c | 114 +++++++++++++++++++++++++++++++++++++
> hw/riscv/riscv-iommu-hpm.h | 2 +
> hw/riscv/riscv-iommu.c | 43 +++++++++-----
> hw/riscv/riscv-iommu.h | 18 ++++++
> 4 files changed, 162 insertions(+), 15 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
> index 5833ab8956..8eca5ee17e 100644
> --- a/hw/riscv/riscv-iommu-hpm.c
> +++ b/hw/riscv/riscv-iommu-hpm.c
> @@ -52,3 +52,117 @@ uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
> return (ctr_val + get_cycles() - ctr_prev) |
> (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF);
> }
> +
> +static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
> +{
> + const uint32_t off = ctr_idx << 3;
> + uint64_t cntr_val;
> +
> + cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
> + stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
> +
> + /* Handle the overflow scenario. */
> + if (cntr_val == UINT64_MAX) {
> + /*
> + * Generate interrupt only if OF bit is clear. +1 to offset the cycle
> + * register OF bit.
> + */
> + const uint32_t ovf =
> + riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF,
> + BIT(ctr_idx + 1), 0);
> + if (!get_field(ovf, BIT(ctr_idx + 1))) {
> + riscv_iommu_reg_mod64(s,
> + RISCV_IOMMU_REG_IOHPMEVT_BASE + off,
> + RISCV_IOMMU_IOHPMEVT_OF,
> + 0);
> + riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
> + }
> + }
> +}
> +
> +void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> + unsigned event_id)
> +{
> + const uint32_t inhibit = riscv_iommu_reg_get32(
> + s, RISCV_IOMMU_REG_IOCOUNTINH);
> + uint32_t did_gscid;
> + uint32_t pid_pscid;
> + uint32_t ctr_idx;
> + gpointer value;
> + uint32_t ctrs;
> + uint64_t evt;
> +
> + if (!(s->cap & RISCV_IOMMU_CAP_HPM)) {
> + return;
> + }
> +
> + value = g_hash_table_lookup(s->hpm_event_ctr_map,
> + GUINT_TO_POINTER(event_id));
> + if (value == NULL) {
> + return;
> + }
> +
> + for (ctrs = GPOINTER_TO_UINT(value); ctrs != 0; ctrs &= ctrs - 1) {
> + ctr_idx = ctz32(ctrs);
> + if (get_field(inhibit, BIT(ctr_idx + 1))) {
> + continue;
> + }
> +
> + evt = riscv_iommu_reg_get64(s,
> + RISCV_IOMMU_REG_IOHPMEVT_BASE + (ctr_idx << 3));
> +
> + /*
> + * It's quite possible that event ID has been changed in counter
> + * but hashtable hasn't been updated yet. We don't want to increment
> + * counter for the old event ID.
> + */
> + if (event_id != get_field(evt, RISCV_IOMMU_IOHPMEVT_EVENT_ID)) {
> + continue;
> + }
> +
> + if (get_field(evt, RISCV_IOMMU_IOHPMEVT_IDT)) {
> + did_gscid = get_field(ctx->gatp, RISCV_IOMMU_DC_IOHGATP_GSCID);
> + pid_pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID);
> + } else {
> + did_gscid = ctx->devid;
> + pid_pscid = ctx->process_id;
> + }
> +
> + if (get_field(evt, RISCV_IOMMU_IOHPMEVT_PV_PSCV)) {
> + /*
> + * If the transaction does not have a valid process_id, counter
> + * increments if device_id matches DID_GSCID. If the transaction
> + * has a valid process_id, counter increments if device_id
> + * matches DID_GSCID and process_id matches PID_PSCID. See
> + * IOMMU Specification, Chapter 5.23. Performance-monitoring
> + * event selector.
> + */
> + if (ctx->process_id &&
> + get_field(evt, RISCV_IOMMU_IOHPMEVT_PID_PSCID) != pid_pscid) {
> + continue;
> + }
> + }
> +
> + if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DV_GSCV)) {
> + uint32_t mask = ~0;
> +
> + if (get_field(evt, RISCV_IOMMU_IOHPMEVT_DMASK)) {
> + /*
> + * 1001 1011 mask = GSCID
> + * 0000 0111 mask = mask ^ (mask + 1)
> + * 1111 1000 mask = ~mask;
> + */
> + mask = get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID);
> + mask = mask ^ (mask + 1);
> + mask = ~mask;
> + }
> +
> + if ((get_field(evt, RISCV_IOMMU_IOHPMEVT_DID_GSCID) & mask) !=
> + (did_gscid & mask)) {
> + continue;
> + }
> + }
> +
> + hpm_incr_ctr(s, ctr_idx);
> + }
> +}
> diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
> index 231c110ff2..411d869dce 100644
> --- a/hw/riscv/riscv-iommu-hpm.h
> +++ b/hw/riscv/riscv-iommu-hpm.h
> @@ -23,5 +23,7 @@
> #include "hw/riscv/riscv-iommu.h"
>
> uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s);
> +void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> + unsigned event_id);
>
> #endif
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 01df25418c..5ce0d24359 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -39,7 +39,6 @@
> #define PPN_PHYS(ppn) ((ppn) << TARGET_PAGE_BITS)
> #define PPN_DOWN(phy) ((phy) >> TARGET_PAGE_BITS)
>
> -typedef struct RISCVIOMMUContext RISCVIOMMUContext;
> typedef struct RISCVIOMMUEntry RISCVIOMMUEntry;
>
> /* Device assigned I/O address space */
> @@ -52,19 +51,6 @@ struct RISCVIOMMUSpace {
> QLIST_ENTRY(RISCVIOMMUSpace) list;
> };
>
> -/* Device translation context state. */
> -struct RISCVIOMMUContext {
> - uint64_t devid:24; /* Requester Id, AKA device_id */
> - uint64_t process_id:20; /* Process ID. PASID for PCIe */
> - uint64_t tc; /* Translation Control */
> - uint64_t ta; /* Translation Attributes */
> - uint64_t satp; /* S-Stage address translation and protection */
> - uint64_t gatp; /* G-Stage address translation and protection */
> - uint64_t msi_addr_mask; /* MSI filtering - address mask */
> - uint64_t msi_addr_pattern; /* MSI filtering - address pattern */
> - uint64_t msiptp; /* MSI redirection page table pointer */
> -};
> -
> /* Address translation cache entry */
> struct RISCVIOMMUEntry {
> uint64_t iova:44; /* IOVA Page Number */
> @@ -93,7 +79,7 @@ static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type)
> }
> }
>
> -static void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
> +void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
> {
> uint32_t ipsr, icvec, vector;
>
> @@ -415,6 +401,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> }
> }
>
> +
> + if (pass == S_STAGE) {
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_S_VS_WALKS);
> + } else {
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_G_WALKS);
> + }
> +
> /* Read page table entry */
> if (sc[pass].ptesize == 4) {
> uint32_t pte32 = 0;
> @@ -933,6 +926,7 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
>
> /* Device directory tree walk */
> for (; depth-- > 0; ) {
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
> /*
> * Select device id index bits based on device directory tree level
> * and device context format.
> @@ -960,6 +954,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
> addr = PPN_PHYS(get_field(de, RISCV_IOMMU_DDTE_PPN));
> }
>
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_DD_WALK);
> +
> /* index into device context entry page */
> addr |= (ctx->devid * dc_len) & ~TARGET_PAGE_MASK;
>
> @@ -1025,6 +1021,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
> }
>
> for (depth = mode - RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8; depth-- > 0; ) {
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
> +
> /*
> * Select process id index bits based on process directory tree
> * level. See IOMMU Specification, 2.2. Process-Directory-Table.
> @@ -1042,6 +1040,8 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx)
> addr = PPN_PHYS(get_field(de, RISCV_IOMMU_PC_FSC_PPN));
> }
>
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK);
> +
> /* Leaf entry in PDT */
> addr |= (ctx->process_id << 4) & ~TARGET_PAGE_MASK;
> if (dma_memory_read(s->target_as, addr, &dc.ta, sizeof(uint64_t) * 2,
> @@ -1347,6 +1347,8 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> GHashTable *iot_cache;
> int fault;
>
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ);
> +
> iot_cache = g_hash_table_ref(s->iot_cache);
> /*
> * TC[32] is reserved for custom extensions, used here to temporarily
> @@ -1357,6 +1359,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
>
> /* Check for ATS request. */
> if (iotlb->perm == IOMMU_NONE) {
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_ATS_RQ);
> /* Check if ATS is disabled. */
> if (!(ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS)) {
> enable_pri = false;
> @@ -1375,6 +1378,8 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> goto done;
> }
>
> + riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_TLB_MISS);
> +
> /* Translate using device directory / page table information. */
> fault = riscv_iommu_spa_fetch(s, ctx, iotlb);
>
> @@ -2274,6 +2279,10 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
> memory_region_init_io(&s->trap_mr, OBJECT(dev), &riscv_iommu_trap_ops, s,
> "riscv-iommu-trap", ~0ULL);
> address_space_init(&s->trap_as, &s->trap_mr, "riscv-iommu-trap-as");
> +
> + if (s->cap & RISCV_IOMMU_CAP_HPM) {
> + s->hpm_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
> + }
> }
>
> static void riscv_iommu_unrealize(DeviceState *dev)
> @@ -2282,6 +2291,10 @@ static void riscv_iommu_unrealize(DeviceState *dev)
>
> g_hash_table_unref(s->iot_cache);
> g_hash_table_unref(s->ctx_cache);
> +
> + if (s->cap & RISCV_IOMMU_CAP_HPM) {
> + g_hash_table_unref(s->hpm_event_ctr_map);
> + }
> }
>
> void riscv_iommu_reset(RISCVIOMMUState *s)
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index 380f7e81d1..a21ab51491 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -90,12 +90,30 @@ struct RISCVIOMMUState {
> /* HPM cycle counter */
> uint64_t hpmcycle_val; /* Current value of cycle register */
> uint64_t hpmcycle_prev; /* Saved value of QEMU_CLOCK_VIRTUAL clock */
> +
> + /* HPM event counters */
> + GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */
> };
>
> void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
> Error **errp);
> void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
> void riscv_iommu_reset(RISCVIOMMUState *s);
> +void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
> +
> +typedef struct RISCVIOMMUContext RISCVIOMMUContext;
> +/* Device translation context state. */
> +struct RISCVIOMMUContext {
> + uint64_t devid:24; /* Requester Id, AKA device_id */
> + uint64_t process_id:20; /* Process ID. PASID for PCIe */
> + uint64_t tc; /* Translation Control */
> + uint64_t ta; /* Translation Attributes */
> + uint64_t satp; /* S-Stage address translation and protection */
> + uint64_t gatp; /* G-Stage address translation and protection */
> + uint64_t msi_addr_mask; /* MSI filtering - address mask */
> + uint64_t msi_addr_pattern; /* MSI filtering - address pattern */
> + uint64_t msiptp; /* MSI redirection page table pointer */
> +};
>
> /* private helpers */
>
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer
2024-12-05 13:29 ` [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer Daniel Henrique Barboza
@ 2025-02-24 2:55 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 2:55 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:35 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@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 <tjeznach@rivosinc.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Acked-by: Alistair Francis <alistair.francis@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
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes
2024-12-05 13:29 ` [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes Daniel Henrique Barboza
@ 2025-02-24 3:04 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:04 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:35 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> RISCV_IOMMU_REG_IOCOUNTINH is done by riscv_iommu_process_iocntinh_cy(),
> which is called during riscv_iommu_mmio_write() callback via a new
> riscv_iommu_pricess_hpm_writes() helper.
>
> 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>
Alistair
> ---
> hw/riscv/riscv-iommu-hpm.c | 60 ++++++++++++++++++++++++++++++++++++++
> hw/riscv/riscv-iommu-hpm.h | 1 +
> hw/riscv/riscv-iommu.c | 38 ++++++++++++++++++++++++
> 3 files changed, 99 insertions(+)
>
> diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
> index 325088333e..70814b942d 100644
> --- a/hw/riscv/riscv-iommu-hpm.c
> +++ b/hw/riscv/riscv-iommu-hpm.c
> @@ -202,3 +202,63 @@ void riscv_iommu_hpm_timer_cb(void *priv)
> riscv_iommu_notify(s, RISCV_IOMMU_INTR_PM);
> }
> }
> +
> +static void hpm_setup_timer(RISCVIOMMUState *s, uint64_t value)
> +{
> + const uint32_t inhibit = riscv_iommu_reg_get32(
> + s, RISCV_IOMMU_REG_IOCOUNTINH);
> + uint64_t overflow_at, overflow_ns;
> +
> + if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
> + return;
> + }
> +
> + /*
> + * We are using INT64_MAX here instead to UINT64_MAX because cycle counter
> + * has 63-bit precision and INT64_MAX is the maximum it can store.
> + */
> + if (value) {
> + overflow_ns = INT64_MAX - value + 1;
> + } else {
> + overflow_ns = INT64_MAX;
> + }
> +
> + overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + overflow_ns;
> +
> + if (overflow_at > INT64_MAX) {
> + s->irq_overflow_left = overflow_at - INT64_MAX;
> + overflow_at = INT64_MAX;
> + }
> +
> + timer_mod_anticipate_ns(s->hpm_timer, overflow_at);
> +}
> +
> +/* Updates the internal cycle counter state when iocntinh:CY is changed. */
> +void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
> +{
> + const uint32_t inhibit = riscv_iommu_reg_get32(
> + s, RISCV_IOMMU_REG_IOCOUNTINH);
> +
> + /* We only need to process CY bit toggle. */
> + if (!(inhibit ^ prev_cy_inh)) {
> + return;
> + }
> +
> + if (!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY)) {
> + /*
> + * Cycle counter is enabled. Just start the timer again and update
> + * the clock snapshot value to point to the current time to make
> + * sure iohpmcycles read is correct.
> + */
> + s->hpmcycle_prev = get_cycles();
> + hpm_setup_timer(s, s->hpmcycle_val);
> + } else {
> + /*
> + * Cycle counter is disabled. Stop the timer and update the cycle
> + * counter to record the current value which is last programmed
> + * value + the cycles passed so far.
> + */
> + s->hpmcycle_val = s->hpmcycle_val + (get_cycles() - s->hpmcycle_prev);
> + timer_del(s->hpm_timer);
> + }
> +}
> diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
> index cd896d3b7c..ee888650fb 100644
> --- a/hw/riscv/riscv-iommu-hpm.h
> +++ b/hw/riscv/riscv-iommu-hpm.h
> @@ -26,5 +26,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);
> +void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh);
>
> #endif
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 2ec388ff3d..56ec2d6d42 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -1923,6 +1923,27 @@ static void riscv_iommu_update_ipsr(RISCVIOMMUState *s, uint64_t data)
> riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IPSR, ipsr_set, ipsr_clr);
> }
>
> +static void riscv_iommu_process_hpm_writes(RISCVIOMMUState *s,
> + uint32_t regb,
> + bool prev_cy_inh)
> +{
> + switch (regb) {
> + case RISCV_IOMMU_REG_IOCOUNTINH:
> + riscv_iommu_process_iocntinh_cy(s, prev_cy_inh);
> + break;
> +
> + case RISCV_IOMMU_REG_IOHPMCYCLES:
> + case RISCV_IOMMU_REG_IOHPMCYCLES + 4:
> + /* not yet implemented */
> + break;
> +
> + case RISCV_IOMMU_REG_IOHPMEVT_BASE ...
> + RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4:
> + /* not yet implemented */
> + break;
> + }
> +}
> +
> /*
> * Write the resulting value of 'data' for the reg specified
> * by 'reg_addr', after considering read-only/read-write/write-clear
> @@ -1950,6 +1971,7 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
> uint32_t regb = addr & ~3;
> uint32_t busy = 0;
> uint64_t val = 0;
> + bool cy_inh = false;
>
> if ((addr & (size - 1)) != 0) {
> /* Unsupported MMIO alignment or access size */
> @@ -2017,6 +2039,16 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
> busy = RISCV_IOMMU_TR_REQ_CTL_GO_BUSY;
> break;
>
> + case RISCV_IOMMU_REG_IOCOUNTINH:
> + if (addr != RISCV_IOMMU_REG_IOCOUNTINH) {
> + break;
> + }
> + /* Store previous value of CY bit. */
> + cy_inh = !!(riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTINH) &
> + RISCV_IOMMU_IOCOUNTINH_CY);
> + break;
> +
> +
> default:
> break;
> }
> @@ -2035,6 +2067,12 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
> stl_le_p(&s->regs_rw[regb], rw | busy);
> }
>
> + /* Process HPM writes and update any internal state if needed. */
> + if (regb >= RISCV_IOMMU_REG_IOCOUNTOVF &&
> + regb <= (RISCV_IOMMU_REG_IOHPMEVT(RISCV_IOMMU_IOCOUNT_NUM) + 4)) {
> + riscv_iommu_process_hpm_writes(s, regb, cy_inh);
> + }
> +
> if (process_fn) {
> process_fn(s);
> }
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write
2024-12-05 13:29 ` [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write Daniel Henrique Barboza
@ 2025-02-24 3:06 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:06 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:34 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> RISCV_IOMMU_REG_IOHPMCYCLES writes are done by
> riscv_iommu_process_hpmcycle_write(), called by the mmio write callback
> via riscv_iommu_process_hpm_writes().
>
> Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/riscv-iommu-hpm.c | 19 +++++++++++++++++++
> hw/riscv/riscv-iommu-hpm.h | 1 +
> hw/riscv/riscv-iommu.c | 2 +-
> 3 files changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
> index 70814b942d..1cea6b1df1 100644
> --- a/hw/riscv/riscv-iommu-hpm.c
> +++ b/hw/riscv/riscv-iommu-hpm.c
> @@ -262,3 +262,22 @@ void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
> timer_del(s->hpm_timer);
> }
> }
> +
> +void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s)
> +{
> + const uint64_t val = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_IOHPMCYCLES);
> + const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
> +
> + /*
> + * Clear OF bit in IOCNTOVF if it's being cleared in IOHPMCYCLES register.
> + */
> + if (get_field(ovf, RISCV_IOMMU_IOCOUNTOVF_CY) &&
> + !get_field(val, RISCV_IOMMU_IOHPMCYCLES_OVF)) {
> + riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_IOCOUNTOVF, 0,
> + RISCV_IOMMU_IOCOUNTOVF_CY);
> + }
> +
> + s->hpmcycle_val = val & ~RISCV_IOMMU_IOHPMCYCLES_OVF;
> + s->hpmcycle_prev = get_cycles();
> + hpm_setup_timer(s, s->hpmcycle_val);
> +}
> diff --git a/hw/riscv/riscv-iommu-hpm.h b/hw/riscv/riscv-iommu-hpm.h
> index ee888650fb..0cd550975d 100644
> --- a/hw/riscv/riscv-iommu-hpm.h
> +++ b/hw/riscv/riscv-iommu-hpm.h
> @@ -27,5 +27,6 @@ void riscv_iommu_hpm_incr_ctr(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
> unsigned event_id);
> 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);
>
> #endif
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 56ec2d6d42..3bdd88df4a 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -1934,7 +1934,7 @@ static void riscv_iommu_process_hpm_writes(RISCVIOMMUState *s,
>
> case RISCV_IOMMU_REG_IOHPMCYCLES:
> case RISCV_IOMMU_REG_IOHPMCYCLES + 4:
> - /* not yet implemented */
> + riscv_iommu_process_hpmcycle_write(s);
> break;
>
> case RISCV_IOMMU_REG_IOHPMEVT_BASE ...
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events mmio write
2024-12-05 13:30 ` [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events " Daniel Henrique Barboza
@ 2025-02-24 3:31 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:31 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:34 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@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 <tjeznach@rivosinc.com>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Acked-by: Alistair Francis <alistair.francis@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
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap
2024-12-05 13:30 ` [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap Daniel Henrique Barboza
@ 2025-02-24 3:32 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:32 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:34 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> From: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> Now that we have every piece in place we can advertise CAP_HTM to
> software, allowing any HPM aware driver to make use of the counters.
>
> HPM is enabled/disabled via the 'hpm-counters' attribute. Default value
> is 31, max value is also 31. Setting it to zero will disable HPM
> support.
>
> 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>
Alistair
> ---
> hw/riscv/riscv-iommu.c | 21 +++++++++++++++++++++
> 1 file changed, 21 insertions(+)
>
> diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
> index 83cd529844..7df40900b0 100644
> --- a/hw/riscv/riscv-iommu.c
> +++ b/hw/riscv/riscv-iommu.c
> @@ -2256,6 +2256,15 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
> RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4;
> }
>
> + if (s->hpm_cntrs > 0) {
> + /* Clip number of HPM counters to maximum supported (31). */
> + if (s->hpm_cntrs > RISCV_IOMMU_IOCOUNT_NUM) {
> + s->hpm_cntrs = RISCV_IOMMU_IOCOUNT_NUM;
> + }
> + /* Enable hardware performance monitor interface */
> + s->cap |= RISCV_IOMMU_CAP_HPM;
> + }
> +
> /* Out-of-reset translation mode: OFF (DMA disabled) BARE (passthrough) */
> s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, s->enable_off ?
> RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE);
> @@ -2303,6 +2312,18 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
> RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
> }
>
> + /* If HPM registers are enabled. */
> + if (s->cap & RISCV_IOMMU_CAP_HPM) {
> + /* +1 for cycle counter bit. */
> + stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOCOUNTINH],
> + ~((2 << s->hpm_cntrs) - 1));
> + stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCYCLES], 0);
> + memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMCTR_BASE],
> + 0x00, s->hpm_cntrs * 8);
> + memset(&s->regs_ro[RISCV_IOMMU_REG_IOHPMEVT_BASE],
> + 0x00, s->hpm_cntrs * 8);
> + }
> +
> /* Memory region for downstream access, if specified. */
> if (s->target_mr) {
> s->target_as = g_new0(AddressSpace, 1);
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events
2024-12-05 13:30 ` [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events Daniel Henrique Barboza
@ 2025-02-24 3:33 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:33 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer
On Thu, Dec 5, 2024 at 11:34 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> Add a handful of trace events to allow for an easier time debugging the
> HPM feature.
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/riscv-iommu-hpm.c | 10 ++++++++++
> hw/riscv/trace-events | 5 +++++
> 2 files changed, 15 insertions(+)
>
> diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
> index 5518c287a5..c5034bff79 100644
> --- a/hw/riscv/riscv-iommu-hpm.c
> +++ b/hw/riscv/riscv-iommu-hpm.c
> @@ -39,6 +39,8 @@ uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s)
> const uint64_t ctr_prev = s->hpmcycle_prev;
> const uint64_t ctr_val = s->hpmcycle_val;
>
> + trace_riscv_iommu_hpm_read(cycle, inhibit, ctr_prev, ctr_val);
> +
> if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) {
> /*
> * Counter should not increment if inhibit bit is set. We can't really
> @@ -61,6 +63,8 @@ static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
> cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
> stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
>
> + trace_riscv_iommu_hpm_incr_ctr(cntr_val);
> +
> /* Handle the overflow scenario. */
> if (cntr_val == UINT64_MAX) {
> /*
> @@ -244,6 +248,8 @@ void riscv_iommu_process_iocntinh_cy(RISCVIOMMUState *s, bool prev_cy_inh)
> return;
> }
>
> + trace_riscv_iommu_hpm_iocntinh_cy(prev_cy_inh);
> +
> if (!(inhibit & RISCV_IOMMU_IOCOUNTINH_CY)) {
> /*
> * Cycle counter is enabled. Just start the timer again and update
> @@ -268,6 +274,8 @@ void riscv_iommu_process_hpmcycle_write(RISCVIOMMUState *s)
> const uint64_t val = riscv_iommu_reg_get64(s, RISCV_IOMMU_REG_IOHPMCYCLES);
> const uint32_t ovf = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_IOCOUNTOVF);
>
> + trace_riscv_iommu_hpm_cycle_write(ovf, val);
> +
> /*
> * Clear OF bit in IOCNTOVF if it's being cleared in IOHPMCYCLES register.
> */
> @@ -352,6 +360,8 @@ void riscv_iommu_process_hpmevt_write(RISCVIOMMUState *s, uint32_t evt_reg)
> return;
> }
>
> + trace_riscv_iommu_hpm_evt_write(ctr_idx, ovf, val);
> +
> /* 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)) {
> diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
> index aaa2c0eb94..846f5f19c7 100644
> --- a/hw/riscv/trace-events
> +++ b/hw/riscv/trace-events
> @@ -19,3 +19,8 @@ riscv_iommu_sys_irq_sent(uint32_t vector) "IRQ sent to vector %u"
> riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
> riscv_iommu_sys_reset_hold(int reset_type) "reset type %d"
> riscv_iommu_pci_reset_hold(int reset_type) "reset type %d"
> +riscv_iommu_hpm_read(uint64_t cycle, uint32_t inhibit, uint64_t ctr_prev, uint64_t ctr_val) "cycle 0x%lx inhibit 0x%x ctr_prev 0x%lx ctr_val 0x%lx"
> +riscv_iommu_hpm_incr_ctr(uint64_t cntr_val) "cntr_val 0x%lx"
> +riscv_iommu_hpm_iocntinh_cy(bool prev_cy_inh) "prev_cy_inh %d"
> +riscv_iommu_hpm_cycle_write(uint32_t ovf, uint64_t val) "ovf 0x%x val 0x%lx"
> +riscv_iommu_hpm_evt_write(uint32_t ctr_idx, uint32_t ovf, uint64_t val) "ctr_idx 0x%x ovf 0x%x val 0x%lx"
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info
2024-12-05 13:30 ` [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info Daniel Henrique Barboza
@ 2025-02-24 3:34 ` Alistair Francis
0 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:34 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer
On Thu, Dec 5, 2024 at 11:33 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> docs/specs/riscv-iommu.rst | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/docs/specs/riscv-iommu.rst b/docs/specs/riscv-iommu.rst
> index b1538c9ead..000c7e1f57 100644
> --- a/docs/specs/riscv-iommu.rst
> +++ b/docs/specs/riscv-iommu.rst
> @@ -82,6 +82,8 @@ Several options are available to control the capabilities of the device, namely:
> - "off" (Out-of-reset translation mode: 'on' for DMA disabled, 'off' for 'BARE' (passthrough))
> - "s-stage": enable s-stage support
> - "g-stage": enable g-stage support
> +- "hpm-counters": number of hardware performance counters available. Maximum value is 31.
> + Default value is 31. Use 0 (zero) to disable HPM support
>
> riscv-iommu-sys device
> ----------------------
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH for-10.0 00/11] riscv: IOMMU HPM support
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
` (10 preceding siblings ...)
2024-12-05 13:30 ` [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info Daniel Henrique Barboza
@ 2025-02-24 3:59 ` Alistair Francis
11 siblings, 0 replies; 24+ messages in thread
From: Alistair Francis @ 2025-02-24 3:59 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, bmeng, liwei1518,
zhiwei_liu, palmer, Tomasz Jeznach
On Thu, Dec 5, 2024 at 11:33 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> Hi,
>
> This is a re-submission of the original Hardware Performance Monitor
> IOMMU support sent by Tomasz back in July 2023 [1] in the first version
> of the IOMMU emulation. In the second version of that work [2] sent in
> February 2024 I said:
>
> ----
> - I'm not contributing the HPM support that was present in v1. It shaved
> off 600 lines of code from the series, which is already large enough
> as is. We'll introduce HPM in later versions or as a follow-up;
> -----
>
> So here I am keeping my end of the deal. The code is basically the same that
> Tomasz sent in v1 with some tweaks:
>
> - Code was split across several patches for easier review;
> - A separated file was created, riscv-iommu-hpm.c, to host all the HPM
> related code. The base emulation will use HPM via public helpers. The
> idea is to avoid clogging riscv-iommu.c;
> - There was a lock in use to read/write the HPM registers in the
> original posting. Based on the current design of the merged IOMMU
> support, a lock-less design, I also removed the locks from HPM;
> - Other minor tweaks such as not naming functions using "__name" and so
> on.
>
> Patch 1 is a header fix required to put the helpers in riscv-iommu-hpm.
> Patches 10 and 11 are new. The original HPM code is split in patches
> 2-9.
>
> Series based on alistair/riscv-to-apply.next.
Looks fine, I didn't check it that closely but any bugs will affect you :P
Do you mind rebasing though?
Alistair
>
> [1] https://lore.kernel.org/qemu-riscv/cover.1689819031.git.tjeznach@rivosinc.com/
> [2] https://lore.kernel.org/qemu-riscv/20240307160319.675044-1-dbarboza@ventanamicro.com/
>
> Cc: Tomasz Jeznach <tjeznach@rivosinc.com>
>
> Daniel Henrique Barboza (3):
> hw/riscv/riscv-iommu.h: add missing headers
> hw/riscv: add IOMMU HPM trace events
> docs/specs/riscv-iommu.rst: add HPM support info
>
> Tomasz Jeznach (8):
> hw/riscv/riscv-iommu-bits.h: HPM bits
> hw/riscv/riscv-iommu: add riscv-iommu-hpm file
> hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr()
> hw/riscv/riscv-iommu: instantiate hpm_timer
> hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes
> hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write
> hw/riscv/riscv-iommu: add hpm events mmio write
> hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap
>
> docs/specs/riscv-iommu.rst | 2 +
> hw/riscv/meson.build | 3 +-
> hw/riscv/riscv-iommu-bits.h | 47 +++++
> hw/riscv/riscv-iommu-hpm.c | 381 ++++++++++++++++++++++++++++++++++++
> hw/riscv/riscv-iommu-hpm.h | 33 ++++
> hw/riscv/riscv-iommu.c | 131 +++++++++++--
> hw/riscv/riscv-iommu.h | 27 +++
> hw/riscv/trace-events | 5 +
> 8 files changed, 612 insertions(+), 17 deletions(-)
> create mode 100644 hw/riscv/riscv-iommu-hpm.c
> create mode 100644 hw/riscv/riscv-iommu-hpm.h
>
> --
> 2.47.1
>
>
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2025-02-24 4:01 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-05 13:29 [PATCH for-10.0 00/11] riscv: IOMMU HPM support Daniel Henrique Barboza
2024-12-05 13:29 ` [PATCH for-10.0 01/11] hw/riscv/riscv-iommu.h: add missing headers Daniel Henrique Barboza
2025-02-24 2:08 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 02/11] hw/riscv/riscv-iommu-bits.h: HPM bits Daniel Henrique Barboza
2025-02-24 2:10 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 03/11] hw/riscv/riscv-iommu: add riscv-iommu-hpm file Daniel Henrique Barboza
2025-02-24 2:16 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 04/11] hw/riscv/riscv-iommu: add riscv_iommu_hpm_incr_ctr() Daniel Henrique Barboza
2025-02-24 2:50 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 05/11] hw/riscv/riscv-iommu: instantiate hpm_timer Daniel Henrique Barboza
2025-02-24 2:55 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 06/11] hw/riscv/riscv-iommu: add IOCOUNTINH mmio writes Daniel Henrique Barboza
2025-02-24 3:04 ` Alistair Francis
2024-12-05 13:29 ` [PATCH for-10.0 07/11] hw/riscv/riscv-iommu: add IOHPMCYCLES mmio write Daniel Henrique Barboza
2025-02-24 3:06 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 08/11] hw/riscv/riscv-iommu: add hpm events " Daniel Henrique Barboza
2025-02-24 3:31 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 09/11] hw/riscv/riscv-iommu.c: add RISCV_IOMMU_CAP_HPM cap Daniel Henrique Barboza
2025-02-24 3:32 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 10/11] hw/riscv: add IOMMU HPM trace events Daniel Henrique Barboza
2025-02-24 3:33 ` Alistair Francis
2024-12-05 13:30 ` [PATCH for-10.0 11/11] docs/specs/riscv-iommu.rst: add HPM support info Daniel Henrique Barboza
2025-02-24 3:34 ` Alistair Francis
2025-02-24 3:59 ` [PATCH for-10.0 00/11] riscv: IOMMU HPM support Alistair Francis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).