[PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling

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

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