[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