[PATCH v3 5/8] riscv/iommu: Add vendor event support for RISC-V IOMMU HPM

Lv Zheng
2026-02-04T09:09:56Z

Adds mechanism to allow vendor events to be registered via userspace
jevents. By default, vendor event identifier matches "riscv,iommu", and
the events are registered as "riscv_iommu_hpm" events.

Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-hpm.c | 63 +++++++++++++++++++++++++++++++++
drivers/iommu/riscv/iommu.h | 1 +
2 files changed, 64 insertions(+)

diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index f1b265634e51..e140cf59c408 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -447,6 +447,30 @@ static const struct attribute_group riscv_iommu_hpm_cpumask_group = {
.attrs = riscv_iommu_hpm_cpumask_attrs,
};

+static ssize_t riscv_iommu_hpm_identifier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+
+ if (!iommu_hpm->identifier)
+ return 0;
+
+ return sysfs_emit(buf, "%s\n", iommu_hpm->identifier);
+}
+
+static struct device_attribute riscv_iommu_hpm_identifier_attr =
+ __ATTR(identifier, 0444, riscv_iommu_hpm_identifier_show, NULL);
+
+static struct attribute *riscv_iommu_hpm_identifier_attrs[] = {
+ &riscv_iommu_hpm_identifier_attr.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_identifier_group = {
+ .attrs = riscv_iommu_hpm_identifier_attrs,
+};
+
#define IOMMU_HPM_EVENT_ATTR(name, config) \
PMU_EVENT_ATTR_ID(name, riscv_iommu_hpm_event_show, config)

@@ -522,6 +546,7 @@ static const struct attribute_group *riscv_iommu_hpm_attr_grps[] = {
&riscv_iommu_hpm_cpumask_group,
&riscv_iommu_hpm_events_group,
&riscv_iommu_hpm_format_group,
+ &riscv_iommu_hpm_identifier_group,
NULL
};

@@ -624,6 +649,36 @@ static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
riscv_iommu_hpm_interrupt_clear(iommu_hpm);
}

+static bool riscv_iommu_hpm_is_identifier_compat(const char *compat)
+{
+ return !strcmp(compat, "riscv,iommu");
+}
+
+static const char *riscv_iommu_hpm_get_identifier(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ const char *compat;
+ int count, i;
+
+ if (!np)
+ return NULL;
+
+ count = of_property_count_strings(np, "compatible");
+ if (count <= 0)
+ return NULL;
+
+ for (i = 0; i < count; i++) {
+ if (of_property_read_string_index(np, "compatible",
+ i, &compat))
+ continue;
+
+ if (riscv_iommu_hpm_is_identifier_compat(compat))
+ return devm_kstrdup(dev, compat, GFP_KERNEL);
+ }
+
+ return NULL;
+}
+
static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hpm)
{
/* Cycles counter is always supported */
@@ -650,6 +705,7 @@ static void riscv_iommu_hpm_remove(void *data)
static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
struct riscv_iommu_hpm *iommu_hpm,
u32 offset, int irq,
+ const char *identifier,
const struct attribute_group **attr_groups,
const char *prefix)
{
@@ -663,6 +719,7 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
memset(iommu_hpm, 0, sizeof(*iommu_hpm));
iommu_hpm->iommu = iommu;
+ iommu_hpm->identifier = identifier;

if (offset + RISCV_IOMMU_REG_SIZE <= iommu->reg_size)
base = iommu->reg + offset;
@@ -791,6 +848,7 @@ static void riscv_iommu_hpm_exit(void)
int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
{
struct device *dev = iommu->dev;
+ const char *identifier;
int irq, rc;

if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
@@ -809,7 +867,12 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
if (rc < 0)
return rc;

+ identifier = riscv_iommu_hpm_get_identifier(dev);
+ if (identifier)
+ dev_info(dev, "HPM: Vendor identifier: %s\n", identifier);
+
rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
+ identifier,
riscv_iommu_hpm_attr_grps,
"riscv_iommu_hpm");
if (rc < 0)
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 0ad9f5cad4de..d3c11abef5cf 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -41,6 +41,7 @@ struct riscv_iommu_hpm {
int irq;
int on_cpu;
struct hlist_node node;
+ const char *identifier;
/*
* Layout of events:
* 0 -> HPMCYCLES
--
2.43.0