* [RFC PATCH 0/6] iommu/riscv: Add MRIF support
@ 2025-08-11 6:10 fangyu.yu
2025-08-11 6:10 ` [RFC PATCH 1/6] RISC-V: Add more elements to irqbypass vcpu_info fangyu.yu
` (6 more replies)
0 siblings, 7 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:10 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
According to the RISC-V IOMMU Spec, an IOMMU may optionally support
memory-resident interrupt files (MRIFs). When the guest interrupt
files are used up, an MRIF can record an incoming MSI.
At present, the hypervisor has allocated an MRIF for each IMSIC, we
only need to configure the PPN of the MRIF into the MSI PTE of the
IOMMU in MRIF mode.At the same time, we also need to configure NPPN
and NID for notice MSIs, in these patches,we use the host interrupt
(allocated via VFIO) as the notice MSIs, so that we don't need to
allocate a new MSI interrupt, and we can easily redirect the guest
interrupt back to the host interrupt when MRIF is not supported on
the IOMMU hardware.
This RFC series are based on [1] by Andrew Jones.
Self Test:
-----------
1. Key parameters for starting host QEMU:
./qemu-system-riscv64 \
-M virt,aia=aplic-imsic,aia-guests=1 -m 8G -smp 2 \
-nographic -device riscv-iommu-pci,vendor-id=0x1efd,device-id=0x0008 \
-netdev user,id=net1,hostfwd=tcp::2323-:22 \
-device e1000e,netdev=net1 \
-drive file=./nvme_disk.qcow2,if=none,id=nvm \
-device nvme,serial=deadbeef,drive=nvm \
...
2. Steps to start a virtual machine:
# lspci
00:00.0 Host bridge: Red Hat, Inc. QEMU PCIe Host bridge
00:01.0 IOMMU: Device 1efd:0008 (rev 01)
00:02.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
00:03.0 Non-Volatile memory controller: Red Hat, Inc. QEMU NVM Express Controller (rev 02)
00:04.0 Unclassified device [0002]: Red Hat, Inc. Virtio filesystem
# echo 0000:00:02.0 > /sys/bus/pci/drivers/e1000e/unbind
# echo 0000:00:03.0 > /sys/bus/pci/drivers/nvme/unbind
# echo 8086 10d3 > /sys/bus/pci/drivers/vfio-pci/new_id
# echo 1b36 0010 > /sys/bus/pci/drivers/vfio-pci/new_id
qemu-system-riscv64 -M virt,aia=aplic-imsic --enable-kvm -m 2G -smp 4 \
-device vfio-pci,host=0000:00:02.0 \
-device vfio-pci,host=0000:00:03.0 \
...
3. Test within guest os:
root@qemu:/mnt/nvme# lspci
00:00.0 Host bridge: Red Hat, Inc. QEMU PCIe Host bridge
00:01.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
00:02.0 Non-Volatile memory controller: Red Hat, Inc. QEMU NVM Express Controller (rev 02)
root@qemu:~# mount /dev/nvme0n1p1 /mnt/nvme/
root@qemu:~# cd /mnt/nvme/
root@qemu:/mnt/nvme# ping 11.122.129.243 -i 0.1 | tee c.txt
64 bytes from 11.122.129.243: icmp_seq=18533 ttl=255 time=1.18 ms
64 bytes from 11.122.129.243: icmp_seq=18534 ttl=255 time=1.60 ms
^C
--- 11.122.129.243 ping statistics ---
18534 packets transmitted, 18534 received, 0% packet loss, time 1934380ms
rtt min/avg/max/mdev = 0.437/11.986/3451.393/118.494 ms, pipe 34
root@qemu:/mnt/nvme# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
10: 49856 218638 192244 58721 RISC-V INTC 5 Edge riscv-timer
12: 0 105519 0 0 PCI-MSIX-0000:00:01.0 0 Edge eth0-rx-0
13: 0 0 97134 0 PCI-MSIX-0000:00:01.0 1 Edge eth0-tx-0
14: 0 0 0 2 PCI-MSIX-0000:00:01.0 2 Edge eth0
16: 0 42752 0 0 PCI-MSIX-0000:00:02.0 0 Edge nvme0q0
17: 376 0 0 0 PCI-MSIX-0000:00:02.0 1 Edge nvme0q1
18: 0 1308 0 0 PCI-MSIX-0000:00:02.0 2 Edge nvme0q2
19: 0 0 49757 0 PCI-MSIX-0000:00:02.0 3 Edge nvme0q3
20: 0 0 0 1282 PCI-MSIX-0000:00:02.0 4 Edge nvme0q4
[1] https://github.com/jones-drew/linux/tree/riscv/iommu-irqbypass-rfc-v2-rc1
Fangyu Yu (6):
RISC-V: Add more elements to irqbypass vcpu_info
RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir
RISC-V: KVM: Add a xarray to record host irq msg
iommu/riscv: Add irq_mask and irq_ack configure for iommu-ir
iommu/riscv: Add MRIF mode support
RISC-V: KVM: Check the MRIF in notice MSI irq handler
arch/riscv/include/asm/irq.h | 3 +
arch/riscv/kvm/aia_imsic.c | 119 ++++++++++++++++++++++++++++---
drivers/iommu/riscv/iommu-bits.h | 6 ++
drivers/iommu/riscv/iommu-ir.c | 40 +++++++++--
4 files changed, 156 insertions(+), 12 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 1/6] RISC-V: Add more elements to irqbypass vcpu_info
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
@ 2025-08-11 6:10 ` fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir fangyu.yu
` (5 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:10 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
To support MRIF mode, we need to add more elements to
let the iommu driver get the ppn of MRIF.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/include/asm/irq.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h
index 8588667cbb5f..6293ac00e051 100644
--- a/arch/riscv/include/asm/irq.h
+++ b/arch/riscv/include/asm/irq.h
@@ -30,6 +30,9 @@ struct riscv_iommu_vcpu_info {
u32 group_index_shift;
u64 gpa;
u64 hpa;
+ u32 host_irq;
+ bool mrif;
+ struct msi_msg *host_msg;
};
#ifdef CONFIG_ACPI
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
2025-08-11 6:10 ` [RFC PATCH 1/6] RISC-V: Add more elements to irqbypass vcpu_info fangyu.yu
@ 2025-08-11 6:11 ` fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 3/6] RISC-V: KVM: Add a xarray to record host irq msg fangyu.yu
` (4 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:11 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
According to the RISC-V IOMMU Spec, an IOMMU may optionally
support memory-resident interrupt files (MRIFs).
When the guest interrupt files are used up, we transfer the
physical address of MRIF to iommu-ir, and enable MRIF mode
if the iommu-ir supports.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kvm/aia_imsic.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 8f5703d9112a..e91164742fd0 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -21,6 +21,8 @@
#define IMSIC_MAX_EIX (IMSIC_MAX_ID / BITS_PER_TYPE(u64))
+static int kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu);
+
struct imsic_mrif_eix {
unsigned long eip[BITS_PER_TYPE(u64) / BITS_PER_LONG];
unsigned long eie[BITS_PER_TYPE(u64) / BITS_PER_LONG];
@@ -717,7 +719,8 @@ void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
vcpu->arch.aia_context.imsic_addr,
IMSIC_MMIO_PAGE_SZ);
- /* TODO: Purge the IOMMU mapping ??? */
+ /* Update the IOMMU mapping */
+ kvm_riscv_vcpu_irq_update(vcpu);
/*
* At this point, all interrupt producers have been re-directed
@@ -795,13 +798,14 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
read_lock_irqsave(&imsic->vsfile_lock, flags);
- if (WARN_ON_ONCE(imsic->vsfile_cpu < 0)) {
- read_unlock_irqrestore(&imsic->vsfile_lock, flags);
- goto out;
+ if (imsic->vsfile_cpu < 0) {
+ vcpu_info.hpa = imsic->swfile_pa;
+ vcpu_info.mrif = true;
+ } else {
+ vcpu_info.hpa = imsic->vsfile_pa;
+ vcpu_info.mrif = false;
}
- vcpu_info.hpa = imsic->vsfile_pa;
-
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
if (ret) {
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
@@ -844,6 +848,13 @@ static int kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
if (!irqfd->producer)
continue;
host_irq = irqfd->producer->irq;
+
+ if (imsic->vsfile_cpu < 0) {
+ vcpu_info.hpa = imsic->swfile_pa;
+ vcpu_info.mrif = true;
+ } else {
+ vcpu_info.mrif = false;
+ }
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
if (ret) {
spin_unlock_irq(&kvm->irqfds.lock);
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 3/6] RISC-V: KVM: Add a xarray to record host irq msg
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
2025-08-11 6:10 ` [RFC PATCH 1/6] RISC-V: Add more elements to irqbypass vcpu_info fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir fangyu.yu
@ 2025-08-11 6:11 ` fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 4/6] iommu/riscv: Add irq_mask and irq_ack configure for iommu-ir fangyu.yu
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:11 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
In the irq bypass scenario,the host interrupt comes from VFIO, and
it is an enabled MSI/MSI-X interrupt. Due to the reconfiguration
of the PCI-e BAR space during the irq bypass process,this host irq
will not be triggered in the host system.
We can use this host irq as a notice MSI in IOMMU MRIF mode.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kvm/aia_imsic.c | 69 +++++++++++++++++++++++++++++++++++++-
1 file changed, 68 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index e91164742fd0..58807e68a3dd 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -60,6 +60,9 @@ struct imsic {
struct imsic_mrif *swfile;
phys_addr_t swfile_pa;
raw_spinlock_t swfile_extirq_lock;
+
+ bool mrif_support;
+ struct xarray hostirq_array; /* Attached host irq array */
};
#define imsic_vs_csr_read(__c) \
@@ -740,6 +743,57 @@ void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
kvm_riscv_aia_free_hgei(old_vsfile_cpu, old_vsfile_hgei);
}
+static int kvm_arch_update_irqfd_unset(struct kvm *kvm, unsigned int host_irq)
+{
+ struct kvm_vcpu *vcpu;
+ unsigned long tmp;
+
+ kvm_for_each_vcpu(tmp, vcpu, kvm) {
+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
+ struct msi_msg *curr = xa_load(&imsic->hostirq_array, host_irq);
+
+ if (!curr)
+ continue;
+
+ xa_erase(&imsic->hostirq_array, host_irq);
+ kfree(curr);
+ break;
+ }
+
+ return irq_set_vcpu_affinity(host_irq, NULL);
+}
+
+static struct msi_msg *kvm_arch_update_irqfd_hostirq(struct imsic *imsic,
+ unsigned int host_irq, int *ret,
+ struct kvm_kernel_irq_routing_entry *e)
+{
+ struct msi_msg *priv_msg = xa_load(&imsic->hostirq_array, host_irq);
+
+ if (!priv_msg) {
+ priv_msg = kzalloc(sizeof(*priv_msg), GFP_KERNEL);
+ if (!priv_msg) {
+ *ret = -ENOMEM;
+ goto out;
+ }
+
+ struct msi_msg host_msg, *curr;
+
+ get_cached_msi_msg(host_irq, &host_msg);
+ priv_msg[0] = host_msg;
+ curr = xa_cmpxchg(&imsic->hostirq_array, host_irq,
+ NULL, priv_msg, GFP_ATOMIC);
+ if (WARN_ON_ONCE(curr)) {
+ *ret = xa_err(curr) ? : -EBUSY;
+ kfree(priv_msg);
+ goto out;
+ }
+ }
+ *ret = 0;
+
+out:
+ return priv_msg;
+}
+
int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
uint32_t guest_irq, bool set)
{
@@ -750,7 +804,7 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
int idx, ret = -ENXIO;
if (!set)
- return irq_set_vcpu_affinity(host_irq, NULL);
+ return kvm_arch_update_irqfd_unset(kvm, host_irq);
idx = srcu_read_lock(&kvm->irq_srcu);
irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
@@ -795,6 +849,11 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
vcpu_info.msi_addr_pattern = tppn & ~vcpu_info.msi_addr_mask;
vcpu_info.gpa = target;
+ vcpu_info.host_irq = host_irq;
+ vcpu_info.host_msg =
+ kvm_arch_update_irqfd_hostirq(imsic, host_irq, &ret, e);
+ if (ret)
+ goto out;
read_lock_irqsave(&imsic->vsfile_lock, flags);
@@ -848,6 +907,10 @@ static int kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
if (!irqfd->producer)
continue;
host_irq = irqfd->producer->irq;
+ vcpu_info.host_irq = host_irq;
+ vcpu_info.host_msg = xa_load(&imsic->hostirq_array, host_irq);
+ if (!vcpu_info.host_msg)
+ continue;
if (imsic->vsfile_cpu < 0) {
vcpu_info.hpa = imsic->swfile_pa;
@@ -855,6 +918,7 @@ static int kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
} else {
vcpu_info.mrif = false;
}
+
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
if (ret) {
spin_unlock_irq(&kvm->irqfds.lock);
@@ -1195,6 +1259,9 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)
imsic->swfile_pa = page_to_phys(swfile_page);
raw_spin_lock_init(&imsic->swfile_extirq_lock);
+ xa_init(&imsic->hostirq_array);
+ imsic->mrif_support = false;
+
/* Setup IO device */
kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops);
mutex_lock(&kvm->slots_lock);
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 4/6] iommu/riscv: Add irq_mask and irq_ack configure for iommu-ir
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
` (2 preceding siblings ...)
2025-08-11 6:11 ` [RFC PATCH 3/6] RISC-V: KVM: Add a xarray to record host irq msg fangyu.yu
@ 2025-08-11 6:11 ` fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 5/6] iommu/riscv: Add MRIF mode support fangyu.yu
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:11 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
The irq_mask and irq_ack are required for host irq to be triggered
under the host system.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
drivers/iommu/riscv/iommu-ir.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c
index 5461dbe18159..73f552ed5b65 100644
--- a/drivers/iommu/riscv/iommu-ir.c
+++ b/drivers/iommu/riscv/iommu-ir.c
@@ -208,6 +208,7 @@ static struct irq_chip riscv_iommu_irq_chip = {
.irq_unmask = irq_chip_unmask_parent,
.irq_set_affinity = irq_chip_set_affinity_parent,
.irq_set_vcpu_affinity = riscv_iommu_irq_set_vcpu_affinity,
+ .irq_ack = irq_chip_ack_parent,
};
static int riscv_iommu_irq_domain_alloc_irqs(struct irq_domain *irqdomain,
@@ -239,7 +240,9 @@ static const struct msi_parent_ops riscv_iommu_msi_parent_ops = {
.supported_flags = MSI_GENERIC_FLAGS_MASK |
MSI_FLAG_PCI_MSIX,
.required_flags = MSI_FLAG_USE_DEF_DOM_OPS |
- MSI_FLAG_USE_DEF_CHIP_OPS,
+ MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_PCI_MSI_MASK_PARENT,
+ .chip_flags = MSI_CHIP_FLAG_SET_ACK,
.init_dev_msi_info = msi_parent_init_dev_msi_info,
};
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 5/6] iommu/riscv: Add MRIF mode support
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
` (3 preceding siblings ...)
2025-08-11 6:11 ` [RFC PATCH 4/6] iommu/riscv: Add irq_mask and irq_ack configure for iommu-ir fangyu.yu
@ 2025-08-11 6:11 ` fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 6/6] RISC-V: KVM: Check the MRIF in notice MSI irq handler fangyu.yu
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:11 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
If the guest interrupt files are exhausted and the MRIF is supported
we configure the MSI PTE with MRIF mode, and set the NPPN and NID
using notice MSI from host irq.
Otherwise, we redirect the guest interrupt back to the original host
irq and inject the interrupt into the guest machine through irqfd.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
drivers/iommu/riscv/iommu-bits.h | 6 ++++++
drivers/iommu/riscv/iommu-ir.c | 35 +++++++++++++++++++++++++++++---
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index d3d98dbed709..3af6436d5c5c 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -39,6 +39,12 @@
/* RISC-V IOMMU PPN <> PHYS address conversions, PHYS <=> PPN[53:10] */
#define riscv_iommu_phys_to_ppn(pa) (((pa) >> 2) & (((1ULL << 44) - 1) << 10))
#define riscv_iommu_ppn_to_phys(pn) (((pn) << 2) & (((1ULL << 44) - 1) << 12))
+/* RISC-V IOMMU MRIF Address <> PHYS address conversions, PHYS <=> MRIF[53:7] */
+#define riscv_iommu_phys_to_mrif(pa) (((pa) >> 2) & (((1ULL << 47) - 1) << 7))
+/* RISC-V IOMMU nppn <> PHYS address conversions, PHYS <=> nppn[53:10] */
+#define riscv_iommu_phys_to_nppn(pa) (((pa) >> 2) & (((1ULL << 44) - 1) << 10))
+#define riscv_iommu_data_to_nid(data) \
+ ((((data) & 0x3FFULL)) | (((((data) >> 10) & 1ULL)) << 60))
/* 5.3 IOMMU Capabilities (64bits) */
#define RISCV_IOMMU_REG_CAPABILITIES 0x0000
diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c
index 73f552ed5b65..f3ebf62de53e 100644
--- a/drivers/iommu/riscv/iommu-ir.c
+++ b/drivers/iommu/riscv/iommu-ir.c
@@ -150,9 +150,12 @@ static int riscv_iommu_irq_set_vcpu_affinity(struct irq_data *data, void *info)
{
struct riscv_iommu_vcpu_info *vcpu_info = info;
struct riscv_iommu_domain *domain = data->domain->host_data;
+ struct device *dev = msi_desc_to_dev(irq_data_get_msi_desc(data));
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
struct riscv_iommu_msipte *pte;
int ret = -EINVAL;
- u64 pteval;
+ u64 pteval, mrifval = 0;
+ bool mrif_support = (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_MRIF);
if (WARN_ON(domain->domain.type != IOMMU_DOMAIN_UNMANAGED))
return ret;
@@ -186,12 +189,38 @@ static int riscv_iommu_irq_set_vcpu_affinity(struct irq_data *data, void *info)
if (!pte)
goto out_unlock;
- pteval = FIELD_PREP(RISCV_IOMMU_MSIPTE_M, 3) |
- riscv_iommu_phys_to_ppn(vcpu_info->hpa) |
+ if (!vcpu_info->mrif) {
+ pteval = FIELD_PREP(RISCV_IOMMU_MSIPTE_M, 3) |
+ riscv_iommu_phys_to_ppn(vcpu_info->hpa) |
+ FIELD_PREP(RISCV_IOMMU_MSIPTE_V, 1);
+ goto update_pte;
+ }
+
+ pteval = FIELD_PREP(RISCV_IOMMU_MSIPTE_M, 1) |
+ riscv_iommu_phys_to_mrif(vcpu_info->hpa) |
FIELD_PREP(RISCV_IOMMU_MSIPTE_V, 1);
+ if (mrif_support) {
+ mrifval = riscv_iommu_data_to_nid(vcpu_info->host_msg->data) |
+ riscv_iommu_phys_to_nppn(
+ (u64)vcpu_info->host_msg->address_hi << 32 |
+ vcpu_info->host_msg->address_lo);
+ } else {
+ /* If the guest interrupt file is exhausted and MRIF is not supported, we
+ * redirect the guest interrupt back to the original host interrupt and
+ * inject the interrupt into the guest machine through irqfd.
+ */
+ struct irq_data *irqdata = irq_get_irq_data(vcpu_info->host_irq);
+
+ irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata,
+ vcpu_info->host_msg);
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+update_pte:
if (pte->pte != pteval) {
pte->pte = pteval;
+ pte->mrif_info = mrifval;
riscv_iommu_ir_msitbl_inval(domain, pte);
}
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 6/6] RISC-V: KVM: Check the MRIF in notice MSI irq handler
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
` (4 preceding siblings ...)
2025-08-11 6:11 ` [RFC PATCH 5/6] iommu/riscv: Add MRIF mode support fangyu.yu
@ 2025-08-11 6:11 ` fangyu.yu
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
6 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2025-08-11 6:11 UTC (permalink / raw)
To: anup, paul.walmsley, palmer, aou, alex, atishp, tjeznach, joro,
will, robin.murphy, sunilvl, rafael.j.wysocki, tglx, ajones
Cc: guoren, guoren, kvm, kvm-riscv, linux-riscv, linux-kernel, iommu,
Fangyu Yu
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
In MRIF mode, the Advanced Interrupt Architecture Specification
defines the operation to store the incoming MSIs into the MRIF
and to generate the notice MSI,the software shold check the MRIF
in the notice MSI irq handler.
And without MRIF support,we redirect the guest interrupt back to
the original host interrupt, the software update and check MRIF
in host irq handler.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
arch/riscv/kvm/aia_imsic.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 58807e68a3dd..f0d1acde0dd4 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -867,11 +867,16 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
if (ret) {
+ if (ret == -ENODEV) {
+ imsic->mrif_support = false;
+ ret = 0;
+ }
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
goto out;
}
- irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata, msg);
+ if (imsic->mrif_support)
+ irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata, msg);
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
}
@@ -921,6 +926,10 @@ static int kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
if (ret) {
+ if (ret == -ENODEV) {
+ imsic->mrif_support = false;
+ ret = 0;
+ }
spin_unlock_irq(&kvm->irqfds.lock);
return ret;
}
@@ -1182,8 +1191,24 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
if (imsic->vsfile_cpu >= 0) {
writel(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);
} else {
+ if (imsic->mrif_support) {
+ struct msi_msg *msg;
+ unsigned long idx;
+
+ /* In MRIF mode, the noticed MSI irq handler will call here to
+ * determine whether the MRIF has been updated.Since the IOMMU
+ * hardware has updated the MRIF,the software does not need to
+ * update the MRIF file again.
+ */
+ xa_for_each(&imsic->hostirq_array, idx, msg) {
+ if (msg->data == iid)
+ goto skip_update_swfile;
+ }
+ }
eix = &imsic->swfile->eix[iid / BITS_PER_TYPE(u64)];
set_bit(iid & (BITS_PER_TYPE(u64) - 1), eix->eip);
+
+skip_update_swfile:
imsic_swfile_extirq_update(vcpu);
}
@@ -1260,7 +1285,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)
raw_spin_lock_init(&imsic->swfile_extirq_lock);
xa_init(&imsic->hostirq_array);
- imsic->mrif_support = false;
+ imsic->mrif_support = true;
/* Setup IO device */
kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops);
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
` (5 preceding siblings ...)
2025-08-11 6:11 ` [RFC PATCH 6/6] RISC-V: KVM: Check the MRIF in notice MSI irq handler fangyu.yu
@ 2026-07-01 4:00 ` Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup Zhanpeng Zhang
` (3 more replies)
6 siblings, 4 replies; 12+ messages in thread
From: Zhanpeng Zhang @ 2026-07-01 4:00 UTC (permalink / raw)
To: Fangyu Yu
Cc: Andrew Jones, Anup Patel, Atish Patra, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Tomasz Jeznach,
Joerg Roedel, Will Deacon, Robin Murphy, Paolo Bonzini,
cuiyunhui, yuanzhu, kvm, kvm-riscv, linux-riscv, iommu,
linux-kernel
Hi Fangyu,
I put together a local test branch based on Andrew's RISC-V IOMMU
irqbypass series [1] and your MRIF RFC series [2], then ran VFIO device
assignment tests on hardware on top of that combined tree.
One test case that exposed a problem was a VFIO guest started with QEMU's
AIA emulation mode, e.g. `riscv-aia=emul`. The guest could hang because
a normal MSI injection was classified as a MRIF notice, so KVM skipped
the software IMSIC EIP update and the interrupt was never made pending.
The issue is that the current code identifies a MRIF notice by comparing
the injected guest interrupt ID with cached host MSI data:
msg->data == iid
That is a payload value comparison, not a source/provenance check. A
normal MSI injection can carry the same interrupt ID value as a cached
host MSI message. If the vCPU is currently using the software IMSIC file
and this collision happens, KVM can misclassify the normal MSI as a MRIF
notice, skip the software IMSIC EIP update, and leave the guest waiting
for an interrupt that was never made pending.
This series identifies MRIF notices by irqfd route provenance instead.
irqfd_wakeup() already injects from a seqcount-protected copy of
irqfd->irq_entry, so patch 2 keeps the architecture's MRIF notice metadata
in that route snapshot. Userspace MSI injection and normal guest MSI
injection do not carry irqfd MRIF provenance and therefore follow the
normal software IMSIC path.
The generic KVM change is needed because the decision must be made from
the same copied route that irqfd_wakeup() injects from; keeping the
provenance in RISC-V side state would not be tied to that route snapshot.
Feel free to fold any of these patches into previous commits if you think
that is a better shape for the next version. I also have a few other local
adaptation and improvement patches on top, but kept them out of this series
to focus on the MRIF notice issue. Please let me know if you already have a
plan for the next revision, I am happy to support your next version in
whichever form is useful.
Zhanpeng Zhang (3):
iommu/riscv: Complete MRIF MSI PTE setup
KVM: Move irqfd arch data into route snapshots
RISC-V: KVM: Identify MRIF notices from irqfd snapshots
These patches are based on a combined tree, not a plain upstream tree.
The combined tree is made up of the following pieces:
In your series, patch 4/6 is already covered by the irqbypass series [1].
I ported patches 1/6, 2/6, 3/6, the relevant MRIF MSI PTE part of 5/6,
and the notice handler part of 6/6, with a few integration changes.
Fangyu Yu's MRIF RFC series [2] (selected patches):
[1/6] RISC-V: Add more elements to irqbypass vcpu_info
[2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir
[3/6] RISC-V: KVM: Add a xarray to record host irq msg
[5/6, adapted] iommu/riscv: Add MRIF mode support
[6/6, adapted] RISC-V: KVM: Check the MRIF in notice MSI irq handler
Andrew Jones et al. [1] (irqbypass series, omitted):
[RFC PATCH v2 00/18] iommu/riscv: Add irqbypass support
[1] https://lists.infradead.org/pipermail/kvm-riscv/2025-September/010148.html
[2] https://lwn.net/ml/all/20250811061104.10326-1-fangyu.yu@linux.alibaba.com/
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
@ 2026-07-01 4:00 ` Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 2/3] KVM: Move irqfd arch data into route snapshots Zhanpeng Zhang
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Zhanpeng Zhang @ 2026-07-01 4:00 UTC (permalink / raw)
To: Fangyu Yu
Cc: Andrew Jones, Anup Patel, Atish Patra, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Tomasz Jeznach,
Joerg Roedel, Will Deacon, Robin Murphy, Paolo Bonzini,
cuiyunhui, yuanzhu, kvm, kvm-riscv, linux-riscv, iommu,
linux-kernel, Zhanpeng Zhang
The MRIF path can retarget an existing MSI table entry, but it does
not fully handle installing a new MRIF MSI table entry. It also encodes
the MRIF target with the normal PPN helper even though a RISC-V IOMMU MSI
PTE uses MRIF_ADDR[53:7] in MRIF mode.
Add a dedicated MRIF PTE helper and use it for both the new-table and
retarget paths. This keeps the normal MSI PTE encoding unchanged while
programming the MRIF address and information fields when vCPU affinity
requests MRIF delivery.
Publish MRIF entries so the notice information is visible before the
valid PTE word is installed. When rewriting a live entry, clear the PTE
word first and order the mrif_info update before publishing the
replacement PTE, so a racing device MSI does not observe a valid MRIF PTE
with stale notice data.
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
---
drivers/iommu/riscv/iommu-ir.c | 96 ++++++++++++++++++++++++++--------
1 file changed, 75 insertions(+), 21 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-ir.c b/drivers/iommu/riscv/iommu-ir.c
index ccbb7aa74a25..82fbb44d6df0 100644
--- a/drivers/iommu/riscv/iommu-ir.c
+++ b/drivers/iommu/riscv/iommu-ir.c
@@ -119,10 +119,11 @@ static void riscv_iommu_ir_set_pte(struct riscv_iommu_msipte *pte, u64 addr)
static void riscv_iommu_ir_set_mrif_pte(struct riscv_iommu_msipte *pte, u64 addr, u64 mrif_info)
{
+ pte->mrif_info = mrif_info;
+ dma_wmb();
pte->pte = FIELD_PREP(RISCV_IOMMU_MSIPTE_M, 1) |
- riscv_iommu_phys_to_ppn(addr) |
+ riscv_iommu_phys_to_mrif(addr) |
FIELD_PREP(RISCV_IOMMU_MSIPTE_V, 1);
- pte->mrif_info = mrif_info;
}
static void riscv_iommu_ir_clear_pte(struct riscv_iommu_msipte *pte)
@@ -131,6 +132,17 @@ static void riscv_iommu_ir_clear_pte(struct riscv_iommu_msipte *pte)
pte->mrif_info = 0;
}
+static void riscv_iommu_ir_update_pte(struct riscv_iommu_msipte *pte,
+ const struct riscv_iommu_msipte *pteval)
+{
+ /* Rewrite live entries without exposing stale MRIF notice data. */
+ pte->pte = 0;
+ dma_wmb();
+ pte->mrif_info = pteval->mrif_info;
+ dma_wmb();
+ pte->pte = pteval->pte;
+}
+
static void riscv_iommu_ir_msitbl_inval(struct riscv_iommu_domain *domain)
{
struct riscv_iommu_bond *bond;
@@ -337,14 +349,65 @@ static bool riscv_iommu_ir_vcpu_check_config(struct riscv_iommu_domain *domain,
domain->group_index_shift == vcpu_info->group_index_shift;
}
+static int riscv_iommu_ir_get_mrif_info(struct irq_data *data,
+ struct riscv_iommu_ir_vcpu_info *vcpu_info,
+ u64 *mrif_info)
+{
+ struct device *dev;
+ struct riscv_iommu_device *iommu;
+ struct msi_desc *desc;
+ struct irq_data *irqdata;
+ struct irq_chip *chip;
+
+ *mrif_info = 0;
+ if (!vcpu_info->mrif)
+ return 0;
+
+ if (!vcpu_info->host_msg)
+ return -EINVAL;
+
+ desc = irq_data_get_msi_desc(data);
+ if (!desc)
+ return -EINVAL;
+
+ dev = msi_desc_to_dev(desc);
+ if (!dev)
+ return -EINVAL;
+
+ iommu = dev_to_iommu(dev);
+ if (!iommu)
+ return -ENODEV;
+
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_MRIF)) {
+ irqdata = irq_get_irq_data(vcpu_info->host_irq);
+ chip = irqdata ? irq_data_get_irq_chip(irqdata) : NULL;
+ if (!chip || !chip->irq_write_msi_msg)
+ return -EOPNOTSUPP;
+
+ chip->irq_write_msi_msg(irqdata, vcpu_info->host_msg);
+ return -ENODEV;
+ }
+
+ *mrif_info = riscv_iommu_data_to_nid(vcpu_info->host_msg->data) |
+ riscv_iommu_phys_to_nppn((u64)vcpu_info->host_msg->address_hi << 32 |
+ vcpu_info->host_msg->address_lo);
+
+ return 0;
+}
+
static int riscv_iommu_ir_vcpu_new_config(struct riscv_iommu_domain *domain,
struct irq_data *data,
struct riscv_iommu_ir_vcpu_info *vcpu_info)
{
struct riscv_iommu_msipte *pte;
+ u64 mrif_info;
size_t idx;
int ret;
+ ret = riscv_iommu_ir_get_mrif_info(data, vcpu_info, &mrif_info);
+ if (ret)
+ return ret;
+
if (domain->pgd_mode)
riscv_iommu_ir_unmap_imsics(domain);
@@ -378,8 +441,10 @@ static int riscv_iommu_ir_vcpu_new_config(struct riscv_iommu_domain *domain,
idx = riscv_iommu_ir_compute_msipte_idx(domain, vcpu_info->gpa);
pte = &domain->msi_root[idx];
riscv_iommu_ir_irq_set_msitbl_info(data, idx, domain->msitbl_config);
- BUG_ON(vcpu_info->mrif);
- riscv_iommu_ir_set_pte(pte, vcpu_info->hpa);
+ if (vcpu_info->mrif)
+ riscv_iommu_ir_set_mrif_pte(pte, vcpu_info->hpa, mrif_info);
+ else
+ riscv_iommu_ir_set_pte(pte, vcpu_info->hpa);
riscv_iommu_ir_msitbl_inval(domain);
refcount_set(&domain->msi_pte_counts[idx], 1);
@@ -393,15 +458,13 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
struct riscv_iommu_info *info = data->domain->host_data;
struct riscv_iommu_domain *domain = info->domain;
struct riscv_iommu_ir_vcpu_info *vcpu_info = arg;
- struct device *dev = msi_desc_to_dev(irq_data_get_msi_desc(data));
- struct riscv_iommu_device *iommu = dev_to_iommu(dev);
struct riscv_iommu_msipte pteval;
struct riscv_iommu_msipte *pte;
bool inc = false, dec = false;
size_t old_idx, new_idx;
u32 old_config;
u64 mrif_info = 0;
- bool mrif_support = (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_MRIF);
+ int ret;
if (!domain->msi_root)
return -EOPNOTSUPP;
@@ -422,18 +485,9 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
if (!riscv_iommu_ir_vcpu_check_config(domain, vcpu_info))
return riscv_iommu_ir_vcpu_new_config(domain, data, vcpu_info);
- if (vcpu_info->mrif) {
- if (!mrif_support) {
- struct irq_data *irqdata = irq_get_irq_data(vcpu_info->host_irq);
- irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata,
- vcpu_info->host_msg);
- return -ENODEV;
- }
- mrif_info = riscv_iommu_data_to_nid(vcpu_info->host_msg->data) |
- riscv_iommu_phys_to_nppn(
- (u64)vcpu_info->host_msg->address_hi << 32 |
- vcpu_info->host_msg->address_lo);
- }
+ ret = riscv_iommu_ir_get_mrif_info(data, vcpu_info, &mrif_info);
+ if (ret)
+ return ret;
new_idx = riscv_iommu_ir_compute_msipte_idx(domain, vcpu_info->gpa);
riscv_iommu_ir_irq_set_msitbl_info(data, new_idx, domain->msitbl_config);
@@ -444,8 +498,8 @@ static int riscv_iommu_ir_irq_set_vcpu_affinity(struct irq_data *data, void *arg
else
riscv_iommu_ir_set_pte(&pteval, vcpu_info->hpa);
- if (pteval.pte != pte->pte) {
- *pte = pteval;
+ if (pteval.pte != pte->pte || pteval.mrif_info != pte->mrif_info) {
+ riscv_iommu_ir_update_pte(pte, &pteval);
riscv_iommu_ir_msitbl_inval(domain);
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 2/3] KVM: Move irqfd arch data into route snapshots
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup Zhanpeng Zhang
@ 2026-07-01 4:00 ` Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 3/3] RISC-V: KVM: Identify MRIF notices from irqfd snapshots Zhanpeng Zhang
2026-07-03 12:38 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling fangyu.yu
3 siblings, 0 replies; 12+ messages in thread
From: Zhanpeng Zhang @ 2026-07-01 4:00 UTC (permalink / raw)
To: Fangyu Yu
Cc: Andrew Jones, Anup Patel, Atish Patra, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Tomasz Jeznach,
Joerg Roedel, Will Deacon, Robin Murphy, Paolo Bonzini,
cuiyunhui, yuanzhu, kvm, kvm-riscv, linux-riscv, iommu,
linux-kernel, Zhanpeng Zhang
irqfd wakeup takes a seqcount-protected copy of irqfd->irq_entry before
injecting an interrupt. Architectures that need to classify an injection
by its irqfd producer need any derived arch state to be part of that same
snapshot.
The irqfd object had per-irqfd arch side state, but that state describes
the current producer, not the specific route snapshot used for an
in-flight injection. Keeping the metadata there can race with route
updates and teardown: the inatomic injection path may observe a new route
with old arch metadata, or old arch metadata after the route has already
been invalidated.
Add optional arch-owned irqfd metadata to struct
kvm_kernel_irq_routing_entry and initialize it whenever KVM refreshes or
clears an irqfd route. Remove the old per-irqfd arch side-state fields
so the route snapshot is the only place carrying this producer
provenance. Userspace MSI injection uses a zero-initialized temporary
route, so it is never reported as irqfd-originated.
This provides the sequencing needed by RISC-V AIA to distinguish MRIF
notice MSI delivery from normal MSI injection without consulting mutable
irqfd state outside irq_entry_sc.
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
---
include/linux/kvm_host.h | 7 +++++++
include/linux/kvm_irqfd.h | 4 ----
virt/kvm/eventfd.c | 5 +++++
virt/kvm/irqchip.c | 4 +++-
4 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5bd76cf394fa..254f8fd132cc 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -685,6 +685,13 @@ struct kvm_kernel_irq_routing_entry {
struct kvm_hv_sint hv_sint;
struct kvm_xen_evtchn xen_evtchn;
};
+ /*
+ * Optional arch-owned irqfd metadata. It is updated under
+ * irq_entry_sc together with the route so irqfd_wakeup() observes a
+ * single consistent snapshot.
+ */
+ struct kvm_vcpu *irqfd_arch_vcpu;
+ void *irqfd_arch_data;
struct hlist_node link;
};
diff --git a/include/linux/kvm_irqfd.h b/include/linux/kvm_irqfd.h
index ef8c134ded8a..44fd2a20b09e 100644
--- a/include/linux/kvm_irqfd.h
+++ b/include/linux/kvm_irqfd.h
@@ -58,10 +58,6 @@ struct kvm_kernel_irqfd {
struct work_struct shutdown;
struct irq_bypass_consumer consumer;
struct irq_bypass_producer *producer;
-
- struct kvm_vcpu *irq_bypass_vcpu;
- struct list_head vcpu_list;
- void *irq_bypass_data;
};
#endif /* __LINUX_KVM_IRQFD_H */
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index a7794ffdb976..399ef2bdce5d 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -273,6 +273,9 @@ static void irqfd_update(struct kvm *kvm, struct kvm_kernel_irqfd *irqfd)
else
irqfd->irq_entry.type = 0;
+ irqfd->irq_entry.irqfd_arch_vcpu = NULL;
+ irqfd->irq_entry.irqfd_arch_data = NULL;
+
write_seqcount_end(&irqfd->irq_entry_sc);
}
@@ -594,6 +597,8 @@ kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
*/
write_seqcount_begin(&irqfd->irq_entry_sc);
irqfd->irq_entry.type = 0;
+ irqfd->irq_entry.irqfd_arch_vcpu = NULL;
+ irqfd->irq_entry.irqfd_arch_data = NULL;
write_seqcount_end(&irqfd->irq_entry_sc);
irqfd_deactivate(irqfd);
}
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index 6ccabfd32287..b163f7ed3c1e 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -47,7 +47,7 @@ int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
{
- struct kvm_kernel_irq_routing_entry route;
+ struct kvm_kernel_irq_routing_entry route = {};
if (!kvm_arch_irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID))
return -EINVAL;
@@ -145,6 +145,8 @@ static int setup_routing_entry(struct kvm *kvm,
e->gsi = gsi;
e->type = ue->type;
+ e->irqfd_arch_vcpu = NULL;
+ e->irqfd_arch_data = NULL;
r = kvm_set_routing_entry(kvm, e, ue);
if (r)
return r;
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC PATCH 3/3] RISC-V: KVM: Identify MRIF notices from irqfd snapshots
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 2/3] KVM: Move irqfd arch data into route snapshots Zhanpeng Zhang
@ 2026-07-01 4:00 ` Zhanpeng Zhang
2026-07-03 12:38 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling fangyu.yu
3 siblings, 0 replies; 12+ messages in thread
From: Zhanpeng Zhang @ 2026-07-01 4:00 UTC (permalink / raw)
To: Fangyu Yu
Cc: Andrew Jones, Anup Patel, Atish Patra, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Tomasz Jeznach,
Joerg Roedel, Will Deacon, Robin Murphy, Paolo Bonzini,
cuiyunhui, yuanzhu, kvm, kvm-riscv, linux-riscv, iommu,
linux-kernel, Zhanpeng Zhang
MRIF notice handling must skip the normal software IMSIC EIP update only
for the physical IRQ that was retargeted as a MRIF notice MSI. The
existing code infers that case by comparing the injected guest IID with
cached host MSI data values.
That value comparison is not a reliable source discriminator. Normal
guest MSI injection also reaches kvm_riscv_vcpu_aia_imsic_inject(), and
its guest IID can collide with a cached host MSI data value. When that
happens, KVM treats a normal guest interrupt as a MRIF notice and drops
the software IMSIC update before the guest observes the interrupt.
Identify MRIF notices from the irqfd route snapshot instead.
irqfd_wakeup() copies irqfd->irq_entry under irq_entry_sc before
injecting the MSI, so keep the RISC-V MRIF notice target in that same
snapshot. Userspace MSI injection passes no irqfd snapshot and therefore
always follows the normal software IMSIC path.
Update the snapshot only while holding kvm->irqfds.lock, including
irq-bypass producer attach and detach callbacks, because irq_entry_sc is
associated with that lock. Record MRIF metadata only after a successful
MRIF retarget; VS-file retargets and unsupported/error paths clear the
metadata so later ordinary irqfd injections cannot be misclassified as
MRIF notices.
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
---
arch/riscv/include/asm/kvm_aia.h | 7 +-
arch/riscv/kvm/aia_device.c | 9 +-
arch/riscv/kvm/aia_imsic.c | 154 +++++++++++++++++++++++--------
arch/riscv/kvm/vm.c | 9 +-
4 files changed, 139 insertions(+), 40 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_aia.h b/arch/riscv/include/asm/kvm_aia.h
index b04ecdd1a860..ab3613b96b7c 100644
--- a/arch/riscv/include/asm/kvm_aia.h
+++ b/arch/riscv/include/asm/kvm_aia.h
@@ -14,6 +14,8 @@
#include <linux/kvm_types.h>
#include <asm/csr.h>
+struct kvm_kernel_irq_routing_entry;
+
struct kvm_aia {
/* In-kernel irqchip created */
bool in_kernel;
@@ -103,6 +105,8 @@ int kvm_riscv_aia_imsic_has_attr(struct kvm *kvm, unsigned long type);
void kvm_riscv_vcpu_aia_imsic_reset(struct kvm_vcpu *vcpu);
int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
u32 guest_index, u32 offset, u32 iid);
+bool kvm_riscv_vcpu_aia_imsic_mrif_notice(struct kvm_vcpu *vcpu,
+ struct kvm_kernel_irq_routing_entry *irq);
int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_aia_imsic_cleanup(struct kvm_vcpu *vcpu);
@@ -155,7 +159,8 @@ void kvm_riscv_vcpu_aia_deinit(struct kvm_vcpu *vcpu);
int kvm_riscv_aia_inject_msi_by_id(struct kvm *kvm, u32 hart_index,
u32 guest_index, u32 iid);
-int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
+int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi,
+ struct kvm_kernel_irq_routing_entry *irq);
int kvm_riscv_aia_inject_irq(struct kvm *kvm, unsigned int irq, bool level);
void kvm_riscv_aia_init_vm(struct kvm *kvm);
diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c
index b195a93add1c..644376abaa34 100644
--- a/arch/riscv/kvm/aia_device.c
+++ b/arch/riscv/kvm/aia_device.c
@@ -559,7 +559,8 @@ int kvm_riscv_aia_inject_msi_by_id(struct kvm *kvm, u32 hart_index,
return 0;
}
-int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
+int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi,
+ struct kvm_kernel_irq_routing_entry *irq)
{
gpa_t tppn, ippn;
unsigned long idx;
@@ -585,6 +586,12 @@ int kvm_riscv_aia_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
IMSIC_MMIO_PAGE_SHIFT;
if (ippn == tppn) {
toff = target & (IMSIC_MMIO_PAGE_SZ - 1);
+ /*
+ * MRIF notices are identified by irqfd routing state,
+ * not MSI value.
+ */
+ if (kvm_riscv_vcpu_aia_imsic_mrif_notice(vcpu, irq))
+ return 0;
return kvm_riscv_vcpu_aia_imsic_inject(vcpu, g,
toff, iid);
}
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index b496953e0c4d..6cb5fc832efb 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -817,6 +817,28 @@ static int kvm_arch_update_irqfd_unset(struct kvm *kvm, unsigned int host_irq)
return irq_set_vcpu_affinity(host_irq, NULL);
}
+static void kvm_arch_update_irqfd_mrif_target(struct kvm_kernel_irqfd *irqfd,
+ struct kvm_vcpu *vcpu,
+ struct imsic *imsic)
+{
+ lockdep_assert_held(&irqfd->kvm->irqfds.lock);
+
+ write_seqcount_begin(&irqfd->irq_entry_sc);
+ irqfd->irq_entry.irqfd_arch_vcpu = vcpu;
+ irqfd->irq_entry.irqfd_arch_data = imsic;
+ write_seqcount_end(&irqfd->irq_entry_sc);
+}
+
+static void kvm_arch_clear_irqfd_mrif_target(struct kvm_kernel_irqfd *irqfd)
+{
+ lockdep_assert_held(&irqfd->kvm->irqfds.lock);
+
+ write_seqcount_begin(&irqfd->irq_entry_sc);
+ irqfd->irq_entry.irqfd_arch_vcpu = NULL;
+ irqfd->irq_entry.irqfd_arch_data = NULL;
+ write_seqcount_end(&irqfd->irq_entry_sc);
+}
+
static struct msi_msg *kvm_arch_update_irqfd_hostirq(struct imsic *imsic,
unsigned int host_irq, int *ret,
struct kvm_kernel_irq_routing_entry *e)
@@ -824,7 +846,7 @@ static struct msi_msg *kvm_arch_update_irqfd_hostirq(struct imsic *imsic,
struct msi_msg *priv_msg = xa_load(&imsic->hostirq_array, host_irq);
if (!priv_msg) {
- priv_msg = kzalloc(sizeof(*priv_msg), GFP_KERNEL);
+ priv_msg = kzalloc(sizeof(*priv_msg), GFP_ATOMIC);
if (!priv_msg) {
*ret = -ENOMEM;
goto out;
@@ -855,22 +877,44 @@ void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
struct riscv_iommu_ir_vcpu_info vcpu_info;
struct kvm *kvm = irqfd->kvm;
struct kvm_aia *aia = &kvm->arch.aia;
- int host_irq = irqfd->producer->irq;
- struct irq_data *irqdata = irq_get_irq_data(host_irq);
+ struct irq_data *irqdata;
unsigned long tmp, flags;
- struct kvm_vcpu *vcpu;
+ struct irq_chip *chip;
+ struct kvm_vcpu *vcpu = NULL;
struct imsic *imsic;
struct msi_msg msg;
u64 msi_addr_mask;
gpa_t target;
- int ret;
+ int host_irq, ret;
+ lockdep_assert_held(&kvm->irqfds.lock);
+
+ if (!irqfd->producer) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ return;
+ }
+
+ /*
+ * Keep the MRIF notice target in the irqfd route snapshot. Successful
+ * retargeting updates this snapshot, same-MSI updates reuse the
+ * previous snapshot, and unroute clears it.
+ */
if (old && old->type == KVM_IRQ_ROUTING_MSI &&
new && new->type == KVM_IRQ_ROUTING_MSI &&
- !memcmp(&old->msi, &new->msi, sizeof(new->msi)))
+ !memcmp(&old->msi, &new->msi, sizeof(new->msi))) {
+ write_seqcount_begin(&irqfd->irq_entry_sc);
+ irqfd->irq_entry.irqfd_arch_vcpu = old->irqfd_arch_vcpu;
+ irqfd->irq_entry.irqfd_arch_data = old->irqfd_arch_data;
+ write_seqcount_end(&irqfd->irq_entry_sc);
return;
+ }
+
+ host_irq = irqfd->producer->irq;
+ irqdata = irq_get_irq_data(host_irq);
+ chip = irqdata ? irq_data_get_irq_chip(irqdata) : NULL;
if (!new) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
if (!WARN_ON_ONCE(!old) && old->type == KVM_IRQ_ROUTING_MSI) {
ret = kvm_arch_update_irqfd_unset(kvm, host_irq);
WARN_ON_ONCE(ret && ret != -EOPNOTSUPP);
@@ -878,12 +922,21 @@ void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
return;
}
- if (new->type != KVM_IRQ_ROUTING_MSI)
+ if (new->type != KVM_IRQ_ROUTING_MSI) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ return;
+ }
+
+ if (!chip || !chip->irq_write_msi_msg) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
return;
+ }
target = ((gpa_t)new->msi.address_hi << 32) | new->msi.address_lo;
- if (WARN_ON_ONCE(target & (IMSIC_MMIO_PAGE_SZ - 1)))
+ if (WARN_ON_ONCE(target & (IMSIC_MMIO_PAGE_SZ - 1))) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
return;
+ }
msg = (struct msi_msg){
.address_hi = new->msi.address_hi,
@@ -895,8 +948,10 @@ void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
if (target == vcpu->arch.aia_context.imsic_addr)
break;
}
- if (!vcpu)
+ if (!vcpu) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
return;
+ }
imsic = vcpu->arch.aia_context.imsic_state;
@@ -910,8 +965,10 @@ void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
.host_irq = host_irq,
.host_msg = kvm_arch_update_irqfd_hostirq(imsic, host_irq, &ret, new),
};
- if (ret)
+ if (ret) {
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
return;
+ }
read_lock_irqsave(&imsic->vsfile_lock, flags);
@@ -924,19 +981,27 @@ void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
}
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
- WARN_ON_ONCE(ret && ret != -EOPNOTSUPP);
- if (ret) {
- if (ret == -ENODEV) {
- imsic->mrif_support = false;
- ret = 0;
- }
+ if (ret == -ENODEV) {
+ imsic->mrif_support = false;
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ ret = 0;
goto out;
}
+ WARN_ON_ONCE(ret && ret != -EOPNOTSUPP);
+ if (ret)
+ goto out;
+
if (imsic->mrif_support)
- irq_data_get_irq_chip(irqdata)->irq_write_msi_msg(irqdata, &msg);
+ chip->irq_write_msi_msg(irqdata, &msg);
+ if (vcpu_info.mrif)
+ kvm_arch_update_irqfd_mrif_target(irqfd, vcpu, imsic);
+ else
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
out:
read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+ if (ret)
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
}
static void kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
@@ -988,13 +1053,21 @@ static void kvm_riscv_vcpu_irq_update(struct kvm_vcpu *vcpu)
vcpu_info.mrif = false;
}
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
- WARN_ON_ONCE(ret && ret != -EOPNOTSUPP);
if (ret == -ENODEV) {
imsic->mrif_support = false;
- ret = 0;
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ continue;
} else if (ret == -EOPNOTSUPP) {
- break;
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ continue;
}
+ if (ret)
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ else if (vcpu_info.mrif)
+ kvm_arch_update_irqfd_mrif_target(irqfd, vcpu, imsic);
+ else
+ kvm_arch_clear_irqfd_mrif_target(irqfd);
+ WARN_ON_ONCE(ret);
}
spin_unlock_irq(&kvm->irqfds.lock);
@@ -1254,24 +1327,9 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
if (imsic->vsfile_cpu >= 0) {
writel(iid, imsic->vsfile_va + IMSIC_MMIO_SETIPNUM_LE);
} else {
- if (imsic->mrif_support) {
- struct msi_msg *msg;
- unsigned long idx;
-
- /* In MRIF mode, the noticed MSI irq handler will call here to
- * determine whether the MRIF has been updated.Since the IOMMU
- * hardware has updated the MRIF,the software does not need to
- * update the MRIF file again.
- */
- xa_for_each(&imsic->hostirq_array, idx, msg) {
- if (msg->data == iid)
- goto skip_update_swfile;
- }
- }
eix = &imsic->swfile->eix[iid / BITS_PER_TYPE(u64)];
set_bit(iid & (BITS_PER_TYPE(u64) - 1), eix->eip);
-skip_update_swfile:
imsic_swfile_extirq_update(vcpu);
}
@@ -1280,6 +1338,30 @@ int kvm_riscv_vcpu_aia_imsic_inject(struct kvm_vcpu *vcpu,
return 0;
}
+bool kvm_riscv_vcpu_aia_imsic_mrif_notice(struct kvm_vcpu *vcpu,
+ struct kvm_kernel_irq_routing_entry *irq)
+{
+ struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
+ unsigned long flags;
+ bool handled = false;
+
+ if (!imsic || !irq ||
+ irq->irqfd_arch_vcpu != vcpu ||
+ irq->irqfd_arch_data != imsic)
+ return false;
+
+ read_lock_irqsave(&imsic->vsfile_lock, flags);
+
+ if (imsic->mrif_support && imsic->vsfile_cpu < 0) {
+ imsic_swfile_extirq_update(vcpu);
+ handled = true;
+ }
+
+ read_unlock_irqrestore(&imsic->vsfile_lock, flags);
+
+ return handled;
+}
+
static int imsic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
@@ -1302,7 +1384,7 @@ static int imsic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
msi.address_hi = addr >> 32;
msi.address_lo = (u32)addr;
msi.data = *((const u32 *)val);
- kvm_riscv_aia_inject_msi(vcpu->kvm, &msi);
+ kvm_riscv_aia_inject_msi(vcpu->kvm, &msi, NULL);
return 0;
};
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index 1d33cff73e00..354036434b5e 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -68,9 +68,12 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
{
struct kvm_kernel_irqfd *irqfd =
container_of(cons, struct kvm_kernel_irqfd, consumer);
+ unsigned long flags;
+ spin_lock_irqsave(&irqfd->kvm->irqfds.lock, flags);
irqfd->producer = prod;
kvm_arch_update_irqfd_routing(irqfd, NULL, &irqfd->irq_entry);
+ spin_unlock_irqrestore(&irqfd->kvm->irqfds.lock, flags);
return 0;
}
@@ -80,11 +83,13 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
{
struct kvm_kernel_irqfd *irqfd =
container_of(cons, struct kvm_kernel_irqfd, consumer);
+ unsigned long flags;
+ spin_lock_irqsave(&irqfd->kvm->irqfds.lock, flags);
WARN_ON(irqfd->producer != prod);
-
kvm_arch_update_irqfd_routing(irqfd, &irqfd->irq_entry, NULL);
irqfd->producer = NULL;
+ spin_unlock_irqrestore(&irqfd->kvm->irqfds.lock, flags);
}
int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql,
@@ -111,7 +116,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
msi.flags = e->msi.flags;
msi.devid = e->msi.devid;
- return kvm_riscv_aia_inject_msi(kvm, &msi);
+ return kvm_riscv_aia_inject_msi(kvm, &msi, e);
}
static int kvm_riscv_set_irq(struct kvm_kernel_irq_routing_entry *e,
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
` (2 preceding siblings ...)
2026-07-01 4:00 ` [RFC PATCH 3/3] RISC-V: KVM: Identify MRIF notices from irqfd snapshots Zhanpeng Zhang
@ 2026-07-03 12:38 ` fangyu.yu
3 siblings, 0 replies; 12+ messages in thread
From: fangyu.yu @ 2026-07-03 12:38 UTC (permalink / raw)
To: zhangzhanpeng.jasper
Cc: ajones, andrew.jones, alex, anup, aou, atish.patra, cuiyunhui,
fangyu.yu, guoren, iommu, joro, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, tjeznach, will,
yuanzhu
>Hi Fangyu,
>
>I put together a local test branch based on Andrew's RISC-V IOMMU
>irqbypass series [1] and your MRIF RFC series [2], then ran VFIO device
>assignment tests on hardware on top of that combined tree.
>
>One test case that exposed a problem was a VFIO guest started with QEMU's
>AIA emulation mode, e.g. `riscv-aia=emul`. The guest could hang because
>a normal MSI injection was classified as a MRIF notice, so KVM skipped
>the software IMSIC EIP update and the interrupt was never made pending.
>
>The issue is that the current code identifies a MRIF notice by comparing
>the injected guest interrupt ID with cached host MSI data:
>
> msg->data == iid
>
>That is a payload value comparison, not a source/provenance check. A
>normal MSI injection can carry the same interrupt ID value as a cached
>host MSI message. If the vCPU is currently using the software IMSIC file
>and this collision happens, KVM can misclassify the normal MSI as a MRIF
>notice, skip the software IMSIC EIP update, and leave the guest waiting
>for an interrupt that was never made pending.
Hi Zhanpeng,
Thanks for reviewing and testing my patches, and for pointing out
the race condition issues. Your analysis is very helpful.
A few notes on the current status:
My original patches were based on Andrew Jones's tree [1]. Andrew
has since published a v2 [2], and I have adapted my work on top of
that version with some additional fixes. However, Andrew's v2 still
needs further adjustments, so I plan to rebase onto his v3 once it
is available.
When I send out my v2, I will take your patchset into consideration.
Thanks again for your effort.
[1] https://github.com/jones-drew/linux/tree/riscv/
iommu-irqbypass-rfc-v2-rc1
[2] https://lore.kernel.org/linux-riscv/
20250920203851.2205115-20-ajones@ventanamicro.com/
Fangyu
>This series identifies MRIF notices by irqfd route provenance instead.
>irqfd_wakeup() already injects from a seqcount-protected copy of
>irqfd->irq_entry, so patch 2 keeps the architecture's MRIF notice metadata
>in that route snapshot. Userspace MSI injection and normal guest MSI
>injection do not carry irqfd MRIF provenance and therefore follow the
>normal software IMSIC path.
>
>The generic KVM change is needed because the decision must be made from
>the same copied route that irqfd_wakeup() injects from; keeping the
>provenance in RISC-V side state would not be tied to that route snapshot.
>
>Feel free to fold any of these patches into previous commits if you think
>that is a better shape for the next version. I also have a few other local
>adaptation and improvement patches on top, but kept them out of this series
>to focus on the MRIF notice issue. Please let me know if you already have a
>plan for the next revision, I am happy to support your next version in
>whichever form is useful.
>
>Zhanpeng Zhang (3):
> iommu/riscv: Complete MRIF MSI PTE setup
> KVM: Move irqfd arch data into route snapshots
> RISC-V: KVM: Identify MRIF notices from irqfd snapshots
>
>These patches are based on a combined tree, not a plain upstream tree.
>The combined tree is made up of the following pieces:
>In your series, patch 4/6 is already covered by the irqbypass series [1].
>I ported patches 1/6, 2/6, 3/6, the relevant MRIF MSI PTE part of 5/6,
>and the notice handler part of 6/6, with a few integration changes.
>
>Fangyu Yu's MRIF RFC series [2] (selected patches):
> [1/6] RISC-V: Add more elements to irqbypass vcpu_info
> [2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir
> [3/6] RISC-V: KVM: Add a xarray to record host irq msg
> [5/6, adapted] iommu/riscv: Add MRIF mode support
> [6/6, adapted] RISC-V: KVM: Check the MRIF in notice MSI irq handler
>
>Andrew Jones et al. [1] (irqbypass series, omitted):
> [RFC PATCH v2 00/18] iommu/riscv: Add irqbypass support
>
>[1] https://lists.infradead.org/pipermail/kvm-riscv/2025-September/010148.html
>[2] https://lwn.net/ml/all/20250811061104.10326-1-fangyu.yu@linux.alibaba.com/
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-07-03 12:38 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-11 6:10 [RFC PATCH 0/6] iommu/riscv: Add MRIF support fangyu.yu
2025-08-11 6:10 ` [RFC PATCH 1/6] RISC-V: Add more elements to irqbypass vcpu_info fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 2/6] RISC-V: KVM: Transfer the physical address of MRIF to iommu-ir fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 3/6] RISC-V: KVM: Add a xarray to record host irq msg fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 4/6] iommu/riscv: Add irq_mask and irq_ack configure for iommu-ir fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 5/6] iommu/riscv: Add MRIF mode support fangyu.yu
2025-08-11 6:11 ` [RFC PATCH 6/6] RISC-V: KVM: Check the MRIF in notice MSI irq handler fangyu.yu
2026-07-01 4:00 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 1/3] iommu/riscv: Complete MRIF MSI PTE setup Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 2/3] KVM: Move irqfd arch data into route snapshots Zhanpeng Zhang
2026-07-01 4:00 ` [RFC PATCH 3/3] RISC-V: KVM: Identify MRIF notices from irqfd snapshots Zhanpeng Zhang
2026-07-03 12:38 ` [RFC PATCH 0/3] RISC-V: KVM/IOMMU: Fix MRIF irqfd notice handling fangyu.yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®