* [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU
[not found] <cover.1769562575.git.lv.zheng@spacemit.com>
@ 2026-01-29 6:08 ` Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
` (7 more replies)
2026-02-04 9:08 ` [PATCH v3 0/8] " Lv Zheng
` (3 subsequent siblings)
4 siblings, 8 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Includes HPM support for RISC-V IOMMU. The HPM hardware mechnism can be
found in the recent announced SpacemiT SoCs (K3, V100), where T100
(SpacemiT distributed IOMMU) is shipped.
The tested result can be found as follows:
root@sdfirm:~# perf stat --timeout 5000 -a -e riscv_iommu_hpm_0/device_dir_walks,config1=0x20c0010000000000/ dmatest; sleep 1
[ 176.110211] dmatest: Started 1 threads using dma0chan0
[ 176.114933] dmatest: dma0chan0-copy0: summary 1 tests, 0 failures 394.94 iops 394 KB/s (0)
Performance counter stats for 'system wide':
3 riscv_iommu_hpm_0/device_dir_walks,config1=0x20c0010000000000/
0.081056000 seconds time elapsed
root@sdfirm:~# perf stat --timeout 5000 -a -e riscv_iommu_hpm_0/s_stage_walks,config1=0x20c0010000000000/ dmatest; sleep 1
[ 68.152992] dmatest: Started 1 threads using dma0chan0
[ 68.158071] dmatest: dma0chan0-copy0: summary 1 tests, 0 failures 401.92 iops 401 KB/s (0)
Performance counter stats for 'system wide':
6 riscv_iommu_hpm_0/s_stage_walks,config1=0x20c0010000000000/
0.083192000 seconds time elapsed
Jingyu Li (3):
iommu/riscv: Enable IOMMU DMA mapping support
iommu/riscv: Fix WSI mode IRQ number handling
iommu/riscv: Add HPM support for performance monitoring
Lv Zheng (4):
dt-bindings: iommu: Add spacemit/t100 features
spacemit/t100: Add vendor event support for RISC-V IOMMU HPM
spacemit/t100: Add global filter support for RISC-V IOMMU HPM
spacemit/t100: Add SpacemiT T100 IOATC HPM support
.../bindings/iommu/riscv,iommu.yaml | 60 +-
drivers/iommu/Kconfig | 2 +-
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 20 +-
drivers/iommu/riscv/iommu-hpm.c | 1135 +++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 12 +-
drivers/iommu/riscv/iommu.c | 25 +-
drivers/iommu/riscv/iommu.h | 45 +-
10 files changed, 1308 insertions(+), 14 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v1.1 1/7] iommu/riscv: Enable IOMMU DMA mapping support
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
@ 2026-01-29 6:08 ` Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 2/7] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
` (6 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
Enables IOMMU DMA mapping support for RISC-V, so that DMACs can be tested
with translation enabled.
Known Issue:
1. When CONFIG_IOMMU_DMA is enabled, current Linux RISC-V IOMMU is lack
of PCIe support, causing riscv_iommu_fault:522 in dealing with NVMe
PCIe devices.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f86262b11416..34d8a792339f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -151,7 +151,7 @@ config OF_IOMMU
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
- def_bool ARM64 || X86 || S390
+ def_bool ARM64 || X86 || S390 || RISCV
select DMA_OPS_HELPERS
select IOMMU_API
select IOMMU_IOVA
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 2/7] iommu/riscv: Fix WSI mode IRQ number handling
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
@ 2026-01-29 6:08 ` Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 3/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
` (5 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
In WSI mode, ICVEC doesn't exist, thus reading it returns 0, which
causes IOMMU driver to fail to find IRQ numbers from device tree
IRQ arrary. The issue is fixed by applying icvec indexes of WSI IRQs.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
---
drivers/iommu/riscv/iommu.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index d9429097a2b5..26630979473b 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
- if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
- FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
- max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
- FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
- return -EINVAL;
+ /*
+ * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
+ * Check if FCTL.WSI is set to determine interrupt mode.
+ */
+ if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
+ if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
+ FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
+ max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
+ FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
+ return -EINVAL;
+ } else {
+ /*
+ * WSI mode: ICVEC is not used. Set to identity mapping for
+ * riscv_iommu_queue_vec() to work correctly.
+ */
+ iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
+ }
return 0;
}
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 3/7] iommu/riscv: Add HPM support for performance monitoring
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 2/7] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
@ 2026-01-29 6:08 ` Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
` (4 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
monitoring capabilities.
Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
IOHPMCTR registers that have already been defined in the iommu-bits.h.
However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
the indexes of other HPMEVENTS, thus care should be taken in dealing with
counter indexes between userspace and kernel space.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
Link: https://github.com/riscv-non-isa/riscv-iommu
---
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 6 +
drivers/iommu/riscv/iommu-hpm.c | 799 +++++++++++++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 8 +-
drivers/iommu/riscv/iommu.h | 42 ++
7 files changed, 875 insertions(+), 3 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index c071816f59a6..2d06a1ef11c9 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -18,3 +18,12 @@ config RISCV_IOMMU_PCI
def_bool y if RISCV_IOMMU && PCI_MSI
help
Support for the PCIe implementation of RISC-V IOMMU architecture.
+
+config RISCV_IOMMU_HPM
+ tristate "RISCV IOMMU HPM support"
+ depends on RISCV_IOMMU
+ help
+ Provides support for the RISC-V IOMMU Hardware Performance Monitor
+ (HPM), which provide monitoring of transactions passing through the
+ IOMMU and allow the resulting information to be filtered based on
+ the device/process ID of the corresponding master.
diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
index b5929f9f23e6..53db3ef62bdd 100644
--- a/drivers/iommu/riscv/Makefile
+++ b/drivers/iommu/riscv/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += iommu.o iommu-platform.o
obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o
+obj-$(CONFIG_RISCV_IOMMU_HPM) += iommu-hpm.o
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 98daf0e1a306..cc6bea064d8f 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -207,6 +207,7 @@ enum riscv_iommu_ddtp_modes {
/* 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))
+#define RISCV_IOMMU_IOHPMEVENT_COUNTER GENMASK_ULL(63, 0)
/* 5.23 Performance monitoring event selectors (31 * 64bits) */
#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
@@ -222,6 +223,9 @@ enum riscv_iommu_ddtp_modes {
/* Number of defined performance-monitoring event selectors */
#define RISCV_IOMMU_IOHPMEVT_CNT 31
+/* Cycles counter is statically indexed as the last counter */
+#define RISCV_IOMMU_HPMCOUNTER_CYCLES RISCV_IOMMU_IOHPMEVT_CNT
+#define RISCV_IOMMU_HPMCOUNTER_MAX (RISCV_IOMMU_IOHPMEVT_CNT + 1)
/**
* enum riscv_iommu_hpmevent_id - Performance-monitoring event identifier
@@ -250,6 +254,8 @@ enum riscv_iommu_hpmevent_id {
RISCV_IOMMU_HPMEVENT_MAX = 9
};
+#define RISCV_IOMMU_HPMEVENT_CYCLES RISCV_IOMMU_HPMEVENT_INVALID
+
/* 5.24 Translation request IOVA (64bits) */
#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
#define RISCV_IOMMU_TR_REQ_IOVA_VPN GENMASK_ULL(63, 12)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
new file mode 100644
index 000000000000..67827b4c1d26
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -0,0 +1,799 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * riscv-hpm.c: RISC-V IOMMU Hardware Performance Monitor driver
+ *
+ * Copyright (C) 2025 SpacemiT Technologies Inc.
+ * Author: 2025 Jingyu Li <joey.li@spacemit.com>
+ * Lv Zheng <lv.zheng@spacemit.com>
+ */
+
+#include "iommu.h"
+
+#define to_iommu_hpm(p) (container_of(p, struct riscv_iommu_hpm, pmu))
+
+#define RISCV_IOMMU_HPM_EVENT_EXTRACTOR(_n, _c, _s, _e) \
+ static inline u32 get_##_n(struct perf_event *event) \
+ { \
+ return FIELD_GET(GENMASK_ULL(_e, _s), \
+ event->attr._c); \
+ }
+
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(event, config, 0, 14);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dmask, config1, 15, 15);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pid_pscid, config1, 16, 35);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_did_gscid, config1, 36, 59);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pv_pscv, config1, 60, 60);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dv_gscv, config1, 61, 61);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_idt, config1, 62, 62);
+
+static DEFINE_MUTEX(riscv_iommu_hpm_lock);
+static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
+static int cpuhp_state_num = -1;
+static int cpuhp_refcnt;
+
+static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
+ u32 val)
+{
+ writel_relaxed(val, hpm->base + reg);
+}
+
+static inline u32 riscv_iommu_hpm_readl(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readl_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_writeq(struct riscv_iommu_hpm *hpm, u32 reg,
+ u64 val)
+{
+ writeq_relaxed(val, hpm->base + reg);
+}
+
+static inline u64 riscv_iommu_hpm_readq(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readq_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_cycles_set_value(struct riscv_iommu_hpm *hpm,
+ u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES,
+ value & RISCV_IOMMU_IOHPMCYCLES_COUNTER);
+}
+
+static inline u64 riscv_iommu_hpm_cycles_get_value(struct riscv_iommu_hpm *hpm)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES) &
+ RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+}
+
+static inline void riscv_iommu_hpm_counter_set_value(struct riscv_iommu_hpm *hpm,
+ u32 idx, u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx), value);
+}
+
+static inline u64 riscv_iommu_hpm_counter_get_value(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx));
+}
+
+static inline void riscv_iommu_hpm_cycles_enable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_disable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_enable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_disable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_clear_ovf(struct riscv_iommu_hpm *hpm)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES);
+
+ val &= ~RISCV_IOMMU_IOHPMCYCLES_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES, val);
+}
+
+static inline void riscv_iommu_hpm_counter_clear_ovf(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx));
+
+ val &= ~RISCV_IOMMU_IOHPMEVT_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx), val);
+}
+
+static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
+{
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
+}
+
+static void riscv_iommu_hpm_event_update(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 delta, prev, now;
+ u32 idx = hwc->idx;
+
+ do {
+ prev = local64_read(&hwc->prev_count);
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ now = riscv_iommu_hpm_cycles_get_value(iommu_hpm);
+ else
+ now = riscv_iommu_hpm_counter_get_value(iommu_hpm, idx);
+ } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
+
+ delta = now - prev;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ delta &= RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ delta &= RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ local64_add(delta, &event->count);
+}
+
+static void riscv_iommu_hpm_set_period(struct riscv_iommu_hpm *iommu_hpm,
+ struct hw_perf_event *hwc)
+{
+ u32 idx = hwc->idx;
+ u64 new, max_period;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ max_period = RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ max_period = RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ /* Start at half the counter range */
+ new = max_period >> 1;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_set_value(iommu_hpm, new);
+ else
+ riscv_iommu_hpm_counter_set_value(iommu_hpm, idx, new);
+
+ local64_set(&hwc->prev_count, new);
+}
+
+static void riscv_iommu_hpm_event_start(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ hwc->state = 0;
+ riscv_iommu_hpm_set_period(iommu_hpm, hwc);
+
+ /* Enable counter */
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_enable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_enable(iommu_hpm, idx);
+}
+
+static void riscv_iommu_hpm_event_stop(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ if (hwc->state & PERF_HES_STOPPED)
+ return;
+
+ /* Disable counter */
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_disable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_disable(iommu_hpm, idx);
+
+ if (flags & PERF_EF_UPDATE)
+ riscv_iommu_hpm_event_update(event);
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+}
+
+static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
+ u32 pid_pscid, u32 did_gscid,
+ u32 pv_pscv,
+ u32 dv_gscv, u32 idt, u32 dmask)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 event_cfg;
+
+ /* Start with event ID */
+ event_cfg = get_event(event);
+ /* Set ID fields - values of 0 are valid */
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_PID_PSCID,
+ pid_pscid & 0xFFFFF);
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_DID_GSCID,
+ did_gscid & 0xFFFFFF);
+ /* Set control flags - 0 means disabled, 1 means enabled */
+ if (pv_pscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_PV_PSCV;
+ if (dv_gscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DV_GSCV;
+ if (idt)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_IDT;
+ if (dmask)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DMASK;
+
+ /* Write to the specific event register for this counter */
+ riscv_iommu_hpm_writeq(iommu_hpm,
+ RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
+}
+
+static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
+{
+ u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
+
+ pid_pscid = get_filter_pid_pscid(event);
+ did_gscid = get_filter_did_gscid(event);
+ pv_pscv = get_filter_pv_pscv(event);
+ dv_gscv = get_filter_dv_gscv(event);
+ idt = get_filter_idt(event);
+ dmask = get_filter_dmask(event);
+
+ riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+}
+
+static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event)
+{
+ int idx;
+ unsigned int num_ctrs = iommu_hpm->num_counters;
+ u16 event_id = get_event(event);
+
+ /* Handle cycles event specially */
+ if (event_id == RISCV_IOMMU_HPMEVENT_CYCLES) {
+ /* Check if cycles counter is already in use */
+ if (test_and_set_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "Cycles counter already in use\n");
+ return -EAGAIN;
+ }
+ return RISCV_IOMMU_HPMCOUNTER_CYCLES;
+ }
+
+ idx = find_first_zero_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (idx == num_ctrs - 1) {
+ dev_dbg(iommu_hpm->pmu.dev, "All counters already in use\n");
+ return -EAGAIN;
+ }
+
+ riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ set_bit(idx, iommu_hpm->used_counters);
+
+ return idx;
+}
+
+static int riscv_iommu_hpm_event_add(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ idx = riscv_iommu_hpm_get_event_idx(iommu_hpm, event);
+ hwc->idx = idx;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ iommu_hpm->events[0] = event;
+ else
+ iommu_hpm->events[idx + 1] = event;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ riscv_iommu_hpm_event_start(event, flags);
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+static void riscv_iommu_hpm_event_del(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ riscv_iommu_hpm_event_stop(event, flags | PERF_EF_UPDATE);
+
+ /* Clear the used counter bit and event array entry */
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ clear_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters);
+ iommu_hpm->events[0] = NULL;
+ } else {
+ clear_bit(idx, iommu_hpm->used_counters);
+ iommu_hpm->events[idx + 1] = NULL;
+ }
+
+ perf_event_update_userpage(event);
+}
+
+static int riscv_iommu_hpm_event_init(struct perf_event *event)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event *sibling;
+ int group_num_events = 1;
+ u16 event_id;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+ if (hwc->sample_period) {
+ dev_dbg(iommu_hpm->pmu.dev, "Sampling not supported\n");
+ return -EOPNOTSUPP;
+ }
+ if (event->cpu < 0) {
+ dev_dbg(iommu_hpm->pmu.dev, "Per-task mode not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ event_id = get_event(event);
+ if (event_id >= RISCV_IOMMU_HPMEVENT_MAX ||
+ !test_bit(event_id, iommu_hpm->supported_events)) {
+ dev_dbg(iommu_hpm->pmu.dev, "Invalid event %d for this PMU\n",
+ event_id);
+ return -EINVAL;
+ }
+
+ if (!is_software_event(event->group_leader)) {
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (is_software_event(sibling))
+ continue;
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ event->cpu = iommu_hpm->on_cpu;
+ hwc->idx = -1;
+
+ return 0;
+}
+
+static ssize_t riscv_iommu_hpm_cpumask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(iommu_hpm->on_cpu));
+}
+
+static struct device_attribute riscv_iommu_hpm_cpumask_attr =
+ __ATTR(cpumask, 0444, riscv_iommu_hpm_cpumask_show, NULL);
+
+static struct attribute *riscv_iommu_hpm_cpumask_attrs[] = {
+ &riscv_iommu_hpm_cpumask_attr.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_cpumask_group = {
+ .attrs = riscv_iommu_hpm_cpumask_attrs,
+};
+
+#define IOMMU_HPM_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_ID(name, riscv_iommu_hpm_event_show, config)
+
+static ssize_t riscv_iommu_hpm_event_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+ return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
+static struct attribute *riscv_iommu_hpm_events[] = {
+ IOMMU_HPM_EVENT_ATTR(cycles, RISCV_IOMMU_HPMEVENT_CYCLES),
+ IOMMU_HPM_EVENT_ATTR(untrans_rq, RISCV_IOMMU_HPMEVENT_URQ),
+ IOMMU_HPM_EVENT_ATTR(trans_rq, RISCV_IOMMU_HPMEVENT_TRQ),
+ IOMMU_HPM_EVENT_ATTR(ats_rq,
+ RISCV_IOMMU_HPMEVENT_ATS_RQ),
+ IOMMU_HPM_EVENT_ATTR(tlb_miss,
+ RISCV_IOMMU_HPMEVENT_TLB_MISS),
+ IOMMU_HPM_EVENT_ATTR(device_dir_walks,
+ RISCV_IOMMU_HPMEVENT_DD_WALK),
+ IOMMU_HPM_EVENT_ATTR(process_dir_walks,
+ RISCV_IOMMU_HPMEVENT_PD_WALK),
+ IOMMU_HPM_EVENT_ATTR(s_stage_walks,
+ RISCV_IOMMU_HPMEVENT_S_VS_WALKS),
+ IOMMU_HPM_EVENT_ATTR(g_stage_walks,
+ RISCV_IOMMU_HPMEVENT_G_WALKS),
+ NULL
+};
+
+static umode_t riscv_iommu_hpm_event_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int unused)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
+ if (test_bit(pmu_attr->id, iommu_hpm->supported_events))
+ return attr->mode;
+
+ return 0;
+}
+
+static const struct attribute_group riscv_iommu_hpm_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_hpm_events,
+ .is_visible = riscv_iommu_hpm_event_is_visible,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-14");
+PMU_FORMAT_ATTR(filter_pid_pscid, "config1:16-35");
+PMU_FORMAT_ATTR(filter_did_gscid, "config1:36-59");
+PMU_FORMAT_ATTR(filter_pv_pscv, "config1:60");
+PMU_FORMAT_ATTR(filter_dv_gscv, "config1:61");
+PMU_FORMAT_ATTR(filter_idt, "config1:62");
+PMU_FORMAT_ATTR(filter_dmask, "config1:15");
+
+static struct attribute *riscv_iommu_hpm_formats[] = {
+ &format_attr_event.attr,
+ &format_attr_filter_pid_pscid.attr,
+ &format_attr_filter_did_gscid.attr,
+ &format_attr_filter_pv_pscv.attr,
+ &format_attr_filter_dv_gscv.attr,
+ &format_attr_filter_idt.attr,
+ &format_attr_filter_dmask.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_format_group = {
+ .name = "format",
+ .attrs = riscv_iommu_hpm_formats,
+};
+
+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,
+ NULL
+};
+
+static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+ struct riscv_iommu_device *iommu = iommu_hpm->iommu;
+ struct perf_event *event;
+ u32 val;
+ int idx;
+ u32 ovf;
+ DECLARE_BITMAP(ovs, 32);
+
+ val = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IPSR);
+ if (!(val & RISCV_IOMMU_IPSR_PMIP))
+ return IRQ_NONE;
+
+ ovf = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTOVF);
+ if (!ovf)
+ return IRQ_HANDLED;
+
+ /* Handle cycles counter overflow (always stored at index 0) */
+ if (ovf & RISCV_IOMMU_IOCOUNTOVF_CY) {
+ event = iommu_hpm->events[0];
+ if (event && event->hw.idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ riscv_iommu_hpm_cycles_clear_ovf(iommu_hpm);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+ }
+
+ /*
+ * Handle regular HPM counter overflows.
+ * IOCOUNTOVF bit mapping:
+ * bit 0: cycles (already handled above)
+ * bit 1: counter 0 -> events[1]
+ * bit 2: counter 1 -> events[2]
+ * ...
+ * bit N: counter N-1 -> events[N]
+ * We need to check bits [1..num_counters] and skip bit 0.
+ */
+ bitmap_from_u64(ovs, ovf);
+ for_each_set_bit(idx, ovs, iommu_hpm->num_counters) {
+ /* Skip bit 0 (cycles counter, already handled) */
+ if (idx == 0)
+ continue;
+
+ /* IOCOUNTOVF bit N corresponds to counter N-1, stored in
+ * events[N]
+ */
+ event = iommu_hpm->events[idx];
+ if (WARN_ON_ONCE(!event))
+ continue;
+
+ dev_dbg(iommu->dev, "counter overflow: hw_idx=%d, counter=%d\n",
+ idx, idx - 1);
+ riscv_iommu_hpm_counter_clear_ovf(iommu_hpm, idx - 1);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+
+ return IRQ_HANDLED;
+}
+
+static int riscv_iommu_hpm_offline_cpu(unsigned int cpu,
+ struct hlist_node *node)
+{
+ struct riscv_iommu_hpm *iommu_hpm;
+ unsigned int target;
+
+ iommu_hpm = hlist_entry_safe(node, struct riscv_iommu_hpm, node);
+ if (cpu != iommu_hpm->on_cpu)
+ return 0;
+
+ if (!iommu_hpm->irq)
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target >= nr_cpu_ids)
+ return 0;
+
+ perf_pmu_migrate_context(&iommu_hpm->pmu, cpu, target);
+ iommu_hpm->on_cpu = target;
+ if (iommu_hpm->irq > 0)
+ WARN_ON(irq_set_affinity(iommu_hpm->irq, cpumask_of(target)));
+
+ return 0;
+}
+
+static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
+{
+ u64 counter_present_mask = (1ULL << iommu_hpm->num_counters) - 1;
+
+ /* Disable all counters */
+ riscv_iommu_hpm_writel(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTINH,
+ counter_present_mask);
+ /* Clear interrupt pending status */
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+}
+
+static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ /* Cycles counter is always supported */
+ set_bit(RISCV_IOMMU_HPMEVENT_CYCLES, iommu_hpm->supported_events);
+
+ /* Standard RISC-V IOMMU HPM events */
+ set_bit(RISCV_IOMMU_HPMEVENT_URQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TRQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_ATS_RQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TLB_MISS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_DD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_PD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_S_VS_WALKS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
+}
+
+static void riscv_iommu_hpm_remove(void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+
+ riscv_iommu_remove_hpm(iommu_hpm->iommu);
+}
+
+static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_hpm *iommu_hpm,
+ u32 offset, int irq,
+ const struct attribute_group **attr_groups,
+ const char *prefix, int index)
+{
+ struct device *dev = iommu->dev;
+ const char *pmu_name;
+ u32 val;
+ int err;
+ int unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ void __iomem *base;
+
+ memset(iommu_hpm, 0, sizeof(*iommu_hpm));
+ iommu_hpm->iommu = iommu;
+
+ if (offset + RISCV_IOMMU_REG_SIZE <= iommu->reg_size)
+ base = iommu->reg + offset;
+ else
+ base = devm_ioremap(dev, iommu->reg_phys + offset,
+ RISCV_IOMMU_REG_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ iommu_hpm->base = base;
+ bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+
+ riscv_iommu_hpm_writel(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
+ val = riscv_iommu_hpm_readl(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH);
+ iommu_hpm->num_counters = hweight32(val & RISCV_IOMMU_IOCOUNTINH_HPM);
+ if (!iommu_hpm->num_counters)
+ return -ENODEV;
+
+ iommu_hpm->on_cpu = raw_smp_processor_id();
+ iommu_hpm->irq = irq;
+
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ riscv_iommu_hpm_reset(iommu_hpm);
+
+ if (index >= 0)
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s%d_%d",
+ prefix, index, unique_id);
+ else
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%d",
+ prefix, unique_id);
+ if (!pmu_name)
+ return -ENOMEM;
+
+ err = devm_request_threaded_irq(dev, iommu_hpm->irq, NULL,
+ riscv_iommu_hpm_handle_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ pmu_name, iommu_hpm);
+ if (err)
+ return err;
+ WARN_ON(irq_set_affinity(iommu_hpm->irq,
+ cpumask_of(iommu_hpm->on_cpu)));
+
+ iommu_hpm->pmu = (struct pmu) {
+ .name = pmu_name,
+ .module = THIS_MODULE,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = riscv_iommu_hpm_event_init,
+ .add = riscv_iommu_hpm_event_add,
+ .del = riscv_iommu_hpm_event_del,
+ .start = riscv_iommu_hpm_event_start,
+ .stop = riscv_iommu_hpm_event_stop,
+ .read = riscv_iommu_hpm_event_update,
+ .attr_groups = attr_groups,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+ };
+
+ err = perf_pmu_register(&iommu_hpm->pmu, pmu_name, -1);
+ if (err)
+ goto err_exit;
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ if (err) {
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ goto err_perf;
+ }
+ cpuhp_refcnt++;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ err = devm_add_action_or_reset(dev, riscv_iommu_hpm_remove,
+ iommu_hpm);
+ if (err)
+ goto err_cpuhp;
+
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
+ pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ return 0;
+
+err_cpuhp:
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ mutex_unlock(&riscv_iommu_hpm_lock);
+err_perf:
+ perf_pmu_unregister(&iommu_hpm->pmu);
+err_exit:
+ return err;
+}
+
+static int riscv_iommu_hpm_init(void)
+{
+ int ret = 0;
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num < 0) {
+ cpuhp_state_num = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ "perf/riscv/iommu:online",
+ NULL,
+ riscv_iommu_hpm_offline_cpu);
+ if (cpuhp_state_num < 0)
+ ret = -EINVAL;
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ return ret;
+}
+
+static void riscv_iommu_hpm_exit(void)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_remove_multi_state(cpuhp_state_num);
+ cpuhp_state_num = -1;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+}
+
+/*
+ * Add HPM support for RISC-V IOMMU.
+ *
+ * @iommu - IOMMU device instance.
+ */
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ struct device *dev = iommu->dev;
+ int irq;
+ int rc;
+
+ if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
+ dev_dbg(dev, "HPM: Not supported\n");
+ return 0;
+ }
+ irq = iommu->irqs[FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec)];
+ if (irq <= 0) {
+ dev_err(dev, "HPM: No IRQ available (vector=%llu)\n",
+ (unsigned long long)FIELD_GET(RISCV_IOMMU_ICVEC_PMIV,
+ iommu->icvec));
+ return -EINVAL;
+ }
+
+ rc = riscv_iommu_hpm_init();
+ if (rc < 0)
+ return rc;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
+ riscv_iommu_hpm_attr_grps,
+ "riscv_iommu_hpm", -1);
+ if (rc < 0)
+ goto err_module;
+ return 0;
+
+err_module:
+ riscv_iommu_hpm_exit();
+ return rc;
+}
+
+/*
+ * Remove HPM support for RISC-V IOMMU.
+ *
+ * @iommu - IOMMU device instance.
+ */
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num >= 0) {
+ cpuhp_refcnt--;
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu->hpm.node);
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ perf_pmu_unregister(&iommu->hpm.pmu);
+ riscv_iommu_hpm_exit();
+}
diff --git a/drivers/iommu/riscv/iommu-pci.c b/drivers/iommu/riscv/iommu-pci.c
index d82d2b00904c..71407aecbf92 100644
--- a/drivers/iommu/riscv/iommu-pci.c
+++ b/drivers/iommu/riscv/iommu-pci.c
@@ -34,6 +34,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
{
struct device *dev = &pdev->dev;
struct riscv_iommu_device *iommu;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
int rc, vec;
rc = pcim_enable_device(pdev);
@@ -43,7 +45,9 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM))
return -ENODEV;
- if (pci_resource_len(pdev, 0) < RISCV_IOMMU_REG_SIZE)
+ reg_phys = pci_resource_start(pdev, 0);
+ reg_size = pci_resource_len(pdev, 0);
+ if (reg_size < RISCV_IOMMU_REG_SIZE)
return -ENODEV;
rc = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
@@ -56,6 +60,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
iommu->dev = dev;
iommu->reg = pcim_iomap_table(pdev)[0];
+ iommu->reg_phys = reg_phys;
+ iommu->reg_size = reg_size;
pci_set_master(pdev);
dev_set_drvdata(dev, iommu);
@@ -91,7 +97,10 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, iommu->fctl);
}
- return riscv_iommu_init(iommu);
+ rc = riscv_iommu_init(iommu);
+ if (rc)
+ return rc;
+ return riscv_iommu_add_hpm(iommu);
}
static void riscv_iommu_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 83a28c83f991..684bc267ac30 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -62,6 +62,9 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(iommu->reg),
"could not map register region\n");
+ iommu->reg_phys = res->start;
+ iommu->reg_size = resource_size(res);
+
dev_set_drvdata(dev, iommu);
/* Check device reported capabilities / features. */
@@ -134,7 +137,10 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, -ENODEV, "invalid IGS\n");
}
- return riscv_iommu_init(iommu);
+ ret = riscv_iommu_init(iommu);
+ if (ret)
+ return ret;
+ return riscv_iommu_add_hpm(iommu);
};
static void riscv_iommu_platform_remove(struct platform_device *pdev)
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..0ad9f5cad4de 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,7 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/iopoll.h>
+#include <linux/perf_event.h>
#include "iommu-bits.h"
@@ -33,6 +34,29 @@ struct riscv_iommu_queue {
u8 qid; /* queue identifier, same as RISCV_IOMMU_INTR_XX */
};
+struct riscv_iommu_hpm {
+ struct riscv_iommu_device *iommu;
+ struct pmu pmu;
+ void __iomem *base;
+ int irq;
+ int on_cpu;
+ struct hlist_node node;
+ /*
+ * Layout of events:
+ * 0 -> HPMCYCLES
+ * 1...n-1 -> HPMEVENTS
+ */
+ struct perf_event *events[RISCV_IOMMU_HPMCOUNTER_MAX];
+ DECLARE_BITMAP(supported_events, RISCV_IOMMU_HPMCOUNTER_MAX);
+ /*
+ * Layout of counters:
+ * 0...min(MAX,n)-2 -> HPMEVENTS
+ * MAX-1 -> HPMCYCLES
+ */
+ DECLARE_BITMAP(used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ unsigned int num_counters;
+};
+
struct riscv_iommu_device {
/* iommu core interface */
struct iommu_device iommu;
@@ -42,6 +66,8 @@ struct riscv_iommu_device {
/* hardware control register space */
void __iomem *reg;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
/* supported and enabled hardware capabilities */
u64 caps;
@@ -60,12 +86,28 @@ struct riscv_iommu_device {
unsigned int ddt_mode;
dma_addr_t ddt_phys;
u64 *ddt_root;
+
+ struct riscv_iommu_hpm hpm;
};
int riscv_iommu_init(struct riscv_iommu_device *iommu);
void riscv_iommu_remove(struct riscv_iommu_device *iommu);
void riscv_iommu_disable(struct riscv_iommu_device *iommu);
+#ifdef CONFIG_RISCV_IOMMU_HPM
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu);
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu);
+#else
+static inline int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ return -ENODEV;
+}
+
+static inline void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+}
+#endif
+
#define riscv_iommu_readl(iommu, addr) \
readl_relaxed((iommu)->reg + (addr))
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
` (2 preceding siblings ...)
2026-01-29 6:08 ` [PATCH v1.1 3/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
@ 2026-01-29 6:09 ` Lv Zheng
2026-01-29 10:08 ` Conor Dooley
2026-01-29 6:09 ` [PATCH v1.1 5/7] spacemit/t100: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
` (3 subsequent siblings)
7 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds device tree bindings for SpacemiT T100 specific features.
vendor-hpm-events: Allow vendor events to be customized in the device
tree.
global-filter: The feature saves silicon area by reducing filters to
one and use it as a global filter across all events.
This usually is sufficient for real applications.
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
.../bindings/iommu/riscv,iommu.yaml | 60 ++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
index d4838c3b3741..0378eef1f34e 100644
--- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
@@ -57,17 +57,42 @@ properties:
interrupts:
minItems: 1
- maxItems: 4
+ maxItems: 68
description:
Wired interrupt vectors available for RISC-V IOMMU to notify the
RISC-V HARTS. The cause to interrupt vector is software defined
using IVEC IOMMU register.
+ Normally the number of interrupt vectors available is 4 for IOATS
+ civ/fiv/pmiv/piv interrupts. But for SpacemiT distributed IOMMU,
+ the number of interrupt vectors includes IOATC pmiv wired
+ interrupts and the maximum number of IOATCs can be up to 64.
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 68
msi-parent: true
power-domains:
maxItems: 1
+ vendor-hpm-events:
+ minItems: 1
+ maxItems: 120
+ description:
+ Each item defines a vendor specific event using the format of
+ "eventId[:eventName]", where the eventId is an integer filling the
+ eventID field of the iohpmevt register and the eventName is an
+ optional string used as the annotation of the event instead of the
+ default name "eventId".
+ $ref: /schemas/types.yaml#/definitions/string-array
+
+ global-filter:
+ type: boolean
+ description:
+ Indicate the filters programmed across iohpmevt registers are wired
+ together in hardware as a global filter applied to all HPM events.
+
required:
- compatible
- reg
@@ -145,3 +170,36 @@ examples:
};
};
};
+
+ - |+
+ /* Example 5 (SpacemiT distributed IOMMU) */
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ iommu4: iommu@1bccd000 {
+ compatible = "qemu,riscv-iommu", "riscv,iommu";
+ reg = <0x1bccd000 0x1000>;
+ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
+ <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
+ <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "civ", "fiv", "ioats-pmiv", "piv",
+ "ioatc0-pmiv", "ioatc1-pmiv";
+ interrupt-parent = <&saplic>;
+ #iommu-cells = <0x01>;
+ /* SpacemiT T100 features */
+ global-filter;
+ vendor-hpm-events = "0x10:pri_page_reqs",
+ "0x11:ptw_cache_reqs",
+ "0x12:dtw_cache_reqs",
+ "0x15:all_trans_reqs",
+ "0x20:dtw_cache_lkps",
+ "0x28:s1l0_ptw_cache_lkps",
+ "0x2A:s1l1_ptw_cache_lkps",
+ "0x2C:s1l2_ptw_cache_lkps",
+ "0x2E:s1l3_ptw_cache_lkps",
+ "0x30:s2l0_ptw_cache_lkps",
+ "0x32:s2l1_ptw_cache_lkps",
+ "0x34:s2l2_ptw_cache_lkps",
+ "0x36:s2l3_ptw_cache_lkps",
+ "0x38:mtlb_lkps",
+ "0x3A:utlb_lkps";
+ };
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 5/7] spacemit/t100: Add vendor event support for RISC-V IOMMU HPM
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
` (3 preceding siblings ...)
2026-01-29 6:09 ` [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-01-29 6:09 ` Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 6/7] spacemit/t100: Add global filter " Lv Zheng
` (2 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds mechanism to allow vendor events to be registered via device tree.
This is useful to support SpacemiT T100 IOMMU where the maximum 128 event
IDs should be supported by T100 IOATS.
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-bits.h | 2 +-
drivers/iommu/riscv/iommu-hpm.c | 94 +++++++++++++++++++++++++++++++-
2 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index cc6bea064d8f..f1fbf3cc6ba5 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -251,7 +251,7 @@ enum riscv_iommu_hpmevent_id {
RISCV_IOMMU_HPMEVENT_PD_WALK = 6,
RISCV_IOMMU_HPMEVENT_S_VS_WALKS = 7,
RISCV_IOMMU_HPMEVENT_G_WALKS = 8,
- RISCV_IOMMU_HPMEVENT_MAX = 9
+ RISCV_IOMMU_HPMEVENT_MAX = 128
};
#define RISCV_IOMMU_HPMEVENT_CYCLES RISCV_IOMMU_HPMEVENT_INVALID
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index 67827b4c1d26..b01d72dd056f 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -584,6 +584,81 @@ static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
riscv_iommu_hpm_interrupt_clear(iommu_hpm);
}
+static int riscv_iommu_hpm_init_vendor_events(struct riscv_iommu_hpm *iommu_hpm,
+ struct attribute ***vendor_attrs)
+{
+ struct device *dev = iommu_hpm->iommu->dev;
+ struct device_node *np = dev->of_node;
+ struct perf_pmu_events_attr *vendor_event_attrs;
+ struct attribute **attrs;
+ const char *event_str;
+ int num_events, i, j;
+ char *event_copy, *colon, *event_name;
+ u32 event_id;
+
+ *vendor_attrs = NULL;
+
+ if (!np)
+ return 0;
+
+ num_events = of_property_count_strings(np, "vendor-hpm-events");
+ if (num_events <= 0)
+ return 0;
+
+ attrs = devm_kcalloc(dev, num_events + 1, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+ vendor_event_attrs = devm_kcalloc(dev, num_events,
+ sizeof(*vendor_event_attrs),
+ GFP_KERNEL);
+ if (!vendor_event_attrs)
+ return -ENOMEM;
+
+ /*
+ * Parse vendor events from device tree.
+ * Format: "event-name:0xNN" where NN is hex event ID
+ */
+ j = 0;
+ for (i = 0; i < num_events; i++) {
+ if (of_property_read_string_index(np, "vendor,hpm-events",
+ i, &event_str))
+ continue;
+
+ event_copy = devm_kstrdup(dev, event_str, GFP_KERNEL);
+ if (!event_copy) {
+ dev_warn(dev, "HPM: Failed to copy string for vendor event '%s'\n",
+ event_str);
+ continue;
+ }
+ colon = strchr(event_copy, ':');
+ if (colon) {
+ *colon = '\0';
+ event_name = colon + 1;
+ } else
+ event_name = event_copy;
+ if (kstrtou32(event_copy, 0, &event_id))
+ continue;
+ if (event_id >= RISCV_IOMMU_HPMEVENT_MAX)
+ continue;
+
+ sysfs_attr_init(&vendor_event_attrs[j].attr.attr);
+ vendor_event_attrs[j].attr.attr.name = event_name;
+ vendor_event_attrs[j].attr.attr.mode = 0444;
+ vendor_event_attrs[j].attr.show = riscv_iommu_hpm_event_show;
+ vendor_event_attrs[j].id = event_id;
+ attrs[j] = &vendor_event_attrs[j].attr.attr;
+ set_bit(event_id, iommu_hpm->supported_events);
+ dev_info(dev, "HPM: Registered vendor event '%s' (0x%x)\n",
+ event_name, event_id);
+ j++;
+ }
+
+ attrs[j] = NULL;
+ *vendor_attrs = attrs;
+
+ return j;
+}
+
static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hpm)
{
/* Cycles counter is always supported */
@@ -749,8 +824,10 @@ static void riscv_iommu_hpm_exit(void)
int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
{
struct device *dev = iommu->dev;
+ struct attribute **vendor_attrs = NULL;
+ int num_vendor_events;
int irq;
- int rc;
+ int rc, i;
if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
dev_dbg(dev, "HPM: Not supported\n");
@@ -773,6 +850,21 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
"riscv_iommu_hpm", -1);
if (rc < 0)
goto err_module;
+
+ num_vendor_events = riscv_iommu_hpm_init_vendor_events(&iommu->hpm,
+ &vendor_attrs);
+ if (num_vendor_events > 0 && vendor_attrs) {
+ for (i = 0; i < num_vendor_events && vendor_attrs[i]; i++) {
+ rc = sysfs_add_file_to_group(&iommu->hpm.pmu.dev->kobj,
+ vendor_attrs[i],
+ "events");
+ if (rc)
+ dev_warn(dev,
+ "HPM: Failed to create sysfs for vendor event '%s'\n",
+ vendor_attrs[i]->name);
+ }
+ }
+
return 0;
err_module:
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 6/7] spacemit/t100: Add global filter support for RISC-V IOMMU HPM
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
` (4 preceding siblings ...)
2026-01-29 6:09 ` [PATCH v1.1 5/7] spacemit/t100: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
@ 2026-01-29 6:09 ` Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 7/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-06 10:44 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Krzysztof Kozlowski
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Introduces global filter support for RISC-V IOMMU HPM. The global filter
can be seen in SpacemiT T100 which only supports single filter to be
applied to all event counters. This silicon design can save the number of
the event bus signals.
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-hpm.c | 93 ++++++++++++++++++++++++++++++---
drivers/iommu/riscv/iommu.h | 1 +
2 files changed, 87 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index b01d72dd056f..23e1afc262ea 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -134,6 +134,49 @@ static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
}
+static bool riscv_iommu_hpm_check_global_filter(struct perf_event *curr,
+ struct perf_event *new)
+{
+ u32 curr_pid_pscid, curr_did_gscid, curr_pv_pscv;
+ u32 curr_dv_gscv, curr_idt, curr_dmask;
+ u32 new_pid_pscid, new_did_gscid, new_pv_pscv;
+ u32 new_dv_gscv, new_idt, new_dmask;
+
+ curr_pid_pscid = get_filter_pid_pscid(curr);
+ curr_did_gscid = get_filter_did_gscid(curr);
+ curr_pv_pscv = get_filter_pv_pscv(curr);
+ curr_dv_gscv = get_filter_dv_gscv(curr);
+ curr_idt = get_filter_idt(curr);
+ curr_dmask = get_filter_dmask(curr);
+
+ new_pid_pscid = get_filter_pid_pscid(new);
+ new_did_gscid = get_filter_did_gscid(new);
+ new_pv_pscv = get_filter_pv_pscv(new);
+ new_dv_gscv = get_filter_dv_gscv(new);
+ new_idt = get_filter_idt(new);
+ new_dmask = get_filter_dmask(new);
+
+ return (curr_pid_pscid == new_pid_pscid &&
+ curr_did_gscid == new_did_gscid &&
+ curr_pv_pscv == new_pv_pscv &&
+ curr_dv_gscv == new_dv_gscv &&
+ curr_idt == new_idt &&
+ curr_dmask == new_dmask);
+}
+
+static bool riscv_iommu_hpm_events_compatible(struct perf_event *curr,
+ struct perf_event *new)
+{
+ if (new->pmu != curr->pmu)
+ return false;
+
+ if (to_iommu_hpm(new->pmu)->global_filter &&
+ !riscv_iommu_hpm_check_global_filter(curr, new))
+ return false;
+
+ return true;
+}
+
static void riscv_iommu_hpm_event_update(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -246,9 +289,10 @@ static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
}
-static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
- struct perf_event *event, int idx)
+static int riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
{
+ unsigned int cur_idx, num_ctrs = iommu_hpm->num_counters;
u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
pid_pscid = get_filter_pid_pscid(event);
@@ -258,14 +302,36 @@ static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm
idt = get_filter_idt(event);
dmask = get_filter_dmask(event);
+ if (iommu_hpm->global_filter) {
+ cur_idx = find_first_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (cur_idx == num_ctrs - 1) {
+ /* First event, set the global filter */
+ riscv_iommu_hpm_set_event_filter(event, 0, pid_pscid,
+ did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+ } else {
+ /* Check if the new event's filter is compatible with
+ * the global filter
+ */
+ if (!riscv_iommu_hpm_check_global_filter(iommu_hpm->events[cur_idx + 1],
+ event)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "HPM: Filter incompatible with global filter\n");
+ return -EAGAIN;
+ }
+ }
+ return 0;
+ }
+
riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
pv_pscv, dv_gscv, idt, dmask);
+ return 0;
}
static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
struct perf_event *event)
{
- int idx;
+ int idx, err;
unsigned int num_ctrs = iommu_hpm->num_counters;
u16 event_id = get_event(event);
@@ -287,7 +353,10 @@ static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
return -EAGAIN;
}
- riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ err = riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ if (err)
+ return err;
+
set_bit(idx, iommu_hpm->used_counters);
return idx;
@@ -363,6 +432,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
}
if (!is_software_event(event->group_leader)) {
+ if (!riscv_iommu_hpm_events_compatible(event->group_leader, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -370,6 +441,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
for_each_sibling_event(sibling, event->group_leader) {
if (is_software_event(sibling))
continue;
+ if (!riscv_iommu_hpm_events_compatible(sibling, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -685,6 +758,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,
+ bool global_filter,
const struct attribute_group **attr_groups,
const char *prefix, int index)
{
@@ -709,6 +783,8 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
iommu_hpm->base = base;
bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+ iommu_hpm->global_filter = of_property_read_bool(dev->of_node,
+ "global-filter");
riscv_iommu_hpm_writel(iommu_hpm,
RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
@@ -775,8 +851,10 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
if (err)
goto err_cpuhp;
- dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
- pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d, %s filter)\n",
+ pmu_name, iommu_hpm->num_counters,
+ iommu_hpm->irq,
+ iommu_hpm->global_filter ? "global" : "per-counter");
return 0;
err_cpuhp:
@@ -845,7 +923,8 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
if (rc < 0)
return rc;
- rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
+ rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm,
+ 0, irq, true,
riscv_iommu_hpm_attr_grps,
"riscv_iommu_hpm", -1);
if (rc < 0)
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 0ad9f5cad4de..5ebf4e85962e 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;
+ bool global_filter;
/*
* Layout of events:
* 0 -> HPMCYCLES
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v1.1 7/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
` (5 preceding siblings ...)
2026-01-29 6:09 ` [PATCH v1.1 6/7] spacemit/t100: Add global filter " Lv Zheng
@ 2026-01-29 6:09 ` Lv Zheng
2026-02-06 10:44 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Krzysztof Kozlowski
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-01-29 6:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds IOATC discovery and HPM support for SpacemiT T100.
SpacemiT T100 supports distributed architecture which allows IOTLBs to be
cached in adjacent to the DMA masters. Such IOTLBs controllers are called
as IOATC, this patch adds distributed HPM support for IOATCs.
Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-bits.h | 12 ++
drivers/iommu/riscv/iommu-hpm.c | 173 ++++++++++++++++++++++++++-
drivers/iommu/riscv/iommu-platform.c | 4 +-
drivers/iommu/riscv/iommu.h | 2 +-
4 files changed, 184 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index f1fbf3cc6ba5..4dae9f378169 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -284,6 +284,18 @@ enum riscv_iommu_hpmevent_id {
#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
+/* 5.28 Distributed translation interface status register (dtisr0-3) (4 * 32-bits) */
+#define RISCV_IOMMU_REG_DTISR_BASE 0x02B0
+#define RISCV_IOMMU_REG_DTISR(_n) (RISCV_IOMMU_REG_DTISR_BASE + ((_n) * 0x04))
+#define RISCV_IOMMU_DTI_STS_SHIFT(_n) (((_n) % 16) * 2)
+#define RISCV_IOMMU_DTI_STS_MASK(_n) (0x3 << RISCV_IOMMU_DTI_STS_SHIFT(_n))
+#define RISCV_IOMMU_DTI_STS_NONE 0x0
+#define RISCV_IOMMU_DTI_STS_TBU_IOATC 0x1
+
+#define MAX_RISCV_IOMMU_IOATC 64
+#define RISCV_IOMMU_IOATC_BASE(_base, _idx) \
+ ((void __iomem *)((u8 __iomem *)(_base) + ((_idx) + 1) * RISCV_IOMMU_REG_SIZE))
+
/* 5.28 MSI Configuration table (32 * 64bits) */
#define RISCV_IOMMU_REG_MSI_CFG_TBL 0x0300
#define RISCV_IOMMU_REG_MSI_CFG_TBL_ADDR(_n) \
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index 23e1afc262ea..b97afddea6b3 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -7,6 +7,7 @@
* Lv Zheng <lv.zheng@spacemit.com>
*/
+#include <linux/platform_device.h>
#include "iommu.h"
#define to_iommu_hpm(p) (container_of(p, struct riscv_iommu_hpm, pmu))
@@ -31,6 +32,94 @@ static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
static int cpuhp_state_num = -1;
static int cpuhp_refcnt;
+struct riscv_iommu_ioatc_desc {
+ u32 offset;
+ int irq;
+ u32 index;
+};
+
+static int riscv_iommu_hpm_collect_ioatcs(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_ioatc_desc *descs,
+ int max_desc)
+{
+ struct device *dev = iommu->dev;
+ struct device_node *np = dev->of_node;
+ struct platform_device *pdev = to_platform_device(dev);
+ int count = 0;
+ int i;
+ int *ioatc_irqs = NULL;
+
+ if (!descs || max_desc <= 0)
+ return 0;
+
+ if (np) {
+ int names_count = of_property_count_strings(np, "interrupt-names");
+ const char *name;
+ int irq_idx;
+ u32 ioatc_idx;
+
+ ioatc_irqs = kcalloc(MAX_RISCV_IOMMU_IOATC, sizeof(int), GFP_KERNEL);
+ if (!ioatc_irqs)
+ goto discover;
+
+ for (i = 0; i < names_count; i++) {
+ if (of_property_read_string_index(np, "interrupt-names",
+ i, &name))
+ continue;
+
+ if (!strstr(name, "ioatc") || !strstr(name, "hpm"))
+ continue;
+
+ if (sscanf(name, "ioatc%u-hpm", &ioatc_idx) != 1)
+ continue;
+
+ if (ioatc_idx >= MAX_RISCV_IOMMU_IOATC)
+ continue;
+
+ if (i < iommu->irqs_count) {
+ irq_idx = iommu->irqs[i];
+ ioatc_irqs[ioatc_idx] = irq_idx;
+ } else {
+ irq_idx = platform_get_irq(pdev, i);
+ if (irq_idx < 0)
+ ioatc_irqs[ioatc_idx] = 0;
+ else
+ ioatc_irqs[ioatc_idx] = irq_idx;
+ }
+ }
+ }
+
+discover:
+ /* Automatically discover IOATCs by scanning DTISR registers */
+ for (i = 0; i < 4 && count < max_desc; i++) {
+ u32 dtisr = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_DTISR(i));
+ int j;
+
+ for (j = 0; j < 16 && count < max_desc; j++) {
+ u32 idx = i * 16 + j;
+ u32 state;
+
+ state = (dtisr & RISCV_IOMMU_DTI_STS_MASK(idx)) >>
+ RISCV_IOMMU_DTI_STS_SHIFT(idx);
+ if (state == RISCV_IOMMU_DTI_STS_TBU_IOATC) {
+ descs[count].offset = (idx + 1) * RISCV_IOMMU_REG_SIZE;
+ descs[count].index = idx;
+
+ if (ioatc_irqs && idx < MAX_RISCV_IOMMU_IOATC &&
+ ioatc_irqs[idx] > 0)
+ descs[count].irq = ioatc_irqs[idx];
+ else
+ descs[count].irq = 0;
+ count++;
+ }
+ }
+ }
+
+ kfree(ioatc_irqs);
+
+ return count;
+}
+
static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
u32 val)
{
@@ -558,6 +647,43 @@ static const struct attribute_group *riscv_iommu_hpm_attr_grps[] = {
NULL
};
+#define IOMMU_IOATC_EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR_ID(ioatc_##_name, riscv_iommu_hpm_event_show, _id)
+
+static struct attribute *riscv_iommu_ioatc_events[] = {
+ IOMMU_IOATC_EVENT_ATTR(untranslated_requests, 1),
+ IOMMU_IOATC_EVENT_ATTR(translated_requests, 2),
+ IOMMU_IOATC_EVENT_ATTR(tlb_miss, 4),
+ IOMMU_IOATC_EVENT_ATTR(translation_requests, 21),
+ IOMMU_IOATC_EVENT_ATTR(translations_issued, 24),
+ IOMMU_IOATC_EVENT_ATTR(transactions_unissued_slot_drain, 25),
+ IOMMU_IOATC_EVENT_ATTR(transactions_unissued_token_drain, 26),
+ IOMMU_IOATC_EVENT_ATTR(write_transactions_unissued_wb_full, 27),
+ IOMMU_IOATC_EVENT_ATTR(write_transactions_using_wb, 28),
+ IOMMU_IOATC_EVENT_ATTR(write_transactions_not_using_wb, 29),
+ IOMMU_IOATC_EVENT_ATTR(makeinvalid_downgrades, 30),
+ IOMMU_IOATC_EVENT_ATTR(stash_fails, 31),
+ IOMMU_IOATC_EVENT_ATTR(mtlb_lookups, 56),
+ IOMMU_IOATC_EVENT_ATTR(mtlb_misses, 57),
+ IOMMU_IOATC_EVENT_ATTR(utlb_lookups, 58),
+ IOMMU_IOATC_EVENT_ATTR(utlb_misses, 59),
+ IOMMU_IOATC_EVENT_ATTR(mtlb_reads, 65),
+ IOMMU_IOATC_EVENT_ATTR(mtlb_errors, 108),
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_ioatc_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_ioatc_events,
+};
+
+static const struct attribute_group *riscv_iommu_ioatc_attr_grps[] = {
+ &riscv_iommu_hpm_cpumask_group,
+ &riscv_iommu_ioatc_events_group,
+ &riscv_iommu_hpm_format_group,
+ NULL
+};
+
static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -748,6 +874,18 @@ static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hp
set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
}
+static void riscv_iommu_hpm_set_ioatc_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ static const unsigned int ioatc_event_ids[] = {
+ 1, 2, 4, 21, 24, 25, 26, 27, 28, 29, 30, 31,
+ 56, 57, 58, 59, 65, 108,
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ioatc_event_ids); i++)
+ set_bit(ioatc_event_ids[i], iommu_hpm->supported_events);
+}
+
static void riscv_iommu_hpm_remove(void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -758,7 +896,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,
- bool global_filter,
+ bool global_filter, bool ioatc,
const struct attribute_group **attr_groups,
const char *prefix, int index)
{
@@ -797,7 +935,10 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
iommu_hpm->on_cpu = raw_smp_processor_id();
iommu_hpm->irq = irq;
- riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ if (ioatc)
+ riscv_iommu_hpm_set_ioatc_events(iommu_hpm);
+ else
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
riscv_iommu_hpm_reset(iommu_hpm);
if (index >= 0)
@@ -902,8 +1043,9 @@ static void riscv_iommu_hpm_exit(void)
int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
{
struct device *dev = iommu->dev;
+ struct riscv_iommu_ioatc_desc ioatcs[MAX_RISCV_IOMMU_IOATC];
struct attribute **vendor_attrs = NULL;
- int num_vendor_events;
+ int ioatc_count, num_vendor_events;
int irq;
int rc, i;
@@ -924,7 +1066,7 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
return rc;
rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm,
- 0, irq, true,
+ 0, irq, true, false,
riscv_iommu_hpm_attr_grps,
"riscv_iommu_hpm", -1);
if (rc < 0)
@@ -944,6 +1086,29 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
}
}
+ ioatc_count = riscv_iommu_hpm_collect_ioatcs(iommu, ioatcs,
+ ARRAY_SIZE(ioatcs));
+ for (i = 0; i < ioatc_count; i++) {
+ struct riscv_iommu_hpm *extra;
+
+ extra = devm_kzalloc(dev, sizeof(*extra), GFP_KERNEL);
+ if (!extra)
+ continue;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, extra,
+ ioatcs[i].offset,
+ ioatcs[i].irq,
+ true, true,
+ riscv_iommu_ioatc_attr_grps,
+ "riscv_iommu_ioatc",
+ ioatcs[i].index);
+ if (rc) {
+ dev_warn(dev,
+ "HPM: Failed to register IOATC%u PMU: %d\n",
+ ioatcs[i].index, rc);
+ }
+ }
+
return 0;
err_module:
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 684bc267ac30..ca8de9ec5266 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -75,8 +75,8 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
if (iommu->irqs_count <= 0)
return dev_err_probe(dev, -ENODEV,
"no IRQ resources provided\n");
- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT)
- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
+ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC)
+ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC;
igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps);
switch (igs) {
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 5ebf4e85962e..b1905e54bd0b 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -75,7 +75,7 @@ struct riscv_iommu_device {
u32 fctl;
/* available interrupt numbers, MSI or WSI */
- unsigned int irqs[RISCV_IOMMU_INTR_COUNT];
+ unsigned int irqs[RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC];
unsigned int irqs_count;
unsigned int icvec;
--
2.43.0
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 6:09 ` [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-01-29 10:08 ` Conor Dooley
2026-01-29 10:43 ` 郑律
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-01-29 10:08 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
[-- Attachment #1: Type: text/plain, Size: 5856 bytes --]
On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
> Adds device tree bindings for SpacemiT T100 specific features.
>
> vendor-hpm-events: Allow vendor events to be customized in the device
> tree.
> global-filter: The feature saves silicon area by reducing filters to
> one and use it as a global filter across all events.
> This usually is sufficient for real applications.
Why can these not be determined from a device specific compatible?
> Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> ---
> .../bindings/iommu/riscv,iommu.yaml | 60 ++++++++++++++++++-
> 1 file changed, 59 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> index d4838c3b3741..0378eef1f34e 100644
> --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> @@ -57,17 +57,42 @@ properties:
>
> interrupts:
> minItems: 1
> - maxItems: 4
> + maxItems: 68
> description:
> Wired interrupt vectors available for RISC-V IOMMU to notify the
> RISC-V HARTS. The cause to interrupt vector is software defined
> using IVEC IOMMU register.
> + Normally the number of interrupt vectors available is 4 for IOATS
> + civ/fiv/pmiv/piv interrupts. But for SpacemiT distributed IOMMU,
> + the number of interrupt vectors includes IOATC pmiv wired
> + interrupts and the maximum number of IOATCs can be up to 64.
The extension to 68 should only be permitted for a soc-specific
compatible.
> +
> + interrupt-names:
> + minItems: 1
> + maxItems: 68
>
> msi-parent: true
>
> power-domains:
> maxItems: 1
>
> + vendor-hpm-events:
> + minItems: 1
> + maxItems: 120
> + description:
> + Each item defines a vendor specific event using the format of
> + "eventId[:eventName]", where the eventId is an integer filling the
> + eventID field of the iohpmevt register and the eventName is an
> + optional string used as the annotation of the event instead of the
> + default name "eventId".
> + $ref: /schemas/types.yaml#/definitions/string-array
> +
> + global-filter:
> + type: boolean
> + description:
> + Indicate the filters programmed across iohpmevt registers are wired
> + together in hardware as a global filter applied to all HPM events.
> +
> required:
> - compatible
> - reg
> @@ -145,3 +170,36 @@ examples:
> };
> };
> };
> +
> + - |+
> + /* Example 5 (SpacemiT distributed IOMMU) */
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + iommu4: iommu@1bccd000 {
> + compatible = "qemu,riscv-iommu", "riscv,iommu";
You cannot use the qemu compatible for your device, you must use a
specific one for the spacemit k3.
Also, why is your version "v1.1"? That should just be "v1", and your
next version "v2" etc.
pw-bot: changes-requested
Cheers,
Conor.
> + reg = <0x1bccd000 0x1000>;
> + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> + <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> + <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "civ", "fiv", "ioats-pmiv", "piv",
> + "ioatc0-pmiv", "ioatc1-pmiv";
> + interrupt-parent = <&saplic>;
> + #iommu-cells = <0x01>;
> + /* SpacemiT T100 features */
> + global-filter;
> + vendor-hpm-events = "0x10:pri_page_reqs",
> + "0x11:ptw_cache_reqs",
> + "0x12:dtw_cache_reqs",
> + "0x15:all_trans_reqs",
> + "0x20:dtw_cache_lkps",
> + "0x28:s1l0_ptw_cache_lkps",
> + "0x2A:s1l1_ptw_cache_lkps",
> + "0x2C:s1l2_ptw_cache_lkps",
> + "0x2E:s1l3_ptw_cache_lkps",
> + "0x30:s2l0_ptw_cache_lkps",
> + "0x32:s2l1_ptw_cache_lkps",
> + "0x34:s2l2_ptw_cache_lkps",
> + "0x36:s2l3_ptw_cache_lkps",
> + "0x38:mtlb_lkps",
> + "0x3A:utlb_lkps";
> + };
> --
> 2.43.0
>
> This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
>
> 本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 10:08 ` Conor Dooley
@ 2026-01-29 10:43 ` 郑律
2026-01-29 16:41 ` Conor Dooley
0 siblings, 1 reply; 62+ messages in thread
From: 郑律 @ 2026-01-29 10:43 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
> From: "Conor Dooley"<conor@kernel.org>
> Date: Thu, Jan 29, 2026, 18:08
> Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> To: "Lv Zheng"<lv.zheng@spacemit.com>
> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "Zhijian Chen"<zhijian@spacemit.com>, <iommu@lists.linux.dev>, <linux-perf-users@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <spacemit@lists.linux.dev>, <devicetree@vger.kernel.org>
> On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
> > Adds device tree bindings for SpacemiT T100 specific features.
> >
> > vendor-hpm-events: Allow vendor events to be customized in the device
> > tree.
> > global-filter: The feature saves silicon area by reducing filters to
> > one and use it as a global filter across all events.
> > This usually is sufficient for real applications.
>
> Why can these not be determined from a device specific compatible?
The specification only defines less than 10 standard event types while the
real silicons should have implemented many other event types based on
their micro-architecture. I tried to provide a common mechanism for all
vendor specific event types across different vendors.
It is similar for the global filter, the global filter mechanism actually
complies to the IOMMU specification, users can alter the iohpmevt
registers as is what is specified in the IOMMU specification. It only
provides slight application difference between the final effection. Thus
this could also be a non-device specific option.
>
> > Signed-off-by: Lv Zheng <lv.zheng@spacemit.com>
> > Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> > ---
> > .../bindings/iommu/riscv,iommu.yaml | 60 ++++++++++++++++++-
> > 1 file changed, 59 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > index d4838c3b3741..0378eef1f34e 100644
> > --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > @@ -57,17 +57,42 @@ properties:
> >
> > interrupts:
> > minItems: 1
> > - maxItems: 4
> > + maxItems: 68
> > description:
> > Wired interrupt vectors available for RISC-V IOMMU to notify the
> > RISC-V HARTS. The cause to interrupt vector is software defined
> > using IVEC IOMMU register.
> > + Normally the number of interrupt vectors available is 4 for IOATS
> > + civ/fiv/pmiv/piv interrupts. But for SpacemiT distributed IOMMU,
> > + the number of interrupt vectors includes IOATC pmiv wired
> > + interrupts and the maximum number of IOATCs can be up to 64.
>
> The extension to 68 should only be permitted for a soc-specific
> compatible.
Sure.
>
> > +
> > + interrupt-names:
> > + minItems: 1
> > + maxItems: 68
> >
> > msi-parent: true
> >
> > power-domains:
> > maxItems: 1
> >
> > + vendor-hpm-events:
> > + minItems: 1
> > + maxItems: 120
> > + description:
> > + Each item defines a vendor specific event using the format of
> > + "eventId[:eventName]", where the eventId is an integer filling the
> > + eventID field of the iohpmevt register and the eventName is an
> > + optional string used as the annotation of the event instead of the
> > + default name "eventId".
> > + $ref: /schemas/types.yaml#/definitions/string-array
> > +
> > + global-filter:
> > + type: boolean
> > + description:
> > + Indicate the filters programmed across iohpmevt registers are wired
> > + together in hardware as a global filter applied to all HPM events.
> > +
> > required:
> > - compatible
> > - reg
> > @@ -145,3 +170,36 @@ examples:
> > };
> > };
> > };
> > +
> > + - |+
> > + /* Example 5 (SpacemiT distributed IOMMU) */
> > + #include <dt-bindings/interrupt-controller/irq.h>
> > +
> > + iommu4: iommu@1bccd000 {
> > + compatible = "qemu,riscv-iommu", "riscv,iommu";
>
> You cannot use the qemu compatible for your device, you must use a
> specific one for the spacemit k3.
Sure.
>
> Also, why is your version "v1.1"? That should just be "v1", and your
> next version "v2" etc.
I'm still using an old fashioned upstream rule, thanks for the reminder.
>
> pw-bot: changes-requested
OK. Will send a revised patchset later.
Cheers,
Lv
>
> Cheers,
> Conor.
>
> > + reg = <0x1bccd000 0x1000>;
> > + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> > + <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> > + <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
> > + interrupt-names = "civ", "fiv", "ioats-pmiv", "piv",
> > + "ioatc0-pmiv", "ioatc1-pmiv";
> > + interrupt-parent = <&saplic>;
> > + #iommu-cells = <0x01>;
> > + /* SpacemiT T100 features */
> > + global-filter;
> > + vendor-hpm-events = "0x10:pri_page_reqs",
> > + "0x11:ptw_cache_reqs",
> > + "0x12:dtw_cache_reqs",
> > + "0x15:all_trans_reqs",
> > + "0x20:dtw_cache_lkps",
> > + "0x28:s1l0_ptw_cache_lkps",
> > + "0x2A:s1l1_ptw_cache_lkps",
> > + "0x2C:s1l2_ptw_cache_lkps",
> > + "0x2E:s1l3_ptw_cache_lkps",
> > + "0x30:s2l0_ptw_cache_lkps",
> > + "0x32:s2l1_ptw_cache_lkps",
> > + "0x34:s2l2_ptw_cache_lkps",
> > + "0x36:s2l3_ptw_cache_lkps",
> > + "0x38:mtlb_lkps",
> > + "0x3A:utlb_lkps";
> > + };
> > --
> > 2.43.0
> >
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 10:43 ` 郑律
@ 2026-01-29 16:41 ` Conor Dooley
2026-01-29 17:06 ` Robin Murphy
2026-01-30 1:39 ` 郑律
0 siblings, 2 replies; 62+ messages in thread
From: Conor Dooley @ 2026-01-29 16:41 UTC (permalink / raw)
To: 郑律
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
[-- Attachment #1: Type: text/plain, Size: 2795 bytes --]
On Thu, Jan 29, 2026 at 06:43:03PM +0800, 郑律 wrote:
> > From: "Conor Dooley"<conor@kernel.org>
> > Date: Thu, Jan 29, 2026, 18:08
> > Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> > To: "Lv Zheng"<lv.zheng@spacemit.com>
> > Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "Zhijian Chen"<zhijian@spacemit.com>, <iommu@lists.linux.dev>, <linux-perf-users@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <spacemit@lists.linux.dev>, <devicetree@vger.kernel.org>
> > On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
> > > Adds device tree bindings for SpacemiT T100 specific features.
> > >
> > > vendor-hpm-events: Allow vendor events to be customized in the device
> > > tree.
> > > global-filter: The feature saves silicon area by reducing filters to
> > > one and use it as a global filter across all events.
> > > This usually is sufficient for real applications.
> >
> > Why can these not be determined from a device specific compatible?
>
> The specification only defines less than 10 standard event types while the
> real silicons should have implemented many other event types based on
> their micro-architecture. I tried to provide a common mechanism for all
> vendor specific event types across different vendors.
Given that the variance is based on uarch, it sounds like it can be
determined from the compatible.
> It is similar for the global filter, the global filter mechanism actually
> complies to the IOMMU specification, users can alter the iohpmevt
> registers as is what is specified in the IOMMU specification. It only
> provides slight application difference between the final effection. Thus
> this could also be a non-device specific option.
What is a "user" in this context? Given you're talking about reducing
silicon area, it sounds like this will be set in stone for each SoC, and
therefore can be determined by compatible. If other devices do this,
they can also determine it from their compatible.
Properties for things that can be determined based on compatible are
generally not permitted, so you'll need to provide a compelling
rationale. Common mechanism isn't one, since determining based on
compatible would be a common mechanism based on match data that people
can tack onto for their devices.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 16:41 ` Conor Dooley
@ 2026-01-29 17:06 ` Robin Murphy
2026-01-30 1:30 ` 郑律
2026-01-30 1:39 ` 郑律
1 sibling, 1 reply; 62+ messages in thread
From: Robin Murphy @ 2026-01-29 17:06 UTC (permalink / raw)
To: Conor Dooley, 郑律
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Jingyu Li, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
On 29/01/2026 4:41 pm, Conor Dooley wrote:
> On Thu, Jan 29, 2026 at 06:43:03PM +0800, 郑律 wrote:
>>> From: "Conor Dooley"<conor@kernel.org>
>>> Date: Thu, Jan 29, 2026, 18:08
>>> Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
>>> To: "Lv Zheng"<lv.zheng@spacemit.com>
>>> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "Zhijian Chen"<zhijian@spacemit.com>, <iommu@lists.linux.dev>, <linux-perf-users@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <spacemit@lists.linux.dev>, <devicetree@vger.kernel.org>
>>> On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
>>>> Adds device tree bindings for SpacemiT T100 specific features.
>>>>
>>>> vendor-hpm-events: Allow vendor events to be customized in the device
>>>> tree.
>>>> global-filter: The feature saves silicon area by reducing filters to
>>>> one and use it as a global filter across all events.
>>>> This usually is sufficient for real applications.
>>>
>>> Why can these not be determined from a device specific compatible?
>>
>> The specification only defines less than 10 standard event types while the
>> real silicons should have implemented many other event types based on
>> their micro-architecture. I tried to provide a common mechanism for all
>> vendor specific event types across different vendors.
>
> Given that the variance is based on uarch, it sounds like it can be
> determined from the compatible.
>
>> It is similar for the global filter, the global filter mechanism actually
>> complies to the IOMMU specification, users can alter the iohpmevt
>> registers as is what is specified in the IOMMU specification. It only
>> provides slight application difference between the final effection. Thus
>> this could also be a non-device specific option.
>
> What is a "user" in this context? Given you're talking about reducing
> silicon area, it sounds like this will be set in stone for each SoC, and
> therefore can be determined by compatible. If other devices do this,
> they can also determine it from their compatible.
>
> Properties for things that can be determined based on compatible are
> generally not permitted, so you'll need to provide a compelling
> rationale. Common mechanism isn't one, since determining based on
> compatible would be a common mechanism based on match data that people
> can tack onto for their devices.
Also, reinventing jevents via devicetree is pretty grim anyway - the PMU
can simply expose an "identifier" attribute that uniquely identifies the
vendor implementation, and perf tooling can match that to a set of event
definitions in userspace, with the added bonus that jevents can also
encode meaningful descriptions, metrics and suchlike. There doesn't
*need* to be a sysfs alias for every possible event. I see the RISC-V
CPU PMUs are already on-board with this approach - note the
"Unit"/"Compat" matching for system/uncore PMUs is a little different
from the mapfile used for CPUs, but see other architectures for examples.
Thanks,
Robin.
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 17:06 ` Robin Murphy
@ 2026-01-30 1:30 ` 郑律
0 siblings, 0 replies; 62+ messages in thread
From: 郑律 @ 2026-01-30 1:30 UTC (permalink / raw)
To: Robin Murphy
Cc: Conor Dooley, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
> From: "Robin Murphy"<robin.murphy@arm.com>
> Date: Fri, Jan 30, 2026, 01:06
> Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> To: "Conor Dooley"<conor@kernel.org>, "郑律"<lv.zheng@spacemit.com>
> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "iommu"<iommu@lists.linux.dev>, "linux-perf-users"<linux-perf-users@vger.kernel.org>, "linux-riscv"<linux-riscv@lists.infradead.org>, "spacemit"<spacemit@lists.linux.dev>, "devicetree"<devicetree@vger.kernel.org>
> On 29/01/2026 4:41 pm, Conor Dooley wrote:
> > On Thu, Jan 29, 2026 at 06:43:03PM +0800, 郑律 wrote:
> >>> From: "Conor Dooley"<conor@kernel.org>
> >>> Date: Thu, Jan 29, 2026, 18:08
> >>> Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> >>> To: "Lv Zheng"<lv.zheng@spacemit.com>
> >>> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "Zhijian Chen"<zhijian@spacemit.com>, <iommu@lists.linux.dev>, <linux-perf-users@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <spacemit@lists.linux.dev>, <devicetree@vger.kernel.org>
> >>> On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
> >>>> Adds device tree bindings for SpacemiT T100 specific features.
> >>>>
> >>>> vendor-hpm-events: Allow vendor events to be customized in the device
> >>>> tree.
> >>>> global-filter: The feature saves silicon area by reducing filters to
> >>>> one and use it as a global filter across all events.
> >>>> This usually is sufficient for real applications.
> >>>
> >>> Why can these not be determined from a device specific compatible?
> >>
> >> The specification only defines less than 10 standard event types while the
> >> real silicons should have implemented many other event types based on
> >> their micro-architecture. I tried to provide a common mechanism for all
> >> vendor specific event types across different vendors.
> >
> > Given that the variance is based on uarch, it sounds like it can be
> > determined from the compatible.
> >
> >> It is similar for the global filter, the global filter mechanism actually
> >> complies to the IOMMU specification, users can alter the iohpmevt
> >> registers as is what is specified in the IOMMU specification. It only
> >> provides slight application difference between the final effection. Thus
> >> this could also be a non-device specific option.
> >
> > What is a "user" in this context? Given you're talking about reducing
> > silicon area, it sounds like this will be set in stone for each SoC, and
> > therefore can be determined by compatible. If other devices do this,
> > they can also determine it from their compatible.
> >
> > Properties for things that can be determined based on compatible are
> > generally not permitted, so you'll need to provide a compelling
> > rationale. Common mechanism isn't one, since determining based on
> > compatible would be a common mechanism based on match data that people
> > can tack onto for their devices.
>
> Also, reinventing jevents via devicetree is pretty grim anyway - the PMU
> can simply expose an "identifier" attribute that uniquely identifies the
> vendor implementation, and perf tooling can match that to a set of event
> definitions in userspace, with the added bonus that jevents can also
> encode meaningful descriptions, metrics and suchlike. There doesn't
> *need* to be a sysfs alias for every possible event. I see the RISC-V
> CPU PMUs are already on-board with this approach - note the
> "Unit"/"Compat" matching for system/uncore PMUs is a little different
> from the mapfile used for CPUs, but see other architectures for examples.
Thanks for the idea. It sounds great and I'll give it a try.
Best regards,
Lv
>
> Thanks,
> Robin.
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
2026-01-29 16:41 ` Conor Dooley
2026-01-29 17:06 ` Robin Murphy
@ 2026-01-30 1:39 ` 郑律
1 sibling, 0 replies; 62+ messages in thread
From: 郑律 @ 2026-01-30 1:39 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
> From: "Conor Dooley"<conor@kernel.org>
> Date: Fri, Jan 30, 2026, 00:42
> Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> To: "郑律"<lv.zheng@spacemit.com>
> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "iommu"<iommu@lists.linux.dev>, "linux-perf-users"<linux-perf-users@vger.kernel.org>, "linux-riscv"<linux-riscv@lists.infradead.org>, "spacemit"<spacemit@lists.linux.dev>, "devicetree"<devicetree@vger.kernel.org>
> On Thu, Jan 29, 2026 at 06:43:03PM +0800, 郑律 wrote:
> > > From: "Conor Dooley"<conor@kernel.org>
> > > Date: Thu, Jan 29, 2026, 18:08
> > > Subject: Re: [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features
> > > To: "Lv Zheng"<lv.zheng@spacemit.com>
> > > Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Rob Herring"<robh@kernel.org>, "Krzysztof Kozlowski"<krzk+dt@kernel.org>, "Conor Dooley"<conor+dt@kernel.org>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, "Jingyu Li"<joey.li@spacemit.com>, "Zhijian Chen"<zhijian@spacemit.com>, <iommu@lists.linux.dev>, <linux-perf-users@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <spacemit@lists.linux.dev>, <devicetree@vger.kernel.org>
> > > On Thu, Jan 29, 2026 at 02:09:13PM +0800, Lv Zheng wrote:
> > > > Adds device tree bindings for SpacemiT T100 specific features.
> > > >
> > > > vendor-hpm-events: Allow vendor events to be customized in the device
> > > > tree.
> > > > global-filter: The feature saves silicon area by reducing filters to
> > > > one and use it as a global filter across all events.
> > > > This usually is sufficient for real applications.
> > >
> > > Why can these not be determined from a device specific compatible?
> >
> > The specification only defines less than 10 standard event types while the
> > real silicons should have implemented many other event types based on
> > their micro-architecture. I tried to provide a common mechanism for all
> > vendor specific event types across different vendors.
>
> Given that the variance is based on uarch, it sounds like it can be
> determined from the compatible.
I'll give Robin's suggestion a try.
> > It is similar for the global filter, the global filter mechanism actually
> > complies to the IOMMU specification, users can alter the iohpmevt
> > registers as is what is specified in the IOMMU specification. It only
> > provides slight application difference between the final effection. Thus
> > this could also be a non-device specific option.
>
> What is a "user" in this context? Given you're talking about reducing
> silicon area, it sounds like this will be set in stone for each SoC, and
> therefore can be determined by compatible. If other devices do this,
> they can also determine it from their compatible.
>
> Properties for things that can be determined based on compatible are
> generally not permitted, so you'll need to provide a compelling
> rationale. Common mechanism isn't one, since determining based on
> compatible would be a common mechanism based on match data that people
> can tack onto for their devices.
I see. This sounds like a reasonable rule of DT attributes. I'll do similar
stuffs based on compatible.
Thanks and best regards,
Lv
This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v3 0/8] iommu/riscv: Add HPM support for RISC-V IOMMU
[not found] <cover.1769562575.git.lv.zheng@spacemit.com>
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
@ 2026-02-04 9:08 ` Lv Zheng
2026-02-06 10:44 ` Krzysztof Kozlowski
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (2 subsequent siblings)
4 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
found in the recent announced SpacemiT SoCs (K3, V100), where T100
(SpacemiT distributed IOMMU) is shipped.
Revisions:
v1
Initial release.
v2 (sent as v1.1)
Split and cleanup DT-bindings.
v3
Refactor using vendor specific compatible.
The tested result can be found as follows:
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioats_hpm_00/dd_walk,config1=0x20c0010000000000/ dmatest; sleep 1
[ 145.630224] dmatest: Started 1 threads using dma0chan0
[ 145.644896] dmatest: dma0chan0-copy0: summary 1 tests, 0 failures 123.60 iops 123 KB/s (0)
Performance counter stats for 'system wide':
3 spacemit_ioats_hpm_00/dd_walk,config1=0x20c0010000000000/
0.193108000 seconds time elapsed
root@sdfirm:~# echo dma0chan1 > /sys/module/dmatest/parameters/channel
[ 327.001820] dmatest: Added 1 threads using dma0chan1
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioats_hpm_00/s_walk,config1=0x20c0011000000000/ dmatest; sleep 1
[ 484.037180] dmatest: Started 1 threads using dma0chan1
[ 484.048832] dmatest: dma0chan1-copy0: summary 1 tests, 0 failures 172.11 iops 172 KB/s (0)
Performance counter stats for 'system wide':
6 spacemit_ioats_hpm_00/s_walk,config1=0x20c0011000000000/
0.191970000 seconds time elapsed
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioatc_hpm_0003/tlb_mis,config1=0x20c0011000000000/ dmatest; sleep 1
[ 546.332494] dmatest: No channels configured, continue with any
[ 546.363062] dmatest: Added 1 threads using dma0chan1
[ 546.377994] dmatest: Started 1 threads using dma0chan1
[ 546.388376] dmatest: dma0chan1-copy0: summary 1 tests, 0 failures 213.94 iops 213 KB/s (0)
Performance counter stats for 'system wide':
3 spacemit_ioatc_hpm_0003/tlb_mis,config1=0x20c0011000000000/
0.225062000 seconds time elapsed
Jingyu Li (3):
iommu/riscv: Enable IOMMU DMA mapping support
iommu/riscv: Fix WSI mode IRQ number handling
iommu/riscv: Add HPM support for performance monitoring
Lv Zheng (5):
dt-bindings: iommu: Add spacemit/t100 features
riscv/iommu: Add vendor event support for RISC-V IOMMU HPM
spacemit/t100: Add global filter awareness for RISC-V IOMMU HPM
spacemit/t100: Add SpacemiT T100 IOATC HPM support
perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM
aliasing
.../bindings/iommu/riscv,iommu.yaml | 37 +
MAINTAINERS | 3 +
drivers/iommu/Kconfig | 2 +-
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 18 +
drivers/iommu/riscv/iommu-hpm.c | 1122 +++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 12 +-
drivers/iommu/riscv/iommu.c | 25 +-
drivers/iommu/riscv/iommu.h | 46 +-
.../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 +
.../arch/riscv/spacemit/iommu/sys/ioats.json | 163 +++
13 files changed, 1469 insertions(+), 12 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
--
2.43.0
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v3 1/8] iommu/riscv: Enable IOMMU DMA mapping support
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
@ 2026-02-04 9:08 ` Lv Zheng
2026-02-04 9:08 ` [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
` (6 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
Enables IOMMU DMA mapping support for RISC-V, so that DMACs can be tested
with translation enabled.
Known Possible Issue:
1. When CONFIG_IOMMU_DMA is enabled, on the tested Linux, RISC-V IOMMU is
lack of PCIe support, causing riscv_iommu_fault:522 in dealing with
NVMe PCIe devices.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f86262b11416..34d8a792339f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -151,7 +151,7 @@ config OF_IOMMU
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
- def_bool ARM64 || X86 || S390
+ def_bool ARM64 || X86 || S390 || RISCV
select DMA_OPS_HELPERS
select IOMMU_API
select IOMMU_IOVA
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
2026-02-04 9:08 ` [PATCH v3 1/8] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
@ 2026-02-04 9:08 ` Lv Zheng
2026-02-04 17:20 ` Andrew Jones
2026-02-04 9:09 ` [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
` (5 subsequent siblings)
7 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:08 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
In WSI mode, ICVEC doesn't exist, thus reading it returns 0, which
causes IOMMU driver to fail to find IRQ numbers from device tree
IRQ arrary. The issue is fixed by applying icvec indexes of WSI IRQs.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
---
drivers/iommu/riscv/iommu.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index d9429097a2b5..26630979473b 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
- if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
- FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
- max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
- FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
- return -EINVAL;
+ /*
+ * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
+ * Check if FCTL.WSI is set to determine interrupt mode.
+ */
+ if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
+ if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
+ FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
+ max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
+ FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
+ return -EINVAL;
+ } else {
+ /*
+ * WSI mode: ICVEC is not used. Set to identity mapping for
+ * riscv_iommu_queue_vec() to work correctly.
+ */
+ iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
+ FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
+ }
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
2026-02-04 9:08 ` [PATCH v3 1/8] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-02-04 9:08 ` [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 18:39 ` Andrew Jones
2026-02-04 9:09 ` [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
` (4 subsequent siblings)
7 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
monitoring capabilities.
Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
IOHPMCTR registers that have already been defined in the iommu-bits.h.
However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
the indexes of other HPMEVENTS, thus care should be taken in dealing with
counter indexes between userspace and kernel space.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Link: https://github.com/riscv-non-isa/riscv-iommu
---
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 6 +
drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 8 +-
drivers/iommu/riscv/iommu.h | 42 ++
7 files changed, 919 insertions(+), 3 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index c071816f59a6..2d06a1ef11c9 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -18,3 +18,12 @@ config RISCV_IOMMU_PCI
def_bool y if RISCV_IOMMU && PCI_MSI
help
Support for the PCIe implementation of RISC-V IOMMU architecture.
+
+config RISCV_IOMMU_HPM
+ tristate "RISCV IOMMU HPM support"
+ depends on RISCV_IOMMU
+ help
+ Provides support for the RISC-V IOMMU Hardware Performance Monitor
+ (HPM), which provide monitoring of transactions passing through the
+ IOMMU and allow the resulting information to be filtered based on
+ the device/process ID of the corresponding master.
diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
index b5929f9f23e6..53db3ef62bdd 100644
--- a/drivers/iommu/riscv/Makefile
+++ b/drivers/iommu/riscv/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += iommu.o iommu-platform.o
obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o
+obj-$(CONFIG_RISCV_IOMMU_HPM) += iommu-hpm.o
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 98daf0e1a306..cc6bea064d8f 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -207,6 +207,7 @@ enum riscv_iommu_ddtp_modes {
/* 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))
+#define RISCV_IOMMU_IOHPMEVENT_COUNTER GENMASK_ULL(63, 0)
/* 5.23 Performance monitoring event selectors (31 * 64bits) */
#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
@@ -222,6 +223,9 @@ enum riscv_iommu_ddtp_modes {
/* Number of defined performance-monitoring event selectors */
#define RISCV_IOMMU_IOHPMEVT_CNT 31
+/* Cycles counter is statically indexed as the last counter */
+#define RISCV_IOMMU_HPMCOUNTER_CYCLES RISCV_IOMMU_IOHPMEVT_CNT
+#define RISCV_IOMMU_HPMCOUNTER_MAX (RISCV_IOMMU_IOHPMEVT_CNT + 1)
/**
* enum riscv_iommu_hpmevent_id - Performance-monitoring event identifier
@@ -250,6 +254,8 @@ enum riscv_iommu_hpmevent_id {
RISCV_IOMMU_HPMEVENT_MAX = 9
};
+#define RISCV_IOMMU_HPMEVENT_CYCLES RISCV_IOMMU_HPMEVENT_INVALID
+
/* 5.24 Translation request IOVA (64bits) */
#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
#define RISCV_IOMMU_TR_REQ_IOVA_VPN GENMASK_ULL(63, 12)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
new file mode 100644
index 000000000000..f1b265634e51
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -0,0 +1,843 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * iommu-hpm.c: RISC-V IOMMU Hardware Performance Monitor driver
+ *
+ * Copyright (C) 2026 SpacemiT Technologies Inc.
+ * Author: 2026 Jingyu Li <joey.li@spacemit.com>
+ * Lv Zheng <lv.zheng@spacemit.com>
+ */
+
+#include "iommu.h"
+
+#define to_iommu_hpm(p) (container_of(p, struct riscv_iommu_hpm, pmu))
+
+#define RISCV_IOMMU_HPM_EVENT_EXTRACTOR(_n, _c, _s, _e) \
+ static inline u32 get_##_n(struct perf_event *event) \
+ { \
+ return FIELD_GET(GENMASK_ULL(_e, _s), \
+ event->attr._c); \
+ }
+
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(event, config, 0, 14);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dmask, config1, 15, 15);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pid_pscid, config1, 16, 35);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_did_gscid, config1, 36, 59);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pv_pscv, config1, 60, 60);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dv_gscv, config1, 61, 61);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_idt, config1, 62, 62);
+
+static DEFINE_MUTEX(riscv_iommu_hpm_lock);
+static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
+static int cpuhp_state_num = -1;
+static int cpuhp_refcnt;
+
+static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
+ u32 val)
+{
+ writel_relaxed(val, hpm->base + reg);
+}
+
+static inline u32 riscv_iommu_hpm_readl(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readl_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_writeq(struct riscv_iommu_hpm *hpm, u32 reg,
+ u64 val)
+{
+ writeq_relaxed(val, hpm->base + reg);
+}
+
+static inline u64 riscv_iommu_hpm_readq(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readq_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_cycles_set_value(struct riscv_iommu_hpm *hpm,
+ u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES,
+ value & RISCV_IOMMU_IOHPMCYCLES_COUNTER);
+}
+
+static inline u64 riscv_iommu_hpm_cycles_get_value(struct riscv_iommu_hpm *hpm)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES) &
+ RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+}
+
+static inline void riscv_iommu_hpm_counter_set_value(struct riscv_iommu_hpm *hpm,
+ u32 idx, u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx), value);
+}
+
+static inline u64 riscv_iommu_hpm_counter_get_value(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx));
+}
+
+static inline void riscv_iommu_hpm_cycles_enable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_disable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_enable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_disable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_clear_ovf(struct riscv_iommu_hpm *hpm)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES);
+
+ val &= ~RISCV_IOMMU_IOHPMCYCLES_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES, val);
+}
+
+static inline void riscv_iommu_hpm_counter_clear_ovf(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx));
+
+ val &= ~RISCV_IOMMU_IOHPMEVT_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx), val);
+}
+
+static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
+{
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
+}
+
+/**
+ * riscv_iommu_hpm_event_update() - Update and return RISC-V IOMMU HPM
+ * event counters
+ *
+ * @event: IOMMU performance event
+ *
+ * This function can be used to implement the .read() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_update(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 delta, prev, now;
+ u32 idx = hwc->idx;
+
+ do {
+ prev = local64_read(&hwc->prev_count);
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ now = riscv_iommu_hpm_cycles_get_value(iommu_hpm);
+ else
+ now = riscv_iommu_hpm_counter_get_value(iommu_hpm, idx);
+ } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
+
+ delta = now - prev;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ delta &= RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ delta &= RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ local64_add(delta, &event->count);
+}
+
+static void riscv_iommu_hpm_set_period(struct riscv_iommu_hpm *iommu_hpm,
+ struct hw_perf_event *hwc)
+{
+ u32 idx = hwc->idx;
+ u64 new, max_period;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ max_period = RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ max_period = RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ /* Start at half the counter range */
+ new = max_period >> 1;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_set_value(iommu_hpm, new);
+ else
+ riscv_iommu_hpm_counter_set_value(iommu_hpm, idx, new);
+
+ local64_set(&hwc->prev_count, new);
+}
+
+/**
+ * riscv_iommu_hpm_event_start() - Start RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .start() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_start(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ hwc->state = 0;
+ riscv_iommu_hpm_set_period(iommu_hpm, hwc);
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_enable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_enable(iommu_hpm, idx);
+}
+
+/**
+ * riscv_iommu_hpm_event_stop() - Stop RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .stop() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_stop(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ if (hwc->state & PERF_HES_STOPPED)
+ return;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_disable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_disable(iommu_hpm, idx);
+
+ if (flags & PERF_EF_UPDATE)
+ riscv_iommu_hpm_event_update(event);
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+}
+
+static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
+ u32 pid_pscid, u32 did_gscid,
+ u32 pv_pscv,
+ u32 dv_gscv, u32 idt, u32 dmask)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 event_cfg;
+
+ /* Start with event ID */
+ event_cfg = get_event(event);
+ /* Set ID fields - values of 0 are valid */
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_PID_PSCID,
+ pid_pscid & 0xFFFFF);
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_DID_GSCID,
+ did_gscid & 0xFFFFFF);
+ /* Set control flags - 0 means disabled, 1 means enabled */
+ if (pv_pscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_PV_PSCV;
+ if (dv_gscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DV_GSCV;
+ if (idt)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_IDT;
+ if (dmask)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DMASK;
+
+ /* Write to the specific event register for this counter */
+ riscv_iommu_hpm_writeq(iommu_hpm,
+ RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
+}
+
+static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
+{
+ u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
+
+ pid_pscid = get_filter_pid_pscid(event);
+ did_gscid = get_filter_did_gscid(event);
+ pv_pscv = get_filter_pv_pscv(event);
+ dv_gscv = get_filter_dv_gscv(event);
+ idt = get_filter_idt(event);
+ dmask = get_filter_dmask(event);
+
+ riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+}
+
+static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event)
+{
+ int idx;
+ unsigned int num_ctrs = iommu_hpm->num_counters;
+ u16 event_id = get_event(event);
+
+ /* Handle cycles event specially */
+ if (event_id == RISCV_IOMMU_HPMEVENT_CYCLES) {
+ /* Check if cycles counter is already in use */
+ if (test_and_set_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "Cycles counter already in use\n");
+ return -EAGAIN;
+ }
+ return RISCV_IOMMU_HPMCOUNTER_CYCLES;
+ }
+
+ idx = find_first_zero_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (idx == num_ctrs - 1) {
+ dev_dbg(iommu_hpm->pmu.dev, "All counters already in use\n");
+ return -EAGAIN;
+ }
+
+ riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ set_bit(idx, iommu_hpm->used_counters);
+
+ return idx;
+}
+
+/**
+ * riscv_iommu_hpm_event_add() - Add a RISC-V IOMMU HPM event
+ *
+ * @event - IOMMU performance event
+ * @flags - Performance event flags
+ *
+ * This function can be used to implement the .add() interface of pmu.
+ */
+static int riscv_iommu_hpm_event_add(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ idx = riscv_iommu_hpm_get_event_idx(iommu_hpm, event);
+ hwc->idx = idx;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ iommu_hpm->events[0] = event;
+ else
+ iommu_hpm->events[idx + 1] = event;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ riscv_iommu_hpm_event_start(event, flags);
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+/**
+ * riscv_iommu_hpm_event_del() - Delete a RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .del() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_del(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ riscv_iommu_hpm_event_stop(event, flags | PERF_EF_UPDATE);
+
+ /* Clear the used counter bit and event array entry */
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ clear_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters);
+ iommu_hpm->events[0] = NULL;
+ } else {
+ clear_bit(idx, iommu_hpm->used_counters);
+ iommu_hpm->events[idx + 1] = NULL;
+ }
+
+ perf_event_update_userpage(event);
+}
+
+/**
+ * riscv_iommu_hpm_event_init() - Initialize HPM event attributes
+ *
+ * @event: IOMMU performance event
+ *
+ * This function can be used to implement the .event_init() interface of
+ * pmu.
+ */
+static int riscv_iommu_hpm_event_init(struct perf_event *event)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event *sibling;
+ int group_num_events = 1;
+ u16 event_id;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+ if (hwc->sample_period) {
+ dev_dbg(iommu_hpm->pmu.dev, "Sampling not supported\n");
+ return -EOPNOTSUPP;
+ }
+ if (event->cpu < 0) {
+ dev_dbg(iommu_hpm->pmu.dev, "Per-task mode not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ event_id = get_event(event);
+ if (event_id >= RISCV_IOMMU_HPMEVENT_MAX ||
+ !test_bit(event_id, iommu_hpm->supported_events)) {
+ dev_dbg(iommu_hpm->pmu.dev, "Invalid event %d for this PMU\n",
+ event_id);
+ return -EINVAL;
+ }
+
+ if (!is_software_event(event->group_leader)) {
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (is_software_event(sibling))
+ continue;
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ event->cpu = iommu_hpm->on_cpu;
+ hwc->idx = -1;
+
+ return 0;
+}
+
+static ssize_t riscv_iommu_hpm_cpumask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(iommu_hpm->on_cpu));
+}
+
+static struct device_attribute riscv_iommu_hpm_cpumask_attr =
+ __ATTR(cpumask, 0444, riscv_iommu_hpm_cpumask_show, NULL);
+
+static struct attribute *riscv_iommu_hpm_cpumask_attrs[] = {
+ &riscv_iommu_hpm_cpumask_attr.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_cpumask_group = {
+ .attrs = riscv_iommu_hpm_cpumask_attrs,
+};
+
+#define IOMMU_HPM_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_ID(name, riscv_iommu_hpm_event_show, config)
+
+static ssize_t riscv_iommu_hpm_event_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+ return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
+static struct attribute *riscv_iommu_hpm_events[] = {
+ IOMMU_HPM_EVENT_ATTR(cycles, RISCV_IOMMU_HPMEVENT_CYCLES),
+ IOMMU_HPM_EVENT_ATTR(untrans_rq, RISCV_IOMMU_HPMEVENT_URQ),
+ IOMMU_HPM_EVENT_ATTR(trans_rq, RISCV_IOMMU_HPMEVENT_TRQ),
+ IOMMU_HPM_EVENT_ATTR(ats_rq, RISCV_IOMMU_HPMEVENT_ATS_RQ),
+ IOMMU_HPM_EVENT_ATTR(tlb_mis, RISCV_IOMMU_HPMEVENT_TLB_MISS),
+ IOMMU_HPM_EVENT_ATTR(dd_walk, RISCV_IOMMU_HPMEVENT_DD_WALK),
+ IOMMU_HPM_EVENT_ATTR(pd_walk, RISCV_IOMMU_HPMEVENT_PD_WALK),
+ IOMMU_HPM_EVENT_ATTR(s_walk, RISCV_IOMMU_HPMEVENT_S_VS_WALKS),
+ IOMMU_HPM_EVENT_ATTR(g_walk, RISCV_IOMMU_HPMEVENT_G_WALKS),
+ NULL
+};
+
+static umode_t riscv_iommu_hpm_event_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int unused)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
+ if (test_bit(pmu_attr->id, iommu_hpm->supported_events))
+ return attr->mode;
+
+ return 0;
+}
+
+static const struct attribute_group riscv_iommu_hpm_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_hpm_events,
+ .is_visible = riscv_iommu_hpm_event_is_visible,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-14");
+PMU_FORMAT_ATTR(filter_pid_pscid, "config1:16-35");
+PMU_FORMAT_ATTR(filter_did_gscid, "config1:36-59");
+PMU_FORMAT_ATTR(filter_pv_pscv, "config1:60");
+PMU_FORMAT_ATTR(filter_dv_gscv, "config1:61");
+PMU_FORMAT_ATTR(filter_idt, "config1:62");
+PMU_FORMAT_ATTR(filter_dmask, "config1:15");
+
+static struct attribute *riscv_iommu_hpm_formats[] = {
+ &format_attr_event.attr,
+ &format_attr_filter_pid_pscid.attr,
+ &format_attr_filter_did_gscid.attr,
+ &format_attr_filter_pv_pscv.attr,
+ &format_attr_filter_dv_gscv.attr,
+ &format_attr_filter_idt.attr,
+ &format_attr_filter_dmask.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_format_group = {
+ .name = "format",
+ .attrs = riscv_iommu_hpm_formats,
+};
+
+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,
+ NULL
+};
+
+static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+ struct riscv_iommu_device *iommu = iommu_hpm->iommu;
+ struct perf_event *event;
+ u32 val;
+ int idx;
+ u32 ovf;
+ DECLARE_BITMAP(ovs, 32);
+
+ val = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IPSR);
+ if (!(val & RISCV_IOMMU_IPSR_PMIP))
+ return IRQ_NONE;
+
+ ovf = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTOVF);
+ if (!ovf)
+ return IRQ_HANDLED;
+
+ /* Handle cycles counter overflow (always stored at index 0) */
+ if (ovf & RISCV_IOMMU_IOCOUNTOVF_CY) {
+ event = iommu_hpm->events[0];
+ if (event && event->hw.idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ riscv_iommu_hpm_cycles_clear_ovf(iommu_hpm);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+ }
+
+ /*
+ * Handle regular HPM counter overflows.
+ * IOCOUNTOVF bit mapping:
+ * bit 0: cycles (already handled above)
+ * bit 1: counter 0 -> events[1]
+ * bit 2: counter 1 -> events[2]
+ * ...
+ * bit N: counter N-1 -> events[N]
+ * We need to check bits [1..num_counters] and skip bit 0.
+ */
+ bitmap_from_u64(ovs, ovf);
+ for_each_set_bit(idx, ovs, iommu_hpm->num_counters) {
+ /* Skip bit 0 (cycles counter, already handled) */
+ if (idx == 0)
+ continue;
+
+ /* IOCOUNTOVF bit N corresponds to counter N-1, stored in
+ * events[N]
+ */
+ event = iommu_hpm->events[idx];
+ if (WARN_ON_ONCE(!event))
+ continue;
+
+ dev_dbg(iommu->dev, "counter overflow: hw_idx=%d, counter=%d\n",
+ idx, idx - 1);
+ riscv_iommu_hpm_counter_clear_ovf(iommu_hpm, idx - 1);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+
+ return IRQ_HANDLED;
+}
+
+static int riscv_iommu_hpm_offline_cpu(unsigned int cpu,
+ struct hlist_node *node)
+{
+ struct riscv_iommu_hpm *iommu_hpm;
+ unsigned int target;
+
+ iommu_hpm = hlist_entry_safe(node, struct riscv_iommu_hpm, node);
+ if (cpu != iommu_hpm->on_cpu)
+ return 0;
+
+ if (!iommu_hpm->irq)
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target >= nr_cpu_ids)
+ return 0;
+
+ perf_pmu_migrate_context(&iommu_hpm->pmu, cpu, target);
+ iommu_hpm->on_cpu = target;
+ if (iommu_hpm->irq > 0)
+ WARN_ON(irq_set_affinity(iommu_hpm->irq, cpumask_of(target)));
+
+ return 0;
+}
+
+static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
+{
+ u64 counter_present_mask = (1ULL << iommu_hpm->num_counters) - 1;
+
+ /* Disable all counters */
+ riscv_iommu_hpm_writel(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTINH,
+ counter_present_mask);
+ /* Clear interrupt pending status */
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+}
+
+static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ /* Cycles counter is always supported */
+ set_bit(RISCV_IOMMU_HPMEVENT_CYCLES, iommu_hpm->supported_events);
+
+ /* Standard RISC-V IOMMU HPM events */
+ set_bit(RISCV_IOMMU_HPMEVENT_URQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TRQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_ATS_RQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TLB_MISS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_DD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_PD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_S_VS_WALKS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
+}
+
+static void riscv_iommu_hpm_remove(void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+
+ riscv_iommu_remove_hpm(iommu_hpm->iommu);
+}
+
+static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_hpm *iommu_hpm,
+ u32 offset, int irq,
+ const struct attribute_group **attr_groups,
+ const char *prefix)
+{
+ struct device *dev = iommu->dev;
+ const char *pmu_name;
+ u32 val;
+ int err;
+ int unique_id;
+ void __iomem *base;
+
+ unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ memset(iommu_hpm, 0, sizeof(*iommu_hpm));
+ iommu_hpm->iommu = iommu;
+
+ if (offset + RISCV_IOMMU_REG_SIZE <= iommu->reg_size)
+ base = iommu->reg + offset;
+ else
+ base = devm_ioremap(dev, iommu->reg_phys + offset,
+ RISCV_IOMMU_REG_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ iommu_hpm->base = base;
+ bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+
+ riscv_iommu_hpm_writel(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
+ val = riscv_iommu_hpm_readl(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH);
+ iommu_hpm->num_counters = hweight32(val & RISCV_IOMMU_IOCOUNTINH_HPM);
+ if (!iommu_hpm->num_counters)
+ return -ENODEV;
+
+ iommu_hpm->on_cpu = raw_smp_processor_id();
+ iommu_hpm->irq = irq;
+
+ riscv_iommu_hpm_reset(iommu_hpm);
+
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
+ prefix, (u8)unique_id);
+ if (!pmu_name)
+ return -ENOMEM;
+
+ err = devm_request_threaded_irq(dev, iommu_hpm->irq, NULL,
+ riscv_iommu_hpm_handle_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ pmu_name, iommu_hpm);
+ if (err)
+ return err;
+ WARN_ON(irq_set_affinity(iommu_hpm->irq,
+ cpumask_of(iommu_hpm->on_cpu)));
+
+ iommu_hpm->pmu = (struct pmu) {
+ .name = pmu_name,
+ .module = THIS_MODULE,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = riscv_iommu_hpm_event_init,
+ .add = riscv_iommu_hpm_event_add,
+ .del = riscv_iommu_hpm_event_del,
+ .start = riscv_iommu_hpm_event_start,
+ .stop = riscv_iommu_hpm_event_stop,
+ .read = riscv_iommu_hpm_event_update,
+ .attr_groups = attr_groups,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+ };
+
+ err = perf_pmu_register(&iommu_hpm->pmu, pmu_name, -1);
+ if (err)
+ goto err_exit;
+
+ dev_set_drvdata(iommu_hpm->pmu.dev, &iommu_hpm->pmu);
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ if (err) {
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ goto err_perf;
+ }
+ cpuhp_refcnt++;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ err = devm_add_action_or_reset(dev, riscv_iommu_hpm_remove,
+ iommu_hpm);
+ if (err)
+ goto err_cpuhp;
+
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
+ pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ return 0;
+
+err_cpuhp:
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ mutex_unlock(&riscv_iommu_hpm_lock);
+err_perf:
+ perf_pmu_unregister(&iommu_hpm->pmu);
+err_exit:
+ return err;
+}
+
+static int riscv_iommu_hpm_init(void)
+{
+ int ret = 0;
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num < 0) {
+ cpuhp_state_num = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ "perf/riscv/iommu:online",
+ NULL,
+ riscv_iommu_hpm_offline_cpu);
+ if (cpuhp_state_num < 0)
+ ret = -EINVAL;
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ return ret;
+}
+
+static void riscv_iommu_hpm_exit(void)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_remove_multi_state(cpuhp_state_num);
+ cpuhp_state_num = -1;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+}
+
+/**
+ * riscv_iommu_add_hpm() - Add HPM support for RISC-V IOMMU
+ *
+ * @iommu: IOMMU device instance
+ *
+ * This API can be invoked from RISC-V IOMMU driver to probe and
+ * initialize the feature of HPM support.
+ */
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ struct device *dev = iommu->dev;
+ int irq, rc;
+
+ if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
+ dev_dbg(dev, "HPM: Not supported\n");
+ return 0;
+ }
+ irq = iommu->irqs[FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec)];
+ if (irq <= 0) {
+ dev_err(dev, "HPM: No IRQ available (vector=%llu)\n",
+ (unsigned long long)FIELD_GET(RISCV_IOMMU_ICVEC_PMIV,
+ iommu->icvec));
+ return -EINVAL;
+ }
+
+ rc = riscv_iommu_hpm_init();
+ if (rc < 0)
+ return rc;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
+ riscv_iommu_hpm_attr_grps,
+ "riscv_iommu_hpm");
+ if (rc < 0)
+ goto err_module;
+ return 0;
+
+err_module:
+ riscv_iommu_hpm_exit();
+ return rc;
+}
+
+/**
+ * riscv_iommu_remove_hpm() - Remove HPM support for RISC-V IOMMU.
+ *
+ * @iommu: IOMMU device instance
+ *
+ * This API can be invoked from RISC-V IOMMU driver to finalize the
+ * feature of HPM support.
+ */
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num >= 0) {
+ cpuhp_refcnt--;
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu->hpm.node);
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ perf_pmu_unregister(&iommu->hpm.pmu);
+ riscv_iommu_hpm_exit();
+}
diff --git a/drivers/iommu/riscv/iommu-pci.c b/drivers/iommu/riscv/iommu-pci.c
index d82d2b00904c..71407aecbf92 100644
--- a/drivers/iommu/riscv/iommu-pci.c
+++ b/drivers/iommu/riscv/iommu-pci.c
@@ -34,6 +34,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
{
struct device *dev = &pdev->dev;
struct riscv_iommu_device *iommu;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
int rc, vec;
rc = pcim_enable_device(pdev);
@@ -43,7 +45,9 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM))
return -ENODEV;
- if (pci_resource_len(pdev, 0) < RISCV_IOMMU_REG_SIZE)
+ reg_phys = pci_resource_start(pdev, 0);
+ reg_size = pci_resource_len(pdev, 0);
+ if (reg_size < RISCV_IOMMU_REG_SIZE)
return -ENODEV;
rc = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
@@ -56,6 +60,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
iommu->dev = dev;
iommu->reg = pcim_iomap_table(pdev)[0];
+ iommu->reg_phys = reg_phys;
+ iommu->reg_size = reg_size;
pci_set_master(pdev);
dev_set_drvdata(dev, iommu);
@@ -91,7 +97,10 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, iommu->fctl);
}
- return riscv_iommu_init(iommu);
+ rc = riscv_iommu_init(iommu);
+ if (rc)
+ return rc;
+ return riscv_iommu_add_hpm(iommu);
}
static void riscv_iommu_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 83a28c83f991..684bc267ac30 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -62,6 +62,9 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(iommu->reg),
"could not map register region\n");
+ iommu->reg_phys = res->start;
+ iommu->reg_size = resource_size(res);
+
dev_set_drvdata(dev, iommu);
/* Check device reported capabilities / features. */
@@ -134,7 +137,10 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, -ENODEV, "invalid IGS\n");
}
- return riscv_iommu_init(iommu);
+ ret = riscv_iommu_init(iommu);
+ if (ret)
+ return ret;
+ return riscv_iommu_add_hpm(iommu);
};
static void riscv_iommu_platform_remove(struct platform_device *pdev)
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..0ad9f5cad4de 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,7 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/iopoll.h>
+#include <linux/perf_event.h>
#include "iommu-bits.h"
@@ -33,6 +34,29 @@ struct riscv_iommu_queue {
u8 qid; /* queue identifier, same as RISCV_IOMMU_INTR_XX */
};
+struct riscv_iommu_hpm {
+ struct riscv_iommu_device *iommu;
+ struct pmu pmu;
+ void __iomem *base;
+ int irq;
+ int on_cpu;
+ struct hlist_node node;
+ /*
+ * Layout of events:
+ * 0 -> HPMCYCLES
+ * 1...n-1 -> HPMEVENTS
+ */
+ struct perf_event *events[RISCV_IOMMU_HPMCOUNTER_MAX];
+ DECLARE_BITMAP(supported_events, RISCV_IOMMU_HPMCOUNTER_MAX);
+ /*
+ * Layout of counters:
+ * 0...min(MAX,n)-2 -> HPMEVENTS
+ * MAX-1 -> HPMCYCLES
+ */
+ DECLARE_BITMAP(used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ unsigned int num_counters;
+};
+
struct riscv_iommu_device {
/* iommu core interface */
struct iommu_device iommu;
@@ -42,6 +66,8 @@ struct riscv_iommu_device {
/* hardware control register space */
void __iomem *reg;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
/* supported and enabled hardware capabilities */
u64 caps;
@@ -60,12 +86,28 @@ struct riscv_iommu_device {
unsigned int ddt_mode;
dma_addr_t ddt_phys;
u64 *ddt_root;
+
+ struct riscv_iommu_hpm hpm;
};
int riscv_iommu_init(struct riscv_iommu_device *iommu);
void riscv_iommu_remove(struct riscv_iommu_device *iommu);
void riscv_iommu_disable(struct riscv_iommu_device *iommu);
+#ifdef CONFIG_RISCV_IOMMU_HPM
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu);
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu);
+#else
+static inline int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ return -ENODEV;
+}
+
+static inline void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+}
+#endif
+
#define riscv_iommu_readl(iommu, addr) \
readl_relaxed((iommu)->reg + (addr))
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (2 preceding siblings ...)
2026-02-04 9:09 ` [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 17:37 ` Conor Dooley
2026-02-04 9:09 ` [PATCH v3 5/8] riscv/iommu: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
` (3 subsequent siblings)
7 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds device tree bindings for SpacemiT T100 specific features by
introducing spacemit,100 compatible. T100 contains distributed IOATCs,
each of which exposes pmiv interrupt.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
.../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
index d4838c3b3741..2da3456e7402 100644
--- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
@@ -32,6 +32,12 @@ properties:
# should be specified along with 'reg' property providing MMIO location.
compatible:
oneOf:
+ - description: SpacemiT distributed IOMMUs
+ items:
+ - enum:
+ - spacemit,t100
+ - const: spacemit,riscv-iommu
+ - const: riscv,iommu
- items:
- enum:
- qemu,riscv-iommu
@@ -75,6 +81,23 @@ required:
additionalProperties: false
+select: false
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: spacemit,riscv-iommu
+ then:
+ properties:
+ interrupts:
+ maxItems: 68
+ description:
+ SpacemiT distributed IOMMU includes additional interrupts for
+ IOATCs. Each IOATC exposes pmiv wired vector as standalone
+ interrupt and the maximum number of IOATCs can be up to 64.
+
examples:
- |+
/* Example 1 (IOMMU device with wired interrupts) */
@@ -145,3 +168,17 @@ examples:
};
};
};
+
+ - |+
+ /* Example 5 (SpacemiT distributed IOMMU) */
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ iommu4: iommu@1bccd000 {
+ compatible = "spacemit,t100", "spacemit,riscv-iommu", "riscv,iommu";
+ reg = <0x1bccd000 0x1000>;
+ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
+ <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
+ <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&saplic>;
+ #iommu-cells = <0x01>;
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 5/8] riscv/iommu: Add vendor event support for RISC-V IOMMU HPM
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (3 preceding siblings ...)
2026-02-04 9:09 ` [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 9:09 ` [PATCH v3 6/8] spacemit/t100: Add global filter awareness " Lv Zheng
` (2 subsequent siblings)
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
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
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 6/8] spacemit/t100: Add global filter awareness for RISC-V IOMMU HPM
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (4 preceding siblings ...)
2026-02-04 9:09 ` [PATCH v3 5/8] riscv/iommu: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 9:09 ` [PATCH v3 7/8] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-04 9:09 ` [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Introduces global filter support for RISC-V IOMMU HPM. The global filter
can be seen in SpacemiT T100 which only supports single filter to be
applied to all event counters.
Drivers can program filters in each iohpmevt registers as normal in such a
silicon design, however the underlying hardware filters are wired together
as a global filter applying to all iohpmevt(s). Since the mechanism is
compatible with standard iohpmevt in programming interface, only adds
sanity checks to allow it to be configured with "global" awareness to
inform users a filter incompatiblity.
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 | 68 ++++++++++++++++++++++++++++++---
drivers/iommu/riscv/iommu.h | 1 +
2 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index e140cf59c408..4a739cb0887c 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -134,6 +134,30 @@ static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
}
+static bool riscv_iommu_hpm_check_global_filter(struct perf_event *curr,
+ struct perf_event *new)
+{
+ return get_filter_pid_pscid(curr) == get_filter_pid_pscid(new) &&
+ get_filter_did_gscid(curr) == get_filter_did_gscid(new) &&
+ get_filter_pv_pscv(curr) == get_filter_pv_pscv(new) &&
+ get_filter_dv_gscv(curr) == get_filter_dv_gscv(new) &&
+ get_filter_idt(curr) == get_filter_idt(new) &&
+ get_filter_dmask(curr) == get_filter_dmask(new);
+}
+
+static bool riscv_iommu_hpm_events_compatible(struct perf_event *curr,
+ struct perf_event *new)
+{
+ if (new->pmu != curr->pmu)
+ return false;
+
+ if (to_iommu_hpm(new->pmu)->global_filter &&
+ !riscv_iommu_hpm_check_global_filter(curr, new))
+ return false;
+
+ return true;
+}
+
/**
* riscv_iommu_hpm_event_update() - Update and return RISC-V IOMMU HPM
* event counters
@@ -268,9 +292,10 @@ static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
}
-static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
- struct perf_event *event, int idx)
+static int riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
{
+ unsigned int cur_idx, num_ctrs = iommu_hpm->num_counters;
u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
pid_pscid = get_filter_pid_pscid(event);
@@ -280,14 +305,36 @@ static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm
idt = get_filter_idt(event);
dmask = get_filter_dmask(event);
+ if (iommu_hpm->global_filter) {
+ cur_idx = find_first_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (cur_idx == num_ctrs - 1) {
+ /* First event, set the global filter */
+ riscv_iommu_hpm_set_event_filter(event, 0, pid_pscid,
+ did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+ } else {
+ /* Check if the new event's filter is compatible with
+ * the global filter
+ */
+ if (!riscv_iommu_hpm_check_global_filter(iommu_hpm->events[cur_idx + 1],
+ event)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "HPM: Filter incompatible with global filter\n");
+ return -EAGAIN;
+ }
+ }
+ return 0;
+ }
+
riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
pv_pscv, dv_gscv, idt, dmask);
+ return 0;
}
static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
struct perf_event *event)
{
- int idx;
+ int idx, err;
unsigned int num_ctrs = iommu_hpm->num_counters;
u16 event_id = get_event(event);
@@ -309,7 +356,9 @@ static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
return -EAGAIN;
}
- riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ err = riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ if (err)
+ return err;
set_bit(idx, iommu_hpm->used_counters);
return idx;
@@ -409,6 +458,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
}
if (!is_software_event(event->group_leader)) {
+ if (!riscv_iommu_hpm_events_compatible(event->group_leader, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -416,6 +467,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
for_each_sibling_event(sibling, event->group_leader) {
if (is_software_event(sibling))
continue;
+ if (!riscv_iommu_hpm_events_compatible(sibling, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -733,6 +786,8 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+ iommu_hpm->global_filter = of_device_is_compatible(dev->of_node,
+ "spacemit,t100");
riscv_iommu_hpm_writel(iommu_hpm,
RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
val = riscv_iommu_hpm_readl(iommu_hpm,
@@ -796,8 +851,9 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
if (err)
goto err_cpuhp;
- dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
- pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d, %s filter)\n",
+ pmu_name, iommu_hpm->num_counters, iommu_hpm->irq,
+ iommu_hpm->global_filter ? "global" : "per-counter");
return 0;
err_cpuhp:
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index d3c11abef5cf..80e96fd7e164 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -42,6 +42,7 @@ struct riscv_iommu_hpm {
int on_cpu;
struct hlist_node node;
const char *identifier;
+ bool global_filter;
/*
* Layout of events:
* 0 -> HPMCYCLES
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 7/8] spacemit/t100: Add SpacemiT T100 IOATC HPM support
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (5 preceding siblings ...)
2026-02-04 9:09 ` [PATCH v3 6/8] spacemit/t100: Add global filter awareness " Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 9:09 ` [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
7 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds IOATC discovery and HPM support for SpacemiT T100.
SpacemiT T100 supports distributed architecture which allows IOTLBs to be
cached in adjacent to the DMA masters. Such IOTLB controllers are called
as IOATCs. Adds distributed HPM support for IOATCs.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-bits.h | 12 ++
drivers/iommu/riscv/iommu-hpm.c | 178 +++++++++++++++++++++++++--
drivers/iommu/riscv/iommu-platform.c | 4 +-
drivers/iommu/riscv/iommu.h | 2 +-
4 files changed, 184 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index cc6bea064d8f..dcf95a99c1d1 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -284,6 +284,18 @@ enum riscv_iommu_hpmevent_id {
#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
+/* 5.28 Distributed translation interface status register (dtisr0-3) (4 * 32-bits) */
+#define RISCV_IOMMU_REG_DTISR_BASE 0x02B0
+#define RISCV_IOMMU_REG_DTISR(_n) (RISCV_IOMMU_REG_DTISR_BASE + ((_n) * 0x04))
+#define RISCV_IOMMU_DTI_STS_SHIFT(_n) (((_n) % 16) * 2)
+#define RISCV_IOMMU_DTI_STS_MASK(_n) (0x3 << RISCV_IOMMU_DTI_STS_SHIFT(_n))
+#define RISCV_IOMMU_DTI_STS_NONE 0x0
+#define RISCV_IOMMU_DTI_STS_IOATC 0x1
+
+#define MAX_RISCV_IOMMU_IOATC 64
+#define RISCV_IOMMU_IOATC_BASE(_base, _idx) \
+ ((void __iomem *)((u8 __iomem *)(_base) + ((_idx) + 1) * RISCV_IOMMU_REG_SIZE))
+
/* 5.28 MSI Configuration table (32 * 64bits) */
#define RISCV_IOMMU_REG_MSI_CFG_TBL 0x0300
#define RISCV_IOMMU_REG_MSI_CFG_TBL_ADDR(_n) \
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index 4a739cb0887c..b027a6ced8b7 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -31,6 +31,73 @@ static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
static int cpuhp_state_num = -1;
static int cpuhp_refcnt;
+struct riscv_iommu_ioatc_desc {
+ u32 offset;
+ int irq;
+ u32 index;
+};
+
+struct riscv_iommu_unit_info {
+ const char *identifier;
+ const char *ioats;
+ const char *ioatc;
+};
+
+#define RISCV_IOMMU_HPM_UNIT_EXTRACTOR(vid, pid, ioats) \
+ { #vid","#pid, #vid"_"#ioats"_hpm", #vid"_ioatc_hpm", }
+
+struct riscv_iommu_unit_info riscv_iommu_hpm_units[] = {
+ RISCV_IOMMU_HPM_UNIT_EXTRACTOR(riscv, iommu, iommu),
+ RISCV_IOMMU_HPM_UNIT_EXTRACTOR(spacemit, riscv-iommu, ioats),
+};
+
+static int riscv_iommu_hpm_collect_ioatcs(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_ioatc_desc *descs,
+ int max_desc)
+{
+ struct device *dev = iommu->dev;
+ struct device_node *np = dev->of_node;
+ int count, index;
+ int i, j;
+ u32 dtisr, state;
+ int nr_irqs, irq;
+
+ if (!descs || max_desc <= 0 || !np)
+ return 0;
+
+ if (iommu->irqs_count <= RISCV_IOMMU_INTR_COUNT)
+ nr_irqs = iommu->irqs_count - RISCV_IOMMU_INTR_COUNT;
+ else
+ nr_irqs = 0;
+
+ /* Automatically discover IOATCs by scanning DTISR registers and
+ * assign IRQs.
+ */
+ count = 0;
+ for (i = 0; i < 4 && count < max_desc; i++) {
+ dtisr = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_DTISR(i));
+ for (j = 0; j < 16 && count < max_desc; j++) {
+ index = i * 16 + j;
+ state = (dtisr & RISCV_IOMMU_DTI_STS_MASK(index)) >>
+ RISCV_IOMMU_DTI_STS_SHIFT(index);
+ if (state != RISCV_IOMMU_DTI_STS_IOATC)
+ continue;
+ descs[count].offset = (index + 1) *
+ RISCV_IOMMU_REG_SIZE;
+ descs[count].index = index;
+ if (count < nr_irqs &&
+ index < MAX_RISCV_IOMMU_IOATC)
+ irq = iommu->irqs[count + RISCV_IOMMU_INTR_COUNT];
+ else
+ irq = 0;
+ descs[count].irq = irq;
+ count++;
+ }
+ }
+
+ return count;
+}
+
static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
u32 val)
{
@@ -603,6 +670,29 @@ static const struct attribute_group *riscv_iommu_hpm_attr_grps[] = {
NULL
};
+#define IOMMU_IOATC_EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR_ID(_name, riscv_iommu_hpm_event_show, _id)
+
+static struct attribute *riscv_iommu_ioatc_events[] = {
+ IOMMU_IOATC_EVENT_ATTR(untrans_rq, RISCV_IOMMU_HPMEVENT_URQ),
+ IOMMU_IOATC_EVENT_ATTR(trans_rq, RISCV_IOMMU_HPMEVENT_TRQ),
+ IOMMU_IOATC_EVENT_ATTR(tlb_mis, RISCV_IOMMU_HPMEVENT_TLB_MISS),
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_ioatc_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_ioatc_events,
+};
+
+static const struct attribute_group *riscv_iommu_ioatc_attr_grps[] = {
+ &riscv_iommu_hpm_cpumask_group,
+ &riscv_iommu_ioatc_events_group,
+ &riscv_iommu_hpm_format_group,
+ &riscv_iommu_hpm_identifier_group,
+ NULL
+};
+
static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -704,7 +794,31 @@ static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
static bool riscv_iommu_hpm_is_identifier_compat(const char *compat)
{
- return !strcmp(compat, "riscv,iommu");
+ int i;
+ struct riscv_iommu_unit_info *info;
+
+ for (i = 0; i < ARRAY_SIZE(riscv_iommu_hpm_units); i++) {
+ info = &riscv_iommu_hpm_units[i];
+ if (!strcmp(info->identifier, compat))
+ return true;
+ }
+ return false;
+}
+
+static const char *riscv_iommu_hpm_get_unit(const char *identifier,
+ bool ioatc)
+{
+ int i;
+ struct riscv_iommu_unit_info *info;
+
+ if (identifier) {
+ for (i = 0; i < ARRAY_SIZE(riscv_iommu_hpm_units); i++) {
+ info = &riscv_iommu_hpm_units[i];
+ if (!strcmp(info->identifier, identifier))
+ return ioatc ? info->ioatc : info->ioats;
+ }
+ }
+ return "riscv_iommu_hpm";
}
static const char *riscv_iommu_hpm_get_identifier(struct device *dev)
@@ -748,6 +862,14 @@ static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hp
set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
}
+static void riscv_iommu_hpm_set_ioatc_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ /* SpacemiT T100 IOATC compatible HPM events */
+ set_bit(RISCV_IOMMU_HPMEVENT_URQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TRQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TLB_MISS, iommu_hpm->supported_events);
+}
+
static void riscv_iommu_hpm_remove(void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -760,16 +882,22 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
u32 offset, int irq,
const char *identifier,
const struct attribute_group **attr_groups,
- const char *prefix)
+ int index, int *puid)
{
struct device *dev = iommu->dev;
- const char *pmu_name;
+ const char *pmu_name, *prefix;
u32 val;
int err;
int unique_id;
void __iomem *base;
- unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ if (index < 0) {
+ unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ *puid = unique_id;
+ } else
+ unique_id = *puid;
+ prefix = riscv_iommu_hpm_get_unit(identifier, index >= 0);
+
memset(iommu_hpm, 0, sizeof(*iommu_hpm));
iommu_hpm->iommu = iommu;
iommu_hpm->identifier = identifier;
@@ -801,9 +929,15 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
riscv_iommu_hpm_reset(iommu_hpm);
- riscv_iommu_hpm_set_standard_events(iommu_hpm);
- pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
- prefix, (u8)unique_id);
+ if (index >= 0) {
+ riscv_iommu_hpm_set_ioatc_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x%02x",
+ prefix, (u8)unique_id, (u8)index);
+ } else {
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
+ prefix, (u8)unique_id);
+ }
if (!pmu_name)
return -ENOMEM;
@@ -905,7 +1039,9 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
{
struct device *dev = iommu->dev;
const char *identifier;
- int irq, rc;
+ int irq, uid, rc, i;
+ struct riscv_iommu_ioatc_desc ioatcs[MAX_RISCV_IOMMU_IOATC];
+ int nr_ioatcs;
if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
dev_dbg(dev, "HPM: Not supported\n");
@@ -930,9 +1066,33 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
identifier,
riscv_iommu_hpm_attr_grps,
- "riscv_iommu_hpm");
+ -1, &uid);
if (rc < 0)
goto err_module;
+
+ nr_ioatcs = riscv_iommu_hpm_collect_ioatcs(iommu, ioatcs,
+ ARRAY_SIZE(ioatcs));
+ for (i = 0; i < nr_ioatcs; i++) {
+ struct riscv_iommu_hpm *extra;
+
+ extra = devm_kzalloc(dev, sizeof(*extra), GFP_KERNEL);
+ if (!extra)
+ continue;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, extra,
+ ioatcs[i].offset,
+ ioatcs[i].irq,
+ identifier,
+ riscv_iommu_ioatc_attr_grps,
+ ioatcs[i].index, &uid);
+ if (rc) {
+ dev_warn(dev,
+ "HPM: Failed to register IOATC%u PMU: %d\n",
+ ioatcs[i].index, rc);
+ continue;
+ }
+ }
+
return 0;
err_module:
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 684bc267ac30..ca8de9ec5266 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -75,8 +75,8 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
if (iommu->irqs_count <= 0)
return dev_err_probe(dev, -ENODEV,
"no IRQ resources provided\n");
- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT)
- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
+ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC)
+ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC;
igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps);
switch (igs) {
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 80e96fd7e164..c2f008d86d63 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -76,7 +76,7 @@ struct riscv_iommu_device {
u32 fctl;
/* available interrupt numbers, MSI or WSI */
- unsigned int irqs[RISCV_IOMMU_INTR_COUNT];
+ unsigned int irqs[RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC];
unsigned int irqs_count;
unsigned int icvec;
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
` (6 preceding siblings ...)
2026-02-04 9:09 ` [PATCH v3 7/8] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
@ 2026-02-04 9:09 ` Lv Zheng
2026-02-04 17:38 ` Conor Dooley
7 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-04 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Add JSON HPM event aliases for SpacemiT distributed IOMMU (T100) which is
general and compatible for all SpacemiT RISC-V SoCs.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
MAINTAINERS | 3 +
.../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 ++++
.../arch/riscv/spacemit/iommu/sys/ioats.json | 163 ++++++++++++++++++
3 files changed, 196 insertions(+)
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c50701b6001..4d91f99aa742 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22459,12 +22459,15 @@ K: riscv
RISC-V IOMMU
M: Tomasz Jeznach <tjeznach@rivosinc.com>
+M: Lv Zheng <lv.zheng@linux.spacemit.com>
+M: Jingyu Li <joey.li@spacemit.com>
L: iommu@lists.linux.dev
L: linux-riscv@lists.infradead.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
F: drivers/iommu/riscv/
+F: tools/perf/pmu-events/arch/riscv/spacemit/iommu/
RISC-V MICROCHIP SUPPORT
M: Conor Dooley <conor.dooley@microchip.com>
diff --git a/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
new file mode 100644
index 000000000000..a16610ba2274
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
@@ -0,0 +1,30 @@
+[
+ {
+ "EventName": "mtlb_lkp",
+ "EventCode": "0x38",
+ "BriefDescription": "IOATC main TLB (MTLB) lookups",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "mtlb_mis",
+ "EventCode": "0x39",
+ "BriefDescription": "IOATC main TLB (MTLB) misses",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "utlb_lkp",
+ "EventCode": "0x3A",
+ "BriefDescription": "IOATC micro TLB (uTLB) lookups",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "utlb_mis",
+ "EventCode": "0x3B",
+ "BriefDescription": "IOATC micro TLB (uTLB) misses",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ }
+]
diff --git a/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
new file mode 100644
index 000000000000..e1fea4e8125c
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
@@ -0,0 +1,163 @@
+[
+ {
+ "EventName": "pri_rq",
+ "EventCode": "0x10",
+ "BriefDescription": "IOATS PCIe page request interface (PRI) requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "ptwc_rq",
+ "EventCode": "0x11",
+ "BriefDescription": "IOATS page table walk (PTW) cache requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_rq",
+ "EventCode": "0x12",
+ "BriefDescription": "IOATS directory table walk (DTW) cache requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_mis",
+ "EventCode": "0x13",
+ "BriefDescription": "IOATS directory table walk (DTW) cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "ptwc_mis",
+ "EventCode": "0x14",
+ "BriefDescription": "IOATS page table walk (PTW) cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "all_trans_rq",
+ "EventCode": "0x15",
+ "BriefDescription": "IOATS all translation requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_lkp",
+ "EventCode": "0x20",
+ "BriefDescription": "IOATS directory table walk (DTW) cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s0_ptwc_lkp",
+ "EventCode": "0x28",
+ "BriefDescription": "IOATS s-stage level-0 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s0_ptwc_mis",
+ "EventCode": "0x29",
+ "BriefDescription": "IOATS s-stage level-0 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s1_ptwc_lkp",
+ "EventCode": "0x2A",
+ "BriefDescription": "IOATS s-stage level-1 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s1_ptwc_mis",
+ "EventCode": "0x2B",
+ "BriefDescription": "IOATS s-stage level-1 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s2_ptwc_lkp",
+ "EventCode": "0x2C",
+ "BriefDescription": "IOATS s-stage level-2 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s2_ptwc_mis",
+ "EventCode": "0x2D",
+ "BriefDescription": "IOATS s-stage level-2 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s3_ptwc_lkp",
+ "EventCode": "0x2E",
+ "BriefDescription": "IOATS s-stage level-3 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s3_ptwc_mis",
+ "EventCode": "0x2F",
+ "BriefDescription": "IOATS s-stage level-3 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g0_ptwc_lkp",
+ "EventCode": "0x30",
+ "BriefDescription": "IOATS g-stage level-0 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g0_ptwc_mis",
+ "EventCode": "0x31",
+ "BriefDescription": "IOATS g-stage level-0 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g1_ptwc_lkp",
+ "EventCode": "0x32",
+ "BriefDescription": "IOATS g-stage level-1 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g1_ptwc_mis",
+ "EventCode": "0x33",
+ "BriefDescription": "IOATS g-stage level-1 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g2_ptwc_lkp",
+ "EventCode": "0x34",
+ "BriefDescription": "IOATS g-stage level-2 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g2_ptwc_mis",
+ "EventCode": "0x35",
+ "BriefDescription": "IOATS g-stage level-2 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g3_ptwc_lkp",
+ "EventCode": "0x36",
+ "BriefDescription": "IOATS g-stage level-3 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g3_ptwc_mis",
+ "EventCode": "0x37",
+ "BriefDescription": "IOATS g-stage level-3 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ }
+]
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
2026-02-04 9:08 ` [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
@ 2026-02-04 17:20 ` Andrew Jones
2026-02-05 3:52 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Andrew Jones @ 2026-02-04 17:20 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On Wed, Feb 04, 2026 at 05:08:52PM +0800, Lv Zheng wrote:
> From: Jingyu Li <joey.li@spacemit.com>
>
> In WSI mode, ICVEC doesn't exist, thus reading it returns 0, which
> causes IOMMU driver to fail to find IRQ numbers from device tree
> IRQ arrary. The issue is fixed by applying icvec indexes of WSI IRQs.
ICVEC always exists, however it may be hardwired to zero when an
implementation only supports a single vector. But, that has nothing
to do with whether wired interrupts or MSIs are used.
If ICVEC on this IOMMU is always reading as zero, even when 0xf is
written to it first, then it should be interpreted as there only
being a single vector (or that the IOMMU's ICVEC is broken, if the
number of sources is known to be more).
>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> ---
> drivers/iommu/riscv/iommu.c | 25 ++++++++++++++++++++-----
> 1 file changed, 20 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index d9429097a2b5..26630979473b 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
> FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
> riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
> iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
> - if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
> - FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
> - max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
> - FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
> - return -EINVAL;
> + /*
> + * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
> + * Check if FCTL.WSI is set to determine interrupt mode.
> + */
> + if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
The behavior of ICVEC does not depend on FCTL.WSI
> + if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
> + FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
> + max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
> + FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
> + return -EINVAL;
> + } else {
> + /*
> + * WSI mode: ICVEC is not used. Set to identity mapping for
> + * riscv_iommu_queue_vec() to work correctly.
> + */
> + iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
> + FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
> + FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
> + FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
It's certainly not correct to set iommu->icvec to anything that can't be
written to the IOMMU's WARL ICVEC fields and read back again.
Thanks,
drew
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-04 9:09 ` [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-02-04 17:37 ` Conor Dooley
2026-02-05 3:11 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-02-04 17:37 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
[-- Attachment #1: Type: text/plain, Size: 3121 bytes --]
On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
> Adds device tree bindings for SpacemiT T100 specific features by
> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
> each of which exposes pmiv interrupt.
>
> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> ---
> .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
> 1 file changed, 37 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> index d4838c3b3741..2da3456e7402 100644
> --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> @@ -32,6 +32,12 @@ properties:
> # should be specified along with 'reg' property providing MMIO location.
> compatible:
> oneOf:
> + - description: SpacemiT distributed IOMMUs
> + items:
> + - enum:
> + - spacemit,t100
> + - const: spacemit,riscv-iommu
What actually is the t100? Is it an SoC or is it the name of the core
complex IP that spacemit is using in multiple SoCs?
> + - const: riscv,iommu
> - items:
> - enum:
> - qemu,riscv-iommu
> @@ -75,6 +81,23 @@ required:
>
> additionalProperties: false
>
> +select: false
Why is this here? It just breaks the whole binding.
pw-bot: changes-requested
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: spacemit,riscv-iommu
> + then:
> + properties:
> + interrupts:
> + maxItems: 68
This isn't right. You would need to make the interrupts property itself
have maxItems: 68, then add an else to this conditional that has
maxItems: 4. What you've done just doesn't work, and if you removed the
"select: false: you'd see.
> + description:
> + SpacemiT distributed IOMMU includes additional interrupts for
> + IOATCs. Each IOATC exposes pmiv wired vector as standalone
> + interrupt and the maximum number of IOATCs can be up to 64.
> +
> examples:
> - |+
> /* Example 1 (IOMMU device with wired interrupts) */
> @@ -145,3 +168,17 @@ examples:
> };
> };
> };
> +
> + - |+
> + /* Example 5 (SpacemiT distributed IOMMU) */
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + iommu4: iommu@1bccd000 {
Remove the iommu4 label, there's no references to it.
Cheers,
Conor.
> + compatible = "spacemit,t100", "spacemit,riscv-iommu", "riscv,iommu";
> + reg = <0x1bccd000 0x1000>;
> + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> + <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
> + <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-parent = <&saplic>;
> + #iommu-cells = <0x01>;
> + };
> --
> 2.43.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing
2026-02-04 9:09 ` [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
@ 2026-02-04 17:38 ` Conor Dooley
2026-02-05 3:22 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-02-04 17:38 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
[-- Attachment #1: Type: text/plain, Size: 1450 bytes --]
On Wed, Feb 04, 2026 at 05:09:52PM +0800, Lv Zheng wrote:
> Add JSON HPM event aliases for SpacemiT distributed IOMMU (T100) which is
> general and compatible for all SpacemiT RISC-V SoCs.
>
> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> ---
> MAINTAINERS | 3 +
> .../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 ++++
> .../arch/riscv/spacemit/iommu/sys/ioats.json | 163 ++++++++++++++++++
> 3 files changed, 196 insertions(+)
> create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
> create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7c50701b6001..4d91f99aa742 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22459,12 +22459,15 @@ K: riscv
>
> RISC-V IOMMU
> M: Tomasz Jeznach <tjeznach@rivosinc.com>
> +M: Lv Zheng <lv.zheng@linux.spacemit.com>
> +M: Jingyu Li <joey.li@spacemit.com>
To be frank, this looks misguided, or at least premature, to me, given the
state of the patchset.
> L: iommu@lists.linux.dev
> L: linux-riscv@lists.infradead.org
> S: Maintained
> T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
> F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> F: drivers/iommu/riscv/
> +F: tools/perf/pmu-events/arch/riscv/spacemit/iommu/
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-04 9:09 ` [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
@ 2026-02-04 18:39 ` Andrew Jones
2026-02-05 2:11 ` Zong Li
2026-02-05 3:35 ` Lv Zheng
0 siblings, 2 replies; 62+ messages in thread
From: Andrew Jones @ 2026-02-04 18:39 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree, zong.li
How does this relate to
https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
From a quick skim it looks like there's plenty of overlap.
Thanks,
drew
On Wed, Feb 04, 2026 at 05:09:01PM +0800, Lv Zheng wrote:
> From: Jingyu Li <joey.li@spacemit.com>
>
> Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
> monitoring capabilities.
>
> Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
> counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
> indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
> IOHPMCTR registers that have already been defined in the iommu-bits.h.
> However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
> the indexes of other HPMEVENTS, thus care should be taken in dealing with
> counter indexes between userspace and kernel space.
>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> Link: https://github.com/riscv-non-isa/riscv-iommu
> ---
> drivers/iommu/riscv/Kconfig | 9 +
> drivers/iommu/riscv/Makefile | 1 +
> drivers/iommu/riscv/iommu-bits.h | 6 +
> drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
> drivers/iommu/riscv/iommu-pci.c | 13 +-
> drivers/iommu/riscv/iommu-platform.c | 8 +-
> drivers/iommu/riscv/iommu.h | 42 ++
> 7 files changed, 919 insertions(+), 3 deletions(-)
> create mode 100644 drivers/iommu/riscv/iommu-hpm.c
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-04 18:39 ` Andrew Jones
@ 2026-02-05 2:11 ` Zong Li
2026-02-05 3:35 ` Lv Zheng
1 sibling, 0 replies; 62+ messages in thread
From: Zong Li @ 2026-02-05 2:11 UTC (permalink / raw)
To: Andrew Jones
Cc: Lv Zheng, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On Thu, Feb 5, 2026 at 2:39 AM Andrew Jones
<andrew.jones@oss.qualcomm.com> wrote:
>
> How does this relate to
>
> https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
>
> From a quick skim it looks like there's plenty of overlap.
>
> Thanks,
> drew
>
Hi all,
Thanks Andrew for bringing me here, and sorry for the long delay on
the IOMMU PMU driver series.
I’m currently working on the next version to incorporate the feedback
from my earlier series. The main goals are to decouple the IOMMU perf
driver from the IOMMU driver itself, and to make it easier to add
custom events.
The implementation is almost done, but I’m still working on binding a
name between the PMU driver with the IOMMU driver on PCIe and ACPI
cases. This part is related to how custom events should be added.
That said, I’m thinking that I could submit the current implementation
first, and then send a separate patch series later to handle the
custom event support.
Also, I’d like to mention that Yaxing has a similar implementation. We
had some discussion about this last month.
https://lore.kernel.org/linux-iommu/2ce9d8be-10b3-48dd-b99e-7358347fc171@bosc.ac.cn/
I think I should be able to submit this next week.
Thanks,
>
> On Wed, Feb 04, 2026 at 05:09:01PM +0800, Lv Zheng wrote:
> > From: Jingyu Li <joey.li@spacemit.com>
> >
> > Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
> > monitoring capabilities.
> >
> > Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
> > counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
> > indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
> > IOHPMCTR registers that have already been defined in the iommu-bits.h.
> > However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
> > the indexes of other HPMEVENTS, thus care should be taken in dealing with
> > counter indexes between userspace and kernel space.
> >
> > Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> > Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> > Link: https://github.com/riscv-non-isa/riscv-iommu
> > ---
> > drivers/iommu/riscv/Kconfig | 9 +
> > drivers/iommu/riscv/Makefile | 1 +
> > drivers/iommu/riscv/iommu-bits.h | 6 +
> > drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
> > drivers/iommu/riscv/iommu-pci.c | 13 +-
> > drivers/iommu/riscv/iommu-platform.c | 8 +-
> > drivers/iommu/riscv/iommu.h | 42 ++
> > 7 files changed, 919 insertions(+), 3 deletions(-)
> > create mode 100644 drivers/iommu/riscv/iommu-hpm.c
> >
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-04 17:37 ` Conor Dooley
@ 2026-02-05 3:11 ` Lv Zheng
2026-02-05 18:24 ` Conor Dooley
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 3:11 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On 2/5/2026 1:37 AM, Conor Dooley wrote:
> On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
>> Adds device tree bindings for SpacemiT T100 specific features by
>> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
>> each of which exposes pmiv interrupt.
>>
>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>> ---
>> .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
>> 1 file changed, 37 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>> index d4838c3b3741..2da3456e7402 100644
>> --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>> +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>> @@ -32,6 +32,12 @@ properties:
>> # should be specified along with 'reg' property providing MMIO location.
>> compatible:
>> oneOf:
>> + - description: SpacemiT distributed IOMMUs
>> + items:
>> + - enum:
>> + - spacemit,t100
>> + - const: spacemit,riscv-iommu
>
> What actually is the t100? Is it an SoC or is it the name of the core
> complex IP that spacemit is using in multiple SoCs?
T100 is the name of the IOMMU IP developed by SpacemiT, announced in
RISC-V 2024 China Summit:
https://www.bilibili.com/video/BV1DNtCeiEBk/
It's world first server SPEC IOMMU in RISC-V, supports IOTLB placed in
adjacent to the DMA masters and supports PCIe ATS and PRI.
You can find it shipped in the recent publicly purchasable SoC SpacemiT K3.
>
>> + - const: riscv,iommu
>> - items:
>> - enum:
>> - qemu,riscv-iommu
>> @@ -75,6 +81,23 @@ required:
>>
>> additionalProperties: false
>>
>> +select: false
>
> Why is this here? It just breaks the whole binding.
> pw-bot: changes-requested
OK.
>
>> +
>> +allOf:
>> + - if:
>> + properties:
>> + compatible:
>> + contains:
>> + const: spacemit,riscv-iommu
>> + then:
>> + properties:
>> + interrupts:
>> + maxItems: 68
>
> This isn't right. You would need to make the interrupts property itself
> have maxItems: 68, then add an else to this conditional that has
> maxItems: 4. What you've done just doesn't work, and if you removed the
> "select: false: you'd see.
Indeed, thanks for pointing this out.
Will dig deeper to correct this.
>
>> + description:
>> + SpacemiT distributed IOMMU includes additional interrupts for
>> + IOATCs. Each IOATC exposes pmiv wired vector as standalone
>> + interrupt and the maximum number of IOATCs can be up to 64.
>> +
>> examples:
>> - |+
>> /* Example 1 (IOMMU device with wired interrupts) */
>> @@ -145,3 +168,17 @@ examples:
>> };
>> };
>> };
>> +
>> + - |+
>> + /* Example 5 (SpacemiT distributed IOMMU) */
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> +
>> + iommu4: iommu@1bccd000 {
>
> Remove the iommu4 label, there's no references to it.
Sure.
Cheers,
Lv
>
> Cheers,
> Conor.
>
>> + compatible = "spacemit,t100", "spacemit,riscv-iommu", "riscv,iommu";
>> + reg = <0x1bccd000 0x1000>;
>> + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
>> + <58 IRQ_TYPE_LEVEL_HIGH>, <58 IRQ_TYPE_LEVEL_HIGH>,
>> + <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
>> + interrupt-parent = <&saplic>;
>> + #iommu-cells = <0x01>;
>> + };
>> --
>> 2.43.0
>>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing
2026-02-04 17:38 ` Conor Dooley
@ 2026-02-05 3:22 ` Lv Zheng
0 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 3:22 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/5/2026 1:38 AM, Conor Dooley wrote:
> On Wed, Feb 04, 2026 at 05:09:52PM +0800, Lv Zheng wrote:
>> Add JSON HPM event aliases for SpacemiT distributed IOMMU (T100) which is
>> general and compatible for all SpacemiT RISC-V SoCs.
>>
>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>> ---
>> MAINTAINERS | 3 +
>> .../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 ++++
>> .../arch/riscv/spacemit/iommu/sys/ioats.json | 163 ++++++++++++++++++
>> 3 files changed, 196 insertions(+)
>> create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
>> create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7c50701b6001..4d91f99aa742 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -22459,12 +22459,15 @@ K: riscv
>>
>> RISC-V IOMMU
>> M: Tomasz Jeznach <tjeznach@rivosinc.com>
>> +M: Lv Zheng <lv.zheng@linux.spacemit.com>
>> +M: Jingyu Li <joey.li@spacemit.com>
>
> To be frank, this looks misguided, or at least premature, to me, given the
> state of the patchset.
Should this be a big deal?
I've been working as kernel maintainers for 5 years (you can find me in
git log using Lv Zheng <lv.zheng@intel.com>) and given the fact that I'm
also the silicon designer of SpacemiT T100, played an active role in
IOMMU spec community, I'm ready to help the community by reviewing
RISC-V IOMMU related changes.
Joey is responsible for SpacemiT RISC-V linux kernel support. We have
chances to test RISC-V linux kernel supports very early using
pre-silicon real hardware here in a silicon team to help the community.
Any suggestions?
>
>> L: iommu@lists.linux.dev
>> L: linux-riscv@lists.infradead.org
>> S: Maintained
>> T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
>> F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>> F: drivers/iommu/riscv/
>> +F: tools/perf/pmu-events/arch/riscv/spacemit/iommu/
checkpatch.pl complains missing files and given the reason above, I
didn't create a "Supported" part of RISC-V IOMMU HPM.
Best regards,
Lv
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-04 18:39 ` Andrew Jones
2026-02-05 2:11 ` Zong Li
@ 2026-02-05 3:35 ` Lv Zheng
2026-02-05 3:47 ` Zong Li
1 sibling, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 3:35 UTC (permalink / raw)
To: Andrew Jones
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree, zong.li
On 2/5/2026 2:39 AM, Andrew Jones wrote:
> How does this relate to
>
> https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
>
> From a quick skim it looks like there's plenty of overlap.
We developed the driver in 2024 and demonstrated it in China summit. We
didn't notice that a patch is on-going now in the community.
Now it looks our approach solved more issues, and we'll check and update
if there are any community concerns still not addressed in this patchset.
We can add Reviewed-by/Tested-by and Signed-off-by of Zong Li to this
patch if he wishes.
Thanks,
Lv
>
> Thanks,
> drew
>
>
> On Wed, Feb 04, 2026 at 05:09:01PM +0800, Lv Zheng wrote:
>> From: Jingyu Li <joey.li@spacemit.com>
>>
>> Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
>> monitoring capabilities.
>>
>> Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
>> counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
>> indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
>> IOHPMCTR registers that have already been defined in the iommu-bits.h.
>> However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
>> the indexes of other HPMEVENTS, thus care should be taken in dealing with
>> counter indexes between userspace and kernel space.
>>
>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>> Link: https://github.com/riscv-non-isa/riscv-iommu
>> ---
>> drivers/iommu/riscv/Kconfig | 9 +
>> drivers/iommu/riscv/Makefile | 1 +
>> drivers/iommu/riscv/iommu-bits.h | 6 +
>> drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
>> drivers/iommu/riscv/iommu-pci.c | 13 +-
>> drivers/iommu/riscv/iommu-platform.c | 8 +-
>> drivers/iommu/riscv/iommu.h | 42 ++
>> 7 files changed, 919 insertions(+), 3 deletions(-)
>> create mode 100644 drivers/iommu/riscv/iommu-hpm.c
>>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-05 3:35 ` Lv Zheng
@ 2026-02-05 3:47 ` Zong Li
2026-02-05 6:11 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Zong Li @ 2026-02-05 3:47 UTC (permalink / raw)
To: Lv Zheng
Cc: Andrew Jones, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Jingyu Li, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On Thu, Feb 5, 2026 at 11:35 AM Lv Zheng <lv.zheng@linux.spacemit.com> wrote:
>
> On 2/5/2026 2:39 AM, Andrew Jones wrote:
> > How does this relate to
> >
> > https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
> >
> > From a quick skim it looks like there's plenty of overlap.
>
> We developed the driver in 2024 and demonstrated it in China summit. We
> didn't notice that a patch is on-going now in the community.
>
> Now it looks our approach solved more issues, and we'll check and update
> if there are any community concerns still not addressed in this patchset.
>
> We can add Reviewed-by/Tested-by and Signed-off-by of Zong Li to this
> patch if he wishes.
>
> Thanks,
> Lv
>
Perhaps I can first post my next revision to the mailing list (hope it
won't waste the community resource), so that you could have a chance
to review it and see whether that version is architecturally closer to
what the community is looking for, while also addressing your issue.
If you also feel that my next revision meets your needs, perhaps you
could append your additional implementations on top of it.
Of course, if the community would prefer to go your version, I’m
perfectly fine with that as well.
> >
> > Thanks,
> > drew
> >
> >
> > On Wed, Feb 04, 2026 at 05:09:01PM +0800, Lv Zheng wrote:
> >> From: Jingyu Li <joey.li@spacemit.com>
> >>
> >> Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
> >> monitoring capabilities.
> >>
> >> Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
> >> counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
> >> indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
> >> IOHPMCTR registers that have already been defined in the iommu-bits.h.
> >> However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
> >> the indexes of other HPMEVENTS, thus care should be taken in dealing with
> >> counter indexes between userspace and kernel space.
> >>
> >> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> >> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> >> Link: https://github.com/riscv-non-isa/riscv-iommu
> >> ---
> >> drivers/iommu/riscv/Kconfig | 9 +
> >> drivers/iommu/riscv/Makefile | 1 +
> >> drivers/iommu/riscv/iommu-bits.h | 6 +
> >> drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
> >> drivers/iommu/riscv/iommu-pci.c | 13 +-
> >> drivers/iommu/riscv/iommu-platform.c | 8 +-
> >> drivers/iommu/riscv/iommu.h | 42 ++
> >> 7 files changed, 919 insertions(+), 3 deletions(-)
> >> create mode 100644 drivers/iommu/riscv/iommu-hpm.c
> >>
> >
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
2026-02-04 17:20 ` Andrew Jones
@ 2026-02-05 3:52 ` Lv Zheng
2026-02-05 15:04 ` Andrew Jones
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 3:52 UTC (permalink / raw)
To: Andrew Jones
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/5/2026 1:20 AM, Andrew Jones wrote:
> On Wed, Feb 04, 2026 at 05:08:52PM +0800, Lv Zheng wrote:
>> From: Jingyu Li <joey.li@spacemit.com>
>>
>> In WSI mode, ICVEC doesn't exist, thus reading it returns 0, which
>> causes IOMMU driver to fail to find IRQ numbers from device tree
>> IRQ arrary. The issue is fixed by applying icvec indexes of WSI IRQs.
>
> ICVEC always exists, however it may be hardwired to zero when an
> implementation only supports a single vector. But, that has nothing
> to do with whether wired interrupts or MSIs are used.
>
> If ICVEC on this IOMMU is always reading as zero, even when 0xf is
> written to it first, then it should be interpreted as there only
> being a single vector (or that the IOMMU's ICVEC is broken, if the
> number of sources is known to be more).
>
>>
>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>> ---
>> drivers/iommu/riscv/iommu.c | 25 ++++++++++++++++++++-----
>> 1 file changed, 20 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
>> index d9429097a2b5..26630979473b 100644
>> --- a/drivers/iommu/riscv/iommu.c
>> +++ b/drivers/iommu/riscv/iommu.c
>> @@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
>> FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
>> riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
>> iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
>> - if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
>> - FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
>> - max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
>> - FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
>> - return -EINVAL;
>> + /*
>> + * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
>> + * Check if FCTL.WSI is set to determine interrupt mode.
>> + */
>> + if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
>
> The behavior of ICVEC does not depend on FCTL.WSI
>
>> + if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
>> + FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
>> + max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
>> + FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
>> + return -EINVAL;
>> + } else {
>> + /*
>> + * WSI mode: ICVEC is not used. Set to identity mapping for
>> + * riscv_iommu_queue_vec() to work correctly.
>> + */
>> + iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
>> + FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
>> + FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
>> + FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
>
> It's certainly not correct to set iommu->icvec to anything that can't be
> written to the IOMMU's WARL ICVEC fields and read back again.
Indeed.
It looks I can keep icvec returned for WSI and keeps the write-and-read
check logic only for MSI.
Thanks,
Lv
>
> Thanks,
> drew
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-05 3:47 ` Zong Li
@ 2026-02-05 6:11 ` Lv Zheng
2026-02-05 15:23 ` Andrew Jones
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 6:11 UTC (permalink / raw)
To: Zong Li
Cc: Andrew Jones, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Jingyu Li, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On 2/5/2026 11:47 AM, Zong Li wrote:
> On Thu, Feb 5, 2026 at 11:35 AM Lv Zheng <lv.zheng@linux.spacemit.com> wrote:
>>
>> On 2/5/2026 2:39 AM, Andrew Jones wrote:
>>> How does this relate to
>>>
>>> https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
>>>
>>> From a quick skim it looks like there's plenty of overlap.
>>
>> We developed the driver in 2024 and demonstrated it in China summit. We
>> didn't notice that a patch is on-going now in the community.
>>
>> Now it looks our approach solved more issues, and we'll check and update
>> if there are any community concerns still not addressed in this patchset.
>>
>> We can add Reviewed-by/Tested-by and Signed-off-by of Zong Li to this
>> patch if he wishes.
>>
>> Thanks,
>> Lv
>>
>
> Perhaps I can first post my next revision to the mailing list (hope it
> won't waste the community resource), so that you could have a chance
> to review it and see whether that version is architecturally closer to
> what the community is looking for, while also addressing your issue.
> If you also feel that my next revision meets your needs, perhaps you
> could append your additional implementations on top of it.
>
It seems we all composed the RISC-V iommu HPM support by referencing
drivers/perf/arm_smmuv3_pmu.
Robin's comments should all be addressed IMHO.
> Of course, if the community would prefer to go your version, I’m
> perfectly fine with that as well.
OK. If we send a next version, we will add your SOB and please help to
review and test.
Thanks in advance,
Lv
>
>>>
>>> Thanks,
>>> drew
>>>
>>>
>>> On Wed, Feb 04, 2026 at 05:09:01PM +0800, Lv Zheng wrote:
>>>> From: Jingyu Li <joey.li@spacemit.com>
>>>>
>>>> Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
>>>> monitoring capabilities.
>>>>
>>>> Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
>>>> counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
>>>> indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
>>>> IOHPMCTR registers that have already been defined in the iommu-bits.h.
>>>> However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
>>>> the indexes of other HPMEVENTS, thus care should be taken in dealing with
>>>> counter indexes between userspace and kernel space.
>>>>
>>>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>>>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>>>> Link: https://github.com/riscv-non-isa/riscv-iommu
>>>> ---
>>>> drivers/iommu/riscv/Kconfig | 9 +
>>>> drivers/iommu/riscv/Makefile | 1 +
>>>> drivers/iommu/riscv/iommu-bits.h | 6 +
>>>> drivers/iommu/riscv/iommu-hpm.c | 843 +++++++++++++++++++++++++++
>>>> drivers/iommu/riscv/iommu-pci.c | 13 +-
>>>> drivers/iommu/riscv/iommu-platform.c | 8 +-
>>>> drivers/iommu/riscv/iommu.h | 42 ++
>>>> 7 files changed, 919 insertions(+), 3 deletions(-)
>>>> create mode 100644 drivers/iommu/riscv/iommu-hpm.c
>>>>
>>>
>>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v4 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU
[not found] <cover.1769562575.git.lv.zheng@spacemit.com>
` (2 preceding siblings ...)
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
@ 2026-02-05 9:09 ` Lv Zheng
2026-02-06 10:46 ` Krzysztof Kozlowski
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
4 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
found in the recent announced SpacemiT SoCs (K3, V100), where T100
(SpacemiT distributed IOMMU) is shipped.
Revisions:
v1
Initial release.
v2 (sent as v1.1)
Split and cleanup DT-bindings.
v3
1. Refactor using vendor specific compatible.
2. Implement vendor events with a userspace identifier.
v4
1. Drop ICVEC check which is not that usful as WSI device tree can use
only 1 vector for IOATS CIV/FIV/PIV/PMIV.
2. Solve DT binding check of "interrupts/maxItems" attribute.
3. Address Robin's comments for an old revision sent by "Zong Li":
https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
4. Limit IOATC enumeration by referencing spacemit,riscv-iommu.
The tested result can be found as follows:
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioats_hpm_00/dd_walk,config1=0x20c0010000000000/ dmatest; sleep 1
[ 145.630224] dmatest: Started 1 threads using dma0chan0
[ 145.644896] dmatest: dma0chan0-copy0: summary 1 tests, 0 failures 123.60 iops 123 KB/s (0)
Performance counter stats for 'system wide':
3 spacemit_ioats_hpm_00/dd_walk,config1=0x20c0010000000000/
0.193108000 seconds time elapsed
root@sdfirm:~# echo dma0chan1 > /sys/module/dmatest/parameters/channel
[ 327.001820] dmatest: Added 1 threads using dma0chan1
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioats_hpm_00/s_walk,config1=0x20c0011000000000/ dmatest; sleep 1
[ 484.037180] dmatest: Started 1 threads using dma0chan1
[ 484.048832] dmatest: dma0chan1-copy0: summary 1 tests, 0 failures 172.11 iops 172 KB/s (0)
Performance counter stats for 'system wide':
6 spacemit_ioats_hpm_00/s_walk,config1=0x20c0011000000000/
0.191970000 seconds time elapsed
root@sdfirm:~# perf stat --timeout 5000 -a -e spacemit_ioatc_hpm_0003/tlb_mis,config1=0x20c0011000000000/ dmatest; sleep 1
[ 546.332494] dmatest: No channels configured, continue with any
[ 546.363062] dmatest: Added 1 threads using dma0chan1
[ 546.377994] dmatest: Started 1 threads using dma0chan1
[ 546.388376] dmatest: dma0chan1-copy0: summary 1 tests, 0 failures 213.94 iops 213 KB/s (0)
Performance counter stats for 'system wide':
3 spacemit_ioatc_hpm_0003/tlb_mis,config1=0x20c0011000000000/
0.225062000 seconds time elapsed
Jingyu Li (2):
iommu/riscv: Enable IOMMU DMA mapping support
iommu/riscv: Add HPM support for performance monitoring
Lv Zheng (5):
dt-bindings: iommu: Add spacemit/t100 features
iommu/riscv: Add vendor event support for RISC-V IOMMU HPM
spacemit/t100: Add global filter awareness for RISC-V IOMMU HPM
spacemit/t100: Add SpacemiT T100 IOATC HPM support
perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM
aliasing
.../bindings/iommu/riscv,iommu.yaml | 53 +-
MAINTAINERS | 3 +
drivers/iommu/Kconfig | 2 +-
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 18 +
drivers/iommu/riscv/iommu-hpm.c | 1123 +++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 12 +-
drivers/iommu/riscv/iommu.h | 46 +-
.../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 +
.../arch/riscv/spacemit/iommu/sys/ioats.json | 163 +++
12 files changed, 1464 insertions(+), 9 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
--
2.43.0
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v4 1/7] iommu/riscv: Enable IOMMU DMA mapping support
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
@ 2026-02-05 9:10 ` Lv Zheng
2026-02-05 9:10 ` [PATCH v4 2/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
` (5 subsequent siblings)
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:10 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
From: Jingyu Li <joey.li@spacemit.com>
Enables IOMMU DMA mapping support for RISC-V, so that DMACs can be tested
with translation enabled.
Known Possible Issue:
1. When CONFIG_IOMMU_DMA is enabled, on the tested Linux, RISC-V IOMMU is
lack of PCIe support, causing riscv_iommu_fault:522 in dealing with
NVMe PCIe devices.
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f86262b11416..34d8a792339f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -151,7 +151,7 @@ config OF_IOMMU
# IOMMU-agnostic DMA-mapping layer
config IOMMU_DMA
- def_bool ARM64 || X86 || S390
+ def_bool ARM64 || X86 || S390 || RISCV
select DMA_OPS_HELPERS
select IOMMU_API
select IOMMU_IOVA
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 2/7] iommu/riscv: Add HPM support for performance monitoring
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
2026-02-05 9:10 ` [PATCH v4 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
@ 2026-02-05 9:10 ` Lv Zheng
2026-02-05 9:10 ` [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
` (4 subsequent siblings)
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:10 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree, Zong Li
From: Jingyu Li <joey.li@spacemit.com>
Introduces perf-based HPM driver for RISC-V IOMMU, enabling performance
monitoring capabilities.
Note that the RISC-V IOMMU HPM module uses COUNTER_MAX-1 as a static
counter index of HPMCYCLES, and 0~COUNTER_MAX-2 as the dynamic counter
indexes of other HPMEVENTS in order to correctly index into IOHPMEVT and
IOHPMCTR registers that have already been defined in the iommu-bits.h.
However the users treat 0 as the index of HPMCYCLES and 1~COUNTER_MAX-1 as
the indexes of other HPMEVENTS, thus care should be taken in dealing with
counter indexes between userspace and kernel space.
Also addresses community comments in the revision sent by "Zong Li".
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Link: https://github.com/riscv-non-isa/riscv-iommu
Link: https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
Signed-off-by: Zong Li <zong.li@sifive.com>
---
drivers/iommu/riscv/Kconfig | 9 +
drivers/iommu/riscv/Makefile | 1 +
drivers/iommu/riscv/iommu-bits.h | 6 +
drivers/iommu/riscv/iommu-hpm.c | 840 +++++++++++++++++++++++++++
drivers/iommu/riscv/iommu-pci.c | 13 +-
drivers/iommu/riscv/iommu-platform.c | 8 +-
drivers/iommu/riscv/iommu.h | 42 ++
7 files changed, 916 insertions(+), 3 deletions(-)
create mode 100644 drivers/iommu/riscv/iommu-hpm.c
diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index c071816f59a6..2d06a1ef11c9 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -18,3 +18,12 @@ config RISCV_IOMMU_PCI
def_bool y if RISCV_IOMMU && PCI_MSI
help
Support for the PCIe implementation of RISC-V IOMMU architecture.
+
+config RISCV_IOMMU_HPM
+ tristate "RISCV IOMMU HPM support"
+ depends on RISCV_IOMMU
+ help
+ Provides support for the RISC-V IOMMU Hardware Performance Monitor
+ (HPM), which provide monitoring of transactions passing through the
+ IOMMU and allow the resulting information to be filtered based on
+ the device/process ID of the corresponding master.
diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
index b5929f9f23e6..53db3ef62bdd 100644
--- a/drivers/iommu/riscv/Makefile
+++ b/drivers/iommu/riscv/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += iommu.o iommu-platform.o
obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o
+obj-$(CONFIG_RISCV_IOMMU_HPM) += iommu-hpm.o
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 98daf0e1a306..cc6bea064d8f 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -207,6 +207,7 @@ enum riscv_iommu_ddtp_modes {
/* 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))
+#define RISCV_IOMMU_IOHPMEVENT_COUNTER GENMASK_ULL(63, 0)
/* 5.23 Performance monitoring event selectors (31 * 64bits) */
#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160
@@ -222,6 +223,9 @@ enum riscv_iommu_ddtp_modes {
/* Number of defined performance-monitoring event selectors */
#define RISCV_IOMMU_IOHPMEVT_CNT 31
+/* Cycles counter is statically indexed as the last counter */
+#define RISCV_IOMMU_HPMCOUNTER_CYCLES RISCV_IOMMU_IOHPMEVT_CNT
+#define RISCV_IOMMU_HPMCOUNTER_MAX (RISCV_IOMMU_IOHPMEVT_CNT + 1)
/**
* enum riscv_iommu_hpmevent_id - Performance-monitoring event identifier
@@ -250,6 +254,8 @@ enum riscv_iommu_hpmevent_id {
RISCV_IOMMU_HPMEVENT_MAX = 9
};
+#define RISCV_IOMMU_HPMEVENT_CYCLES RISCV_IOMMU_HPMEVENT_INVALID
+
/* 5.24 Translation request IOVA (64bits) */
#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258
#define RISCV_IOMMU_TR_REQ_IOVA_VPN GENMASK_ULL(63, 12)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
new file mode 100644
index 000000000000..fe51f60c0c75
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -0,0 +1,840 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * iommu-hpm.c: RISC-V IOMMU Hardware Performance Monitor driver
+ *
+ * Copyright (C) 2026 SpacemiT Technologies Inc.
+ * Author: 2026 Jingyu Li <joey.li@spacemit.com>
+ * Lv Zheng <lv.zheng@spacemit.com>
+ */
+
+#include "iommu.h"
+
+#define to_iommu_hpm(p) (container_of(p, struct riscv_iommu_hpm, pmu))
+
+#define RISCV_IOMMU_HPM_EVENT_EXTRACTOR(_n, _c, _s, _e) \
+ static inline u32 get_##_n(struct perf_event *event) \
+ { \
+ return FIELD_GET(GENMASK_ULL(_e, _s), \
+ event->attr._c); \
+ }
+
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(event, config, 0, 14);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dmask, config1, 15, 15);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pid_pscid, config1, 16, 35);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_did_gscid, config1, 36, 59);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_pv_pscv, config1, 60, 60);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_dv_gscv, config1, 61, 61);
+RISCV_IOMMU_HPM_EVENT_EXTRACTOR(filter_idt, config1, 62, 62);
+
+static DEFINE_MUTEX(riscv_iommu_hpm_lock);
+static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
+static int cpuhp_state_num = -1;
+static int cpuhp_refcnt;
+
+static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
+ u32 val)
+{
+ writel_relaxed(val, hpm->base + reg);
+}
+
+static inline u32 riscv_iommu_hpm_readl(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readl_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_writeq(struct riscv_iommu_hpm *hpm, u32 reg,
+ u64 val)
+{
+ writeq_relaxed(val, hpm->base + reg);
+}
+
+static inline u64 riscv_iommu_hpm_readq(struct riscv_iommu_hpm *hpm, u32 reg)
+{
+ return readq_relaxed(hpm->base + reg);
+}
+
+static inline void riscv_iommu_hpm_cycles_set_value(struct riscv_iommu_hpm *hpm,
+ u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES,
+ value & RISCV_IOMMU_IOHPMCYCLES_COUNTER);
+}
+
+static inline u64 riscv_iommu_hpm_cycles_get_value(struct riscv_iommu_hpm *hpm)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES) &
+ RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+}
+
+static inline void riscv_iommu_hpm_counter_set_value(struct riscv_iommu_hpm *hpm,
+ u32 idx, u64 value)
+{
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx), value);
+}
+
+static inline u64 riscv_iommu_hpm_counter_get_value(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ return riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCTR(idx));
+}
+
+static inline void riscv_iommu_hpm_cycles_enable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_disable(struct riscv_iommu_hpm *hpm)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= RISCV_IOMMU_IOCOUNTINH_CY;
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_enable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val &= ~BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_counter_disable(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u32 val = riscv_iommu_hpm_readl(hpm, RISCV_IOMMU_REG_IOCOUNTINH);
+
+ val |= BIT(idx + 1);
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IOCOUNTINH, val);
+}
+
+static inline void riscv_iommu_hpm_cycles_clear_ovf(struct riscv_iommu_hpm *hpm)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES);
+
+ val &= ~RISCV_IOMMU_IOHPMCYCLES_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMCYCLES, val);
+}
+
+static inline void riscv_iommu_hpm_counter_clear_ovf(struct riscv_iommu_hpm *hpm,
+ u32 idx)
+{
+ u64 val = riscv_iommu_hpm_readq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx));
+
+ val &= ~RISCV_IOMMU_IOHPMEVT_OF;
+ riscv_iommu_hpm_writeq(hpm, RISCV_IOMMU_REG_IOHPMEVT(idx), val);
+}
+
+static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
+{
+ riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
+}
+
+/**
+ * riscv_iommu_hpm_event_update() - Update and return RISC-V IOMMU HPM
+ * event counters
+ *
+ * @event: IOMMU performance event
+ *
+ * This function can be used to implement the .read() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_update(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 delta, prev, now;
+ u32 idx = hwc->idx;
+
+ do {
+ prev = local64_read(&hwc->prev_count);
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ now = riscv_iommu_hpm_cycles_get_value(iommu_hpm);
+ else
+ now = riscv_iommu_hpm_counter_get_value(iommu_hpm, idx);
+ } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
+
+ delta = now - prev;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ delta &= RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ delta &= RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ local64_add(delta, &event->count);
+}
+
+static void riscv_iommu_hpm_set_period(struct riscv_iommu_hpm *iommu_hpm,
+ struct hw_perf_event *hwc)
+{
+ u32 idx = hwc->idx;
+ u64 new, max_period;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ max_period = RISCV_IOMMU_IOHPMCYCLES_COUNTER;
+ else
+ max_period = RISCV_IOMMU_IOHPMEVENT_COUNTER;
+
+ /* Start at half the counter range */
+ new = max_period >> 1;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_set_value(iommu_hpm, new);
+ else
+ riscv_iommu_hpm_counter_set_value(iommu_hpm, idx, new);
+
+ local64_set(&hwc->prev_count, new);
+}
+
+/**
+ * riscv_iommu_hpm_event_start() - Start RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .start() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_start(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ hwc->state = 0;
+ riscv_iommu_hpm_set_period(iommu_hpm, hwc);
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_enable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_enable(iommu_hpm, idx);
+}
+
+/**
+ * riscv_iommu_hpm_event_stop() - Stop RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .stop() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_stop(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ if (hwc->state & PERF_HES_STOPPED)
+ return;
+
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ riscv_iommu_hpm_cycles_disable(iommu_hpm);
+ else
+ riscv_iommu_hpm_counter_disable(iommu_hpm, idx);
+
+ if (flags & PERF_EF_UPDATE)
+ riscv_iommu_hpm_event_update(event);
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+}
+
+static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
+ u32 pid_pscid, u32 did_gscid,
+ u32 pv_pscv,
+ u32 dv_gscv, u32 idt, u32 dmask)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ u64 event_cfg;
+
+ /* Start with event ID */
+ event_cfg = get_event(event);
+ /* Set ID fields - values of 0 are valid */
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_PID_PSCID,
+ pid_pscid & 0xFFFFF);
+ event_cfg |= FIELD_PREP(RISCV_IOMMU_IOHPMEVT_DID_GSCID,
+ did_gscid & 0xFFFFFF);
+ /* Set control flags - 0 means disabled, 1 means enabled */
+ if (pv_pscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_PV_PSCV;
+ if (dv_gscv)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DV_GSCV;
+ if (idt)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_IDT;
+ if (dmask)
+ event_cfg |= RISCV_IOMMU_IOHPMEVT_DMASK;
+
+ /* Write to the specific event register for this counter */
+ riscv_iommu_hpm_writeq(iommu_hpm,
+ RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
+}
+
+static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
+{
+ u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
+
+ pid_pscid = get_filter_pid_pscid(event);
+ did_gscid = get_filter_did_gscid(event);
+ pv_pscv = get_filter_pv_pscv(event);
+ dv_gscv = get_filter_dv_gscv(event);
+ idt = get_filter_idt(event);
+ dmask = get_filter_dmask(event);
+
+ riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+}
+
+static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event)
+{
+ int idx;
+ unsigned int num_ctrs = iommu_hpm->num_counters;
+ u16 event_id = get_event(event);
+
+ /* Handle cycles event specially */
+ if (event_id == RISCV_IOMMU_HPMEVENT_CYCLES) {
+ /* Check if cycles counter is already in use */
+ if (test_and_set_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "Cycles counter already in use\n");
+ return -EAGAIN;
+ }
+ return RISCV_IOMMU_HPMCOUNTER_CYCLES;
+ }
+
+ idx = find_first_zero_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (idx == num_ctrs - 1) {
+ dev_dbg(iommu_hpm->pmu.dev, "All counters already in use\n");
+ return -EAGAIN;
+ }
+
+ riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ set_bit(idx, iommu_hpm->used_counters);
+
+ return idx;
+}
+
+/**
+ * riscv_iommu_hpm_event_add() - Add a RISC-V IOMMU HPM event
+ *
+ * @event - IOMMU performance event
+ * @flags - Performance event flags
+ *
+ * This function can be used to implement the .add() interface of pmu.
+ */
+static int riscv_iommu_hpm_event_add(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ idx = riscv_iommu_hpm_get_event_idx(iommu_hpm, event);
+ hwc->idx = idx;
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES)
+ iommu_hpm->events[0] = event;
+ else
+ iommu_hpm->events[idx + 1] = event;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ riscv_iommu_hpm_event_start(event, flags);
+ perf_event_update_userpage(event);
+
+ return 0;
+}
+
+/**
+ * riscv_iommu_hpm_event_del() - Delete a RISC-V IOMMU HPM event
+ *
+ * @event: IOMMU performance event
+ * @flags: Performance event flags
+ *
+ * This function can be used to implement the .del() interface of pmu.
+ */
+static void riscv_iommu_hpm_event_del(struct perf_event *event, int flags)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u32 idx = hwc->idx;
+
+ riscv_iommu_hpm_event_stop(event, flags | PERF_EF_UPDATE);
+
+ /* Clear the used counter bit and event array entry */
+ if (idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ clear_bit(RISCV_IOMMU_HPMCOUNTER_CYCLES,
+ iommu_hpm->used_counters);
+ iommu_hpm->events[0] = NULL;
+ } else {
+ clear_bit(idx, iommu_hpm->used_counters);
+ iommu_hpm->events[idx + 1] = NULL;
+ }
+
+ perf_event_update_userpage(event);
+}
+
+/**
+ * riscv_iommu_hpm_event_init() - Initialize HPM event attributes
+ *
+ * @event: IOMMU performance event
+ *
+ * This function can be used to implement the .event_init() interface of
+ * pmu.
+ */
+static int riscv_iommu_hpm_event_init(struct perf_event *event)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event *sibling;
+ int group_num_events = 1;
+ u16 event_id;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+ if (hwc->sample_period)
+ return -EINVAL;
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ event_id = get_event(event);
+ if (event_id >= RISCV_IOMMU_HPMEVENT_MAX ||
+ !test_bit(event_id, iommu_hpm->supported_events)) {
+ dev_dbg(iommu_hpm->pmu.dev, "Invalid event %d for this PMU\n",
+ event_id);
+ return -EINVAL;
+ }
+
+ if (!is_software_event(event->group_leader)) {
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (is_software_event(sibling))
+ continue;
+ if (++group_num_events > iommu_hpm->num_counters)
+ return -EINVAL;
+ }
+
+ event->cpu = iommu_hpm->on_cpu;
+ hwc->idx = -1;
+
+ return 0;
+}
+
+static ssize_t riscv_iommu_hpm_cpumask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(iommu_hpm->on_cpu));
+}
+
+static struct device_attribute riscv_iommu_hpm_cpumask_attr =
+ __ATTR(cpumask, 0444, riscv_iommu_hpm_cpumask_show, NULL);
+
+static struct attribute *riscv_iommu_hpm_cpumask_attrs[] = {
+ &riscv_iommu_hpm_cpumask_attr.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_cpumask_group = {
+ .attrs = riscv_iommu_hpm_cpumask_attrs,
+};
+
+#define IOMMU_HPM_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_ID(name, riscv_iommu_hpm_event_show, config)
+
+static ssize_t riscv_iommu_hpm_event_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+ return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
+static struct attribute *riscv_iommu_hpm_events[] = {
+ IOMMU_HPM_EVENT_ATTR(cycles, RISCV_IOMMU_HPMEVENT_CYCLES),
+ IOMMU_HPM_EVENT_ATTR(untrans_rq, RISCV_IOMMU_HPMEVENT_URQ),
+ IOMMU_HPM_EVENT_ATTR(trans_rq, RISCV_IOMMU_HPMEVENT_TRQ),
+ IOMMU_HPM_EVENT_ATTR(ats_rq, RISCV_IOMMU_HPMEVENT_ATS_RQ),
+ IOMMU_HPM_EVENT_ATTR(tlb_mis, RISCV_IOMMU_HPMEVENT_TLB_MISS),
+ IOMMU_HPM_EVENT_ATTR(dd_walk, RISCV_IOMMU_HPMEVENT_DD_WALK),
+ IOMMU_HPM_EVENT_ATTR(pd_walk, RISCV_IOMMU_HPMEVENT_PD_WALK),
+ IOMMU_HPM_EVENT_ATTR(s_walk, RISCV_IOMMU_HPMEVENT_S_VS_WALKS),
+ IOMMU_HPM_EVENT_ATTR(g_walk, RISCV_IOMMU_HPMEVENT_G_WALKS),
+ NULL
+};
+
+static umode_t riscv_iommu_hpm_event_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int unused)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct riscv_iommu_hpm *iommu_hpm = to_iommu_hpm(dev_get_drvdata(dev));
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr);
+ if (test_bit(pmu_attr->id, iommu_hpm->supported_events))
+ return attr->mode;
+
+ return 0;
+}
+
+static const struct attribute_group riscv_iommu_hpm_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_hpm_events,
+ .is_visible = riscv_iommu_hpm_event_is_visible,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-14");
+PMU_FORMAT_ATTR(filter_pid_pscid, "config1:16-35");
+PMU_FORMAT_ATTR(filter_did_gscid, "config1:36-59");
+PMU_FORMAT_ATTR(filter_pv_pscv, "config1:60");
+PMU_FORMAT_ATTR(filter_dv_gscv, "config1:61");
+PMU_FORMAT_ATTR(filter_idt, "config1:62");
+PMU_FORMAT_ATTR(filter_dmask, "config1:15");
+
+static struct attribute *riscv_iommu_hpm_formats[] = {
+ &format_attr_event.attr,
+ &format_attr_filter_pid_pscid.attr,
+ &format_attr_filter_did_gscid.attr,
+ &format_attr_filter_pv_pscv.attr,
+ &format_attr_filter_dv_gscv.attr,
+ &format_attr_filter_idt.attr,
+ &format_attr_filter_dmask.attr,
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_hpm_format_group = {
+ .name = "format",
+ .attrs = riscv_iommu_hpm_formats,
+};
+
+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,
+ NULL
+};
+
+static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+ struct riscv_iommu_device *iommu = iommu_hpm->iommu;
+ struct perf_event *event;
+ u32 val;
+ int idx;
+ u32 ovf;
+ DECLARE_BITMAP(ovs, 32);
+
+ val = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IPSR);
+ if (!(val & RISCV_IOMMU_IPSR_PMIP))
+ return IRQ_NONE;
+
+ ovf = riscv_iommu_hpm_readl(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTOVF);
+ if (!ovf)
+ return IRQ_HANDLED;
+
+ /* Handle cycles counter overflow (always stored at index 0) */
+ if (ovf & RISCV_IOMMU_IOCOUNTOVF_CY) {
+ event = iommu_hpm->events[0];
+ if (event && event->hw.idx == RISCV_IOMMU_HPMCOUNTER_CYCLES) {
+ riscv_iommu_hpm_cycles_clear_ovf(iommu_hpm);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+ }
+
+ /*
+ * Handle regular HPM counter overflows.
+ * IOCOUNTOVF bit mapping:
+ * bit 0: cycles (already handled above)
+ * bit 1: counter 0 -> events[1]
+ * bit 2: counter 1 -> events[2]
+ * ...
+ * bit N: counter N-1 -> events[N]
+ * We need to check bits [1..num_counters] and skip bit 0.
+ */
+ bitmap_from_u64(ovs, ovf);
+ for_each_set_bit(idx, ovs, iommu_hpm->num_counters) {
+ /* Skip bit 0 (cycles counter, already handled) */
+ if (idx == 0)
+ continue;
+
+ /* IOCOUNTOVF bit N corresponds to counter N-1, stored in
+ * events[N]
+ */
+ event = iommu_hpm->events[idx];
+ if (WARN_ON_ONCE(!event))
+ continue;
+
+ dev_dbg(iommu->dev, "counter overflow: hw_idx=%d, counter=%d\n",
+ idx, idx - 1);
+ riscv_iommu_hpm_counter_clear_ovf(iommu_hpm, idx - 1);
+ riscv_iommu_hpm_event_update(event);
+ riscv_iommu_hpm_set_period(iommu_hpm, &event->hw);
+ }
+
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+
+ return IRQ_HANDLED;
+}
+
+static int riscv_iommu_hpm_offline_cpu(unsigned int cpu,
+ struct hlist_node *node)
+{
+ struct riscv_iommu_hpm *iommu_hpm;
+ unsigned int target;
+
+ iommu_hpm = hlist_entry_safe(node, struct riscv_iommu_hpm, node);
+ if (cpu != iommu_hpm->on_cpu)
+ return 0;
+
+ if (!iommu_hpm->irq)
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target >= nr_cpu_ids)
+ return 0;
+
+ perf_pmu_migrate_context(&iommu_hpm->pmu, cpu, target);
+ iommu_hpm->on_cpu = target;
+ if (iommu_hpm->irq > 0)
+ WARN_ON(irq_set_affinity(iommu_hpm->irq, cpumask_of(target)));
+
+ return 0;
+}
+
+static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
+{
+ u64 counter_present_mask = (1ULL << iommu_hpm->num_counters) - 1;
+
+ /* Disable all counters */
+ riscv_iommu_hpm_writel(iommu_hpm, RISCV_IOMMU_REG_IOCOUNTINH,
+ counter_present_mask);
+ /* Clear interrupt pending status */
+ riscv_iommu_hpm_interrupt_clear(iommu_hpm);
+}
+
+static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ /* Cycles counter is always supported */
+ set_bit(RISCV_IOMMU_HPMEVENT_CYCLES, iommu_hpm->supported_events);
+
+ /* Standard RISC-V IOMMU HPM events */
+ set_bit(RISCV_IOMMU_HPMEVENT_URQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TRQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_ATS_RQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TLB_MISS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_DD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_PD_WALK, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_S_VS_WALKS, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
+}
+
+static void riscv_iommu_hpm_remove(void *data)
+{
+ struct riscv_iommu_hpm *iommu_hpm = data;
+
+ riscv_iommu_remove_hpm(iommu_hpm->iommu);
+}
+
+static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_hpm *iommu_hpm,
+ u32 offset, int irq,
+ const struct attribute_group **attr_groups,
+ const char *prefix)
+{
+ struct device *dev = iommu->dev;
+ const char *pmu_name;
+ u32 val;
+ int err;
+ int unique_id;
+ void __iomem *base;
+
+ unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ memset(iommu_hpm, 0, sizeof(*iommu_hpm));
+ iommu_hpm->iommu = iommu;
+
+ if (offset + RISCV_IOMMU_REG_SIZE <= iommu->reg_size)
+ base = iommu->reg + offset;
+ else
+ base = devm_ioremap(dev, iommu->reg_phys + offset,
+ RISCV_IOMMU_REG_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ iommu_hpm->base = base;
+ bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+
+ riscv_iommu_hpm_writel(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
+ val = riscv_iommu_hpm_readl(iommu_hpm,
+ RISCV_IOMMU_REG_IOCOUNTINH);
+ iommu_hpm->num_counters = hweight32(val & RISCV_IOMMU_IOCOUNTINH_HPM);
+ if (!iommu_hpm->num_counters)
+ return -ENODEV;
+
+ iommu_hpm->on_cpu = raw_smp_processor_id();
+ iommu_hpm->irq = irq;
+
+ riscv_iommu_hpm_reset(iommu_hpm);
+
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
+ prefix, (u8)unique_id);
+ if (!pmu_name)
+ return -ENOMEM;
+
+ err = devm_request_threaded_irq(dev, iommu_hpm->irq, NULL,
+ riscv_iommu_hpm_handle_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ pmu_name, iommu_hpm);
+ if (err)
+ return err;
+ WARN_ON(irq_set_affinity(iommu_hpm->irq,
+ cpumask_of(iommu_hpm->on_cpu)));
+
+ iommu_hpm->pmu = (struct pmu) {
+ .name = pmu_name,
+ .module = THIS_MODULE,
+ .parent = dev,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = riscv_iommu_hpm_event_init,
+ .add = riscv_iommu_hpm_event_add,
+ .del = riscv_iommu_hpm_event_del,
+ .start = riscv_iommu_hpm_event_start,
+ .stop = riscv_iommu_hpm_event_stop,
+ .read = riscv_iommu_hpm_event_update,
+ .attr_groups = attr_groups,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE,
+ };
+
+ err = perf_pmu_register(&iommu_hpm->pmu, pmu_name, -1);
+ if (err)
+ goto err_exit;
+
+ dev_set_drvdata(iommu_hpm->pmu.dev, &iommu_hpm->pmu);
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ if (err) {
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ goto err_perf;
+ }
+ cpuhp_refcnt++;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ err = devm_add_action_or_reset(dev, riscv_iommu_hpm_remove,
+ iommu_hpm);
+ if (err)
+ goto err_cpuhp;
+
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
+ pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ return 0;
+
+err_cpuhp:
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu_hpm->node);
+ mutex_unlock(&riscv_iommu_hpm_lock);
+err_perf:
+ perf_pmu_unregister(&iommu_hpm->pmu);
+err_exit:
+ return err;
+}
+
+static int riscv_iommu_hpm_init(void)
+{
+ int ret = 0;
+
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num < 0) {
+ cpuhp_state_num = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
+ "perf/riscv/iommu:online",
+ NULL,
+ riscv_iommu_hpm_offline_cpu);
+ if (cpuhp_state_num < 0)
+ ret = -EINVAL;
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+
+ return ret;
+}
+
+static void riscv_iommu_hpm_exit(void)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ cpuhp_remove_multi_state(cpuhp_state_num);
+ cpuhp_state_num = -1;
+ mutex_unlock(&riscv_iommu_hpm_lock);
+}
+
+/**
+ * riscv_iommu_add_hpm() - Add HPM support for RISC-V IOMMU
+ *
+ * @iommu: IOMMU device instance
+ *
+ * This API can be invoked from RISC-V IOMMU driver to probe and
+ * initialize the feature of HPM support.
+ */
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ struct device *dev = iommu->dev;
+ int irq, rc;
+
+ if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
+ dev_dbg(dev, "HPM: Not supported\n");
+ return 0;
+ }
+ irq = iommu->irqs[FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec)];
+ if (irq <= 0) {
+ dev_err(dev, "HPM: No IRQ available (vector=%llu)\n",
+ (unsigned long long)FIELD_GET(RISCV_IOMMU_ICVEC_PMIV,
+ iommu->icvec));
+ return -EINVAL;
+ }
+
+ rc = riscv_iommu_hpm_init();
+ if (rc < 0)
+ return rc;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
+ riscv_iommu_hpm_attr_grps,
+ "riscv_iommu_hpm");
+ if (rc < 0)
+ goto err_module;
+ return 0;
+
+err_module:
+ riscv_iommu_hpm_exit();
+ return rc;
+}
+
+/**
+ * riscv_iommu_remove_hpm() - Remove HPM support for RISC-V IOMMU.
+ *
+ * @iommu: IOMMU device instance
+ *
+ * This API can be invoked from RISC-V IOMMU driver to finalize the
+ * feature of HPM support.
+ */
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+ mutex_lock(&riscv_iommu_hpm_lock);
+ if (cpuhp_state_num >= 0) {
+ cpuhp_refcnt--;
+ cpuhp_state_remove_instance_nocalls(cpuhp_state_num,
+ &iommu->hpm.node);
+ }
+ mutex_unlock(&riscv_iommu_hpm_lock);
+ perf_pmu_unregister(&iommu->hpm.pmu);
+ riscv_iommu_hpm_exit();
+}
diff --git a/drivers/iommu/riscv/iommu-pci.c b/drivers/iommu/riscv/iommu-pci.c
index d82d2b00904c..71407aecbf92 100644
--- a/drivers/iommu/riscv/iommu-pci.c
+++ b/drivers/iommu/riscv/iommu-pci.c
@@ -34,6 +34,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
{
struct device *dev = &pdev->dev;
struct riscv_iommu_device *iommu;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
int rc, vec;
rc = pcim_enable_device(pdev);
@@ -43,7 +45,9 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM))
return -ENODEV;
- if (pci_resource_len(pdev, 0) < RISCV_IOMMU_REG_SIZE)
+ reg_phys = pci_resource_start(pdev, 0);
+ reg_size = pci_resource_len(pdev, 0);
+ if (reg_size < RISCV_IOMMU_REG_SIZE)
return -ENODEV;
rc = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
@@ -56,6 +60,8 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
iommu->dev = dev;
iommu->reg = pcim_iomap_table(pdev)[0];
+ iommu->reg_phys = reg_phys;
+ iommu->reg_size = reg_size;
pci_set_master(pdev);
dev_set_drvdata(dev, iommu);
@@ -91,7 +97,10 @@ static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_i
riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, iommu->fctl);
}
- return riscv_iommu_init(iommu);
+ rc = riscv_iommu_init(iommu);
+ if (rc)
+ return rc;
+ return riscv_iommu_add_hpm(iommu);
}
static void riscv_iommu_pci_remove(struct pci_dev *pdev)
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 83a28c83f991..684bc267ac30 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -62,6 +62,9 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(iommu->reg),
"could not map register region\n");
+ iommu->reg_phys = res->start;
+ iommu->reg_size = resource_size(res);
+
dev_set_drvdata(dev, iommu);
/* Check device reported capabilities / features. */
@@ -134,7 +137,10 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
return dev_err_probe(dev, -ENODEV, "invalid IGS\n");
}
- return riscv_iommu_init(iommu);
+ ret = riscv_iommu_init(iommu);
+ if (ret)
+ return ret;
+ return riscv_iommu_add_hpm(iommu);
};
static void riscv_iommu_platform_remove(struct platform_device *pdev)
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..0ad9f5cad4de 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,7 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/iopoll.h>
+#include <linux/perf_event.h>
#include "iommu-bits.h"
@@ -33,6 +34,29 @@ struct riscv_iommu_queue {
u8 qid; /* queue identifier, same as RISCV_IOMMU_INTR_XX */
};
+struct riscv_iommu_hpm {
+ struct riscv_iommu_device *iommu;
+ struct pmu pmu;
+ void __iomem *base;
+ int irq;
+ int on_cpu;
+ struct hlist_node node;
+ /*
+ * Layout of events:
+ * 0 -> HPMCYCLES
+ * 1...n-1 -> HPMEVENTS
+ */
+ struct perf_event *events[RISCV_IOMMU_HPMCOUNTER_MAX];
+ DECLARE_BITMAP(supported_events, RISCV_IOMMU_HPMCOUNTER_MAX);
+ /*
+ * Layout of counters:
+ * 0...min(MAX,n)-2 -> HPMEVENTS
+ * MAX-1 -> HPMCYCLES
+ */
+ DECLARE_BITMAP(used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
+ unsigned int num_counters;
+};
+
struct riscv_iommu_device {
/* iommu core interface */
struct iommu_device iommu;
@@ -42,6 +66,8 @@ struct riscv_iommu_device {
/* hardware control register space */
void __iomem *reg;
+ phys_addr_t reg_phys;
+ resource_size_t reg_size;
/* supported and enabled hardware capabilities */
u64 caps;
@@ -60,12 +86,28 @@ struct riscv_iommu_device {
unsigned int ddt_mode;
dma_addr_t ddt_phys;
u64 *ddt_root;
+
+ struct riscv_iommu_hpm hpm;
};
int riscv_iommu_init(struct riscv_iommu_device *iommu);
void riscv_iommu_remove(struct riscv_iommu_device *iommu);
void riscv_iommu_disable(struct riscv_iommu_device *iommu);
+#ifdef CONFIG_RISCV_IOMMU_HPM
+int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu);
+void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu);
+#else
+static inline int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
+{
+ return -ENODEV;
+}
+
+static inline void riscv_iommu_remove_hpm(struct riscv_iommu_device *iommu)
+{
+}
+#endif
+
#define riscv_iommu_readl(iommu, addr) \
readl_relaxed((iommu)->reg + (addr))
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
2026-02-05 9:10 ` [PATCH v4 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-02-05 9:10 ` [PATCH v4 2/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
@ 2026-02-05 9:10 ` Lv Zheng
2026-02-05 18:26 ` Conor Dooley
2026-02-05 9:10 ` [PATCH v4 4/7] iommu/riscv: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
` (3 subsequent siblings)
6 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:10 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds device tree bindings for SpacemiT T100 specific features by
introducing spacemit,100 compatible. T100 contains distributed IOATCs,
each of which exposes pmiv interrupt.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
.../bindings/iommu/riscv,iommu.yaml | 53 ++++++++++++++++++-
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
index d4838c3b3741..67d226a1a90d 100644
--- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
@@ -32,6 +32,12 @@ properties:
# should be specified along with 'reg' property providing MMIO location.
compatible:
oneOf:
+ - description: SpacemiT distributed IOMMUs
+ items:
+ - enum:
+ - spacemit,t100
+ - const: spacemit,riscv-iommu
+ - const: riscv,iommu
- items:
- enum:
- qemu,riscv-iommu
@@ -57,11 +63,21 @@ properties:
interrupts:
minItems: 1
- maxItems: 4
+ maxItems: 68
description:
Wired interrupt vectors available for RISC-V IOMMU to notify the
RISC-V HARTS. The cause to interrupt vector is software defined
- using IVEC IOMMU register.
+ using ICVEC IOMMU register. For WSI only mode, the number of the
+ interrupt vectors should be 1 while for MSI possible mode, the
+ maximum of the interrupt vectors should be 4 with the cause indexed
+ as "CIV=0, FIV=1, PIV=2, PMIV=3".
+ SpacemiT distributed IOMMU includes additional interrupts for
+ IOATCs. Each IOATC exposes PMIV wired vector as standalone
+ interrupt and the maximum number of IOATCs can be up to 64. Thus for
+ WSI only mode, the maximum number of the interrupt vectors should be
+ 65 while for MSI possible mode, the maximum number of the interrupt
+ vectors should be 68 with the cause indexed as "IOATS CIV=0,
+ IOATS FIV=1, IOATS PIV=2, IOATS PMIV=3, IOATC0..n PMIV=4..4+n".
msi-parent: true
@@ -75,6 +91,18 @@ required:
additionalProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ const: spacemit,riscv-iommu
+ then:
+ properties:
+ interrupts:
+ maxItems: 4
+
examples:
- |+
/* Example 1 (IOMMU device with wired interrupts) */
@@ -145,3 +173,24 @@ examples:
};
};
};
+
+ - |+
+ /* Example 5 (SpacemiT distributed IOMMU) */
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ iommu4: iommu@1bccd000 {
+ compatible = "spacemit,t100", "spacemit,riscv-iommu", "riscv,iommu";
+ reg = <0x1bccd000 0x1000>;
+ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>,
+ <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>,
+ <62 IRQ_TYPE_LEVEL_HIGH>, <63 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&saplic>;
+ #iommu-cells = <0x01>;
+ };
+
+ /* Device with four IOMMU device IDs */
+ master2 {
+ #iommu-cells = <1>;
+ iommus = <&iommu4 0xc0010>, <&iommu4 0xc0011>,
+ <&iommu4 0xc0012>, <&iommu4 0xc0013>;
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 4/7] iommu/riscv: Add vendor event support for RISC-V IOMMU HPM
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
` (2 preceding siblings ...)
2026-02-05 9:10 ` [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-02-05 9:10 ` Lv Zheng
2026-02-05 9:11 ` [PATCH v4 5/7] spacemit/t100: Add global filter awareness " Lv Zheng
` (2 subsequent siblings)
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:10 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
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 fe51f60c0c75..4615c4b161a0 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -443,6 +443,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)
@@ -518,6 +542,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
};
@@ -620,6 +645,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 */
@@ -646,6 +701,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)
{
@@ -659,6 +715,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;
@@ -788,6 +845,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)) {
@@ -806,7 +864,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
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 5/7] spacemit/t100: Add global filter awareness for RISC-V IOMMU HPM
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
` (3 preceding siblings ...)
2026-02-05 9:10 ` [PATCH v4 4/7] iommu/riscv: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
@ 2026-02-05 9:11 ` Lv Zheng
2026-02-05 9:11 ` [PATCH v4 6/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-05 9:11 ` [PATCH v4 7/7] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:11 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Introduces global filter support for RISC-V IOMMU HPM. The global filter
can be seen in SpacemiT T100 which only supports single filter to be
applied to all event counters.
Drivers can program filters in each iohpmevt registers as normal in such a
silicon design, however the underlying hardware filters are wired together
as a global filter applying to all iohpmevt(s). Since the mechanism is
compatible with standard iohpmevt in programming interface, only adds
sanity checks to allow it to be configured with "global" awareness to
inform users a filter incompatiblity.
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 | 68 ++++++++++++++++++++++++++++++---
drivers/iommu/riscv/iommu.h | 1 +
2 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index 4615c4b161a0..6860714fb61e 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -134,6 +134,30 @@ static inline void riscv_iommu_hpm_interrupt_clear(struct riscv_iommu_hpm *hpm)
riscv_iommu_hpm_writel(hpm, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
}
+static bool riscv_iommu_hpm_check_global_filter(struct perf_event *curr,
+ struct perf_event *new)
+{
+ return get_filter_pid_pscid(curr) == get_filter_pid_pscid(new) &&
+ get_filter_did_gscid(curr) == get_filter_did_gscid(new) &&
+ get_filter_pv_pscv(curr) == get_filter_pv_pscv(new) &&
+ get_filter_dv_gscv(curr) == get_filter_dv_gscv(new) &&
+ get_filter_idt(curr) == get_filter_idt(new) &&
+ get_filter_dmask(curr) == get_filter_dmask(new);
+}
+
+static bool riscv_iommu_hpm_events_compatible(struct perf_event *curr,
+ struct perf_event *new)
+{
+ if (new->pmu != curr->pmu)
+ return false;
+
+ if (to_iommu_hpm(new->pmu)->global_filter &&
+ !riscv_iommu_hpm_check_global_filter(curr, new))
+ return false;
+
+ return true;
+}
+
/**
* riscv_iommu_hpm_event_update() - Update and return RISC-V IOMMU HPM
* event counters
@@ -268,9 +292,10 @@ static void riscv_iommu_hpm_set_event_filter(struct perf_event *event, int idx,
RISCV_IOMMU_REG_IOHPMEVT(idx), event_cfg);
}
-static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
- struct perf_event *event, int idx)
+static int riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm,
+ struct perf_event *event, int idx)
{
+ unsigned int cur_idx, num_ctrs = iommu_hpm->num_counters;
u32 pid_pscid, did_gscid, pv_pscv, dv_gscv, idt, dmask;
pid_pscid = get_filter_pid_pscid(event);
@@ -280,14 +305,36 @@ static void riscv_iommu_hpm_apply_event_filter(struct riscv_iommu_hpm *iommu_hpm
idt = get_filter_idt(event);
dmask = get_filter_dmask(event);
+ if (iommu_hpm->global_filter) {
+ cur_idx = find_first_bit(iommu_hpm->used_counters, num_ctrs - 1);
+ if (cur_idx == num_ctrs - 1) {
+ /* First event, set the global filter */
+ riscv_iommu_hpm_set_event_filter(event, 0, pid_pscid,
+ did_gscid,
+ pv_pscv, dv_gscv, idt, dmask);
+ } else {
+ /* Check if the new event's filter is compatible with
+ * the global filter
+ */
+ if (!riscv_iommu_hpm_check_global_filter(iommu_hpm->events[cur_idx + 1],
+ event)) {
+ dev_dbg(iommu_hpm->pmu.dev,
+ "HPM: Filter incompatible with global filter\n");
+ return -EAGAIN;
+ }
+ }
+ return 0;
+ }
+
riscv_iommu_hpm_set_event_filter(event, idx, pid_pscid, did_gscid,
pv_pscv, dv_gscv, idt, dmask);
+ return 0;
}
static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
struct perf_event *event)
{
- int idx;
+ int idx, err;
unsigned int num_ctrs = iommu_hpm->num_counters;
u16 event_id = get_event(event);
@@ -309,7 +356,9 @@ static int riscv_iommu_hpm_get_event_idx(struct riscv_iommu_hpm *iommu_hpm,
return -EAGAIN;
}
- riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ err = riscv_iommu_hpm_apply_event_filter(iommu_hpm, event, idx);
+ if (err)
+ return err;
set_bit(idx, iommu_hpm->used_counters);
return idx;
@@ -405,6 +454,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
}
if (!is_software_event(event->group_leader)) {
+ if (!riscv_iommu_hpm_events_compatible(event->group_leader, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -412,6 +463,8 @@ static int riscv_iommu_hpm_event_init(struct perf_event *event)
for_each_sibling_event(sibling, event->group_leader) {
if (is_software_event(sibling))
continue;
+ if (!riscv_iommu_hpm_events_compatible(sibling, event))
+ return -EINVAL;
if (++group_num_events > iommu_hpm->num_counters)
return -EINVAL;
}
@@ -729,6 +782,8 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
bitmap_zero(iommu_hpm->used_counters, RISCV_IOMMU_HPMCOUNTER_MAX);
bitmap_zero(iommu_hpm->supported_events, RISCV_IOMMU_HPMEVENT_MAX);
+ iommu_hpm->global_filter = of_device_is_compatible(dev->of_node,
+ "spacemit,t100");
riscv_iommu_hpm_writel(iommu_hpm,
RISCV_IOMMU_REG_IOCOUNTINH, 0xFFFFFFFF);
val = riscv_iommu_hpm_readl(iommu_hpm,
@@ -793,8 +848,9 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
if (err)
goto err_cpuhp;
- dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d)\n",
- pmu_name, iommu_hpm->num_counters, iommu_hpm->irq);
+ dev_info(dev, "HPM: Registered %s (%d counters, IRQ %d, %s filter)\n",
+ pmu_name, iommu_hpm->num_counters, iommu_hpm->irq,
+ iommu_hpm->global_filter ? "global" : "per-counter");
return 0;
err_cpuhp:
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index d3c11abef5cf..80e96fd7e164 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -42,6 +42,7 @@ struct riscv_iommu_hpm {
int on_cpu;
struct hlist_node node;
const char *identifier;
+ bool global_filter;
/*
* Layout of events:
* 0 -> HPMCYCLES
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 6/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
` (4 preceding siblings ...)
2026-02-05 9:11 ` [PATCH v4 5/7] spacemit/t100: Add global filter awareness " Lv Zheng
@ 2026-02-05 9:11 ` Lv Zheng
2026-02-05 9:11 ` [PATCH v4 7/7] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:11 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Adds IOATC discovery and HPM support for SpacemiT T100.
SpacemiT T100 supports distributed architecture which allows IOTLBs to be
cached in adjacent to the DMA masters. Such IOTLB controllers are called
as IOATCs. Adds distributed HPM support for IOATCs.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
drivers/iommu/riscv/iommu-bits.h | 12 ++
drivers/iommu/riscv/iommu-hpm.c | 182 +++++++++++++++++++++++++--
drivers/iommu/riscv/iommu-platform.c | 4 +-
drivers/iommu/riscv/iommu.h | 2 +-
4 files changed, 188 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index cc6bea064d8f..dcf95a99c1d1 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -284,6 +284,18 @@ enum riscv_iommu_hpmevent_id {
#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
+/* 5.28 Distributed translation interface status register (dtisr0-3) (4 * 32-bits) */
+#define RISCV_IOMMU_REG_DTISR_BASE 0x02B0
+#define RISCV_IOMMU_REG_DTISR(_n) (RISCV_IOMMU_REG_DTISR_BASE + ((_n) * 0x04))
+#define RISCV_IOMMU_DTI_STS_SHIFT(_n) (((_n) % 16) * 2)
+#define RISCV_IOMMU_DTI_STS_MASK(_n) (0x3 << RISCV_IOMMU_DTI_STS_SHIFT(_n))
+#define RISCV_IOMMU_DTI_STS_NONE 0x0
+#define RISCV_IOMMU_DTI_STS_IOATC 0x1
+
+#define MAX_RISCV_IOMMU_IOATC 64
+#define RISCV_IOMMU_IOATC_BASE(_base, _idx) \
+ ((void __iomem *)((u8 __iomem *)(_base) + ((_idx) + 1) * RISCV_IOMMU_REG_SIZE))
+
/* 5.28 MSI Configuration table (32 * 64bits) */
#define RISCV_IOMMU_REG_MSI_CFG_TBL 0x0300
#define RISCV_IOMMU_REG_MSI_CFG_TBL_ADDR(_n) \
diff --git a/drivers/iommu/riscv/iommu-hpm.c b/drivers/iommu/riscv/iommu-hpm.c
index 6860714fb61e..4463416537a7 100644
--- a/drivers/iommu/riscv/iommu-hpm.c
+++ b/drivers/iommu/riscv/iommu-hpm.c
@@ -31,6 +31,77 @@ static atomic_t riscv_iommu_hpm_ids = ATOMIC_INIT(0);
static int cpuhp_state_num = -1;
static int cpuhp_refcnt;
+struct riscv_iommu_ioatc_desc {
+ u32 offset;
+ int irq;
+ u32 index;
+};
+
+struct riscv_iommu_unit_info {
+ const char *identifier;
+ const char *ioats;
+ const char *ioatc;
+};
+
+#define RISCV_IOMMU_HPM_UNIT_EXTRACTOR(vid, pid, ioats) \
+ { #vid","#pid, #vid"_"#ioats"_hpm", #vid"_ioatc_hpm", }
+
+struct riscv_iommu_unit_info riscv_iommu_hpm_units[] = {
+ RISCV_IOMMU_HPM_UNIT_EXTRACTOR(riscv, iommu, iommu),
+ RISCV_IOMMU_HPM_UNIT_EXTRACTOR(spacemit, riscv-iommu, ioats),
+};
+
+static int riscv_iommu_hpm_collect_ioatcs(struct riscv_iommu_device *iommu,
+ struct riscv_iommu_ioatc_desc *descs,
+ int max_desc)
+{
+ struct device *dev = iommu->dev;
+ int count, index;
+ int i, j;
+ u32 dtisr, state;
+ int irq, nr_ioats_irqs, nr_ioatc_irqs;
+
+ if (!of_device_is_compatible(dev->of_node, "spacemit,riscv-iommu"))
+ return 0;
+
+ if (iommu->fctl & RISCV_IOMMU_FCTL_WSI)
+ nr_ioats_irqs = 1;
+ else
+ nr_ioats_irqs = RISCV_IOMMU_INTR_COUNT;
+
+ if (iommu->irqs_count > nr_ioats_irqs)
+ nr_ioatc_irqs = iommu->irqs_count - nr_ioats_irqs;
+ else
+ nr_ioatc_irqs = 0;
+
+ /* Automatically discover IOATCs by scanning DTISR registers and
+ * assign IRQs.
+ */
+ count = 0;
+ for (i = 0; i < 4 && count < max_desc; i++) {
+ dtisr = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_DTISR(i));
+ for (j = 0; j < 16 && count < max_desc; j++) {
+ index = i * 16 + j;
+ state = (dtisr & RISCV_IOMMU_DTI_STS_MASK(index)) >>
+ RISCV_IOMMU_DTI_STS_SHIFT(index);
+ if (state != RISCV_IOMMU_DTI_STS_IOATC)
+ continue;
+ descs[count].offset = (index + 1) *
+ RISCV_IOMMU_REG_SIZE;
+ descs[count].index = index;
+ if (count < nr_ioatc_irqs &&
+ index < MAX_RISCV_IOMMU_IOATC)
+ irq = iommu->irqs[count + nr_ioats_irqs];
+ else
+ irq = 0;
+ descs[count].irq = irq;
+ count++;
+ }
+ }
+
+ return count;
+}
+
static inline void riscv_iommu_hpm_writel(struct riscv_iommu_hpm *hpm, u32 reg,
u32 val)
{
@@ -599,6 +670,29 @@ static const struct attribute_group *riscv_iommu_hpm_attr_grps[] = {
NULL
};
+#define IOMMU_IOATC_EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR_ID(_name, riscv_iommu_hpm_event_show, _id)
+
+static struct attribute *riscv_iommu_ioatc_events[] = {
+ IOMMU_IOATC_EVENT_ATTR(untrans_rq, RISCV_IOMMU_HPMEVENT_URQ),
+ IOMMU_IOATC_EVENT_ATTR(trans_rq, RISCV_IOMMU_HPMEVENT_TRQ),
+ IOMMU_IOATC_EVENT_ATTR(tlb_mis, RISCV_IOMMU_HPMEVENT_TLB_MISS),
+ NULL
+};
+
+static const struct attribute_group riscv_iommu_ioatc_events_group = {
+ .name = "events",
+ .attrs = riscv_iommu_ioatc_events,
+};
+
+static const struct attribute_group *riscv_iommu_ioatc_attr_grps[] = {
+ &riscv_iommu_hpm_cpumask_group,
+ &riscv_iommu_ioatc_events_group,
+ &riscv_iommu_hpm_format_group,
+ &riscv_iommu_hpm_identifier_group,
+ NULL
+};
+
static irqreturn_t riscv_iommu_hpm_handle_irq(int irq_num, void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -700,7 +794,31 @@ static void riscv_iommu_hpm_reset(struct riscv_iommu_hpm *iommu_hpm)
static bool riscv_iommu_hpm_is_identifier_compat(const char *compat)
{
- return !strcmp(compat, "riscv,iommu");
+ int i;
+ struct riscv_iommu_unit_info *info;
+
+ for (i = 0; i < ARRAY_SIZE(riscv_iommu_hpm_units); i++) {
+ info = &riscv_iommu_hpm_units[i];
+ if (!strcmp(info->identifier, compat))
+ return true;
+ }
+ return false;
+}
+
+static const char *riscv_iommu_hpm_get_unit(const char *identifier,
+ bool ioatc)
+{
+ int i;
+ struct riscv_iommu_unit_info *info;
+
+ if (identifier) {
+ for (i = 0; i < ARRAY_SIZE(riscv_iommu_hpm_units); i++) {
+ info = &riscv_iommu_hpm_units[i];
+ if (!strcmp(info->identifier, identifier))
+ return ioatc ? info->ioatc : info->ioats;
+ }
+ }
+ return "riscv_iommu_hpm";
}
static const char *riscv_iommu_hpm_get_identifier(struct device *dev)
@@ -744,6 +862,14 @@ static void riscv_iommu_hpm_set_standard_events(struct riscv_iommu_hpm *iommu_hp
set_bit(RISCV_IOMMU_HPMEVENT_G_WALKS, iommu_hpm->supported_events);
}
+static void riscv_iommu_hpm_set_ioatc_events(struct riscv_iommu_hpm *iommu_hpm)
+{
+ /* SpacemiT T100 IOATC compatible HPM events */
+ set_bit(RISCV_IOMMU_HPMEVENT_URQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TRQ, iommu_hpm->supported_events);
+ set_bit(RISCV_IOMMU_HPMEVENT_TLB_MISS, iommu_hpm->supported_events);
+}
+
static void riscv_iommu_hpm_remove(void *data)
{
struct riscv_iommu_hpm *iommu_hpm = data;
@@ -756,16 +882,22 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
u32 offset, int irq,
const char *identifier,
const struct attribute_group **attr_groups,
- const char *prefix)
+ int index, int *puid)
{
struct device *dev = iommu->dev;
- const char *pmu_name;
+ const char *pmu_name, *prefix;
u32 val;
int err;
int unique_id;
void __iomem *base;
- unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ if (index < 0) {
+ unique_id = atomic_fetch_inc(&riscv_iommu_hpm_ids);
+ *puid = unique_id;
+ } else
+ unique_id = *puid;
+ prefix = riscv_iommu_hpm_get_unit(identifier, index >= 0);
+
memset(iommu_hpm, 0, sizeof(*iommu_hpm));
iommu_hpm->iommu = iommu;
iommu_hpm->identifier = identifier;
@@ -797,9 +929,15 @@ static int riscv_iommu_hpm_register_unit(struct riscv_iommu_device *iommu,
riscv_iommu_hpm_reset(iommu_hpm);
- riscv_iommu_hpm_set_standard_events(iommu_hpm);
- pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
- prefix, (u8)unique_id);
+ if (index >= 0) {
+ riscv_iommu_hpm_set_ioatc_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x%02x",
+ prefix, (u8)unique_id, (u8)index);
+ } else {
+ riscv_iommu_hpm_set_standard_events(iommu_hpm);
+ pmu_name = devm_kasprintf(dev, GFP_KERNEL, "%s_%02x",
+ prefix, (u8)unique_id);
+ }
if (!pmu_name)
return -ENOMEM;
@@ -902,7 +1040,9 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
{
struct device *dev = iommu->dev;
const char *identifier;
- int irq, rc;
+ int irq, uid, rc, i;
+ struct riscv_iommu_ioatc_desc ioatcs[MAX_RISCV_IOMMU_IOATC];
+ int nr_ioatcs;
if (!FIELD_GET(RISCV_IOMMU_CAPABILITIES_HPM, iommu->caps)) {
dev_dbg(dev, "HPM: Not supported\n");
@@ -927,9 +1067,33 @@ int riscv_iommu_add_hpm(struct riscv_iommu_device *iommu)
rc = riscv_iommu_hpm_register_unit(iommu, &iommu->hpm, 0, irq,
identifier,
riscv_iommu_hpm_attr_grps,
- "riscv_iommu_hpm");
+ -1, &uid);
if (rc < 0)
goto err_module;
+
+ nr_ioatcs = riscv_iommu_hpm_collect_ioatcs(iommu, ioatcs,
+ ARRAY_SIZE(ioatcs));
+ for (i = 0; i < nr_ioatcs; i++) {
+ struct riscv_iommu_hpm *extra;
+
+ extra = devm_kzalloc(dev, sizeof(*extra), GFP_KERNEL);
+ if (!extra)
+ continue;
+
+ rc = riscv_iommu_hpm_register_unit(iommu, extra,
+ ioatcs[i].offset,
+ ioatcs[i].irq,
+ identifier,
+ riscv_iommu_ioatc_attr_grps,
+ ioatcs[i].index, &uid);
+ if (rc) {
+ dev_warn(dev,
+ "HPM: Failed to register IOATC%u: %d\n",
+ ioatcs[i].index, rc);
+ continue;
+ }
+ }
+
return 0;
err_module:
diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c
index 684bc267ac30..ca8de9ec5266 100644
--- a/drivers/iommu/riscv/iommu-platform.c
+++ b/drivers/iommu/riscv/iommu-platform.c
@@ -75,8 +75,8 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev)
if (iommu->irqs_count <= 0)
return dev_err_probe(dev, -ENODEV,
"no IRQ resources provided\n");
- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT)
- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT;
+ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC)
+ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC;
igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps);
switch (igs) {
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 80e96fd7e164..c2f008d86d63 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -76,7 +76,7 @@ struct riscv_iommu_device {
u32 fctl;
/* available interrupt numbers, MSI or WSI */
- unsigned int irqs[RISCV_IOMMU_INTR_COUNT];
+ unsigned int irqs[RISCV_IOMMU_INTR_COUNT + MAX_RISCV_IOMMU_IOATC];
unsigned int irqs_count;
unsigned int icvec;
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v4 7/7] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
` (5 preceding siblings ...)
2026-02-05 9:11 ` [PATCH v4 6/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
@ 2026-02-05 9:11 ` Lv Zheng
6 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-05 9:11 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Lv Zheng, Zhijian Chen, iommu, linux-perf-users,
linux-riscv, spacemit, devicetree
Add JSON HPM event aliases for SpacemiT distributed IOMMU (T100) which is
general and compatible for all SpacemiT RISC-V SoCs.
Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
Signed-off-by: Jingyu Li <joey.li@spacemit.com>
---
MAINTAINERS | 3 +
.../arch/riscv/spacemit/iommu/sys/ioatc.json | 30 ++++
.../arch/riscv/spacemit/iommu/sys/ioats.json | 163 ++++++++++++++++++
3 files changed, 196 insertions(+)
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
create mode 100644 tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c50701b6001..4d91f99aa742 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22459,12 +22459,15 @@ K: riscv
RISC-V IOMMU
M: Tomasz Jeznach <tjeznach@rivosinc.com>
+M: Lv Zheng <lv.zheng@linux.spacemit.com>
+M: Jingyu Li <joey.li@spacemit.com>
L: iommu@lists.linux.dev
L: linux-riscv@lists.infradead.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
F: drivers/iommu/riscv/
+F: tools/perf/pmu-events/arch/riscv/spacemit/iommu/
RISC-V MICROCHIP SUPPORT
M: Conor Dooley <conor.dooley@microchip.com>
diff --git a/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
new file mode 100644
index 000000000000..a16610ba2274
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioatc.json
@@ -0,0 +1,30 @@
+[
+ {
+ "EventName": "mtlb_lkp",
+ "EventCode": "0x38",
+ "BriefDescription": "IOATC main TLB (MTLB) lookups",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "mtlb_mis",
+ "EventCode": "0x39",
+ "BriefDescription": "IOATC main TLB (MTLB) misses",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "utlb_lkp",
+ "EventCode": "0x3A",
+ "BriefDescription": "IOATC micro TLB (uTLB) lookups",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "utlb_mis",
+ "EventCode": "0x3B",
+ "BriefDescription": "IOATC micro TLB (uTLB) misses",
+ "Unit": "spacemit_ioatc_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ }
+]
diff --git a/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
new file mode 100644
index 000000000000..e1fea4e8125c
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/spacemit/iommu/sys/ioats.json
@@ -0,0 +1,163 @@
+[
+ {
+ "EventName": "pri_rq",
+ "EventCode": "0x10",
+ "BriefDescription": "IOATS PCIe page request interface (PRI) requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "ptwc_rq",
+ "EventCode": "0x11",
+ "BriefDescription": "IOATS page table walk (PTW) cache requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_rq",
+ "EventCode": "0x12",
+ "BriefDescription": "IOATS directory table walk (DTW) cache requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_mis",
+ "EventCode": "0x13",
+ "BriefDescription": "IOATS directory table walk (DTW) cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "ptwc_mis",
+ "EventCode": "0x14",
+ "BriefDescription": "IOATS page table walk (PTW) cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "all_trans_rq",
+ "EventCode": "0x15",
+ "BriefDescription": "IOATS all translation requests",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "dtwc_lkp",
+ "EventCode": "0x20",
+ "BriefDescription": "IOATS directory table walk (DTW) cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s0_ptwc_lkp",
+ "EventCode": "0x28",
+ "BriefDescription": "IOATS s-stage level-0 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s0_ptwc_mis",
+ "EventCode": "0x29",
+ "BriefDescription": "IOATS s-stage level-0 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s1_ptwc_lkp",
+ "EventCode": "0x2A",
+ "BriefDescription": "IOATS s-stage level-1 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s1_ptwc_mis",
+ "EventCode": "0x2B",
+ "BriefDescription": "IOATS s-stage level-1 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s2_ptwc_lkp",
+ "EventCode": "0x2C",
+ "BriefDescription": "IOATS s-stage level-2 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s2_ptwc_mis",
+ "EventCode": "0x2D",
+ "BriefDescription": "IOATS s-stage level-2 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s3_ptwc_lkp",
+ "EventCode": "0x2E",
+ "BriefDescription": "IOATS s-stage level-3 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "s3_ptwc_mis",
+ "EventCode": "0x2F",
+ "BriefDescription": "IOATS s-stage level-3 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g0_ptwc_lkp",
+ "EventCode": "0x30",
+ "BriefDescription": "IOATS g-stage level-0 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g0_ptwc_mis",
+ "EventCode": "0x31",
+ "BriefDescription": "IOATS g-stage level-0 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g1_ptwc_lkp",
+ "EventCode": "0x32",
+ "BriefDescription": "IOATS g-stage level-1 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g1_ptwc_mis",
+ "EventCode": "0x33",
+ "BriefDescription": "IOATS g-stage level-1 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g2_ptwc_lkp",
+ "EventCode": "0x34",
+ "BriefDescription": "IOATS g-stage level-2 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g2_ptwc_mis",
+ "EventCode": "0x35",
+ "BriefDescription": "IOATS g-stage level-2 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g3_ptwc_lkp",
+ "EventCode": "0x36",
+ "BriefDescription": "IOATS g-stage level-3 PTW cache lookups",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ },
+ {
+ "EventName": "g3_ptwc_mis",
+ "EventCode": "0x37",
+ "BriefDescription": "IOATS g-stage level-3 PTW cache misses",
+ "Unit": "spacemit_ioats_hpm",
+ "Compat": "spacemit,riscv-iommu"
+ }
+]
--
2.43.0
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
2026-02-05 3:52 ` Lv Zheng
@ 2026-02-05 15:04 ` Andrew Jones
2026-02-06 1:36 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Andrew Jones @ 2026-02-05 15:04 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On Thu, Feb 05, 2026 at 11:52:57AM +0800, Lv Zheng wrote:
> On 2/5/2026 1:20 AM, Andrew Jones wrote:
> > On Wed, Feb 04, 2026 at 05:08:52PM +0800, Lv Zheng wrote:
...
> > > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > > index d9429097a2b5..26630979473b 100644
> > > --- a/drivers/iommu/riscv/iommu.c
> > > +++ b/drivers/iommu/riscv/iommu.c
> > > @@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
> > > FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
> > > riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
> > > iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
> > > - if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
> > > - FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
> > > - max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
> > > - FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
> > > - return -EINVAL;
> > > + /*
> > > + * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
> > > + * Check if FCTL.WSI is set to determine interrupt mode.
> > > + */
> > > + if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
> >
> > The behavior of ICVEC does not depend on FCTL.WSI
> >
> > > + if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
> > > + FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
> > > + max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
> > > + FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
> > > + return -EINVAL;
> > > + } else {
> > > + /*
> > > + * WSI mode: ICVEC is not used. Set to identity mapping for
> > > + * riscv_iommu_queue_vec() to work correctly.
> > > + */
> > > + iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
> > > + FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
> > > + FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
> > > + FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
> >
> > It's certainly not correct to set iommu->icvec to anything that can't be
> > written to the IOMMU's WARL ICVEC fields and read back again.
>
> Indeed.
> It looks I can keep icvec returned for WSI and keeps the write-and-read
> check logic only for MSI.
>
You shouldn't need to touch this code at all. I don't see anything to fix
wrt the spec. As I said, if iommu->irqs_count is known to be greater than
one but you're getting zero back from ICVEC even after writing 0xffff to
it first, then ICVEC on your IOMMU is broken. Once you've confirmed that,
then the best you can do is add some workaround for your specific IOMMU
here.
Thanks,
drew
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-05 6:11 ` Lv Zheng
@ 2026-02-05 15:23 ` Andrew Jones
2026-02-06 3:42 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Andrew Jones @ 2026-02-05 15:23 UTC (permalink / raw)
To: Lv Zheng
Cc: Zong Li, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On Thu, Feb 05, 2026 at 02:11:48PM +0800, Lv Zheng wrote:
> On 2/5/2026 11:47 AM, Zong Li wrote:
> > On Thu, Feb 5, 2026 at 11:35 AM Lv Zheng <lv.zheng@linux.spacemit.com> wrote:
> > >
> > > On 2/5/2026 2:39 AM, Andrew Jones wrote:
> > > > How does this relate to
> > > >
> > > > https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
> > > >
> > > > From a quick skim it looks like there's plenty of overlap.
> > >
> > > We developed the driver in 2024 and demonstrated it in China summit. We
> > > didn't notice that a patch is on-going now in the community.
> > >
> > > Now it looks our approach solved more issues, and we'll check and update
> > > if there are any community concerns still not addressed in this patchset.
> > >
> > > We can add Reviewed-by/Tested-by and Signed-off-by of Zong Li to this
> > > patch if he wishes.
> > >
> > > Thanks,
> > > Lv
> > >
> >
> > Perhaps I can first post my next revision to the mailing list (hope it
> > won't waste the community resource), so that you could have a chance
> > to review it and see whether that version is architecturally closer to
> > what the community is looking for, while also addressing your issue.
> > If you also feel that my next revision meets your needs, perhaps you
> > could append your additional implementations on top of it.
> >
>
> It seems we all composed the RISC-V iommu HPM support by referencing
> drivers/perf/arm_smmuv3_pmu.
>
> Robin's comments should all be addressed IMHO.
>
> > Of course, if the community would prefer to go your version, I’m
> > perfectly fine with that as well.
>
> OK. If we send a next version, we will add your SOB and please help to
> review and test.
Zong Li's SOB should only be on the patches he authored. Don't put
anybody's SOB on patches they haven't been involved in. See
Documentation/process/submitting-patches.rst
"""
The Signed-off-by: tag indicates that the signer was involved in the
development of the patch, or that he/she was in the patch's delivery path.
"""
Since Zong Li's patches were already on the list then your series should
at least discuss them in the cover letter, explaining why you've opted
not to adopt them. But, most likely some of the patches can be adopted,
so those should be extracted from Zong Li's work (with authorship
preserved) and based upon in order to respect that prior work.
Thanks,
drew
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-05 3:11 ` Lv Zheng
@ 2026-02-05 18:24 ` Conor Dooley
2026-02-06 1:33 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-02-05 18:24 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
[-- Attachment #1: Type: text/plain, Size: 2500 bytes --]
On Thu, Feb 05, 2026 at 11:11:51AM +0800, Lv Zheng wrote:
> On 2/5/2026 1:37 AM, Conor Dooley wrote:
> > On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
> > > Adds device tree bindings for SpacemiT T100 specific features by
> > > introducing spacemit,100 compatible. T100 contains distributed IOATCs,
> > > each of which exposes pmiv interrupt.
> > >
> > > Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> > > Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> > > ---
> > > .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
> > > 1 file changed, 37 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > index d4838c3b3741..2da3456e7402 100644
> > > --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > @@ -32,6 +32,12 @@ properties:
> > > # should be specified along with 'reg' property providing MMIO location.
> > > compatible:
> > > oneOf:
> > > + - description: SpacemiT distributed IOMMUs
> > > + items:
> > > + - enum:
> > > + - spacemit,t100
> > > + - const: spacemit,riscv-iommu
> >
> > What actually is the t100? Is it an SoC or is it the name of the core
> > complex IP that spacemit is using in multiple SoCs?
>
> T100 is the name of the IOMMU IP developed by SpacemiT, announced in RISC-V
> 2024 China Summit:
> https://www.bilibili.com/video/BV1DNtCeiEBk/
> It's world first server SPEC IOMMU in RISC-V, supports IOTLB placed in
> adjacent to the DMA masters and supports PCIe ATS and PRI.
> You can find it shipped in the recent publicly purchasable SoC SpacemiT K3.
Right, then what you need here is something like:
items:
- enum:
- spacemit,k3-iommu
- spacemit,t100-iommu
- riscv,iommu
Driver can then match on spacemit,t100-iommu - but you need to have
soc-specific compatibles.
I'm not convinced that riscv,iommu is suitable here though, does the
driver work on your platform without the portions of code that are added
by this series and enabled by your new compatible? If not, the I don't
think the riscv,iommu fallback should be here.
Additionally, please stop sending new versions so frequently and in
response to earlier submissions. I have a v4 in my inbox while we are
still discussing v3.
Cheers,
Conor.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features
2026-02-05 9:10 ` [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
@ 2026-02-05 18:26 ` Conor Dooley
2026-02-06 3:44 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-02-05 18:26 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
[-- Attachment #1: Type: text/plain, Size: 575 bytes --]
On Thu, Feb 05, 2026 at 05:10:43PM +0800, Lv Zheng wrote:
> Adds device tree bindings for SpacemiT T100 specific features by
> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
> each of which exposes pmiv interrupt.
>
> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
Please wait until discussion has finished on prior versions before
sending more. The merge window opens next week, so there's absolutely no
rush with this series, there's weeks before anything could happen with
it.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-05 18:24 ` Conor Dooley
@ 2026-02-06 1:33 ` Lv Zheng
2026-02-06 10:24 ` Conor Dooley
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-06 1:33 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/6/2026 2:24 AM, Conor Dooley wrote:
> On Thu, Feb 05, 2026 at 11:11:51AM +0800, Lv Zheng wrote:
>> On 2/5/2026 1:37 AM, Conor Dooley wrote:
>>> On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
>>>> Adds device tree bindings for SpacemiT T100 specific features by
>>>> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
>>>> each of which exposes pmiv interrupt.
>>>>
>>>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>>>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>>>> ---
>>>> .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
>>>> 1 file changed, 37 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>> index d4838c3b3741..2da3456e7402 100644
>>>> --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>> +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>> @@ -32,6 +32,12 @@ properties:
>>>> # should be specified along with 'reg' property providing MMIO location.
>>>> compatible:
>>>> oneOf:
>>>> + - description: SpacemiT distributed IOMMUs
>>>> + items:
>>>> + - enum:
>>>> + - spacemit,t100
>>>> + - const: spacemit,riscv-iommu
>>>
>>> What actually is the t100? Is it an SoC or is it the name of the core
>>> complex IP that spacemit is using in multiple SoCs?
>>
>> T100 is the name of the IOMMU IP developed by SpacemiT, announced in RISC-V
>> 2024 China Summit:
>> https://www.bilibili.com/video/BV1DNtCeiEBk/
>> It's world first server SPEC IOMMU in RISC-V, supports IOTLB placed in
>> adjacent to the DMA masters and supports PCIe ATS and PRI.
>> You can find it shipped in the recent publicly purchasable SoC SpacemiT K3.
>
> Right, then what you need here is something like:
>
> items:
> - enum:
> - spacemit,k3-iommu
> - spacemit,t100-iommu
> - riscv,iommu
>
> Driver can then match on spacemit,t100-iommu - but you need to have
> soc-specific compatibles.
> I'm not convinced that riscv,iommu is suitable here though, does the
> driver work on your platform without the portions of code that are added
> by this series and enabled by your new compatible? If not, the I don't
> think the riscv,iommu fallback should be here.
>
> Additionally, please stop sending new versions so frequently and in
> response to earlier submissions. I have a v4 in my inbox while we are
> still discussing v3.
SpacemiT provides RISC-V IOMMU implementation, T100 is the first
generation of the this IP product line, we have plan to develop T200,
T300, etc., with more features introduced to be adoptive to new
RISC-V IOMMU specifications.
Besides, T100 is not only shipped in K3, but also shipped in V100 and
the follow-up SoCs, like Kn, Vn00, they will likely use the same
synthesis result of T100 RTLs.
From SpacemiT's point of view, we need a common sense of this IP
series for something like IOATCs, that's why spacemit,riscv-iommu
(this is same like qemu,riscv-iommu) is introduced. And a common sense
of T100 for all SoCs shipped T100 (like global filters, vendor events
and etc.,).
IMO, the current compatible is proper to reflect these concerns.
What do you think?
Cheers,
Lv
>
> Cheers,
> Conor.
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
2026-02-05 15:04 ` Andrew Jones
@ 2026-02-06 1:36 ` Lv Zheng
0 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-06 1:36 UTC (permalink / raw)
To: Andrew Jones
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/5/2026 11:04 PM, Andrew Jones wrote:
> On Thu, Feb 05, 2026 at 11:52:57AM +0800, Lv Zheng wrote:
>> On 2/5/2026 1:20 AM, Andrew Jones wrote:
>>> On Wed, Feb 04, 2026 at 05:08:52PM +0800, Lv Zheng wrote:
> ...
>>>> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
>>>> index d9429097a2b5..26630979473b 100644
>>>> --- a/drivers/iommu/riscv/iommu.c
>>>> +++ b/drivers/iommu/riscv/iommu.c
>>>> @@ -1593,11 +1593,26 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
>>>> FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count);
>>>> riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec);
>>>> iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC);
>>>> - if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
>>>> - FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
>>>> - max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
>>>> - FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
>>>> - return -EINVAL;
>>>> + /*
>>>> + * In WSI mode, ICVEC may read as zero. Only validate if using MSI.
>>>> + * Check if FCTL.WSI is set to determine interrupt mode.
>>>> + */
>>>> + if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) {
>>>
>>> The behavior of ICVEC does not depend on FCTL.WSI
>>>
>>>> + if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec),
>>>> + FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)),
>>>> + max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec),
>>>> + FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count)
>>>> + return -EINVAL;
>>>> + } else {
>>>> + /*
>>>> + * WSI mode: ICVEC is not used. Set to identity mapping for
>>>> + * riscv_iommu_queue_vec() to work correctly.
>>>> + */
>>>> + iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_CIV, 0) |
>>>> + FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1) |
>>>> + FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2) |
>>>> + FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3);
>>>
>>> It's certainly not correct to set iommu->icvec to anything that can't be
>>> written to the IOMMU's WARL ICVEC fields and read back again.
>>
>> Indeed.
>> It looks I can keep icvec returned for WSI and keeps the write-and-read
>> check logic only for MSI.
>>
>
> You shouldn't need to touch this code at all. I don't see anything to fix
> wrt the spec. As I said, if iommu->irqs_count is known to be greater than
> one but you're getting zero back from ICVEC even after writing 0xffff to
> it first, then ICVEC on your IOMMU is broken. Once you've confirmed that,
> then the best you can do is add some workaround for your specific IOMMU
> here.
>
> Thanks,
> drew
>
This patch is an approach trying to give PMIV a standalone wired IRQ#
which is required by pre-silicon spacemit T100 RTLs when it is
configured to report both MSI/WSI caps. However there is no such real
product on the market, I just drop it it in the next version.
Thanks,
Lv
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-05 15:23 ` Andrew Jones
@ 2026-02-06 3:42 ` Lv Zheng
2026-02-06 15:09 ` Andrew Jones
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-06 3:42 UTC (permalink / raw)
To: Andrew Jones
Cc: Zong Li, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/5/2026 11:23 PM, Andrew Jones wrote:
> On Thu, Feb 05, 2026 at 02:11:48PM +0800, Lv Zheng wrote:
>> On 2/5/2026 11:47 AM, Zong Li wrote:
>>> On Thu, Feb 5, 2026 at 11:35 AM Lv Zheng <lv.zheng@linux.spacemit.com> wrote:
>>>>
>>>> On 2/5/2026 2:39 AM, Andrew Jones wrote:
>>>>> How does this relate to
>>>>>
>>>>> https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
>>>>>
>>>>> From a quick skim it looks like there's plenty of overlap.
>>>>
>>>> We developed the driver in 2024 and demonstrated it in China summit. We
>>>> didn't notice that a patch is on-going now in the community.
>>>>
>>>> Now it looks our approach solved more issues, and we'll check and update
>>>> if there are any community concerns still not addressed in this patchset.
>>>>
>>>> We can add Reviewed-by/Tested-by and Signed-off-by of Zong Li to this
>>>> patch if he wishes.
>>>>
>>>> Thanks,
>>>> Lv
>>>>
>>>
>>> Perhaps I can first post my next revision to the mailing list (hope it
>>> won't waste the community resource), so that you could have a chance
>>> to review it and see whether that version is architecturally closer to
>>> what the community is looking for, while also addressing your issue.
>>> If you also feel that my next revision meets your needs, perhaps you
>>> could append your additional implementations on top of it.
>>>
>>
>> It seems we all composed the RISC-V iommu HPM support by referencing
>> drivers/perf/arm_smmuv3_pmu.
>>
>> Robin's comments should all be addressed IMHO.
>>
>>> Of course, if the community would prefer to go your version, I’m
>>> perfectly fine with that as well.
>>
>> OK. If we send a next version, we will add your SOB and please help to
>> review and test.
>
> Zong Li's SOB should only be on the patches he authored. Don't put
> anybody's SOB on patches they haven't been involved in. See
> Documentation/process/submitting-patches.rst
> """
> The Signed-off-by: tag indicates that the signer was involved in the
> development of the patch, or that he/she was in the patch's delivery path.
> """
>
> Since Zong Li's patches were already on the list then your
serieswould> at least discuss them in the cover letter, explaining why
you've opted
> not to adopt them. But, most likely some of the patches can be adopted,
> so those should be extracted from Zong Li's work (with authorship
> preserved) and based upon in order to respect that prior work.
>
You can see we have contacted each other in community, and decided to
cooperate in this way to honor his contribution. But final decision is
left for the community to decide:
From Zong Li:
>> Of course, if the community would prefer to go your version, I’m
>> perfectly fine with that as well.
We respect all contributions, We'll add the link in cover letter to the
follow-up revisions, let me know if anything else should be done to the
new revisions.
--------------------------------------------------------------------
And let me describe in details to compare the functionalities and
addressed comments between what is provided by Joey and by Zong:
https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
There is no missing functionalities between the two approaches, I also
checked the original Robin's comments, let me describe them in details:
1. The following comments require a split CYCLES implementation:
comment 1:
>> Why not use an extra config bit to encode cycles events completely
>> independently of the regular eventID space? Or even just use 0 since
>> by definition that cannot overlap a valid eventID?
comment 2:
>> It's also horribly confusing to use GENMASK for something which is
>> not actually a mask at all.
comment 3:
>> Hmm, from experience I would expect these variables to be
>> number-of-counters related, but I guess there must be some special
>> cleverness going on since that number-of-counters looking
>> RISCV_IOMMU_HPM_COUNTER_NUM definition is conspicuously not used,
>> so it must be significant that these are instead related to the
>> number of...
>>
>> [ goes off to search code... ]
>>
>> ...event selectors? But with a magic +1 for reasons so obvious they
>> clearly don't need explaining.
comment 4:
>> One of those conditions is literally impossible, the other should
>> already be avoided by construction.
comment 5:
>> I don't think you need this - as best I can tell, you never
>> initialise a counter without also (re)enabling the interrupt (which
>> is logical), so since "value" for the cycle counter should always
>> implicitly have OF=0 anyway, it should work to just write it like the
>> other counters.
comment 6:
>> Is RISCV_IOMMU_IOHPMCTR_COUNTER honestly useful? Or is it actively
>> hurting readability by obfuscating that we are in fact just using the
>> full 64-bit value in all those places?
comment 7:
>> And that's a very creative way to spell "if (idx == 0)".
comment 8:
>> (and as above, I think you can make this a no-op for the cycle
>> counter)
These comments require a software architecture change to handle CYCLES
in a neat way. CYCLES is split and handled in the clean way in
iommu-hpm.
2. The following comments require an uncore non-sampling mechanism:
comment 1:
>> You also need a "cpumask" attribute to tell userspace this is a
>> system/uncore PMU.
comment 2:
>> None of this is relevant or necessary. This is not a CPU PMU, so it
>> can't support sampling because it doesn't have a meaningful context
>> to sample.
comment 3:
>> You first need to validate that the event is for this PMU at all,
>> and return -ENOENT if not.
comment 4:
>> As above, you can't support sampling events anyway, so you should
>> reject them with -EINVAL.
>>
>> You also need to validate event groups to ensure they don't contain
>> more events than could ever be scheduled at once.
comment 5:
>> This will never do anything, since even if we could ever get here,
>> it would not be at a time when there are any active events.
>> Unregistering an in-use PMU does not end well (hence why standalone
>> PMU drivers need to use suppress_bind_attrs)...
Here, Joey does check PMU type, does not include sampling event stuffs,
and cpuhp is handled in a fine grained locking way. And since locking is
handled correctly, it's safe to keep iommu-hpm as tristate.
The new approach requires more system software architecture techniques.
3. The following comments require a IRQ handling improvement:
comment 1:
>> TBH I'd be inclined to just leave out all the dead cleanup code if
>> the PMU driver is tied to the IOMMU driver and can never
>> realistically be removed.
comment 2:
>> Surely this should only touch the counter(s) that overflowed and
>> have been handled? It might be cleaner to keep that within the IRQ
>> handler itself.
comment 3:
>> This needs to start all active counters together, not one-by-one.
comment 4:
>> This does nothing, since set_event has just implicitly written
>> OF=0.
>>
>> ...unless, that is, the user was mischievous and also set bit 63
>> in event->attr.config, since you never sanitised the input ;)
comment 5:
>> What do these regs represent? If you look at the perf_event_open
>> ABI, you'll see that events can target various combinations of CPU
>> and/or pid, but there is no encoding for "whichever CPU takes the
>> IOMMU PMU interrupt". Thus whatever you get here is more than likely
>> not what the user asked for, and this is why non-CPU PMUs cannot
>> reasonably support sampling ;)
comment 6:
>> You still need to handle counter rollover for all events, otherwise
>> they can start losing counts and rapidly turn to nonsense. Admittedly
>> it's largely theoretical with full 64-bit counters, but still...
comment 7:
>> Hmm, shared interrupts are tricky for PMUs, since perf requires any
>> IRQ handler touching a PMU is running on pmu->cpu, so you have to be
>> very careful about maintaining affinity and not letting anyone else
>> change it behind your back.
>>
>> The other thing is that if it really is shared, at this point you
>> could now be in riscv_iommu_pmu_handle_irq() dereferencing NULL.
comment 8:
>> In general it's not a great idea to register an IRQ handler before
>> the data passed to that handler is initialised. What is pointed to by
>> (&iommu->pmu)->reg + RISCV_IOMMU_REG_IOCOUNTOVF if the IRQ fires
>> right now (and/or if CONFIG_DEBUG_SHIRQ ever gets fixed)? ;)
>>
>> (OK, it's not *literally* NULL, but hey...)
Here OVF interrupt is handled as a standalone threaded per-cpu shared
IRQ in iommu-hpm.c and iocountinh register is not used as OVF interrupt
is always enabled and overflows is stored to software counters. The new
approach passed testings.
4. Other programming style fixes, they are all not in this patch.
comment 1:
>> sysfs_emit()
No such problem here.
comment 2:
>> Might be worth leaving a comment just in case anyone does try to
>> enable this for 32-bit that the io-64-nonatomic readq() isn't enough
>> to work properly here.
Not addressed in v3 and v4. And probably not necessary.
comment 3:
>> That's a wonderfully expensive way to spell
>> "pmu->events[idx]->hw.config"...
No such problem here, get_event() is used.
comment 4:
>> Initially this looks weird - why bother storing constants in memory
>> if they're constant? - but I see the spec implies they are not
>> necessarily fixed, and we can only actually assume at least one
>> counter at least 32 bits wide, so I guess this is really more of
>> a placeholder? Is there a well-defined way we're supposed to be able
>> to discover these, like some more ID register fields somewhere, or
>> writing all 1s to various registers to see what sticks, or is it
>> liable to be a mess of just having to know what each implementation
>> has by matching DT compatibles and/or PCI IDs?
Here WARL registers are handled in RISC-V programming style.
comment 5:
>> The new thing is that you can now set pmu.parent to the IOMMU device
>> so their relationship is clear in sysfs, rather than having to play
>> tricks with the PMU name.
Not addressed here but addressed in v4.
IMO, the Joey's approach addressed issue 1, 2 and 3, which does require
more software architecture changes. Her contribution and authorship
might also be honored.
--------------------------------------------------------------------
Am I missing something in the above list? Robin might help to confirm if
the new approach has addressed all his comments.
Thanks and best regards,
Lv
> Thanks,
> drew
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features
2026-02-05 18:26 ` Conor Dooley
@ 2026-02-06 3:44 ` Lv Zheng
0 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-06 3:44 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li,
Zhijian Chen, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On 2/6/2026 2:26 AM, Conor Dooley wrote:
> On Thu, Feb 05, 2026 at 05:10:43PM +0800, Lv Zheng wrote:
>> Adds device tree bindings for SpacemiT T100 specific features by
>> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
>> each of which exposes pmiv interrupt.
>>
>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>
> Please wait until discussion has finished on prior versions before
> sending more. The merge window opens next week, so there's absolutely no
> rush with this series, there's weeks before anything could happen with
> it.
Sure, thanks for the help.
Cheers,
Lv
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-06 1:33 ` Lv Zheng
@ 2026-02-06 10:24 ` Conor Dooley
2026-02-07 4:24 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Conor Dooley @ 2026-02-06 10:24 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
[-- Attachment #1: Type: text/plain, Size: 4546 bytes --]
On Fri, Feb 06, 2026 at 09:33:09AM +0800, Lv Zheng wrote:
> On 2/6/2026 2:24 AM, Conor Dooley wrote:
> > On Thu, Feb 05, 2026 at 11:11:51AM +0800, Lv Zheng wrote:
> > > On 2/5/2026 1:37 AM, Conor Dooley wrote:
> > > > On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
> > > > > Adds device tree bindings for SpacemiT T100 specific features by
> > > > > introducing spacemit,100 compatible. T100 contains distributed IOATCs,
> > > > > each of which exposes pmiv interrupt.
> > > > >
> > > > > Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
> > > > > Signed-off-by: Jingyu Li <joey.li@spacemit.com>
> > > > > ---
> > > > > .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
> > > > > 1 file changed, 37 insertions(+)
> > > > >
> > > > > diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > > > index d4838c3b3741..2da3456e7402 100644
> > > > > --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > > > +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
> > > > > @@ -32,6 +32,12 @@ properties:
> > > > > # should be specified along with 'reg' property providing MMIO location.
> > > > > compatible:
> > > > > oneOf:
> > > > > + - description: SpacemiT distributed IOMMUs
> > > > > + items:
> > > > > + - enum:
> > > > > + - spacemit,t100
> > > > > + - const: spacemit,riscv-iommu
> > > >
> > > > What actually is the t100? Is it an SoC or is it the name of the core
> > > > complex IP that spacemit is using in multiple SoCs?
> > >
> > > T100 is the name of the IOMMU IP developed by SpacemiT, announced in RISC-V
> > > 2024 China Summit:
> > > https://www.bilibili.com/video/BV1DNtCeiEBk/
> > > It's world first server SPEC IOMMU in RISC-V, supports IOTLB placed in
> > > adjacent to the DMA masters and supports PCIe ATS and PRI.
> > > You can find it shipped in the recent publicly purchasable SoC SpacemiT K3.
> >
> > Right, then what you need here is something like:
> >
> > items:
> > - enum:
> > - spacemit,k3-iommu
> > - spacemit,t100-iommu
> > - riscv,iommu
> >
> > Driver can then match on spacemit,t100-iommu - but you need to have
> > soc-specific compatibles.
> > I'm not convinced that riscv,iommu is suitable here though, does the
> > driver work on your platform without the portions of code that are added
> > by this series and enabled by your new compatible? If not, the I don't
> > think the riscv,iommu fallback should be here.
> >
> > Additionally, please stop sending new versions so frequently and in
> > response to earlier submissions. I have a v4 in my inbox while we are
> > still discussing v3.
>
> SpacemiT provides RISC-V IOMMU implementation, T100 is the first
> generation of the this IP product line, we have plan to develop T200,
> T300, etc., with more features introduced to be adoptive to new
> RISC-V IOMMU specifications.
> Besides, T100 is not only shipped in K3, but also shipped in V100 and
> the follow-up SoCs, like Kn, Vn00, they will likely use the same
> synthesis result of T100 RTLs.
>
> From SpacemiT's point of view, we need a common sense of this IP
> series for something like IOATCs, that's why spacemit,riscv-iommu
> (this is same like qemu,riscv-iommu) is introduced. And a common sense
No, it's not the same as qemu,riscv-iommu. That exists to avoid
riscv,iommu being allowed in isolation and as a "SoC"/integration
specific compatible. The driver matches against riscv,iommu not
qemu,riscv-iommu and has no qemu,riscv-iommu specific behaviours.
It is akin to having spacemit,k3-iommu.
> of T100 for all SoCs shipped T100 (like global filters, vendor events
> and etc.,).
>
> IMO, the current compatible is proper to reflect these concerns.
> What do you think?
I pretty much already told you what I think, that you need SoC-specific
compatibles for SoCs that integrate this IP and that the you should drop
the spacemit,riscv-iommu compatible. The spacemit,riscv-iommu compatible
doesn't provide any additional value over spacemit,t100-iommu, and has
the downside of maybe being confusing in the future if spacemit
produces a iommu that doesn't have the IOATC behaviour.
Also, I don't see an answer to my question about whether the hardware
will work without the driver changes this series introduces and enables
with the new compatible?
Cheers,
Conor.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
` (6 preceding siblings ...)
2026-01-29 6:09 ` [PATCH v1.1 7/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
@ 2026-02-06 10:44 ` Krzysztof Kozlowski
7 siblings, 0 replies; 62+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-06 10:44 UTC (permalink / raw)
To: Lv Zheng, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
On 29/01/2026 07:08, Lv Zheng wrote:
> Includes HPM support for RISC-V IOMMU. The HPM hardware mechnism can be
> found in the recent announced SpacemiT SoCs (K3, V100), where T100
> (SpacemiT distributed IOMMU) is shipped.
>
> The tested result can be found as follows:
What is v1.1 in this patch? Why aren't you following standard process
which allows us to make review easier (try yourself with b4 diff)?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 0/8] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-04 9:08 ` [PATCH v3 0/8] " Lv Zheng
@ 2026-02-06 10:44 ` Krzysztof Kozlowski
2026-02-07 3:41 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-06 10:44 UTC (permalink / raw)
To: Lv Zheng, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
On 04/02/2026 10:08, Lv Zheng wrote:
> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
> found in the recent announced SpacemiT SoCs (K3, V100), where T100
> (SpacemiT distributed IOMMU) is shipped.
>
> Revisions:
> v1
> Initial release.
> v2 (sent as v1.1)
> Split and cleanup DT-bindings.
> v3
> Refactor using vendor specific compatible.
>
Do not attach (thread) your patchsets to some other threads (unrelated
or older versions). This buries them deep in the mailbox and might
interfere with applying entire sets. See also:
https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v4 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-05 9:09 ` [PATCH v4 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
@ 2026-02-06 10:46 ` Krzysztof Kozlowski
2026-02-07 3:54 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-06 10:46 UTC (permalink / raw)
To: Lv Zheng, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
On 05/02/2026 10:09, Lv Zheng wrote:
> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
> found in the recent announced SpacemiT SoCs (K3, V100), where T100
> (SpacemiT distributed IOMMU) is shipped.
>
> Revisions:
> v1
> Initial release.
> v2 (sent as v1.1)
> Split and cleanup DT-bindings.
> v3
> 1. Refactor using vendor specific compatible.
> 2. Implement vendor events with a userspace identifier.
> v4
And now also v4 is in the same thread? This is total mess!
How tools are supposed to handle this?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-06 3:42 ` Lv Zheng
@ 2026-02-06 15:09 ` Andrew Jones
2026-02-07 2:11 ` Zong Li
0 siblings, 1 reply; 62+ messages in thread
From: Andrew Jones @ 2026-02-06 15:09 UTC (permalink / raw)
To: Lv Zheng
Cc: Zong Li, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree, Yaxing Guo
On Fri, Feb 06, 2026 at 11:42:39AM +0800, Lv Zheng wrote:
> On 2/5/2026 11:23 PM, Andrew Jones wrote:
...
> > Since Zong Li's patches were already on the list then your serieswould> at
> least discuss them in the cover letter, explaining why you've opted
> > not to adopt them. But, most likely some of the patches can be adopted,
> > so those should be extracted from Zong Li's work (with authorship
> > preserved) and based upon in order to respect that prior work.
> >
>
> You can see we have contacted each other in community, and decided to
> cooperate in this way to honor his contribution. But final decision is
> left for the community to decide:
>
> From Zong Li:
> >> Of course, if the community would prefer to go your version, I’m
> >> perfectly fine with that as well.
>
> We respect all contributions, We'll add the link in cover letter to the
> follow-up revisions, let me know if anything else should be done to the
> new revisions.
Just do all the communication before posting, allowing that communication
to be summarized in the cover letter and in any appropriate commit
messages so reviewers know what's going on. Also don't forget to CC
anybody previously involved to ensure they have a chance to chime in.
>
> --------------------------------------------------------------------
>
> And let me describe in details to compare the functionalities and
> addressed comments between what is provided by Joey and by Zong:
>
> https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
>
> There is no missing functionalities between the two approaches, I also
> checked the original Robin's comments, let me describe them in details:
My concern wasn't whether or not Robin's comments were addressed in this
posting (that's important, but not what I'm talking about). My concern
was that Zong Li's work wasn't addressed in any way, so appeared to be
a chance for duplicated efforts. Indeed his reply [1] indicates exactly
that and even that there is a third patch series being worked
independently. Please work out who and what patches are going to be
the focus going forward and describe that decision in the cover letter
for the next revision. And please don't forget to CC Zong Li and Yaxing
Guo.
[1] https://lore.kernel.org/all/CANXhq0oi9nE7ffLGsz5j8GnC1UDTD-4bE4cantRjW2fXHYrjHA@mail.gmail.com/
Thanks,
drew
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring
2026-02-06 15:09 ` Andrew Jones
@ 2026-02-07 2:11 ` Zong Li
0 siblings, 0 replies; 62+ messages in thread
From: Zong Li @ 2026-02-07 2:11 UTC (permalink / raw)
To: Andrew Jones
Cc: Lv Zheng, Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree, Yaxing Guo
On Fri, Feb 6, 2026 at 11:09 PM Andrew Jones
<andrew.jones@oss.qualcomm.com> wrote:
>
> On Fri, Feb 06, 2026 at 11:42:39AM +0800, Lv Zheng wrote:
> > On 2/5/2026 11:23 PM, Andrew Jones wrote:
> ...
> > > Since Zong Li's patches were already on the list then your serieswould> at
> > least discuss them in the cover letter, explaining why you've opted
> > > not to adopt them. But, most likely some of the patches can be adopted,
> > > so those should be extracted from Zong Li's work (with authorship
> > > preserved) and based upon in order to respect that prior work.
> > >
> >
> > You can see we have contacted each other in community, and decided to
> > cooperate in this way to honor his contribution. But final decision is
> > left for the community to decide:
> >
> > From Zong Li:
> > >> Of course, if the community would prefer to go your version, I’m
> > >> perfectly fine with that as well.
> >
> > We respect all contributions, We'll add the link in cover letter to the
> > follow-up revisions, let me know if anything else should be done to the
> > new revisions.
>
> Just do all the communication before posting, allowing that communication
> to be summarized in the cover letter and in any appropriate commit
> messages so reviewers know what's going on. Also don't forget to CC
> anybody previously involved to ensure they have a chance to chime in.
>
> >
> > --------------------------------------------------------------------
> >
> > And let me describe in details to compare the functionalities and
> > addressed comments between what is provided by Joey and by Zong:
> >
> > https://lore.kernel.org/all/20250115030306.29735-1-zong.li@sifive.com/
> >
> > There is no missing functionalities between the two approaches, I also
> > checked the original Robin's comments, let me describe them in details:
>
> My concern wasn't whether or not Robin's comments were addressed in this
> posting (that's important, but not what I'm talking about). My concern
> was that Zong Li's work wasn't addressed in any way, so appeared to be
> a chance for duplicated efforts. Indeed his reply [1] indicates exactly
> that and even that there is a third patch series being worked
> independently. Please work out who and what patches are going to be
> the focus going forward and describe that decision in the cover letter
> for the next revision. And please don't forget to CC Zong Li and Yaxing
> Guo.
>
> [1] https://lore.kernel.org/all/CANXhq0oi9nE7ffLGsz5j8GnC1UDTD-4bE4cantRjW2fXHYrjHA@mail.gmail.com/
>
First of all, I apologize for the delay of the PMU series and any
inconvenience it may have caused. I also really appreciate Andrew for
pointing out the upstream culture and consensus.
My next version (v3 series) is expected to be sent out in the next
couple of days. It will pick up all the suggestions and feedback from
the previous versions. Apart from that, the main structural change is
that the PMU driver has been moved under drivers/perf/, which is
something that has been mentioned repeatedly by several people.
To allow everyone to review the major changes in the next version as
soon as possible, the custom event support will be split into a
separate series. Its overall idea will be similar to a typical
platform driver, where vendor-specific PMU events are defined through
driver data. More details will be described in the v3 cover letter.
Additionally, since I did not follow up the patches from Lv Zheng,
Jingyu Li, or Yaxing, it is very possible that my v3 series may miss
some important features or fixes from their work. If that is the case,
I apologize, I was not aware that those patches had been posted to
the mailing list, which is also why I did not respond to their v1
patch series in a timely manner. Therefore, I would really appreciate
it if everyone could help review the v3 series and point out any
additional fixes or feature support that I may have missed.
I also really appreciate everyone for always helping to bring us
together and keep the discussions aligned.
Thanks
> Thanks,
> drew
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 0/8] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-06 10:44 ` Krzysztof Kozlowski
@ 2026-02-07 3:41 ` Lv Zheng
2026-02-13 22:21 ` Yixun Lan
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-07 3:41 UTC (permalink / raw)
To: Krzysztof Kozlowski, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
On 2/6/2026 6:44 PM, Krzysztof Kozlowski wrote:
> On 04/02/2026 10:08, Lv Zheng wrote:
>> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
>> found in the recent announced SpacemiT SoCs (K3, V100), where T100
>> (SpacemiT distributed IOMMU) is shipped.
>>
>> Revisions:
>> v1
>> Initial release.
>> v2 (sent as v1.1)
>> Split and cleanup DT-bindings.
>> v3
>> Refactor using vendor specific compatible.
>>
>
>
> Do not attach (thread) your patchsets to some other threads (unrelated
> or older versions). This buries them deep in the mailbox and might
> interfere with applying entire sets. See also:
> https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830
Got it.
I'm still using an old fashioned upstream way to collect all revisions
into one thread. Will align to the preferred style.
Thanks,
Lv
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v4 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-06 10:46 ` Krzysztof Kozlowski
@ 2026-02-07 3:54 ` Lv Zheng
0 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-07 3:54 UTC (permalink / raw)
To: Krzysztof Kozlowski, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Jingyu Li, iommu, linux-perf-users, linux-riscv, spacemit,
devicetree
On 2/6/2026 6:46 PM, Krzysztof Kozlowski wrote:
> On 05/02/2026 10:09, Lv Zheng wrote:
>> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
>> found in the recent announced SpacemiT SoCs (K3, V100), where T100
>> (SpacemiT distributed IOMMU) is shipped.
>>
>> Revisions:
>> v1
>> Initial release.
>> v2 (sent as v1.1)
>> Split and cleanup DT-bindings.
>> v3
>> 1. Refactor using vendor specific compatible.
>> 2. Implement vendor events with a userspace identifier.
>> v4
>
> And now also v4 is in the same thread? This is total mess!
>
> How tools are supposed to handle this?
I'm using the tools I was using several years ago.
It's able to handle revisions using one single thread if a "msgid" is
provided via its command line:
# Prepare --in-reply-to argument of git-format-patch
if [ "x$1" != "x" -a "x$1" != "xnone" ]; then
echo "Found Message-Id: <$msgid>."
GFPFLAGS="$GFPFLAGS --in-reply-to=$msgid"
fi
And I have a configuration file in my $HOME collecting all patchsets'
first msgid:
if [ "x$require_msgid" = "xno" ]; then
fatal "Invalid Message-Id: $1 shouldn't be specified
for v${MAJOR}.${MINOR}."
fi
msgid=`cat $MSGIDS | grep $1 | cut -f2`
if [ "x$msgid" = "x" ]; then
fatal "Invalid Message-Id: cannot find $1 in $MSGIDS."
fi
That's the old fashion I was doing upstream related work, as some online
tools was able to update patchsets automatically if the thread top
matched and then showed the new revision up in their web portal.
Will stop using such single thread style as what you suggested.
Thanks,
Lv
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-06 10:24 ` Conor Dooley
@ 2026-02-07 4:24 ` Lv Zheng
2026-02-07 14:55 ` Conor Dooley
0 siblings, 1 reply; 62+ messages in thread
From: Lv Zheng @ 2026-02-07 4:24 UTC (permalink / raw)
To: Conor Dooley
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
On 2/6/2026 6:24 PM, Conor Dooley wrote:
> On Fri, Feb 06, 2026 at 09:33:09AM +0800, Lv Zheng wrote:
>> On 2/6/2026 2:24 AM, Conor Dooley wrote:
>>> On Thu, Feb 05, 2026 at 11:11:51AM +0800, Lv Zheng wrote:
>>>> On 2/5/2026 1:37 AM, Conor Dooley wrote:
>>>>> On Wed, Feb 04, 2026 at 05:09:12PM +0800, Lv Zheng wrote:
>>>>>> Adds device tree bindings for SpacemiT T100 specific features by
>>>>>> introducing spacemit,100 compatible. T100 contains distributed IOATCs,
>>>>>> each of which exposes pmiv interrupt.
>>>>>>
>>>>>> Signed-off-by: Lv Zheng <lv.zheng@linux.spacemit.com>
>>>>>> Signed-off-by: Jingyu Li <joey.li@spacemit.com>
>>>>>> ---
>>>>>> .../bindings/iommu/riscv,iommu.yaml | 37 +++++++++++++++++++
>>>>>> 1 file changed, 37 insertions(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>>>> index d4838c3b3741..2da3456e7402 100644
>>>>>> --- a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>>>> +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml
>>>>>> @@ -32,6 +32,12 @@ properties:
>>>>>> # should be specified along with 'reg' property providing MMIO location.
>>>>>> compatible:
>>>>>> oneOf:
>>>>>> + - description: SpacemiT distributed IOMMUs
>>>>>> + items:
>>>>>> + - enum:
>>>>>> + - spacemit,t100
>>>>>> + - const: spacemit,riscv-iommu
>>>>>
>>>>> What actually is the t100? Is it an SoC or is it the name of the core
>>>>> complex IP that spacemit is using in multiple SoCs?
>>>>
>>>> T100 is the name of the IOMMU IP developed by SpacemiT, announced in RISC-V
>>>> 2024 China Summit:
>>>> https://www.bilibili.com/video/BV1DNtCeiEBk/
>>>> It's world first server SPEC IOMMU in RISC-V, supports IOTLB placed in
>>>> adjacent to the DMA masters and supports PCIe ATS and PRI.
>>>> You can find it shipped in the recent publicly purchasable SoC SpacemiT K3.
>>>
>>> Right, then what you need here is something like:
>>>
>>> items:
>>> - enum:
>>> - spacemit,k3-iommu
>>> - spacemit,t100-iommu
>>> - riscv,iommu
>>>
>>> Driver can then match on spacemit,t100-iommu - but you need to have
>>> soc-specific compatibles.
>>> I'm not convinced that riscv,iommu is suitable here though, does the
>>> driver work on your platform without the portions of code that are added
>>> by this series and enabled by your new compatible? If not, the I don't
>>> think the riscv,iommu fallback should be here.
>>>
>>> Additionally, please stop sending new versions so frequently and in
>>> response to earlier submissions. I have a v4 in my inbox while we are
>>> still discussing v3.
>>
>> SpacemiT provides RISC-V IOMMU implementation, T100 is the first
>> generation of the this IP product line, we have plan to develop T200,
>> T300, etc., with more features introduced to be adoptive to new
>> RISC-V IOMMU specifications.
>> Besides, T100 is not only shipped in K3, but also shipped in V100 and
>> the follow-up SoCs, like Kn, Vn00, they will likely use the same
>> synthesis result of T100 RTLs.
>>
>> From SpacemiT's point of view, we need a common sense of this IP
>> series for something like IOATCs, that's why spacemit,riscv-iommu
>> (this is same like qemu,riscv-iommu) is introduced. And a common sense
>
> No, it's not the same as qemu,riscv-iommu. That exists to avoid
> riscv,iommu being allowed in isolation and as a "SoC"/integration
> specific compatible. The driver matches against riscv,iommu not
> qemu,riscv-iommu and has no qemu,riscv-iommu specific behaviours.
> It is akin to having spacemit,k3-iommu.
Got it.
>
>> of T100 for all SoCs shipped T100 (like global filters, vendor events
>> and etc.,).
>>
>> IMO, the current compatible is proper to reflect these concerns.
>> What do you think?
>
> I pretty much already told you what I think, that you need SoC-specific
> compatibles for SoCs that integrate this IP and that the you should drop
> the spacemit,riscv-iommu compatible. The spacemit,riscv-iommu compatible
> doesn't provide any additional value over spacemit,t100-iommu, and has
> the downside of maybe being confusing in the future if spacemit
> produces a iommu that doesn't have the IOATC behaviour.
Sounds reasonable. Thanks.
>
> Also, I don't see an answer to my question about whether the hardware
> will work without the driver changes this series introduces and enables
> with the new compatible?
Basically, T100 is riscv,iommu compatible, its IOATS part should be able
to work using standard HPM events with standard riscv,iommu HPM
compatible driver. People can now test the real hardware of spacemit
T100 on K3.
https://canonical.com/blog/spacemit-announces-availability-of-ubuntu-on-k3-k1-series
I'll try to ask our product team to find third party testers, and if
any, adds Cc(s) in the next revision.
Without the awareness of this compatible, hardware will face the
following problems:
Handled in this series:
1. No vendor event matches
2. No global filter awareness
3. No IOATC enumeration
That's the basic support introduced in this series to enable some basic
features of T100 that we couldn't find in the upstream.
And there are other features not handled in this series:
4. No identities matching vendors
5. No awareness of only PMIV working as WSI, others (CIV/FIV/PIV) are
configurable as MSI to make IOATS/IOATC PMIV behaves same and more
suitable for kernel performance sampling.
6. And many other SpacemiT specific features people can find the
discussions in the IOMMU spec community that is not limited to HPM,
ex., RISC-V DMA64 compliance, QEMU old style MSI-PTE support, etc.
7. ACPI support for spacemit,v100-iommu.
8. PCIe ATS/PRI support for spacemit,k3-iommu/spacemit,v100-iommu.
9. etc.
Cheers,
Lv
>
> Cheers,
> Conor.
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features
2026-02-07 4:24 ` Lv Zheng
@ 2026-02-07 14:55 ` Conor Dooley
0 siblings, 0 replies; 62+ messages in thread
From: Conor Dooley @ 2026-02-07 14:55 UTC (permalink / raw)
To: Lv Zheng
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Jingyu Li, iommu,
linux-perf-users, linux-riscv, spacemit, devicetree
[-- Attachment #1: Type: text/plain, Size: 505 bytes --]
On Sat, Feb 07, 2026 at 12:24:30PM +0800, Lv Zheng wrote:
>
> >
> > Also, I don't see an answer to my question about whether the hardware
> > will work without the driver changes this series introduces and enables
> > with the new compatible?
>
> Basically, T100 is riscv,iommu compatible, its IOATS part should be able
> to work using standard HPM events with standard riscv,iommu HPM
> compatible driver.
That's fine, that's all I wanted to know. The riscv,iommu compatible can
stay :)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 0/8] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-07 3:41 ` Lv Zheng
@ 2026-02-13 22:21 ` Yixun Lan
2026-02-27 5:55 ` Lv Zheng
0 siblings, 1 reply; 62+ messages in thread
From: Yixun Lan @ 2026-02-13 22:21 UTC (permalink / raw)
To: Lv Zheng
Cc: Krzysztof Kozlowski, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
Hi Lv,
On 11:41 Sat 07 Feb , Lv Zheng wrote:
> On 2/6/2026 6:44 PM, Krzysztof Kozlowski wrote:
> > On 04/02/2026 10:08, Lv Zheng wrote:
> >> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
> >> found in the recent announced SpacemiT SoCs (K3, V100), where T100
> >> (SpacemiT distributed IOMMU) is shipped.
> >>
> >> Revisions:
> >> v1
> >> Initial release.
> >> v2 (sent as v1.1)
> >> Split and cleanup DT-bindings.
> >> v3
> >> Refactor using vendor specific compatible.
> >>
> >
> >
> > Do not attach (thread) your patchsets to some other threads (unrelated
> > or older versions). This buries them deep in the mailbox and might
> > interfere with applying entire sets. See also:
> > https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830
>
> Got it.
> I'm still using an old fashioned upstream way to collect all revisions
> into one thread. Will align to the preferred style.
>
Using b4 will automate this procedure, you can also take a look at
Konstantin's articles, and the b4 doc
https://people.kernel.org/monsieuricon/sending-a-kernel-patch-with-b4-part-1
https://b4.docs.kernel.org/en/latest/
> Thanks,
> Lv
>
> >
> > Best regards,
> > Krzysztof
> >
>
>
>
--
Yixun Lan (dlan)
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v3 0/8] iommu/riscv: Add HPM support for RISC-V IOMMU
2026-02-13 22:21 ` Yixun Lan
@ 2026-02-27 5:55 ` Lv Zheng
0 siblings, 0 replies; 62+ messages in thread
From: Lv Zheng @ 2026-02-27 5:55 UTC (permalink / raw)
To: Yixun Lan
Cc: Krzysztof Kozlowski, Tomasz Jeznach, Joerg Roedel, Will Deacon,
Robin Murphy, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Jingyu Li, Zhijian Chen, iommu, linux-perf-users, linux-riscv,
spacemit, devicetree
On 2/14/2026 6:21 AM, Yixun Lan wrote:
> Hi Lv,
>
> On 11:41 Sat 07 Feb , Lv Zheng wrote:
>> On 2/6/2026 6:44 PM, Krzysztof Kozlowski wrote:
>>> On 04/02/2026 10:08, Lv Zheng wrote:
>>>> Includes HPM support for RISC-V IOMMU. The HPM hardware mechanism can be
>>>> found in the recent announced SpacemiT SoCs (K3, V100), where T100
>>>> (SpacemiT distributed IOMMU) is shipped.
>>>>
>>>> Revisions:
>>>> v1
>>>> Initial release.
>>>> v2 (sent as v1.1)
>>>> Split and cleanup DT-bindings.
>>>> v3
>>>> Refactor using vendor specific compatible.
>>>>
>>>
>>>
>>> Do not attach (thread) your patchsets to some other threads (unrelated
>>> or older versions). This buries them deep in the mailbox and might
>>> interfere with applying entire sets. See also:
>>> https://elixir.bootlin.com/linux/v6.16-rc2/source/Documentation/process/submitting-patches.rst#L830
>>
>> Got it.
>> I'm still using an old fashioned upstream way to collect all revisions
>> into one thread. Will align to the preferred style.
>>
> Using b4 will automate this procedure, you can also take a look at
> Konstantin's articles, and the b4 doc
> https://people.kernel.org/monsieuricon/sending-a-kernel-patch-with-b4-part-1
> https://b4.docs.kernel.org/en/latest/
Yes, we've tried b4, it really can automate this process a lot.
Thanks,
Lv
>
>> Thanks,
>> Lv
>>
>>>
>>> Best regards,
>>> Krzysztof
>>>
>>
>>
>>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
end of thread, other threads:[~2026-02-27 5:56 UTC | newest]
Thread overview: 62+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <cover.1769562575.git.lv.zheng@spacemit.com>
2026-01-29 6:08 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 2/7] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
2026-01-29 6:08 ` [PATCH v1.1 3/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 4/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
2026-01-29 10:08 ` Conor Dooley
2026-01-29 10:43 ` 郑律
2026-01-29 16:41 ` Conor Dooley
2026-01-29 17:06 ` Robin Murphy
2026-01-30 1:30 ` 郑律
2026-01-30 1:39 ` 郑律
2026-01-29 6:09 ` [PATCH v1.1 5/7] spacemit/t100: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 6/7] spacemit/t100: Add global filter " Lv Zheng
2026-01-29 6:09 ` [PATCH v1.1 7/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-06 10:44 ` [PATCH v1.1 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Krzysztof Kozlowski
2026-02-04 9:08 ` [PATCH v3 0/8] " Lv Zheng
2026-02-06 10:44 ` Krzysztof Kozlowski
2026-02-07 3:41 ` Lv Zheng
2026-02-13 22:21 ` Yixun Lan
2026-02-27 5:55 ` Lv Zheng
[not found] ` <cover.1770195980.git.lv.zheng@linux.spacemit.com>
2026-02-04 9:08 ` [PATCH v3 1/8] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-02-04 9:08 ` [PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling Lv Zheng
2026-02-04 17:20 ` Andrew Jones
2026-02-05 3:52 ` Lv Zheng
2026-02-05 15:04 ` Andrew Jones
2026-02-06 1:36 ` Lv Zheng
2026-02-04 9:09 ` [PATCH v3 3/8] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
2026-02-04 18:39 ` Andrew Jones
2026-02-05 2:11 ` Zong Li
2026-02-05 3:35 ` Lv Zheng
2026-02-05 3:47 ` Zong Li
2026-02-05 6:11 ` Lv Zheng
2026-02-05 15:23 ` Andrew Jones
2026-02-06 3:42 ` Lv Zheng
2026-02-06 15:09 ` Andrew Jones
2026-02-07 2:11 ` Zong Li
2026-02-04 9:09 ` [PATCH v3 4/8] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
2026-02-04 17:37 ` Conor Dooley
2026-02-05 3:11 ` Lv Zheng
2026-02-05 18:24 ` Conor Dooley
2026-02-06 1:33 ` Lv Zheng
2026-02-06 10:24 ` Conor Dooley
2026-02-07 4:24 ` Lv Zheng
2026-02-07 14:55 ` Conor Dooley
2026-02-04 9:09 ` [PATCH v3 5/8] riscv/iommu: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
2026-02-04 9:09 ` [PATCH v3 6/8] spacemit/t100: Add global filter awareness " Lv Zheng
2026-02-04 9:09 ` [PATCH v3 7/8] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-04 9:09 ` [PATCH v3 8/8] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
2026-02-04 17:38 ` Conor Dooley
2026-02-05 3:22 ` Lv Zheng
2026-02-05 9:09 ` [PATCH v4 0/7] iommu/riscv: Add HPM support for RISC-V IOMMU Lv Zheng
2026-02-06 10:46 ` Krzysztof Kozlowski
2026-02-07 3:54 ` Lv Zheng
[not found] ` <cover.1770281596.git.lv.zheng@linux.spacemit.com>
2026-02-05 9:10 ` [PATCH v4 1/7] iommu/riscv: Enable IOMMU DMA mapping support Lv Zheng
2026-02-05 9:10 ` [PATCH v4 2/7] iommu/riscv: Add HPM support for performance monitoring Lv Zheng
2026-02-05 9:10 ` [PATCH v4 3/7] dt-bindings: iommu: Add spacemit/t100 features Lv Zheng
2026-02-05 18:26 ` Conor Dooley
2026-02-06 3:44 ` Lv Zheng
2026-02-05 9:10 ` [PATCH v4 4/7] iommu/riscv: Add vendor event support for RISC-V IOMMU HPM Lv Zheng
2026-02-05 9:11 ` [PATCH v4 5/7] spacemit/t100: Add global filter awareness " Lv Zheng
2026-02-05 9:11 ` [PATCH v4 6/7] spacemit/t100: Add SpacemiT T100 IOATC HPM support Lv Zheng
2026-02-05 9:11 ` [PATCH v4 7/7] perf vendor events riscv:: Add support for spacemit,riscv-iommu HPM aliasing Lv Zheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox