[RFC PATCH 11/12] iommu/riscv: Accept unpublished interrupt files in IRQ forwarding

Gong Shuai gong.shuai at sanechips.com.cn
Wed Oct 14 23:52:31 PDT 2026


A guest with a vIOMMU needs the complete IMSIC topology of the VM in the
MSI table, since the hardware resolves the target vCPU from the MSI
address on its own. That table is installed when the first device MSI is
forwarded, which can happen before every vCPU has its interrupt file
published, so a request for the whole VM cannot require all of them.

Skip the unpublished ones instead of rejecting the whole request. An MSI
that resolves to one of them faults only for that vCPU and is reported
in the fault queue, whereas a failed request would take IRQ bypass away
from the entire virtual machine.

Co-developed-by: Wu Fei <wu.fei9 at sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai at sanechips.com.cn>
---
 drivers/iommu/riscv/iommu-ir.c      | 25 +++++++++++++++++++++----
 include/linux/irqchip/riscv-imsic.h | 14 ++++++++------
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c
index b3f0a56475ed..94971959a581 100644
--- a/drivers/iommu/riscv/iommu-ir.c
+++ b/drivers/iommu/riscv/iommu-ir.c
@@ -78,18 +78,28 @@ static int riscv_iommu_ir_validate_target(const struct riscv_iommu_ir_vcpu_info
 static int riscv_iommu_ir_validate_targets(const struct riscv_iommu_ir_vcpu_info *vcpu_info,
 					   size_t nr_ptes, u64 *required_caps)
 {
+	unsigned int nr_valid = 0;
 	int ret;
 
-	if (!vcpu_info->targets || !vcpu_info->nr_targets || vcpu_info->nr_targets > nr_ptes)
+	if (!vcpu_info->targets || !vcpu_info->nr_targets)
 		return -EINVAL;
 
 	for (unsigned int i = 0; i < vcpu_info->nr_targets; i++) {
+		/* Interrupt files the host has not published yet are skipped. */
+		if (vcpu_info->targets[i].type == RISCV_IOMMU_IR_TARGET_INVALID)
+			continue;
+
 		ret = riscv_iommu_ir_validate_target(vcpu_info, &vcpu_info->targets[i],
 						     required_caps);
 		if (ret)
 			return ret;
+		nr_valid++;
 	}
 
+	/* The table only has to be able to deliver some interrupt file. */
+	if (!nr_valid || nr_valid > nr_ptes)
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -147,9 +157,16 @@ static int riscv_iommu_ir_activate(struct riscv_iommu_msi_table *msi_table,
 
 	for (unsigned int i = 0; i < vcpu_info->nr_targets; i++) {
 		const struct riscv_iommu_ir_target *target = &vcpu_info->targets[i];
-		size_t idx = riscv_iommu_ir_extract(target->gpa >> IMSIC_MMIO_PAGE_SHIFT,
-						    vcpu_info->msi_addr_mask);
-		struct riscv_iommu_msipte *msipte = &msi_table->root[idx];
+		size_t idx;
+		struct riscv_iommu_msipte *msipte;
+
+		/* Interrupt files the host has not published yet are skipped. */
+		if (target->type == RISCV_IOMMU_IR_TARGET_INVALID)
+			continue;
+
+		idx = riscv_iommu_ir_extract(target->gpa >> IMSIC_MMIO_PAGE_SHIFT,
+					     vcpu_info->msi_addr_mask);
+		msipte = &msi_table->root[idx];
 
 		/* A populated entry in the initially clear table indicates duplicate targets. */
 		if (msipte->pte || msipte->mrif_info) {
diff --git a/include/linux/irqchip/riscv-imsic.h b/include/linux/irqchip/riscv-imsic.h
index 02a836ce03b4..947c406d512b 100644
--- a/include/linux/irqchip/riscv-imsic.h
+++ b/include/linux/irqchip/riscv-imsic.h
@@ -138,12 +138,14 @@ struct riscv_iommu_ir_target {
 };
 
 /*
- * FORWARD enables forwarding for one IRQ and provides the complete target array
- * so the first forwarded IRQ can initialize the domain MSI table. UPDATE_TARGET
- * replaces one target without changing per-IRQ forwarding state. The caller
- * must quiesce all MSI producers using the table when changing both words of a
- * live MRIF PTE because the update temporarily invalidates the entry. A NULL
- * vcpu_info disables forwarding for the IRQ.
+ * FORWARD enables forwarding for one IRQ and provides the target array so the
+ * first forwarded IRQ can initialize the domain MSI table. Entries of type
+ * RISCV_IOMMU_IR_TARGET_INVALID are skipped, so a caller may forward the whole
+ * virtual machine topology while only some of its interrupt files are hardware
+ * backed. UPDATE_TARGET replaces one target without changing per-IRQ forwarding
+ * state. The caller must quiesce all MSI producers using the table when
+ * changing both words of a live MRIF PTE because the update temporarily
+ * invalidates the entry. A NULL vcpu_info disables forwarding for the IRQ.
  *
  * A well-formed request which is incompatible with the producer or current
  * domain configuration returns -EOPNOTSUPP, allowing the caller to fall back
-- 
2.53.0




More information about the kvm-riscv mailing list