* [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
@ 2025-09-15 2:09 Yaxing Guo
2025-09-15 2:09 ` [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU " Yaxing Guo
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Yaxing Guo @ 2025-09-15 2:09 UTC (permalink / raw)
To: linux-riscv
Cc: iommu, tjeznach, joro, will, robin.murphy, paul.walmsley, palmer,
aou, alex, anxu, wangran, Yaxing Guo
This patch introduces a performance monitor driver for RISC-V IOMMU
iohpm implementions that support hardware performance counters.
The driver expose RISC-V-IOMMU-specific performance events (eg. cycles,
tlb miss ...)through the Linux perf subsystem, enabling developers
to profile and optimize I/O translation performance.
Key features:
- Implements a perf PMU driver for RISC-V IOMMU.
- Exposes IOMMU perf events, such as 'cycles', 'tlb_miss'... via
/sys/devices/riscv-iommu-pmu/events/, allowing use with perf
tools:
perf stat -C 0 -e riscv-iommu-pmu/cycles/ ...
perf stat -C 0 -e riscv-iommu-pmu/tlb_miss/ ...
...
- Supports event filtering through configureable attributes exposed
in /sys/devices/riscv-iommu-pmu/format/, including:
dv_gscv, pv_pscv,did_gscid,pid_pscid,idt (riscv iommu spec 5-23).
- Implements overflow interrupt handling.
- Adds device tree binding support via optional 'pmu-name' property
allowing platform-specific IOMMU implementations to specify a custom
defined event ID list. If not provided, the driver defaults to only
supporting 'cycles'. When set to 'dummy', it enables all 9 standard
event IDs as defined in riscv iommu spec(5-23).
Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
---
drivers/iommu/riscv/iommu-perf.c | 535 +++++++++++++++++++++++++++++++
drivers/iommu/riscv/iommu-perf.h | 88 +++++
drivers/iommu/riscv/iommu.h | 8 +
3 files changed, 631 insertions(+)
create mode 100644 drivers/iommu/riscv/iommu-perf.c
create mode 100644 drivers/iommu/riscv/iommu-perf.h
diff --git a/drivers/iommu/riscv/iommu-perf.c b/drivers/iommu/riscv/iommu-perf.c
new file mode 100644
index 000000000000..a9a8788a5776
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-perf.c
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IOMMU hpm implementations
+ * Copyright(c) 2025 Beijing Institute of Open Source Chip (BOSC)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/perf_event.h>
+#include <linux/iommu.h>
+#include "iommu.h"
+#include "iommu-perf.h"
+
+#define EVENT_CYCLES 0
+#define EVENT_UNTRANSLATED_REQ 1
+#define EVENT_TRANSLATED_REQUESTS 2
+#define EVENT_ATS_TRANSLATION_REQ 3
+#define EVENT_TLB_MISS 4
+#define EVENT_DDT_WALK 5
+#define EVENT_PDT_WALK 6
+#define EVENT_STAGE1_PT_WALK 7
+#define EVENT_STAGE2_PT_WALK 8
+
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(translated_req, "config=0x001")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(untranslated_req, "config=0x002")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(ats_translation_req, "config=0x003")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(tlb_miss, "config=0x004")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(ddt_walk, "config=0x005")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(pdt_walk, "config=0x006")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(stage1_pt_walk, "config=0x007")
+RISCV_IOMMU_PMU_EXT_EVENT_ATTR(stage2_pt_walk, "config=0x008")
+
+static const struct attribute_group *riscv_iommu_pmu_attr_update_dummy[] = {
+ &translated_req,
+ &untranslated_req,
+ &ats_translation_req,
+ &tlb_miss,
+ &ddt_walk,
+ &pdt_walk,
+ &stage1_pt_walk,
+ &stage2_pt_walk,
+ NULL
+};
+
+static struct riscv_iommu_pmu_event_map event_map[] = {
+ { "dummy", riscv_iommu_pmu_attr_update_dummy },
+ { NULL, NULL}
+};
+
+PMU_EVENT_ATTR_STRING(pv_pscv, format_pv_pscv_attr, "config1:0");
+PMU_EVENT_ATTR_STRING(dv_gscv, format_dv_gscv_attr, "config1:1");
+PMU_EVENT_ATTR_STRING(idt, format_idt_attr, "config1:2");
+PMU_EVENT_ATTR_STRING(pid_pscid, format_pid_pscid_attr, "config1:20-39");
+PMU_EVENT_ATTR_STRING(did_gscid, format_did_gscid_attr, "config1:40-63");
+
+static struct attribute *formats_attrs[] = {
+ &format_pv_pscv_attr.attr.attr,
+ &format_dv_gscv_attr.attr.attr,
+ &format_idt_attr.attr.attr,
+ &format_pid_pscid_attr.attr.attr,
+ &format_did_gscid_attr.attr.attr,
+ NULL
+};
+
+static struct attribute_group riscv_iommu_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = formats_attrs,
+};
+
+PMU_EVENT_ATTR_STRING(cycles, event_cycles_attr, "config=0x0");
+
+static struct attribute *events_attrs[] = {
+ &event_cycles_attr.attr.attr,
+ NULL
+};
+
+static struct attribute_group riscv_iommu_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = events_attrs,
+};
+
+static const struct attribute_group *riscv_iommu_pmu_attr_groups[] = {
+ &riscv_iommu_pmu_format_attr_group,
+ &riscv_iommu_pmu_events_attr_group,
+ NULL,
+};
+
+static void __riscv_iommu_pmu_unregister(struct riscv_iommu_pmu *iommu_pmu);
+static void riscv_iommu_pmu_read(struct perf_event *event);
+
+static void riscv_iommu_pmu_hpmevt_set(iohpmevt_t *hpmevt, unsigned long event_id,
+ int pv_pscv, int dv_gscv, int idt,
+ int pid_pscid, int did_gscid, int of)
+{
+ hpmevt->val = 0;
+ hpmevt->eventID = event_id;
+ hpmevt->IDT = idt;
+ hpmevt->OF = of;
+ hpmevt->PID_PSCID = pid_pscid;
+ hpmevt->DID_GSCID = did_gscid;
+ hpmevt->PV_PSCV = pv_pscv;
+ hpmevt->DV_GSCV = dv_gscv;
+}
+
+static struct riscv_iommu_perf_event *
+get_riscv_iommu_perf_event(struct riscv_iommu_pmu *iommu_pmu,
+ struct perf_event *event,
+ int pv_pscv, int dv_gscv, int idt,
+ int pid_pscid, int did_gscid,
+ int *idx)
+{
+ int i, nr;
+ struct riscv_iommu_device *iommu = iommu_pmu->iommu;
+ struct riscv_iommu_perf_event *iommu_event;
+
+ for (i = 0; i < RISCV_IOMMU_IOHPMCTR_CNT; i++) {
+ iommu_event = iommu->events[i];
+ if (iommu_event == NULL)
+ continue;
+
+ if (iommu_event->perf_event == event) {
+ nr = i;
+ goto update;
+ }
+ }
+
+ nr = find_first_zero_bit(&iommu->iohpmctr_bitmap,
+ RISCV_IOMMU_IOHPMCTR_CNT);
+ if (nr >= RISCV_IOMMU_IOHPMCTR_CNT)
+ return NULL;
+again:
+ if (test_and_set_bit(nr, &iommu_pmu->iommu->iohpmctr_bitmap))
+ goto again;
+
+ iommu_event = kzalloc(sizeof(struct riscv_iommu_perf_event), GFP_KERNEL);
+ if (!iommu_event)
+ return NULL;
+update:
+ iommu_event->perf_event = event;
+ iommu_event->pv_pscv = pv_pscv;
+ iommu_event->dv_gscv = dv_gscv;
+ iommu_event->idt = idt;
+ iommu_event->pid_pscid = pid_pscid;
+ iommu_event->did_gscid = did_gscid;
+ iommu->events[nr] = iommu_event;
+
+ *idx = nr;
+
+ return iommu_event;
+}
+
+static int riscv_iommu_pmu_event_add(struct riscv_iommu_pmu *iommu_pmu,
+ struct perf_event *event)
+{
+ int nr = -1, of;
+ unsigned long event_id = event->attr.config;
+ riscv_iommu_pmu_cfg1_t config1;
+ struct hw_perf_event *hwc = &event->hw;
+ struct riscv_iommu_device *iommu = iommu_pmu->iommu;
+
+ config1.val = event->attr.config1;
+
+ if (event_id >= RISCV_IOMMU_IOHPMCTR_CNT)
+ return -EINVAL;
+
+ if (iommu->hpm_irq)
+ of = 0;
+ else
+ of = 1;
+
+ if (event_id == EVENT_CYCLES) {
+ unsigned long val;
+
+ val = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES);
+ if (of)
+ val &= ~RISCV_IOMMU_IOHPMCYCLES_OF;
+ else
+ val |= RISCV_IOMMU_IOHPMCYCLES_OF;
+ riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES, val);
+
+ hwc->idx = 0;
+ iommu->events[0]->perf_event = event;
+ } else {
+ struct riscv_iommu_perf_event *iommu_perf_event;
+
+ iommu_perf_event = get_riscv_iommu_perf_event(iommu_pmu, event,
+ config1.pv_pscv, config1.dv_gscv,
+ config1.idt, config1.pid_pscid,
+ config1.did_gscid, &nr);
+ if (!iommu_perf_event)
+ return -ENOSPC;
+
+ riscv_iommu_pmu_hpmevt_set(&iommu_pmu->iommu->iohpmevt[nr], event_id,
+ iommu_perf_event->pv_pscv, iommu_perf_event->dv_gscv,
+ iommu_perf_event->idt, iommu_perf_event->pid_pscid,
+ iommu_perf_event->did_gscid, of);
+ riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMEVT(nr),
+ iommu_pmu->iommu->iohpmevt[nr].val);
+
+ hwc->idx = nr;
+ }
+
+ return 0;
+}
+
+static int riscv_iommu_pmu_hpmevt_idx_get(struct riscv_iommu_pmu *iommu_pmu, int event_id)
+{
+ int i;
+ iohpmevt_t *iohpmevt;
+
+ for (i = 0; i < RISCV_IOMMU_IOHPMCTR_CNT; i++) {
+ iohpmevt = &iommu_pmu->iommu->iohpmevt[i];
+ if (iohpmevt->eventID == event_id)
+ return iohpmevt - iommu_pmu->iommu->iohpmevt;
+ }
+
+ return -1;
+}
+
+static int riscv_iommu_event_del(struct riscv_iommu_pmu *iommu_pmu,
+ struct perf_event *event)
+{
+ unsigned long config = event->attr.config;
+ struct riscv_iommu_device *iommu = iommu_pmu->iommu;
+
+ if (config >= RISCV_IOMMU_IOHPMCTR_CNT)
+ return -EINVAL;
+
+ if (config == EVENT_CYCLES) {
+ iommu->events[0] = NULL;
+ } else {
+ int nr;
+
+ nr = riscv_iommu_pmu_hpmevt_idx_get(iommu_pmu, config);
+ if (-1 == nr)
+ return -1;
+ riscv_iommu_pmu_hpmevt_set(&iommu_pmu->iommu->iohpmevt[nr], 0,
+ 0, 0, 0, 0, 0, 0);
+ clear_bit(nr, &iommu_pmu->iommu->iohpmctr_bitmap);
+ riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMEVT(nr),
+ 0);
+ kfree(iommu->events[nr]);
+ iommu->events[nr] = NULL;
+ }
+
+ return 0;
+}
+
+static int riscv_iommu_pmu_event_init(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (event->attr.sample_period)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ hwc->config = event->attr.config;
+
+ return 0;
+}
+
+static void riscv_iommu_pmu_enable(struct pmu *pmu)
+{
+}
+
+static void riscv_iommu_pmu_disable(struct pmu *pmu)
+{
+}
+
+static void riscv_iommu_pmu_start(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_pmu *iommu_pmu = riscv_iommu_event_to_pmu(event);
+ struct hw_perf_event *hwc = &event->hw;
+ unsigned long count;
+
+ hwc->state = 0;
+
+ if (hwc->idx == EVENT_CYCLES)
+ count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES);
+ else
+ count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCTR(hwc->idx));
+
+ local64_set((&hwc->prev_count), count);
+
+ perf_event_update_userpage(event);
+}
+
+static void riscv_iommu_pmu_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!(hwc->state & PERF_HES_STOPPED)) {
+ riscv_iommu_pmu_read(event);
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+ }
+}
+
+static int riscv_iommu_pmu_add(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_pmu *iommu_pmu = riscv_iommu_event_to_pmu(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ riscv_iommu_pmu_event_add(iommu_pmu, event);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ riscv_iommu_pmu_start(event, 0);
+
+ return 0;
+}
+
+static void riscv_iommu_pmu_del(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_pmu *iommu_pmu = riscv_iommu_event_to_pmu(event);
+
+ riscv_iommu_pmu_stop(event, PERF_EF_UPDATE);
+
+ riscv_iommu_event_del(iommu_pmu, event);
+ event->hw.idx = -1;
+
+ perf_event_update_userpage(event);
+}
+
+static void riscv_iommu_pmu_read(struct perf_event *event)
+{
+ struct riscv_iommu_pmu *iommu_pmu = riscv_iommu_event_to_pmu(event);
+ struct hw_perf_event *hwc = &event->hw;
+ unsigned long prev_count, new_count, delta;
+
+again:
+ prev_count = local64_read(&hwc->prev_count);
+ if (hwc->idx == EVENT_CYCLES)
+ new_count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES);
+ else
+ new_count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCTR(hwc->idx));
+
+ if (local64_xchg(&hwc->prev_count, new_count) != prev_count)
+ goto again;
+ delta = new_count - prev_count;
+
+ local64_add(delta, &event->count);
+}
+
+int riscv_iommu_pmu_alloc(struct riscv_iommu_device *iommu)
+{
+ struct riscv_iommu_pmu *iommu_pmu;
+ struct riscv_iommu_perf_event *iommu_event;
+ int ret = 0;
+
+ if (iommu->pmu)
+ return -EEXIST;
+
+ iommu_pmu = kzalloc(sizeof(struct riscv_iommu_pmu), GFP_KERNEL);
+ if (!iommu_pmu)
+ return -ENOMEM;
+
+ iommu_pmu->iommu = iommu;
+ iommu->pmu = iommu_pmu;
+
+ set_bit(0, &iommu_pmu->iommu->iohpmctr_bitmap);
+ iommu_event = kzalloc(sizeof(struct riscv_iommu_perf_event), GFP_KERNEL);
+ if (!iommu_event) {
+ ret = -ENOMEM;
+ goto free_pmu;
+ }
+ iommu->events[0] = iommu_event;
+
+ return 0;
+
+free_pmu:
+ kfree(iommu_pmu);
+ return ret;
+}
+
+static void riscv_iommu_pmu_do_overflow(struct riscv_iommu_device *iommu)
+{
+ int idx;
+ struct riscv_iommu_perf_event *iommu_event;
+
+ for_each_set_bit(idx, &iommu->iohpmctr_bitmap,
+ RISCV_IOMMU_IOHPMCTR_CNT) {
+ iohpmevt_t hpmevt;
+ unsigned int val;
+
+ if (idx == 0)
+ continue;
+ iommu_event = iommu->events[idx];
+ if (!iommu_event)
+ continue;
+ hpmevt.val = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_IOHPMEVT(idx));
+ if (hpmevt.OF) {
+ riscv_iommu_pmu_read(iommu_event->perf_event);
+
+ hpmevt.OF = 0;
+ riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_IOHPMEVT(idx), hpmevt.val);
+
+ val = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_IPSR);
+ val &= ~RISCV_IOMMU_IPSR_PMIP;
+ riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, val);
+ }
+ }
+}
+
+static irqreturn_t riscv_iommu_pmu_irq_handler(int irq, void *data)
+{
+ struct riscv_iommu_device *iommu = (struct riscv_iommu_device *)data;
+
+ riscv_iommu_pmu_do_overflow(iommu);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t riscv_iommu_pmu_ipsr(int irq, void *data)
+{
+ struct riscv_iommu_device *iommu = (struct riscv_iommu_device *)data;
+
+ if (riscv_iommu_readl(iommu, RISCV_IOMMU_REG_IPSR) & RISCV_IOMMU_IPSR_PMIP)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+static int riscv_iommu_pmu_vec(struct riscv_iommu_device *iommu)
+{
+ return FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec);
+}
+
+static int riscv_iommu_pmu_set_irq(struct riscv_iommu_device *iommu)
+{
+ int irq, ret;
+
+ if (!iommu)
+ return -EINVAL;
+ irq = iommu->irqs[riscv_iommu_pmu_vec(iommu)];
+ if (!irq)
+ return -EEXIST;
+ iommu->hpm_irq = irq;
+
+ ret = request_threaded_irq(irq, riscv_iommu_pmu_ipsr,
+ riscv_iommu_pmu_irq_handler,
+ IRQF_ONESHOT, "rv-iommu-pmu-irq", iommu);
+ if (ret) {
+ iommu->hpm_irq = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct attribute_group **
+riscv_iommu_get_ext_attr(struct riscv_iommu_pmu *iommu_pmu)
+{
+ struct riscv_iommu_pmu_event_map *map = event_map;
+ const char *str;
+ struct device *dev = iommu_pmu->iommu->dev;
+
+ if (of_property_read_string(dev->of_node, "pmu-name", &str))
+ return NULL;
+
+ while (map->compatible) {
+ if (!strcmp(map->compatible, str))
+ return map->attr_group;
+ }
+
+ return NULL;
+}
+
+static int __riscv_iommu_pmu_register(struct riscv_iommu_pmu *iommu_pmu,
+ const char *name)
+{
+ int ret;
+
+ if (!iommu_pmu)
+ return -EINVAL;
+
+ iommu_pmu->pmu.attr_groups = riscv_iommu_pmu_attr_groups;
+ iommu_pmu->pmu.attr_update = riscv_iommu_get_ext_attr(iommu_pmu);
+ iommu_pmu->pmu.task_ctx_nr = perf_invalid_context;
+ iommu_pmu->pmu.event_init = riscv_iommu_pmu_event_init;
+ iommu_pmu->pmu.pmu_enable = riscv_iommu_pmu_enable;
+ iommu_pmu->pmu.pmu_disable = riscv_iommu_pmu_disable;
+ iommu_pmu->pmu.add = riscv_iommu_pmu_add;
+ iommu_pmu->pmu.del = riscv_iommu_pmu_del;
+ iommu_pmu->pmu.start = riscv_iommu_pmu_start;
+ iommu_pmu->pmu.stop = riscv_iommu_pmu_stop;
+ iommu_pmu->pmu.read = riscv_iommu_pmu_read;
+
+ ret = perf_pmu_register(&iommu_pmu->pmu, name, -1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __riscv_iommu_pmu_unregister(struct riscv_iommu_pmu *iommu_pmu)
+{
+ if (!iommu_pmu)
+ return;
+
+ perf_pmu_unregister(&iommu_pmu->pmu);
+
+ kfree(iommu_pmu->iommu->events[0]);
+ kfree(iommu_pmu);
+}
+
+int riscv_iommu_pmu_register(struct riscv_iommu_device *iommu)
+{
+ int ret;
+
+ ret = __riscv_iommu_pmu_register(iommu->pmu, "riscv-iommu-pmu");
+ if (ret)
+ goto err;
+
+ ret = riscv_iommu_pmu_set_irq(iommu);
+ if (ret)
+ goto unregister;
+
+ return 0;
+
+unregister:
+ riscv_iommu_pmu_unregister(iommu);
+err:
+ return ret;
+}
+
+void riscv_iommu_pmu_unregister(struct riscv_iommu_device *iommu)
+{
+ __riscv_iommu_pmu_unregister(iommu->pmu);
+
+ iommu->pmu = NULL;
+}
diff --git a/drivers/iommu/riscv/iommu-perf.h b/drivers/iommu/riscv/iommu-perf.h
new file mode 100644
index 000000000000..5c4cc7b9a978
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-perf.h
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IOMMU hpm implementations
+ * Copyright(c) 2025 Beijing Institute of Open Source Chip (BOSC)
+ */
+
+#ifndef __IOMMU_PERF_H__
+#define __IOMMU_PERF_H__
+
+#include <linux/sysfs.h>
+#include <linux/perf_event.h>
+#include <linux/bitops.h>
+
+typedef union {
+ struct {
+ unsigned long eventID:15;
+ unsigned long DMASK:1;
+ unsigned long PID_PSCID:20;
+ unsigned long DID_GSCID:24;
+ unsigned long PV_PSCV:1;
+ unsigned long DV_GSCV:1;
+ unsigned long IDT:1;
+ unsigned long OF:1;
+ };
+ unsigned long val;
+} iohpmevt_t;
+
+typedef union {
+ struct {
+ unsigned long pv_pscv:1;
+ unsigned long dv_gscv:1;
+ unsigned long idt:1;
+ unsigned long reserved:17;
+ unsigned long pid_pscid:20;
+ unsigned long did_gscid:24;
+ };
+ unsigned long val;
+} riscv_iommu_pmu_cfg1_t;
+
+struct riscv_iommu_pmu_event_map {
+ const char *compatible;
+ const struct attribute_group **attr_group;
+};
+
+#define RISCV_IOMMU_IOHPMCTR_CNT 32
+
+struct riscv_iommu_perf_event {
+ int pv_pscv;
+ int dv_gscv;
+ int idt;
+ int pid_pscid;
+ int did_gscid;
+ struct perf_event *perf_event;
+};
+
+struct riscv_iommu_pmu {
+ struct riscv_iommu_device *iommu;
+ struct pmu pmu;
+};
+
+static inline struct riscv_iommu_pmu *dev_to_riscv_iommu_pmu(struct device *dev)
+{
+ return container_of(dev_get_drvdata(dev), struct riscv_iommu_pmu, pmu);
+}
+
+static inline struct riscv_iommu_pmu *riscv_iommu_event_to_pmu(struct perf_event *event)
+{
+ return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
+}
+
+#define RISCV_IOMMU_PMU_EXT_EVENT_ATTR(_name, _string) \
+ PMU_EVENT_ATTR_STRING(_name, event_attr_##_name, _string) \
+ \
+static struct attribute *_name##_attr[] = { \
+ &event_attr_##_name.attr.attr, \
+ NULL \
+}; \
+ \
+static struct attribute_group _name = { \
+ .name = "events", \
+ .attrs = _name##_attr, \
+};
+
+int riscv_iommu_pmu_alloc(struct riscv_iommu_device *iommu);
+int riscv_iommu_pmu_register(struct riscv_iommu_device *iommu);
+void riscv_iommu_pmu_unregister(struct riscv_iommu_device *iommu);
+
+#endif
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..1eabe04dbbc1 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,8 +14,10 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/iopoll.h>
+#include <linux/perf_event.h>
#include "iommu-bits.h"
+#include "iommu-perf.h"
struct riscv_iommu_device;
@@ -60,6 +62,12 @@ struct riscv_iommu_device {
unsigned int ddt_mode;
dma_addr_t ddt_phys;
u64 *ddt_root;
+
+ iohpmevt_t iohpmevt[RISCV_IOMMU_IOHPMCTR_CNT];
+ unsigned long iohpmctr_bitmap;
+ struct riscv_iommu_pmu *pmu;
+ int hpm_irq;
+ struct riscv_iommu_perf_event *events[RISCV_IOMMU_IOHPMCTR_CNT];
};
int riscv_iommu_init(struct riscv_iommu_device *iommu);
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU perf driver
2025-09-15 2:09 [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Yaxing Guo
@ 2025-09-15 2:09 ` Yaxing Guo
2025-09-16 3:40 ` kernel test robot
2025-09-15 2:09 ` [PATCH v1 3/3] iommu/riscv: Register RISC-V IOMMU PMU at init time Yaxing Guo
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Yaxing Guo @ 2025-09-15 2:09 UTC (permalink / raw)
To: linux-riscv
Cc: iommu, tjeznach, joro, will, robin.murphy, paul.walmsley, palmer,
aou, alex, anxu, wangran, Yaxing Guo
Add compilation rules for iommu-perf.o to support
the new RISC-V IOMMU perf driver.
Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
---
drivers/iommu/riscv/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
index b5929f9f23e6..5e9c7c1ed928 100644
--- a/drivers/iommu/riscv/Makefile
+++ b/drivers/iommu/riscv/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += iommu.o iommu-platform.o
+obj-y += iommu.o iommu-platform.o iommu-perf.o
obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU perf driver
2025-09-15 2:09 ` [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU " Yaxing Guo
@ 2025-09-16 3:40 ` kernel test robot
0 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2025-09-16 3:40 UTC (permalink / raw)
To: Yaxing Guo, linux-riscv
Cc: llvm, oe-kbuild-all, iommu, tjeznach, joro, will, robin.murphy,
paul.walmsley, palmer, aou, alex, anxu, wangran, Yaxing Guo
Hi Yaxing,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.17-rc6 next-20250915]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yaxing-Guo/iommu-riscv-Add-Makefile-support-for-RISC-V-IOMMU-perf-driver/20250915-101640
base: linus/master
patch link: https://lore.kernel.org/r/20250915020911.1313-2-guoyaxing%40bosc.ac.cn
patch subject: [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU perf driver
:::::: branch date: 25 hours ago
:::::: commit date: 25 hours ago
config: riscv-randconfig-001-20250916 (https://download.01.org/0day-ci/archive/20250916/202509161121.SHWsStQM-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 65ad21d730d25789454d18e811f8ff5db79cb5d4)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250916/202509161121.SHWsStQM-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202509161121.SHWsStQM-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/iommu/riscv/iommu-perf.c:12:
In file included from drivers/iommu/riscv/iommu.h:20:
drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:157:34: error: no member named 'attr' in 'struct perf_event'
157 | unsigned long event_id = event->attr.config;
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:159:38: error: no member named 'hw' in 'struct perf_event'
159 | struct hw_perf_event *hwc = &event->hw;
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.c:162:23: error: no member named 'attr' in 'struct perf_event'
162 | config1.val = event->attr.config1;
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:182:8: error: no member named 'idx' in 'struct hw_perf_event'
182 | hwc->idx = 0;
| ~~~ ^
drivers/iommu/riscv/iommu-perf.c:201:8: error: no member named 'idx' in 'struct hw_perf_event'
201 | hwc->idx = nr;
| ~~~ ^
drivers/iommu/riscv/iommu-perf.c:224:32: error: no member named 'attr' in 'struct perf_event'
224 | unsigned long config = event->attr.config;
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.c:252:38: error: no member named 'hw' in 'struct perf_event'
252 | struct hw_perf_event *hwc = &event->hw;
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.c:254:13: error: no member named 'attr' in 'struct perf_event'
254 | if (event->attr.sample_period)
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:257:13: error: no member named 'cpu' in 'struct perf_event'
257 | if (event->cpu < 0)
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:260:7: error: no member named 'config' in 'struct hw_perf_event'
260 | hwc->config = event->attr.config;
| ~~~ ^
drivers/iommu/riscv/iommu-perf.c:260:23: error: no member named 'attr' in 'struct perf_event'
260 | hwc->config = event->attr.config;
| ~~~~~ ^
drivers/iommu/riscv/iommu-perf.c:276:38: error: no member named 'hw' in 'struct perf_event'
276 | struct hw_perf_event *hwc = &event->hw;
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:279:7: error: no member named 'state' in 'struct hw_perf_event'
279 | hwc->state = 0;
| ~~~ ^
drivers/iommu/riscv/iommu-perf.c:281:11: error: no member named 'idx' in 'struct hw_perf_event'
281 | if (hwc->idx == EVENT_CYCLES)
| ~~~ ^
drivers/iommu/riscv/iommu-perf.c:284:77: error: no member named 'idx' in 'struct hw_perf_event'
284 | count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCTR(hwc->idx));
| ~~~ ^
>> drivers/iommu/riscv/iommu-perf.c:286:21: error: no member named 'prev_count' in 'struct hw_perf_event'
286 | local64_set((&hwc->prev_count), count);
| ~~~ ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
vim +157 drivers/iommu/riscv/iommu-perf.c
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 152
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 153 static int riscv_iommu_pmu_event_add(struct riscv_iommu_pmu *iommu_pmu,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 154 struct perf_event *event)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 155 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 156 int nr = -1, of;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @157 unsigned long event_id = event->attr.config;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 158 riscv_iommu_pmu_cfg1_t config1;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @159 struct hw_perf_event *hwc = &event->hw;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 160 struct riscv_iommu_device *iommu = iommu_pmu->iommu;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 161
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 162 config1.val = event->attr.config1;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 163
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 164 if (event_id >= RISCV_IOMMU_IOHPMCTR_CNT)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 165 return -EINVAL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 166
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 167 if (iommu->hpm_irq)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 168 of = 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 169 else
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 170 of = 1;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 171
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 172 if (event_id == EVENT_CYCLES) {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 173 unsigned long val;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 174
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 175 val = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 176 if (of)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 177 val &= ~RISCV_IOMMU_IOHPMCYCLES_OF;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 178 else
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 179 val |= RISCV_IOMMU_IOHPMCYCLES_OF;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 180 riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES, val);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 181
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @182 hwc->idx = 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 183 iommu->events[0]->perf_event = event;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 184 } else {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 185 struct riscv_iommu_perf_event *iommu_perf_event;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 186
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 187 iommu_perf_event = get_riscv_iommu_perf_event(iommu_pmu, event,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 188 config1.pv_pscv, config1.dv_gscv,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 189 config1.idt, config1.pid_pscid,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 190 config1.did_gscid, &nr);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 191 if (!iommu_perf_event)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 192 return -ENOSPC;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 193
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 194 riscv_iommu_pmu_hpmevt_set(&iommu_pmu->iommu->iohpmevt[nr], event_id,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 195 iommu_perf_event->pv_pscv, iommu_perf_event->dv_gscv,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 196 iommu_perf_event->idt, iommu_perf_event->pid_pscid,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 197 iommu_perf_event->did_gscid, of);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 198 riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMEVT(nr),
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 199 iommu_pmu->iommu->iohpmevt[nr].val);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 200
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 201 hwc->idx = nr;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 202 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 203
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 204 return 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 205 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 206
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 207 static int riscv_iommu_pmu_hpmevt_idx_get(struct riscv_iommu_pmu *iommu_pmu, int event_id)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 208 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 209 int i;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 210 iohpmevt_t *iohpmevt;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 211
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 212 for (i = 0; i < RISCV_IOMMU_IOHPMCTR_CNT; i++) {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 213 iohpmevt = &iommu_pmu->iommu->iohpmevt[i];
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 214 if (iohpmevt->eventID == event_id)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 215 return iohpmevt - iommu_pmu->iommu->iohpmevt;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 216 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 217
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 218 return -1;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 219 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 220
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 221 static int riscv_iommu_event_del(struct riscv_iommu_pmu *iommu_pmu,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 222 struct perf_event *event)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 223 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @224 unsigned long config = event->attr.config;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 225 struct riscv_iommu_device *iommu = iommu_pmu->iommu;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 226
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 227 if (config >= RISCV_IOMMU_IOHPMCTR_CNT)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 228 return -EINVAL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 229
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 230 if (config == EVENT_CYCLES) {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 231 iommu->events[0] = NULL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 232 } else {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 233 int nr;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 234
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 235 nr = riscv_iommu_pmu_hpmevt_idx_get(iommu_pmu, config);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 236 if (-1 == nr)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 237 return -1;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 238 riscv_iommu_pmu_hpmevt_set(&iommu_pmu->iommu->iohpmevt[nr], 0,
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 239 0, 0, 0, 0, 0, 0);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 240 clear_bit(nr, &iommu_pmu->iommu->iohpmctr_bitmap);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 241 riscv_iommu_writeq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMEVT(nr),
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 242 0);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 243 kfree(iommu->events[nr]);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 244 iommu->events[nr] = NULL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 245 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 246
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 247 return 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 248 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 249
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 250 static int riscv_iommu_pmu_event_init(struct perf_event *event)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 251 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @252 struct hw_perf_event *hwc = &event->hw;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 253
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 254 if (event->attr.sample_period)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 255 return -EINVAL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 256
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @257 if (event->cpu < 0)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 258 return -EINVAL;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 259
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @260 hwc->config = event->attr.config;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 261
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 262 return 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 263 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 264
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 265 static void riscv_iommu_pmu_enable(struct pmu *pmu)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 266 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 267 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 268
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 269 static void riscv_iommu_pmu_disable(struct pmu *pmu)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 270 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 271 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 272
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 273 static void riscv_iommu_pmu_start(struct perf_event *event, int flags)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 274 {
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 275 struct riscv_iommu_pmu *iommu_pmu = riscv_iommu_event_to_pmu(event);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 276 struct hw_perf_event *hwc = &event->hw;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 277 unsigned long count;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 278
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @279 hwc->state = 0;
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 280
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 281 if (hwc->idx == EVENT_CYCLES)
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 282 count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCYCLES);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 283 else
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 284 count = riscv_iommu_readq(iommu_pmu->iommu, RISCV_IOMMU_REG_IOHPMCTR(hwc->idx));
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 285
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 @286 local64_set((&hwc->prev_count), count);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 287
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 288 perf_event_update_userpage(event);
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 289 }
8cf5fb280f5fc0 Yaxing Guo 2025-09-15 290
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v1 3/3] iommu/riscv: Register RISC-V IOMMU PMU at init time
2025-09-15 2:09 [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Yaxing Guo
2025-09-15 2:09 ` [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU " Yaxing Guo
@ 2025-09-15 2:09 ` Yaxing Guo
2025-09-15 10:38 ` [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Will Deacon
2025-09-16 1:47 ` kernel test robot
3 siblings, 0 replies; 10+ messages in thread
From: Yaxing Guo @ 2025-09-15 2:09 UTC (permalink / raw)
To: linux-riscv
Cc: iommu, tjeznach, joro, will, robin.murphy, paul.walmsley, palmer,
aou, alex, anxu, wangran, Yaxing Guo
Register the RISC-V IOMMU driver during IOMMU driver
initialization.
Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
---
drivers/iommu/riscv/iommu.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 0eae2f4bdc5e..453d04b03c6c 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -23,6 +23,7 @@
#include "../iommu-pages.h"
#include "iommu-bits.h"
#include "iommu.h"
+#include "iommu-perf.h"
/* Timeouts in [us] */
#define RISCV_IOMMU_QCSR_TIMEOUT 150000
@@ -1604,6 +1605,7 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu)
riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
riscv_iommu_queue_disable(&iommu->cmdq);
riscv_iommu_queue_disable(&iommu->fltq);
+ riscv_iommu_pmu_unregister(iommu);
}
int riscv_iommu_init(struct riscv_iommu_device *iommu)
@@ -1656,6 +1658,14 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
goto err_remove_sysfs;
}
+ rc = riscv_iommu_pmu_alloc(iommu);
+ if (rc) {
+ dev_err(iommu->dev, "cannot alloc iommu pmu (%d)\n", rc);
+ iommu_device_sysfs_remove(&iommu->iommu);
+ goto err_remove_sysfs;
+ }
+ riscv_iommu_pmu_register(iommu);
+
return 0;
err_remove_sysfs:
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-15 2:09 [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Yaxing Guo
2025-09-15 2:09 ` [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU " Yaxing Guo
2025-09-15 2:09 ` [PATCH v1 3/3] iommu/riscv: Register RISC-V IOMMU PMU at init time Yaxing Guo
@ 2025-09-15 10:38 ` Will Deacon
2025-09-16 10:27 ` guoyaxing
2025-09-16 1:47 ` kernel test robot
3 siblings, 1 reply; 10+ messages in thread
From: Will Deacon @ 2025-09-15 10:38 UTC (permalink / raw)
To: Yaxing Guo
Cc: linux-riscv, iommu, tjeznach, joro, robin.murphy, paul.walmsley,
palmer, aou, alex, anxu, wangran
On Mon, Sep 15, 2025 at 10:09:09AM +0800, Yaxing Guo wrote:
> This patch introduces a performance monitor driver for RISC-V IOMMU
> iohpm implementions that support hardware performance counters.
> The driver expose RISC-V-IOMMU-specific performance events (eg. cycles,
> tlb miss ...)through the Linux perf subsystem, enabling developers
> to profile and optimize I/O translation performance.
>
> Key features:
> - Implements a perf PMU driver for RISC-V IOMMU.
>
> - Exposes IOMMU perf events, such as 'cycles', 'tlb_miss'... via
> /sys/devices/riscv-iommu-pmu/events/, allowing use with perf
> tools:
> perf stat -C 0 -e riscv-iommu-pmu/cycles/ ...
> perf stat -C 0 -e riscv-iommu-pmu/tlb_miss/ ...
> ...
> - Supports event filtering through configureable attributes exposed
> in /sys/devices/riscv-iommu-pmu/format/, including:
> dv_gscv, pv_pscv,did_gscid,pid_pscid,idt (riscv iommu spec 5-23).
>
> - Implements overflow interrupt handling.
>
> - Adds device tree binding support via optional 'pmu-name' property
> allowing platform-specific IOMMU implementations to specify a custom
> defined event ID list. If not provided, the driver defaults to only
> supporting 'cycles'. When set to 'dummy', it enables all 9 standard
> event IDs as defined in riscv iommu spec(5-23).
>
> Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
> ---
> drivers/iommu/riscv/iommu-perf.c | 535 +++++++++++++++++++++++++++++++
> drivers/iommu/riscv/iommu-perf.h | 88 +++++
> drivers/iommu/riscv/iommu.h | 8 +
> 3 files changed, 631 insertions(+)
> create mode 100644 drivers/iommu/riscv/iommu-perf.c
> create mode 100644 drivers/iommu/riscv/iommu-perf.h
PMU drivers are better placed under drivers/perf/
(the Arm SMMUv3 PMU driver lives there, for example).
Will
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-15 10:38 ` [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Will Deacon
@ 2025-09-16 10:27 ` guoyaxing
2025-09-17 12:10 ` Will Deacon
0 siblings, 1 reply; 10+ messages in thread
From: guoyaxing @ 2025-09-16 10:27 UTC (permalink / raw)
To: will
Cc: linux-riscv, iommu, tjeznach, joro, robin.murphy, paul.walmsley,
palmer, aou, alex, anxu, wangran
Hi, Will
From: Will Deacon
Date: 2025-09-15 18:38
To: Yaxing Guo
CC: linux-riscv; iommu; tjeznach; joro; robin.murphy; paul.walmsley; palmer; aou; alex; anxu; wangran
Subject: Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
On Mon, Sep 15, 2025 at 10:09:09AM +0800, Yaxing Guo wrote:
>> This patch introduces a performance monitor driver for RISC-V IOMMU
>> iohpm implementions that support hardware performance counters.
>> The driver expose RISC-V-IOMMU-specific performance events (eg. cycles,
>> tlb miss ...)through the Linux perf subsystem, enabling developers
>> to profile and optimize I/O translation performance.
>>
>> Key features:
>> - Implements a perf PMU driver for RISC-V IOMMU.
>>
>> - Exposes IOMMU perf events, such as 'cycles', 'tlb_miss'... via
>> /sys/devices/riscv-iommu-pmu/events/, allowing use with perf
>> tools:
>> perf stat -C 0 -e riscv-iommu-pmu/cycles/ ...
>> perf stat -C 0 -e riscv-iommu-pmu/tlb_miss/ ...
>> ...
>> - Supports event filtering through configureable attributes exposed
>> in /sys/devices/riscv-iommu-pmu/format/, including:
>> dv_gscv, pv_pscv,did_gscid,pid_pscid,idt (riscv iommu spec 5-23).
>>
>> - Implements overflow interrupt handling.
>>
>> - Adds device tree binding support via optional 'pmu-name' property
>> allowing platform-specific IOMMU implementations to specify a custom
>> defined event ID list. If not provided, the driver defaults to only
>> supporting 'cycles'. When set to 'dummy', it enables all 9 standard
>> event IDs as defined in riscv iommu spec(5-23).
>>
>> Signed-off-by: Yaxing Guo <guoyaxing@bosc.ac.cn>
>> ---
>> drivers/iommu/riscv/iommu-perf.c | 535 +++++++++++++++++++++++++++++++
>> drivers/iommu/riscv/iommu-perf.h | 88 +++++
>> drivers/iommu/riscv/iommu.h | 8 +
>> 3 files changed, 631 insertions(+)
>> create mode 100644 drivers/iommu/riscv/iommu-perf.c
>> create mode 100644 drivers/iommu/riscv/iommu-perf.h
> PMU drivers are better placed under drivers/perf/
> (the Arm SMMUv3 PMU driver lives there, for example).
I did a quick reading of SMMU pmu driver in drivers/perf/. However, If the RISC-V IOMMU PMU driver is placed under drivers/perf/ as the SMMU did, it would cause an overlap in the iomem resource region between the two devices(iommu & iommu pmu), because it needs to share interrupt-related registers (such as the IPSR register) with the main IOMMU driver.
Yaxing Guo
> Will
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-16 10:27 ` guoyaxing
@ 2025-09-17 12:10 ` Will Deacon
2025-09-18 3:20 ` 郭亚星
0 siblings, 1 reply; 10+ messages in thread
From: Will Deacon @ 2025-09-17 12:10 UTC (permalink / raw)
To: guoyaxing@bosc.ac.cn
Cc: linux-riscv, iommu, tjeznach, joro, robin.murphy, paul.walmsley,
palmer, aou, alex, anxu, wangran
[nit: your email client has made a big mess of the thread here]
On Tue, Sep 16, 2025 at 06:27:23PM +0800, guoyaxing@bosc.ac.cn wrote:
> > PMU drivers are better placed under drivers/perf/
>
> I did a quick reading of SMMU pmu driver in drivers/perf/. However, If
> the RISC-V IOMMU PMU driver is placed under drivers/perf/ as the SMMU did,
> it would cause an overlap in the iomem resource region between the two
> devices(iommu & iommu pmu), because it needs to share interrupt-related
> registers (such as the IPSR register) with the main IOMMU driver.
Is that not something you can resolve with IRQF_SHARED?
Will
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-17 12:10 ` Will Deacon
@ 2025-09-18 3:20 ` 郭亚星
2025-09-18 14:20 ` Will Deacon
0 siblings, 1 reply; 10+ messages in thread
From: 郭亚星 @ 2025-09-18 3:20 UTC (permalink / raw)
To: Will Deacon
Cc: linux-riscv, iommu, tjeznach, joro, robin.murphy, paul.walmsley,
palmer, aou, alex, anxu, wangran
[Sorry, I tried switching a new email client and made some settings...]
On 9/17/2025 8:10 PM, Will Deacon wrote:
> [nit: your email client has made a big mess of the thread here]
>
> On Tue, Sep 16, 2025 at 06:27:23PM +0800, guoyaxing@bosc.ac.cn wrote:
>>> PMU drivers are better placed under drivers/perf/
>>
>> I did a quick reading of SMMU pmu driver in drivers/perf/. However, If
>> the RISC-V IOMMU PMU driver is placed under drivers/perf/ as the SMMU did,
>> it would cause an overlap in the iomem resource region between the two
>> devices(iommu & iommu pmu), because it needs to share interrupt-related
>> registers (such as the IPSR register) with the main IOMMU driver.
>
> Is that not something you can resolve with IRQF_SHARED?
>
Actually IOMMU perf is using stand-along interrupt, so might not need
IRQF_SHARED with IOMMU driver.
What I mean is the IOMMU and IOMMU perf share the same registers, such
as IPSR. This could result in overlap on this iomem regions between
them, which is highly undesirable.
For now, two ideas come to my mind:
1. Integrate IOMMU perf functionality into IOMMU driver, just as
previous version patch.
2. Let IOMMU driver export external api for IOMMU perf
(to obtain virtual address of IPSR register) for perf related operations.
So what's your suggestion?
> Will
Yaxing Guo
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-18 3:20 ` 郭亚星
@ 2025-09-18 14:20 ` Will Deacon
0 siblings, 0 replies; 10+ messages in thread
From: Will Deacon @ 2025-09-18 14:20 UTC (permalink / raw)
To: 郭亚星
Cc: linux-riscv, iommu, tjeznach, joro, robin.murphy, paul.walmsley,
palmer, aou, alex, anxu, wangran
On Thu, Sep 18, 2025 at 11:20:55AM +0800, 郭亚星 wrote:
> [Sorry, I tried switching a new email client and made some settings...]
>
> On 9/17/2025 8:10 PM, Will Deacon wrote:
> > [nit: your email client has made a big mess of the thread here]
> >
> > On Tue, Sep 16, 2025 at 06:27:23PM +0800, guoyaxing@bosc.ac.cn wrote:
> > > > PMU drivers are better placed under drivers/perf/
> > >
> > > I did a quick reading of SMMU pmu driver in drivers/perf/. However, If
> > > the RISC-V IOMMU PMU driver is placed under drivers/perf/ as the SMMU did,
> > > it would cause an overlap in the iomem resource region between the two
> > > devices(iommu & iommu pmu), because it needs to share interrupt-related
> > > registers (such as the IPSR register) with the main IOMMU driver.
> >
> > Is that not something you can resolve with IRQF_SHARED?
> >
>
> Actually IOMMU perf is using stand-along interrupt, so might not need
> IRQF_SHARED with IOMMU driver.
Hrm. Two separate interrupts that share the same interrupt-handling
registers is an "interesting" design for a piece of hardware :/
> What I mean is the IOMMU and IOMMU perf share the same registers, such as
> IPSR. This could result in overlap on this iomem regions between them, which
> is highly undesirable.
>
> For now, two ideas come to my mind:
> 1. Integrate IOMMU perf functionality into IOMMU driver, just as previous
> version patch.
>
> 2. Let IOMMU driver export external api for IOMMU perf
> (to obtain virtual address of IPSR register) for perf related operations.
>
> So what's your suggestion?
I wonder if you could create the PMU device as a child of the IOMMU?
I'm sure Robin had fun dealing with shared MMIO regions before, but I
can't remember the details (was it the CMN PMU driver?)
Will
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
2025-09-15 2:09 [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Yaxing Guo
` (2 preceding siblings ...)
2025-09-15 10:38 ` [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Will Deacon
@ 2025-09-16 1:47 ` kernel test robot
3 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2025-09-16 1:47 UTC (permalink / raw)
To: Yaxing Guo, linux-riscv
Cc: llvm, oe-kbuild-all, iommu, tjeznach, joro, will, robin.murphy,
paul.walmsley, palmer, aou, alex, anxu, wangran, Yaxing Guo
Hi Yaxing,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.17-rc6 next-20250912]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yaxing-Guo/iommu-riscv-Add-Makefile-support-for-RISC-V-IOMMU-perf-driver/20250915-101640
base: linus/master
patch link: https://lore.kernel.org/r/20250915020911.1313-1-guoyaxing%40bosc.ac.cn
patch subject: [PATCH v1 1/3] iommu/riscv: Add iommu perf driver
config: riscv-randconfig-001-20250916 (https://download.01.org/0day-ci/archive/20250916/202509160926.OINmzlTz-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 65ad21d730d25789454d18e811f8ff5db79cb5d4)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250916/202509160926.OINmzlTz-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509160926.OINmzlTz-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/iommu/riscv/iommu-pci.c:21:
In file included from drivers/iommu/riscv/iommu.h:20:
>> drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
>> drivers/iommu/riscv/iommu-perf.h:68:29: error: no member named 'pmu' in 'struct perf_event'
68 | return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
| ~~~~~ ^
3 errors generated.
vim +68 drivers/iommu/riscv/iommu-perf.h
65
66 static inline struct riscv_iommu_pmu *riscv_iommu_event_to_pmu(struct perf_event *event)
67 {
> 68 return container_of(event->pmu, struct riscv_iommu_pmu, pmu);
69 }
70
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-09-18 14:20 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-15 2:09 [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Yaxing Guo
2025-09-15 2:09 ` [PATCH v1 2/3] iommu/riscv: Add Makefile support for RISC-V IOMMU " Yaxing Guo
2025-09-16 3:40 ` kernel test robot
2025-09-15 2:09 ` [PATCH v1 3/3] iommu/riscv: Register RISC-V IOMMU PMU at init time Yaxing Guo
2025-09-15 10:38 ` [PATCH v1 1/3] iommu/riscv: Add iommu perf driver Will Deacon
2025-09-16 10:27 ` guoyaxing
2025-09-17 12:10 ` Will Deacon
2025-09-18 3:20 ` 郭亚星
2025-09-18 14:20 ` Will Deacon
2025-09-16 1:47 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox