[PATCH v3 2/8] iommu/riscv: Fix WSI mode IRQ number handling
Lv Zheng
lv.zheng at linux.spacemit.com
Wed Feb 4 19:52:57 PST 2026
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 at 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 at spacemit.com>
>> Signed-off-by: Lv Zheng <lv.zheng at 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
>
More information about the linux-riscv
mailing list