* [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
with its own vIOMMU can own the first stage of a device context while the
host keeps the second stage, and add the interrupt support. This is an RFC
and comments on the design are welcome.
Background
A RISC-V IOMMU device context carries a first stage in DC.fsc and
DC.iosatp and a second stage in DC.iohgatp. A guest with its own vIOMMU
owns the first stage, because the second stage is what isolates the guest
from the host, and the host cannot provide first stage semantics for the
guest address space.
iommufd already has the framework for this split. User space allocates a
second stage hwpt with IOMMU_HWPT_ALLOC_NEST_PARENT, allocates a vIOMMU
on it with IOMMU_VIOMMU_ALLOC, allocates nested page tables from that
vIOMMU with driver specific data, attaches devices to the nested hwpt and
forwards guest invalidations with IOMMU_HWPT_INVALIDATE against the
vIOMMU. Add the missing RISC-V uAPI definitions and the driver
implementation of those ops.
uAPI
Add IOMMU_HWPT_DATA_RISCV_S1 with struct iommu_hwpt_riscv, which carries
the guest first stage fields tc and iosatp for allocating a nested hwpt,
and add IOMMU_VIOMMU_TYPE_RISCV, which allocates a RISC-V vIOMMU on a
nesting parent hwpt. Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV with struct
iommu_viommu_riscv_invalidate, which carries one IOTINVAL command in the
encoding of the IOMMU command queue, and add IOMMU_HW_INFO_TYPE_RISCV
with struct iommu_hw_info_riscv, which reports the IOMMU Capabilities
register so a VMM can discover what the physical IOMMU implements.
Driver
Keep the nesting parent domain, which is the second stage domain, and the
GSCID it was allocated in the vIOMMU object, and advertise the vIOMMU type
only on hardware which implements both stages.
A nested domain keeps only the guest device context, sanitized when it is
allocated, because user space controls it entirely. Everything user space
provides is checked against the fields this IOMMU and this host support
before it can reach the hardware.
riscv_iommu_attach_dev_nested() composes the device context the hardware
is programmed with from the guest first stage and the host second stage,
and bonds the device to the second stage parent instead of the nested
domain, so a device using nested translation shares the bond list, the
MSI table and the invalidation state with the devices attached to the
parent directly. The update keeps an active guest MSI table in place, so
no MSI is lost across the switch.
Accept IOTINVAL.VMA only and reject reserved bits in cache invalidation.
The isolation operands belong to the host, so they are replaced with the
GSCID assigned to the vIOMMU and a PSCID of 0, and a guest cannot
invalidate the caches of another VM. PASID and the process directory
table, ATS and PRI, and T2GPA install and invalidation are not
implemented.
Interrupts
The prerequisite IRQ bypass requires HWACCEL mode and every interrupt file
to be published, and it forwards an MSI only when it can name the target
vCPU by matching the device MSI address against the guest IMSIC addresses
of the vCPUs. A guest with a vIOMMU programs its device with an address
from its own IOVA space, which the IOMMU resolves through the guest first
stage page tables before it looks the translated address up in the MSI
table, so no vCPU can be named at that point. Host delivery is not an
option either. The device would keep the MSI address the host composed for
it, and since every access from a device in a nested domain is translated
by the guest first stage page tables, that address cannot be resolved to
the intended interrupt file.
Forward MSIs for the whole VM when the address names no vIMSIC, and let
the MSI table decide, since it holds the IMSIC topology of the whole VM
and the hardware then finds the target vCPU itself once the address is
translated. Program such a producer with the MSI message composed by the
guest. Install the table with the interrupt files the host has published
at that time and skip the others, since rejecting the request would leave
the VM without forwarding, and a vIOMMU guest cannot fall back to host
delivery. An MSI that resolves to an unpublished file faults only that
MSI and is reported in the fault queue. Replace the AIA mode check with
the per address hardware backing checks, so the default AUTO mode works,
which publishes an IMSIC VS-file whenever one is available and falls back
to the SW-file only when the host has none left. Such a producer can reach
any published vCPU of the VM, so unforward it whenever a VS-file is
released and retarget it whenever a vCPU migrates.
Patch organization
Patch 1 takes the device context valid bit from DC.tc.V instead of
overloading a translation attribute bit, so a full device context can be
programmed, with no functional change for the existing domains.
Patches 2 and 3 add the uAPI types.
Patches 4 to 9 add the vIOMMU object, the nested domain, cache
invalidation, hw_info and nested device attachment.
Patches 10 to 12 make IRQ bypass usable for a guest with a vIOMMU.
Dependencies
The series applies on top of linux-iommu/next at 634706fe6e36, with the
MSI remapping, IOMMU_DMA and VFIO series v6 [1], the hardware dirty
tracking for second stage domains RFC v4 [2], which also supplies the
second stage domain allocation and the RISC-V iohgatp page table, the IRQ
bypass support RFC v3 [3] and the KVM IRQ bypass client on the branch that
posting refers to [4], the generic iommu page table for SMMUv3 v2 [5], on
which the second stage page table is built, and the generic_pt fix from
Andrew Jones which adds Svpbmt to the RISC-V supported feature mask.
A branch with the whole dependency stack and this series is available from
[6].
Testing
The host is a RISC-V machine whose physical IOMMU is provided by an outer
QEMU riscv-iommu model, which implements both translation stages. An NVMe
controller under it is bound to vfio-pci and passed through to the guest.
The guest is started by a QEMU built with the accel series [7][8], which
exposes a first stage IOMMU to the guest and leaves the second stage to
the host IOMMU. For simplicity the guest runs the same kernel as the host,
and inside the guest it mainly uses the normal IOMMU driver and the NVMe
driver.
The layering of the setup is
Host HW, a RISC-V virt machine from latest QEMU(v11.1.2), with a
riscv-iommu model that implements two stage translation and with the NVMe
controller
Host OS, the kernel with this series
riscv-iommu driver, second stage and MSI table vfio-pci and KVM
Guest HW, QEMU with the accel series [7][8]
riscv-iommu accel, first stage only
Guest OS, the same kernel as the host
riscv-iommu driver, NVMe driver
A DMA address from the NVMe controller is translated by the guest first
stage and then by the host second stage on the physical IOMMU. An MSI
address is translated by the guest first stage into a guest IMSIC address,
which the flat MSI table then resolves straight to the interrupt file of
the target vCPU, instead of walking the second stage.
DMA device --> guest first stage --> host second stage --> RAM
MSI device --> guest first stage --> MSI table --> VS-file
The host was started with
$HOST_QEMU \
-M virt,aia=aplic-imsic,aia-guests=7,iommu-sys=on \
-cpu rva23s64,sv48=on -nographic \
-smp 16 -m 16G \
-kernel $HOST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommufd.allow_unsafe_interrupts=1" \
-drive file=$HOST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0 \
-device pcie-root-port,id=port0,chassis=0,slot=0,addr=3.0 \
-drive file=fake-nvme-disk.img,if=none,id=nvme0,format=qcow2 \
-device nvme,drive=nvme0,serial=deadbeef,bus=port0,addr=0.0
and the guest with
$GUEST_QEMU \
-machine virt,accel=kvm,aia=aplic-imsic,aia-guests=5 \
-cpu host -nographic \
-smp 4 -m 4G \
-object iommufd,id=iommufd0 \
-device riscv-iommu-pci,addr=1.0,s-stage=on,g-stage=off,accel=on \
-device vfio-pci,host=0000:01:00.0,iommufd=iommufd0 \
-kernel $GUEST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommu.passthrough=0 iommu.strict=1" \
-drive file=$GUEST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0
Correctness was checked by running fio with verification enabled against
the passed through disk.
Known limitations and future work
PASID and the process directory table are not supported, PDTV is rejected
and PSCID is fixed at 0. The ATS, PRI and T2GPA fields are validated on
the nested domain, but ATS.INVAL and the PRI queue are not forwarded. A
vIOMMU is bound to a single physical IOMMU instance. The new uAPI types
have no selftest coverage yet.
Coding assistants based on LLMs were used during development for code
exploration, patch review, test execution and for drafting and editing
commit messages. We have reviewed and finalized all resulting code and
text.
[1] https://lore.kernel.org/all/20260925151659.419512-1-andrew.jones@oss.qualcomm.com/
[2] https://lore.kernel.org/all/20260915032828.11250-1-fangyu.yu@linux.alibaba.com/
[3] https://lore.kernel.org/linux-riscv/20260928143113.49838-1-andrew.jones@oss.qualcomm.com/
[4] https://github.com/jones-drew/linux/commits/riscv/iommu-irqbypass-rfc-v3-kvm/
[5] https://lore.kernel.org/linux-iommu/0-v2-563ee63886f0+1209-iommupt_armv8_jgg@nvidia.com/
[6] https://github.com/leaprise/linux/tree/riscv/iommu-nested-rfc1
[7] https://lore.kernel.org/qemu-devel/202610140811.69E8BqaU098670@mse-fl2.zte.com.cn/
[8] https://github.com/leaprise/qemu/tree/riscv/iommu-nested-rfc1
Gong Shuai (5):
iommu/riscv: Use DC.tc.V as the device context valid bit
iommu/riscv: Add vIOMMU cache invalidation
RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
RISC-V: KVM: Forward MSIs for guests with a vIOMMU
Wu Fei (7):
iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
iommufd: Add RISC-V IOMMU cache invalidation data type
iommu/riscv: Add vIOMMU object support
iommu/riscv: Add nested domain allocation
iommufd: Add RISC-V IOMMU hardware info type
iommu/riscv: Add riscv_iommu_hw_info
iommu/riscv: Add riscv_iommu_attach_dev_nested
arch/riscv/kvm/aia_imsic.c | 74 +++--
drivers/iommu/riscv/iommu-bits.h | 19 ++
drivers/iommu/riscv/iommu-ir.c | 25 +-
drivers/iommu/riscv/iommu.c | 428 +++++++++++++++++++++++++++-
include/linux/irqchip/riscv-imsic.h | 14 +-
include/linux/kvm_irqfd.h | 2 +
include/uapi/linux/iommufd.h | 52 ++++
7 files changed, 569 insertions(+), 45 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 63+ messages in thread
* [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
with its own vIOMMU can own the first stage of a device context while the
host keeps the second stage, and add the interrupt support. This is an RFC
and comments on the design are welcome.
Background
A RISC-V IOMMU device context carries a first stage in DC.fsc and
DC.iosatp and a second stage in DC.iohgatp. A guest with its own vIOMMU
owns the first stage, because the second stage is what isolates the guest
from the host, and the host cannot provide first stage semantics for the
guest address space.
iommufd already has the framework for this split. User space allocates a
second stage hwpt with IOMMU_HWPT_ALLOC_NEST_PARENT, allocates a vIOMMU
on it with IOMMU_VIOMMU_ALLOC, allocates nested page tables from that
vIOMMU with driver specific data, attaches devices to the nested hwpt and
forwards guest invalidations with IOMMU_HWPT_INVALIDATE against the
vIOMMU. Add the missing RISC-V uAPI definitions and the driver
implementation of those ops.
uAPI
Add IOMMU_HWPT_DATA_RISCV_S1 with struct iommu_hwpt_riscv, which carries
the guest first stage fields tc and iosatp for allocating a nested hwpt,
and add IOMMU_VIOMMU_TYPE_RISCV, which allocates a RISC-V vIOMMU on a
nesting parent hwpt. Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV with struct
iommu_viommu_riscv_invalidate, which carries one IOTINVAL command in the
encoding of the IOMMU command queue, and add IOMMU_HW_INFO_TYPE_RISCV
with struct iommu_hw_info_riscv, which reports the IOMMU Capabilities
register so a VMM can discover what the physical IOMMU implements.
Driver
Keep the nesting parent domain, which is the second stage domain, and the
GSCID it was allocated in the vIOMMU object, and advertise the vIOMMU type
only on hardware which implements both stages.
A nested domain keeps only the guest device context, sanitized when it is
allocated, because user space controls it entirely. Everything user space
provides is checked against the fields this IOMMU and this host support
before it can reach the hardware.
riscv_iommu_attach_dev_nested() composes the device context the hardware
is programmed with from the guest first stage and the host second stage,
and bonds the device to the second stage parent instead of the nested
domain, so a device using nested translation shares the bond list, the
MSI table and the invalidation state with the devices attached to the
parent directly. The update keeps an active guest MSI table in place, so
no MSI is lost across the switch.
Accept IOTINVAL.VMA only and reject reserved bits in cache invalidation.
The isolation operands belong to the host, so they are replaced with the
GSCID assigned to the vIOMMU and a PSCID of 0, and a guest cannot
invalidate the caches of another VM. PASID and the process directory
table, ATS and PRI, and T2GPA install and invalidation are not
implemented.
Interrupts
The prerequisite IRQ bypass requires HWACCEL mode and every interrupt file
to be published, and it forwards an MSI only when it can name the target
vCPU by matching the device MSI address against the guest IMSIC addresses
of the vCPUs. A guest with a vIOMMU programs its device with an address
from its own IOVA space, which the IOMMU resolves through the guest first
stage page tables before it looks the translated address up in the MSI
table, so no vCPU can be named at that point. Host delivery is not an
option either. The device would keep the MSI address the host composed for
it, and since every access from a device in a nested domain is translated
by the guest first stage page tables, that address cannot be resolved to
the intended interrupt file.
Forward MSIs for the whole VM when the address names no vIMSIC, and let
the MSI table decide, since it holds the IMSIC topology of the whole VM
and the hardware then finds the target vCPU itself once the address is
translated. Program such a producer with the MSI message composed by the
guest. Install the table with the interrupt files the host has published
at that time and skip the others, since rejecting the request would leave
the VM without forwarding, and a vIOMMU guest cannot fall back to host
delivery. An MSI that resolves to an unpublished file faults only that
MSI and is reported in the fault queue. Replace the AIA mode check with
the per address hardware backing checks, so the default AUTO mode works,
which publishes an IMSIC VS-file whenever one is available and falls back
to the SW-file only when the host has none left. Such a producer can reach
any published vCPU of the VM, so unforward it whenever a VS-file is
released and retarget it whenever a vCPU migrates.
Patch organization
Patch 1 takes the device context valid bit from DC.tc.V instead of
overloading a translation attribute bit, so a full device context can be
programmed, with no functional change for the existing domains.
Patches 2 and 3 add the uAPI types.
Patches 4 to 9 add the vIOMMU object, the nested domain, cache
invalidation, hw_info and nested device attachment.
Patches 10 to 12 make IRQ bypass usable for a guest with a vIOMMU.
Dependencies
The series applies on top of linux-iommu/next at 634706fe6e36, with the
MSI remapping, IOMMU_DMA and VFIO series v6 [1], the hardware dirty
tracking for second stage domains RFC v4 [2], which also supplies the
second stage domain allocation and the RISC-V iohgatp page table, the IRQ
bypass support RFC v3 [3] and the KVM IRQ bypass client on the branch that
posting refers to [4], the generic iommu page table for SMMUv3 v2 [5], on
which the second stage page table is built, and the generic_pt fix from
Andrew Jones which adds Svpbmt to the RISC-V supported feature mask.
A branch with the whole dependency stack and this series is available from
[6].
Testing
The host is a RISC-V machine whose physical IOMMU is provided by an outer
QEMU riscv-iommu model, which implements both translation stages. An NVMe
controller under it is bound to vfio-pci and passed through to the guest.
The guest is started by a QEMU built with the accel series [7][8], which
exposes a first stage IOMMU to the guest and leaves the second stage to
the host IOMMU. For simplicity the guest runs the same kernel as the host,
and inside the guest it mainly uses the normal IOMMU driver and the NVMe
driver.
The layering of the setup is
Host HW, a RISC-V virt machine from latest QEMU(v11.1.2), with a
riscv-iommu model that implements two stage translation and with the NVMe
controller
Host OS, the kernel with this series
riscv-iommu driver, second stage and MSI table vfio-pci and KVM
Guest HW, QEMU with the accel series [7][8]
riscv-iommu accel, first stage only
Guest OS, the same kernel as the host
riscv-iommu driver, NVMe driver
A DMA address from the NVMe controller is translated by the guest first
stage and then by the host second stage on the physical IOMMU. An MSI
address is translated by the guest first stage into a guest IMSIC address,
which the flat MSI table then resolves straight to the interrupt file of
the target vCPU, instead of walking the second stage.
DMA device --> guest first stage --> host second stage --> RAM
MSI device --> guest first stage --> MSI table --> VS-file
The host was started with
$HOST_QEMU \
-M virt,aia=aplic-imsic,aia-guests=7,iommu-sys=on \
-cpu rva23s64,sv48=on -nographic \
-smp 16 -m 16G \
-kernel $HOST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommufd.allow_unsafe_interrupts=1" \
-drive file=$HOST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0 \
-device pcie-root-port,id=port0,chassis=0,slot=0,addr=3.0 \
-drive file=fake-nvme-disk.img,if=none,id=nvme0,format=qcow2 \
-device nvme,drive=nvme0,serial=deadbeef,bus=port0,addr=0.0
and the guest with
$GUEST_QEMU \
-machine virt,accel=kvm,aia=aplic-imsic,aia-guests=5 \
-cpu host -nographic \
-smp 4 -m 4G \
-object iommufd,id=iommufd0 \
-device riscv-iommu-pci,addr=1.0,s-stage=on,g-stage=off,accel=on \
-device vfio-pci,host=0000:01:00.0,iommufd=iommufd0 \
-kernel $GUEST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommu.passthrough=0 iommu.strict=1" \
-drive file=$GUEST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0
Correctness was checked by running fio with verification enabled against
the passed through disk.
Known limitations and future work
PASID and the process directory table are not supported, PDTV is rejected
and PSCID is fixed at 0. The ATS, PRI and T2GPA fields are validated on
the nested domain, but ATS.INVAL and the PRI queue are not forwarded. A
vIOMMU is bound to a single physical IOMMU instance. The new uAPI types
have no selftest coverage yet.
Coding assistants based on LLMs were used during development for code
exploration, patch review, test execution and for drafting and editing
commit messages. We have reviewed and finalized all resulting code and
text.
[1] https://lore.kernel.org/all/20260925151659.419512-1-andrew.jones@oss.qualcomm.com/
[2] https://lore.kernel.org/all/20260915032828.11250-1-fangyu.yu@linux.alibaba.com/
[3] https://lore.kernel.org/linux-riscv/20260928143113.49838-1-andrew.jones@oss.qualcomm.com/
[4] https://github.com/jones-drew/linux/commits/riscv/iommu-irqbypass-rfc-v3-kvm/
[5] https://lore.kernel.org/linux-iommu/0-v2-563ee63886f0+1209-iommupt_armv8_jgg@nvidia.com/
[6] https://github.com/leaprise/linux/tree/riscv/iommu-nested-rfc1
[7] https://lore.kernel.org/qemu-devel/202610140811.69E8BqaU098670@mse-fl2.zte.com.cn/
[8] https://github.com/leaprise/qemu/tree/riscv/iommu-nested-rfc1
Gong Shuai (5):
iommu/riscv: Use DC.tc.V as the device context valid bit
iommu/riscv: Add vIOMMU cache invalidation
RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
RISC-V: KVM: Forward MSIs for guests with a vIOMMU
Wu Fei (7):
iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
iommufd: Add RISC-V IOMMU cache invalidation data type
iommu/riscv: Add vIOMMU object support
iommu/riscv: Add nested domain allocation
iommufd: Add RISC-V IOMMU hardware info type
iommu/riscv: Add riscv_iommu_hw_info
iommu/riscv: Add riscv_iommu_attach_dev_nested
arch/riscv/kvm/aia_imsic.c | 74 +++--
drivers/iommu/riscv/iommu-bits.h | 19 ++
drivers/iommu/riscv/iommu-ir.c | 25 +-
drivers/iommu/riscv/iommu.c | 428 +++++++++++++++++++++++++++-
include/linux/irqchip/riscv-imsic.h | 14 +-
include/linux/kvm_irqfd.h | 2 +
include/uapi/linux/iommufd.h | 52 ++++
7 files changed, 569 insertions(+), 45 deletions(-)
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
with its own vIOMMU can own the first stage of a device context while the
host keeps the second stage, and add the interrupt support. This is an RFC
and comments on the design are welcome.
Background
A RISC-V IOMMU device context carries a first stage in DC.fsc and
DC.iosatp and a second stage in DC.iohgatp. A guest with its own vIOMMU
owns the first stage, because the second stage is what isolates the guest
from the host, and the host cannot provide first stage semantics for the
guest address space.
iommufd already has the framework for this split. User space allocates a
second stage hwpt with IOMMU_HWPT_ALLOC_NEST_PARENT, allocates a vIOMMU
on it with IOMMU_VIOMMU_ALLOC, allocates nested page tables from that
vIOMMU with driver specific data, attaches devices to the nested hwpt and
forwards guest invalidations with IOMMU_HWPT_INVALIDATE against the
vIOMMU. Add the missing RISC-V uAPI definitions and the driver
implementation of those ops.
uAPI
Add IOMMU_HWPT_DATA_RISCV_S1 with struct iommu_hwpt_riscv, which carries
the guest first stage fields tc and iosatp for allocating a nested hwpt,
and add IOMMU_VIOMMU_TYPE_RISCV, which allocates a RISC-V vIOMMU on a
nesting parent hwpt. Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV with struct
iommu_viommu_riscv_invalidate, which carries one IOTINVAL command in the
encoding of the IOMMU command queue, and add IOMMU_HW_INFO_TYPE_RISCV
with struct iommu_hw_info_riscv, which reports the IOMMU Capabilities
register so a VMM can discover what the physical IOMMU implements.
Driver
Keep the nesting parent domain, which is the second stage domain, and the
GSCID it was allocated in the vIOMMU object, and advertise the vIOMMU type
only on hardware which implements both stages.
A nested domain keeps only the guest device context, sanitized when it is
allocated, because user space controls it entirely. Everything user space
provides is checked against the fields this IOMMU and this host support
before it can reach the hardware.
riscv_iommu_attach_dev_nested() composes the device context the hardware
is programmed with from the guest first stage and the host second stage,
and bonds the device to the second stage parent instead of the nested
domain, so a device using nested translation shares the bond list, the
MSI table and the invalidation state with the devices attached to the
parent directly. The update keeps an active guest MSI table in place, so
no MSI is lost across the switch.
Accept IOTINVAL.VMA only and reject reserved bits in cache invalidation.
The isolation operands belong to the host, so they are replaced with the
GSCID assigned to the vIOMMU and a PSCID of 0, and a guest cannot
invalidate the caches of another VM. PASID and the process directory
table, ATS and PRI, and T2GPA install and invalidation are not
implemented.
Interrupts
The prerequisite IRQ bypass requires HWACCEL mode and every interrupt file
to be published, and it forwards an MSI only when it can name the target
vCPU by matching the device MSI address against the guest IMSIC addresses
of the vCPUs. A guest with a vIOMMU programs its device with an address
from its own IOVA space, which the IOMMU resolves through the guest first
stage page tables before it looks the translated address up in the MSI
table, so no vCPU can be named at that point. Host delivery is not an
option either. The device would keep the MSI address the host composed for
it, and since every access from a device in a nested domain is translated
by the guest first stage page tables, that address cannot be resolved to
the intended interrupt file.
Forward MSIs for the whole VM when the address names no vIMSIC, and let
the MSI table decide, since it holds the IMSIC topology of the whole VM
and the hardware then finds the target vCPU itself once the address is
translated. Program such a producer with the MSI message composed by the
guest. Install the table with the interrupt files the host has published
at that time and skip the others, since rejecting the request would leave
the VM without forwarding, and a vIOMMU guest cannot fall back to host
delivery. An MSI that resolves to an unpublished file faults only that
MSI and is reported in the fault queue. Replace the AIA mode check with
the per address hardware backing checks, so the default AUTO mode works,
which publishes an IMSIC VS-file whenever one is available and falls back
to the SW-file only when the host has none left. Such a producer can reach
any published vCPU of the VM, so unforward it whenever a VS-file is
released and retarget it whenever a vCPU migrates.
Patch organization
Patch 1 takes the device context valid bit from DC.tc.V instead of
overloading a translation attribute bit, so a full device context can be
programmed, with no functional change for the existing domains.
Patches 2 and 3 add the uAPI types.
Patches 4 to 9 add the vIOMMU object, the nested domain, cache
invalidation, hw_info and nested device attachment.
Patches 10 to 12 make IRQ bypass usable for a guest with a vIOMMU.
Dependencies
The series applies on top of linux-iommu/next at 634706fe6e36, with the
MSI remapping, IOMMU_DMA and VFIO series v6 [1], the hardware dirty
tracking for second stage domains RFC v4 [2], which also supplies the
second stage domain allocation and the RISC-V iohgatp page table, the IRQ
bypass support RFC v3 [3] and the KVM IRQ bypass client on the branch that
posting refers to [4], the generic iommu page table for SMMUv3 v2 [5], on
which the second stage page table is built, and the generic_pt fix from
Andrew Jones which adds Svpbmt to the RISC-V supported feature mask.
A branch with the whole dependency stack and this series is available from
[6].
Testing
The host is a RISC-V machine whose physical IOMMU is provided by an outer
QEMU riscv-iommu model, which implements both translation stages. An NVMe
controller under it is bound to vfio-pci and passed through to the guest.
The guest is started by a QEMU built with the accel series [7][8], which
exposes a first stage IOMMU to the guest and leaves the second stage to
the host IOMMU. For simplicity the guest runs the same kernel as the host,
and inside the guest it mainly uses the normal IOMMU driver and the NVMe
driver.
The layering of the setup is
Host HW, a RISC-V virt machine from latest QEMU(v11.1.2), with a
riscv-iommu model that implements two stage translation and with the NVMe
controller
Host OS, the kernel with this series
riscv-iommu driver, second stage and MSI table vfio-pci and KVM
Guest HW, QEMU with the accel series [7][8]
riscv-iommu accel, first stage only
Guest OS, the same kernel as the host
riscv-iommu driver, NVMe driver
A DMA address from the NVMe controller is translated by the guest first
stage and then by the host second stage on the physical IOMMU. An MSI
address is translated by the guest first stage into a guest IMSIC address,
which the flat MSI table then resolves straight to the interrupt file of
the target vCPU, instead of walking the second stage.
DMA device --> guest first stage --> host second stage --> RAM
MSI device --> guest first stage --> MSI table --> VS-file
The host was started with
$HOST_QEMU \
-M virt,aia=aplic-imsic,aia-guests=7,iommu-sys=on \
-cpu rva23s64,sv48=on -nographic \
-smp 16 -m 16G \
-kernel $HOST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommufd.allow_unsafe_interrupts=1" \
-drive file=$HOST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0 \
-device pcie-root-port,id=port0,chassis=0,slot=0,addr=3.0 \
-drive file=fake-nvme-disk.img,if=none,id=nvme0,format=qcow2 \
-device nvme,drive=nvme0,serial=deadbeef,bus=port0,addr=0.0
and the guest with
$GUEST_QEMU \
-machine virt,accel=kvm,aia=aplic-imsic,aia-guests=5 \
-cpu host -nographic \
-smp 4 -m 4G \
-object iommufd,id=iommufd0 \
-device riscv-iommu-pci,addr=1.0,s-stage=on,g-stage=off,accel=on \
-device vfio-pci,host=0000:01:00.0,iommufd=iommufd0 \
-kernel $GUEST_KERNEL \
-append "root=/dev/vda rw earlycon=sbi console=ttyS0 iommu.passthrough=0 iommu.strict=1" \
-drive file=$GUEST_ROOTFS,if=none,id=d0,format=qcow2 -device virtio-blk-device,drive=d0
Correctness was checked by running fio with verification enabled against
the passed through disk.
Known limitations and future work
PASID and the process directory table are not supported, PDTV is rejected
and PSCID is fixed at 0. The ATS, PRI and T2GPA fields are validated on
the nested domain, but ATS.INVAL and the PRI queue are not forwarded. A
vIOMMU is bound to a single physical IOMMU instance. The new uAPI types
have no selftest coverage yet.
Coding assistants based on LLMs were used during development for code
exploration, patch review, test execution and for drafting and editing
commit messages. We have reviewed and finalized all resulting code and
text.
[1] https://lore.kernel.org/all/20260925151659.419512-1-andrew.jones@oss.qualcomm.com/
[2] https://lore.kernel.org/all/20260915032828.11250-1-fangyu.yu@linux.alibaba.com/
[3] https://lore.kernel.org/linux-riscv/20260928143113.49838-1-andrew.jones@oss.qualcomm.com/
[4] https://github.com/jones-drew/linux/commits/riscv/iommu-irqbypass-rfc-v3-kvm/
[5] https://lore.kernel.org/linux-iommu/0-v2-563ee63886f0+1209-iommupt_armv8_jgg@nvidia.com/
[6] https://github.com/leaprise/linux/tree/riscv/iommu-nested-rfc1
[7] https://lore.kernel.org/qemu-devel/202610140811.69E8BqaU098670@mse-fl2.zte.com.cn/
[8] https://github.com/leaprise/qemu/tree/riscv/iommu-nested-rfc1
Gong Shuai (5):
iommu/riscv: Use DC.tc.V as the device context valid bit
iommu/riscv: Add vIOMMU cache invalidation
RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
RISC-V: KVM: Forward MSIs for guests with a vIOMMU
Wu Fei (7):
iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
iommufd: Add RISC-V IOMMU cache invalidation data type
iommu/riscv: Add vIOMMU object support
iommu/riscv: Add nested domain allocation
iommufd: Add RISC-V IOMMU hardware info type
iommu/riscv: Add riscv_iommu_hw_info
iommu/riscv: Add riscv_iommu_attach_dev_nested
arch/riscv/kvm/aia_imsic.c | 74 +++--
drivers/iommu/riscv/iommu-bits.h | 19 ++
drivers/iommu/riscv/iommu-ir.c | 25 +-
drivers/iommu/riscv/iommu.c | 428 +++++++++++++++++++++++++++-
include/linux/irqchip/riscv-imsic.h | 14 +-
include/linux/kvm_irqfd.h | 2 +
include/uapi/linux/iommufd.h | 52 ++++
7 files changed, 569 insertions(+), 45 deletions(-)
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* [RFC PATCH 01/12] iommu/riscv: Use DC.tc.V as the device context valid bit
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
riscv_iommu_iodir_update() used bit 0 of the translation attributes
argument as the "device context valid" flag. Now that it takes a full
device context, take the validity bit from DC.tc.V.
The defined bits of the caller's DC.tc are no longer dropped. This is
not a functional change for the existing callers: the paging and identity
domains set V, and the blocking domain leaves the context invalid. Nested
translation needs those bits to reach the hardware.
Use the DC prefixed field macros for device context fields while here,
instead of the PC (process context) ones.
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 6 ++++++
drivers/iommu/riscv/iommu.c | 26 ++++++++++++--------------
2 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 51a2e660b06a..2a8230a0c1bb 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -348,6 +348,12 @@ struct riscv_iommu_dc {
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
+/*
+ * All bits of dc.tc as defined by the spec. Bits 12-23 and 32-63
+ * are reserved for future standard use, bits 24-31 are for custom use.
+ */
+#define RISCV_IOMMU_DC_TC_DEFINED GENMASK_ULL(11, 0)
+
/* Second-stage (aka G-stage) context fields */
#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 55c167df2c2e..dd97c2731d95 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1218,7 +1218,6 @@ void riscv_iommu_msi_table_inval_all(struct riscv_iommu_msi_table *msi_table)
riscv_iommu_iotlb_inval(domain, &gather);
}
-#define RISCV_IOMMU_FSC_BARE 0
/*
* This function sends IOTINVAL commands as required by the RISC-V
* IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version)
@@ -1329,16 +1328,14 @@ static void riscv_iommu_iodir_update(struct device *dev, struct riscv_iommu_dc *
riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
/*
- * For device context with DC_TC_PDTV = 0, translation attributes valid bit
- * is stored as DC_TC_V bit (both sharing the same location at BIT(0)).
+ * Only defined bits are writable by the driver.
*/
for (i = 0; i < fwspec->num_ids; i++) {
dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]);
- tc = READ_ONCE(dc->tc);
- tc |= new_dc->ta & RISCV_IOMMU_DC_TC_V;
+ tc = new_dc->tc & RISCV_IOMMU_DC_TC_DEFINED;
WRITE_ONCE(dc->fsc, new_dc->fsc);
- WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_PC_TA_PSCID);
+ WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_DC_TA_PSCID);
WRITE_ONCE(dc->iohgatp, new_dc->iohgatp);
if (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_FLAT) {
WRITE_ONCE(dc->msiptp, new_dc->msiptp);
@@ -1600,11 +1597,11 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
if (!riscv_iommu_fsc_supported(iommu, pt_info.fsc_iosatp_mode))
return -ENODEV;
- dc.fsc = FIELD_PREP(RISCV_IOMMU_PC_FSC_MODE, pt_info.fsc_iosatp_mode) |
- FIELD_PREP(RISCV_IOMMU_PC_FSC_PPN, pt_info.ppn);
+ dc.fsc = FIELD_PREP(RISCV_IOMMU_DC_FSC_MODE, pt_info.fsc_iosatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_FSC_PPN, pt_info.ppn);
}
- dc.ta = FIELD_PREP(RISCV_IOMMU_PC_TA_PSCID, domain->pscid) |
- RISCV_IOMMU_PC_TA_V;
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, domain->pscid);
+ dc.tc |= RISCV_IOMMU_DC_TC_V;
bond = kzalloc_obj(*bond);
if (!bond)
@@ -1773,9 +1770,10 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = 0;
- /* Make device context invalid, translation requests will fault w/ #258 */
+ /* Make device context invalid (DC.tc.V = 0), translation requests will fault w/ #258 */
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
riscv_iommu_iodir_update(dev, &info->dc);
@@ -1801,8 +1799,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
- dc.ta = RISCV_IOMMU_PC_TA_V;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = RISCV_IOMMU_DC_TC_V;
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 01/12] iommu/riscv: Use DC.tc.V as the device context valid bit
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
riscv_iommu_iodir_update() used bit 0 of the translation attributes
argument as the "device context valid" flag. Now that it takes a full
device context, take the validity bit from DC.tc.V.
The defined bits of the caller's DC.tc are no longer dropped. This is
not a functional change for the existing callers: the paging and identity
domains set V, and the blocking domain leaves the context invalid. Nested
translation needs those bits to reach the hardware.
Use the DC prefixed field macros for device context fields while here,
instead of the PC (process context) ones.
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 6 ++++++
drivers/iommu/riscv/iommu.c | 26 ++++++++++++--------------
2 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 51a2e660b06a..2a8230a0c1bb 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -348,6 +348,12 @@ struct riscv_iommu_dc {
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
+/*
+ * All bits of dc.tc as defined by the spec. Bits 12-23 and 32-63
+ * are reserved for future standard use, bits 24-31 are for custom use.
+ */
+#define RISCV_IOMMU_DC_TC_DEFINED GENMASK_ULL(11, 0)
+
/* Second-stage (aka G-stage) context fields */
#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 55c167df2c2e..dd97c2731d95 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1218,7 +1218,6 @@ void riscv_iommu_msi_table_inval_all(struct riscv_iommu_msi_table *msi_table)
riscv_iommu_iotlb_inval(domain, &gather);
}
-#define RISCV_IOMMU_FSC_BARE 0
/*
* This function sends IOTINVAL commands as required by the RISC-V
* IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version)
@@ -1329,16 +1328,14 @@ static void riscv_iommu_iodir_update(struct device *dev, struct riscv_iommu_dc *
riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
/*
- * For device context with DC_TC_PDTV = 0, translation attributes valid bit
- * is stored as DC_TC_V bit (both sharing the same location at BIT(0)).
+ * Only defined bits are writable by the driver.
*/
for (i = 0; i < fwspec->num_ids; i++) {
dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]);
- tc = READ_ONCE(dc->tc);
- tc |= new_dc->ta & RISCV_IOMMU_DC_TC_V;
+ tc = new_dc->tc & RISCV_IOMMU_DC_TC_DEFINED;
WRITE_ONCE(dc->fsc, new_dc->fsc);
- WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_PC_TA_PSCID);
+ WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_DC_TA_PSCID);
WRITE_ONCE(dc->iohgatp, new_dc->iohgatp);
if (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_FLAT) {
WRITE_ONCE(dc->msiptp, new_dc->msiptp);
@@ -1600,11 +1597,11 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
if (!riscv_iommu_fsc_supported(iommu, pt_info.fsc_iosatp_mode))
return -ENODEV;
- dc.fsc = FIELD_PREP(RISCV_IOMMU_PC_FSC_MODE, pt_info.fsc_iosatp_mode) |
- FIELD_PREP(RISCV_IOMMU_PC_FSC_PPN, pt_info.ppn);
+ dc.fsc = FIELD_PREP(RISCV_IOMMU_DC_FSC_MODE, pt_info.fsc_iosatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_FSC_PPN, pt_info.ppn);
}
- dc.ta = FIELD_PREP(RISCV_IOMMU_PC_TA_PSCID, domain->pscid) |
- RISCV_IOMMU_PC_TA_V;
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, domain->pscid);
+ dc.tc |= RISCV_IOMMU_DC_TC_V;
bond = kzalloc_obj(*bond);
if (!bond)
@@ -1773,9 +1770,10 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = 0;
- /* Make device context invalid, translation requests will fault w/ #258 */
+ /* Make device context invalid (DC.tc.V = 0), translation requests will fault w/ #258 */
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
riscv_iommu_iodir_update(dev, &info->dc);
@@ -1801,8 +1799,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
- dc.ta = RISCV_IOMMU_PC_TA_V;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = RISCV_IOMMU_DC_TC_V;
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 01/12] iommu/riscv: Use DC.tc.V as the device context valid bit
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
riscv_iommu_iodir_update() used bit 0 of the translation attributes
argument as the "device context valid" flag. Now that it takes a full
device context, take the validity bit from DC.tc.V.
The defined bits of the caller's DC.tc are no longer dropped. This is
not a functional change for the existing callers: the paging and identity
domains set V, and the blocking domain leaves the context invalid. Nested
translation needs those bits to reach the hardware.
Use the DC prefixed field macros for device context fields while here,
instead of the PC (process context) ones.
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 6 ++++++
drivers/iommu/riscv/iommu.c | 26 ++++++++++++--------------
2 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 51a2e660b06a..2a8230a0c1bb 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -348,6 +348,12 @@ struct riscv_iommu_dc {
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
+/*
+ * All bits of dc.tc as defined by the spec. Bits 12-23 and 32-63
+ * are reserved for future standard use, bits 24-31 are for custom use.
+ */
+#define RISCV_IOMMU_DC_TC_DEFINED GENMASK_ULL(11, 0)
+
/* Second-stage (aka G-stage) context fields */
#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD
#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 55c167df2c2e..dd97c2731d95 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1218,7 +1218,6 @@ void riscv_iommu_msi_table_inval_all(struct riscv_iommu_msi_table *msi_table)
riscv_iommu_iotlb_inval(domain, &gather);
}
-#define RISCV_IOMMU_FSC_BARE 0
/*
* This function sends IOTINVAL commands as required by the RISC-V
* IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version)
@@ -1329,16 +1328,14 @@ static void riscv_iommu_iodir_update(struct device *dev, struct riscv_iommu_dc *
riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
/*
- * For device context with DC_TC_PDTV = 0, translation attributes valid bit
- * is stored as DC_TC_V bit (both sharing the same location at BIT(0)).
+ * Only defined bits are writable by the driver.
*/
for (i = 0; i < fwspec->num_ids; i++) {
dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]);
- tc = READ_ONCE(dc->tc);
- tc |= new_dc->ta & RISCV_IOMMU_DC_TC_V;
+ tc = new_dc->tc & RISCV_IOMMU_DC_TC_DEFINED;
WRITE_ONCE(dc->fsc, new_dc->fsc);
- WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_PC_TA_PSCID);
+ WRITE_ONCE(dc->ta, new_dc->ta & RISCV_IOMMU_DC_TA_PSCID);
WRITE_ONCE(dc->iohgatp, new_dc->iohgatp);
if (iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_FLAT) {
WRITE_ONCE(dc->msiptp, new_dc->msiptp);
@@ -1600,11 +1597,11 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
if (!riscv_iommu_fsc_supported(iommu, pt_info.fsc_iosatp_mode))
return -ENODEV;
- dc.fsc = FIELD_PREP(RISCV_IOMMU_PC_FSC_MODE, pt_info.fsc_iosatp_mode) |
- FIELD_PREP(RISCV_IOMMU_PC_FSC_PPN, pt_info.ppn);
+ dc.fsc = FIELD_PREP(RISCV_IOMMU_DC_FSC_MODE, pt_info.fsc_iosatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_FSC_PPN, pt_info.ppn);
}
- dc.ta = FIELD_PREP(RISCV_IOMMU_PC_TA_PSCID, domain->pscid) |
- RISCV_IOMMU_PC_TA_V;
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, domain->pscid);
+ dc.tc |= RISCV_IOMMU_DC_TC_V;
bond = kzalloc_obj(*bond);
if (!bond)
@@ -1773,9 +1770,10 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = 0;
- /* Make device context invalid, translation requests will fault w/ #258 */
+ /* Make device context invalid (DC.tc.V = 0), translation requests will fault w/ #258 */
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
riscv_iommu_iodir_update(dev, &info->dc);
@@ -1801,8 +1799,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
- dc.fsc = RISCV_IOMMU_FSC_BARE;
- dc.ta = RISCV_IOMMU_PC_TA_V;
+ dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
+ dc.tc = RISCV_IOMMU_DC_TC_V;
flags = riscv_iommu_msi_tables_lock(old, NULL);
info->dc = dc;
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Introduce the user-space API data for RISC-V IOMMU nested domains:
- IOMMU_HWPT_DATA_RISCV_S1 together with struct iommu_hwpt_riscv, which
carries the first-stage(guest) device-context fields (tc and iosatp)
for allocating a nested hwpt;
- IOMMU_VIOMMU_TYPE_RISCV so user space can request a RISC-V IOMMU
vIOMMU object.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 206fa667c782..7458878386c5 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -506,18 +506,31 @@ struct iommu_hwpt_amd_guest {
__aligned_u64 dte[4];
};
+/**
+ * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
+ * (IOMMU_HWPT_DATA_RISCV_S1)
+ * @tc: Guest device context translation control
+ * @iosatp: Guest device context stage-1 root page table pointer
+ */
+struct iommu_hwpt_riscv {
+ __aligned_u64 tc;
+ __aligned_u64 iosatp;
+};
+
/**
* enum iommu_hwpt_data_type - IOMMU HWPT Data Type
* @IOMMU_HWPT_DATA_NONE: no data
* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table
* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table
* @IOMMU_HWPT_DATA_AMD_GUEST: AMD IOMMU guest page table
+ * @IOMMU_HWPT_DATA_RISCV_S1: RISC-V IOMMU stage-1 page table
*/
enum iommu_hwpt_data_type {
IOMMU_HWPT_DATA_NONE = 0,
IOMMU_HWPT_DATA_VTD_S1 = 1,
IOMMU_HWPT_DATA_ARM_SMMUV3 = 2,
IOMMU_HWPT_DATA_AMD_GUEST = 3,
+ IOMMU_HWPT_DATA_RISCV_S1 = 4,
};
/**
@@ -1095,6 +1108,7 @@ struct iommu_fault_alloc {
* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type
* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) enabled ARM SMMUv3 type
+ * @IOMMU_VIOMMU_TYPE_RISCV: RISC-V IOMMU driver specific type
*/
enum iommu_viommu_type {
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
@@ -1105,6 +1119,7 @@ enum iommu_viommu_type {
* VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register
*/
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
+ IOMMU_VIOMMU_TYPE_RISCV = 3,
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Introduce the user-space API data for RISC-V IOMMU nested domains:
- IOMMU_HWPT_DATA_RISCV_S1 together with struct iommu_hwpt_riscv, which
carries the first-stage(guest) device-context fields (tc and iosatp)
for allocating a nested hwpt;
- IOMMU_VIOMMU_TYPE_RISCV so user space can request a RISC-V IOMMU
vIOMMU object.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 206fa667c782..7458878386c5 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -506,18 +506,31 @@ struct iommu_hwpt_amd_guest {
__aligned_u64 dte[4];
};
+/**
+ * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
+ * (IOMMU_HWPT_DATA_RISCV_S1)
+ * @tc: Guest device context translation control
+ * @iosatp: Guest device context stage-1 root page table pointer
+ */
+struct iommu_hwpt_riscv {
+ __aligned_u64 tc;
+ __aligned_u64 iosatp;
+};
+
/**
* enum iommu_hwpt_data_type - IOMMU HWPT Data Type
* @IOMMU_HWPT_DATA_NONE: no data
* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table
* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table
* @IOMMU_HWPT_DATA_AMD_GUEST: AMD IOMMU guest page table
+ * @IOMMU_HWPT_DATA_RISCV_S1: RISC-V IOMMU stage-1 page table
*/
enum iommu_hwpt_data_type {
IOMMU_HWPT_DATA_NONE = 0,
IOMMU_HWPT_DATA_VTD_S1 = 1,
IOMMU_HWPT_DATA_ARM_SMMUV3 = 2,
IOMMU_HWPT_DATA_AMD_GUEST = 3,
+ IOMMU_HWPT_DATA_RISCV_S1 = 4,
};
/**
@@ -1095,6 +1108,7 @@ struct iommu_fault_alloc {
* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type
* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) enabled ARM SMMUv3 type
+ * @IOMMU_VIOMMU_TYPE_RISCV: RISC-V IOMMU driver specific type
*/
enum iommu_viommu_type {
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
@@ -1105,6 +1119,7 @@ enum iommu_viommu_type {
* VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register
*/
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
+ IOMMU_VIOMMU_TYPE_RISCV = 3,
};
/**
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Introduce the user-space API data for RISC-V IOMMU nested domains:
- IOMMU_HWPT_DATA_RISCV_S1 together with struct iommu_hwpt_riscv, which
carries the first-stage(guest) device-context fields (tc and iosatp)
for allocating a nested hwpt;
- IOMMU_VIOMMU_TYPE_RISCV so user space can request a RISC-V IOMMU
vIOMMU object.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 206fa667c782..7458878386c5 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -506,18 +506,31 @@ struct iommu_hwpt_amd_guest {
__aligned_u64 dte[4];
};
+/**
+ * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
+ * (IOMMU_HWPT_DATA_RISCV_S1)
+ * @tc: Guest device context translation control
+ * @iosatp: Guest device context stage-1 root page table pointer
+ */
+struct iommu_hwpt_riscv {
+ __aligned_u64 tc;
+ __aligned_u64 iosatp;
+};
+
/**
* enum iommu_hwpt_data_type - IOMMU HWPT Data Type
* @IOMMU_HWPT_DATA_NONE: no data
* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table
* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table
* @IOMMU_HWPT_DATA_AMD_GUEST: AMD IOMMU guest page table
+ * @IOMMU_HWPT_DATA_RISCV_S1: RISC-V IOMMU stage-1 page table
*/
enum iommu_hwpt_data_type {
IOMMU_HWPT_DATA_NONE = 0,
IOMMU_HWPT_DATA_VTD_S1 = 1,
IOMMU_HWPT_DATA_ARM_SMMUV3 = 2,
IOMMU_HWPT_DATA_AMD_GUEST = 3,
+ IOMMU_HWPT_DATA_RISCV_S1 = 4,
};
/**
@@ -1095,6 +1108,7 @@ struct iommu_fault_alloc {
* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type
* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) enabled ARM SMMUv3 type
+ * @IOMMU_VIOMMU_TYPE_RISCV: RISC-V IOMMU driver specific type
*/
enum iommu_viommu_type {
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
@@ -1105,6 +1119,7 @@ enum iommu_viommu_type {
* VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register
*/
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
+ IOMMU_VIOMMU_TYPE_RISCV = 3,
};
/**
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 03/12] iommufd: Add RISC-V IOMMU cache invalidation data type
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV and the matching
struct iommu_viommu_riscv_invalidate, so user space can pass RISC-V
IOMMU IOTINVAL commands to the vIOMMU cache invalidation path using a
payload layout that is shared with the kernel, instead of relying on the
driver internal struct riscv_iommu_command.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 7458878386c5..36e6187bb34b 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -903,10 +903,12 @@ struct iommu_hwpt_get_dirty_bitmap {
* Data Type
* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1
* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3
+ * @IOMMU_VIOMMU_INVALIDATE_DATA_RISCV: Invalidation data for RISC-V IOMMU
*/
enum iommu_hwpt_invalidate_data_type {
IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 = 0,
IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 = 1,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV = 2,
};
/**
@@ -967,6 +969,31 @@ struct iommu_viommu_arm_smmuv3_invalidate {
__aligned_le64 cmd[2];
};
+/**
+ * struct iommu_viommu_riscv_invalidate - RISC-V IOMMU cache invalidation
+ * (IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ * @cmd: 128-bit cache invalidation command that runs in the IOMMU command
+ * queue, in the format defined by the "IOMMU Page-table cache
+ * invalidation" section of the RISC-V IOMMU specification. Must be
+ * little-endian.
+ *
+ * Supported command list only when passing in a vIOMMU via @hwpt_id:
+ * IOTINVAL.VMA
+ *
+ * The isolation operands are owned by the kernel, which overwrites them
+ * before the command is issued:
+ * GV = 1 and GSCID = the GSCID assigned to the vIOMMU
+ * PSCV = 1 and PSCID = 0
+ *
+ * All other reserved bits must be 0.
+ *
+ * -EIO will be returned if the command is not supported, -EINVAL if it is
+ * malformed.
+ */
+struct iommu_viommu_riscv_invalidate {
+ __aligned_le64 cmd[2];
+};
+
/**
* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE)
* @size: sizeof(struct iommu_hwpt_invalidate)
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 03/12] iommufd: Add RISC-V IOMMU cache invalidation data type
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV and the matching
struct iommu_viommu_riscv_invalidate, so user space can pass RISC-V
IOMMU IOTINVAL commands to the vIOMMU cache invalidation path using a
payload layout that is shared with the kernel, instead of relying on the
driver internal struct riscv_iommu_command.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 7458878386c5..36e6187bb34b 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -903,10 +903,12 @@ struct iommu_hwpt_get_dirty_bitmap {
* Data Type
* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1
* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3
+ * @IOMMU_VIOMMU_INVALIDATE_DATA_RISCV: Invalidation data for RISC-V IOMMU
*/
enum iommu_hwpt_invalidate_data_type {
IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 = 0,
IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 = 1,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV = 2,
};
/**
@@ -967,6 +969,31 @@ struct iommu_viommu_arm_smmuv3_invalidate {
__aligned_le64 cmd[2];
};
+/**
+ * struct iommu_viommu_riscv_invalidate - RISC-V IOMMU cache invalidation
+ * (IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ * @cmd: 128-bit cache invalidation command that runs in the IOMMU command
+ * queue, in the format defined by the "IOMMU Page-table cache
+ * invalidation" section of the RISC-V IOMMU specification. Must be
+ * little-endian.
+ *
+ * Supported command list only when passing in a vIOMMU via @hwpt_id:
+ * IOTINVAL.VMA
+ *
+ * The isolation operands are owned by the kernel, which overwrites them
+ * before the command is issued:
+ * GV = 1 and GSCID = the GSCID assigned to the vIOMMU
+ * PSCV = 1 and PSCID = 0
+ *
+ * All other reserved bits must be 0.
+ *
+ * -EIO will be returned if the command is not supported, -EINVAL if it is
+ * malformed.
+ */
+struct iommu_viommu_riscv_invalidate {
+ __aligned_le64 cmd[2];
+};
+
/**
* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE)
* @size: sizeof(struct iommu_hwpt_invalidate)
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 03/12] iommufd: Add RISC-V IOMMU cache invalidation data type
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_VIOMMU_INVALIDATE_DATA_RISCV and the matching
struct iommu_viommu_riscv_invalidate, so user space can pass RISC-V
IOMMU IOTINVAL commands to the vIOMMU cache invalidation path using a
payload layout that is shared with the kernel, instead of relying on the
driver internal struct riscv_iommu_command.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 7458878386c5..36e6187bb34b 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -903,10 +903,12 @@ struct iommu_hwpt_get_dirty_bitmap {
* Data Type
* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1
* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3
+ * @IOMMU_VIOMMU_INVALIDATE_DATA_RISCV: Invalidation data for RISC-V IOMMU
*/
enum iommu_hwpt_invalidate_data_type {
IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 = 0,
IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 = 1,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV = 2,
};
/**
@@ -967,6 +969,31 @@ struct iommu_viommu_arm_smmuv3_invalidate {
__aligned_le64 cmd[2];
};
+/**
+ * struct iommu_viommu_riscv_invalidate - RISC-V IOMMU cache invalidation
+ * (IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ * @cmd: 128-bit cache invalidation command that runs in the IOMMU command
+ * queue, in the format defined by the "IOMMU Page-table cache
+ * invalidation" section of the RISC-V IOMMU specification. Must be
+ * little-endian.
+ *
+ * Supported command list only when passing in a vIOMMU via @hwpt_id:
+ * IOTINVAL.VMA
+ *
+ * The isolation operands are owned by the kernel, which overwrites them
+ * before the command is issued:
+ * GV = 1 and GSCID = the GSCID assigned to the vIOMMU
+ * PSCV = 1 and PSCID = 0
+ *
+ * All other reserved bits must be 0.
+ *
+ * -EIO will be returned if the command is not supported, -EINVAL if it is
+ * malformed.
+ */
+struct iommu_viommu_riscv_invalidate {
+ __aligned_le64 cmd[2];
+};
+
/**
* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE)
* @size: sizeof(struct iommu_hwpt_invalidate)
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 04/12] iommu/riscv: Add vIOMMU object support
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the vIOMMU ops so user space can allocate a RISC-V IOMMU
vIOMMU on a stage-2 parent domain and query the size to allocate for
it. The object keeps the parent domain and the GSCID the parent was
allocated, which the nested domain and cache invalidation support added
on top of it will need.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 60 +++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index dd97c2731d95..bf02cd984d86 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -19,6 +19,7 @@
#include <linux/dma-map-ops.h>
#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/iommufd.h>
#include <linux/iopoll.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/kernel.h>
@@ -862,6 +863,7 @@ struct riscv_iommu_domain {
struct mutex mutex; /* serialize domain state updates */
int pscid;
int gscid;
+ bool nest_parent;
struct riscv_iommu_msi_table msi_table;
};
PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
@@ -1497,6 +1499,20 @@ static bool riscv_iommu_iohgatp_supported(struct riscv_iommu_device *iommu,
return false;
}
+static bool riscv_iommu_supports_s1(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39);
+}
+
+static bool riscv_iommu_supports_s2(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39X4);
+}
+
static int riscv_iommu_msi_table_alloc(struct riscv_iommu_domain *domain,
struct riscv_iommu_device *iommu,
struct riscv_iommu_info *info)
@@ -1734,6 +1750,7 @@ riscv_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags,
ret = -ENOMEM;
goto err_free;
}
+ domain->nest_parent = !!(flags & IOMMU_HWPT_ALLOC_NEST_PARENT);
/*
* Capture the current number of MSI PTEs now since it must remain
@@ -1906,6 +1923,47 @@ static void riscv_iommu_release_device(struct device *dev)
kfree_rcu_mightsleep(info);
}
+struct riscv_viommu {
+ struct iommufd_viommu core;
+ struct riscv_iommu_device *iommu;
+ struct riscv_iommu_domain *s2_parent;
+ int gscid;
+};
+
+static const struct iommufd_viommu_ops riscv_viommu_ops = {
+};
+
+static size_t riscv_iommu_get_viommu_size(struct device *dev,
+ enum iommu_viommu_type viommu_type)
+{
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ if (viommu_type != IOMMU_VIOMMU_TYPE_RISCV)
+ return 0;
+
+ if (!riscv_iommu_supports_s1(iommu) || !riscv_iommu_supports_s2(iommu))
+ return 0;
+
+ return VIOMMU_STRUCT_SIZE(struct riscv_viommu, core);
+}
+
+static int riscv_viommu_init(struct iommufd_viommu *viommu,
+ struct iommu_domain *parent_domain,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu =
+ container_of(viommu->iommu_dev, struct riscv_iommu_device, iommu);
+ struct riscv_iommu_domain *s2_parent = iommu_domain_to_riscv(parent_domain);
+
+ rv_viommu->iommu = iommu;
+ rv_viommu->s2_parent = s2_parent;
+ rv_viommu->gscid = s2_parent->gscid;
+ viommu->ops = &riscv_viommu_ops;
+
+ return 0;
+}
+
static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *head)
{
struct iommu_resv_region *region;
@@ -1930,6 +1988,8 @@ static const struct iommu_ops riscv_iommu_ops = {
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
.domain_alloc_paging_flags = riscv_iommu_domain_alloc_paging_flags,
+ .get_viommu_size = riscv_iommu_get_viommu_size,
+ .viommu_init = riscv_viommu_init,
.device_group = riscv_iommu_device_group,
.probe_device = riscv_iommu_probe_device,
.release_device = riscv_iommu_release_device,
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 04/12] iommu/riscv: Add vIOMMU object support
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the vIOMMU ops so user space can allocate a RISC-V IOMMU
vIOMMU on a stage-2 parent domain and query the size to allocate for
it. The object keeps the parent domain and the GSCID the parent was
allocated, which the nested domain and cache invalidation support added
on top of it will need.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 60 +++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index dd97c2731d95..bf02cd984d86 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -19,6 +19,7 @@
#include <linux/dma-map-ops.h>
#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/iommufd.h>
#include <linux/iopoll.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/kernel.h>
@@ -862,6 +863,7 @@ struct riscv_iommu_domain {
struct mutex mutex; /* serialize domain state updates */
int pscid;
int gscid;
+ bool nest_parent;
struct riscv_iommu_msi_table msi_table;
};
PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
@@ -1497,6 +1499,20 @@ static bool riscv_iommu_iohgatp_supported(struct riscv_iommu_device *iommu,
return false;
}
+static bool riscv_iommu_supports_s1(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39);
+}
+
+static bool riscv_iommu_supports_s2(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39X4);
+}
+
static int riscv_iommu_msi_table_alloc(struct riscv_iommu_domain *domain,
struct riscv_iommu_device *iommu,
struct riscv_iommu_info *info)
@@ -1734,6 +1750,7 @@ riscv_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags,
ret = -ENOMEM;
goto err_free;
}
+ domain->nest_parent = !!(flags & IOMMU_HWPT_ALLOC_NEST_PARENT);
/*
* Capture the current number of MSI PTEs now since it must remain
@@ -1906,6 +1923,47 @@ static void riscv_iommu_release_device(struct device *dev)
kfree_rcu_mightsleep(info);
}
+struct riscv_viommu {
+ struct iommufd_viommu core;
+ struct riscv_iommu_device *iommu;
+ struct riscv_iommu_domain *s2_parent;
+ int gscid;
+};
+
+static const struct iommufd_viommu_ops riscv_viommu_ops = {
+};
+
+static size_t riscv_iommu_get_viommu_size(struct device *dev,
+ enum iommu_viommu_type viommu_type)
+{
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ if (viommu_type != IOMMU_VIOMMU_TYPE_RISCV)
+ return 0;
+
+ if (!riscv_iommu_supports_s1(iommu) || !riscv_iommu_supports_s2(iommu))
+ return 0;
+
+ return VIOMMU_STRUCT_SIZE(struct riscv_viommu, core);
+}
+
+static int riscv_viommu_init(struct iommufd_viommu *viommu,
+ struct iommu_domain *parent_domain,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu =
+ container_of(viommu->iommu_dev, struct riscv_iommu_device, iommu);
+ struct riscv_iommu_domain *s2_parent = iommu_domain_to_riscv(parent_domain);
+
+ rv_viommu->iommu = iommu;
+ rv_viommu->s2_parent = s2_parent;
+ rv_viommu->gscid = s2_parent->gscid;
+ viommu->ops = &riscv_viommu_ops;
+
+ return 0;
+}
+
static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *head)
{
struct iommu_resv_region *region;
@@ -1930,6 +1988,8 @@ static const struct iommu_ops riscv_iommu_ops = {
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
.domain_alloc_paging_flags = riscv_iommu_domain_alloc_paging_flags,
+ .get_viommu_size = riscv_iommu_get_viommu_size,
+ .viommu_init = riscv_viommu_init,
.device_group = riscv_iommu_device_group,
.probe_device = riscv_iommu_probe_device,
.release_device = riscv_iommu_release_device,
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 04/12] iommu/riscv: Add vIOMMU object support
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the vIOMMU ops so user space can allocate a RISC-V IOMMU
vIOMMU on a stage-2 parent domain and query the size to allocate for
it. The object keeps the parent domain and the GSCID the parent was
allocated, which the nested domain and cache invalidation support added
on top of it will need.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 60 +++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index dd97c2731d95..bf02cd984d86 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -19,6 +19,7 @@
#include <linux/dma-map-ops.h>
#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/iommufd.h>
#include <linux/iopoll.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/kernel.h>
@@ -862,6 +863,7 @@ struct riscv_iommu_domain {
struct mutex mutex; /* serialize domain state updates */
int pscid;
int gscid;
+ bool nest_parent;
struct riscv_iommu_msi_table msi_table;
};
PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
@@ -1497,6 +1499,20 @@ static bool riscv_iommu_iohgatp_supported(struct riscv_iommu_device *iommu,
return false;
}
+static bool riscv_iommu_supports_s1(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39);
+}
+
+static bool riscv_iommu_supports_s2(struct riscv_iommu_device *iommu)
+{
+ return (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48X4) ||
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39X4);
+}
+
static int riscv_iommu_msi_table_alloc(struct riscv_iommu_domain *domain,
struct riscv_iommu_device *iommu,
struct riscv_iommu_info *info)
@@ -1734,6 +1750,7 @@ riscv_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags,
ret = -ENOMEM;
goto err_free;
}
+ domain->nest_parent = !!(flags & IOMMU_HWPT_ALLOC_NEST_PARENT);
/*
* Capture the current number of MSI PTEs now since it must remain
@@ -1906,6 +1923,47 @@ static void riscv_iommu_release_device(struct device *dev)
kfree_rcu_mightsleep(info);
}
+struct riscv_viommu {
+ struct iommufd_viommu core;
+ struct riscv_iommu_device *iommu;
+ struct riscv_iommu_domain *s2_parent;
+ int gscid;
+};
+
+static const struct iommufd_viommu_ops riscv_viommu_ops = {
+};
+
+static size_t riscv_iommu_get_viommu_size(struct device *dev,
+ enum iommu_viommu_type viommu_type)
+{
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ if (viommu_type != IOMMU_VIOMMU_TYPE_RISCV)
+ return 0;
+
+ if (!riscv_iommu_supports_s1(iommu) || !riscv_iommu_supports_s2(iommu))
+ return 0;
+
+ return VIOMMU_STRUCT_SIZE(struct riscv_viommu, core);
+}
+
+static int riscv_viommu_init(struct iommufd_viommu *viommu,
+ struct iommu_domain *parent_domain,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu =
+ container_of(viommu->iommu_dev, struct riscv_iommu_device, iommu);
+ struct riscv_iommu_domain *s2_parent = iommu_domain_to_riscv(parent_domain);
+
+ rv_viommu->iommu = iommu;
+ rv_viommu->s2_parent = s2_parent;
+ rv_viommu->gscid = s2_parent->gscid;
+ viommu->ops = &riscv_viommu_ops;
+
+ return 0;
+}
+
static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *head)
{
struct iommu_resv_region *region;
@@ -1930,6 +1988,8 @@ static const struct iommu_ops riscv_iommu_ops = {
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
.domain_alloc_paging_flags = riscv_iommu_domain_alloc_paging_flags,
+ .get_viommu_size = riscv_iommu_get_viommu_size,
+ .viommu_init = riscv_viommu_init,
.device_group = riscv_iommu_device_group,
.probe_device = riscv_iommu_probe_device,
.release_device = riscv_iommu_release_device,
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 05/12] iommu/riscv: Add nested domain allocation
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement alloc_domain_nested for the vIOMMU, which builds a nested
domain out of the stage-1 device context that the guest provides. The
context is sanitized before it is stored, since it is entirely user
controlled and bits this IOMMU or this host does not support would
otherwise be programmed into the hardware unchanged.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 146 ++++++++++++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index bf02cd984d86..8046cadefbd8 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1930,7 +1930,153 @@ struct riscv_viommu {
int gscid;
};
+struct riscv_iommu_nested_domain {
+ struct iommu_domain domain;
+ struct riscv_viommu *viommu;
+
+ u64 tc;
+ u64 iosatp;
+};
+
+#define to_riscv_iommu_nested_domain(domain) \
+ container_of(domain, struct riscv_iommu_nested_domain, domain)
+
+static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
+{
+ kfree(to_riscv_iommu_nested_domain(domain));
+}
+
+static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .free = riscv_iommu_domain_nested_free,
+};
+
+static int riscv_iommu_validate_vdc(struct riscv_iommu_device *iommu,
+ struct iommu_hwpt_riscv *arg)
+{
+ u64 mode;
+
+ if (!(arg->tc & RISCV_IOMMU_DC_TC_V)) {
+ arg->tc = 0;
+ arg->iosatp = 0;
+ return 0;
+ }
+
+ /*
+ * Reject reserved/custom bits, the physical IOMMU may treat the
+ * DC as misconfigured.
+ */
+ if (arg->tc & ~RISCV_IOMMU_DC_TC_DEFINED)
+ return -EINVAL;
+ if (arg->iosatp & ~(RISCV_IOMMU_DC_FSC_PPN | RISCV_IOMMU_DC_FSC_MODE))
+ return -EINVAL;
+
+ /* Process directory tables are not supported now. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_PDTV)
+ return -EOPNOTSUPP;
+
+ /* With PDTV=0 the DPE bit is reserved for future use. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_DPE)
+ return -EINVAL;
+
+ /* Only 64-bit (SXL=0) stage-1 is supported. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_SXL)
+ return -EOPNOTSUPP;
+
+ /* ATS/PRI/T2GPA/PRPR consistency. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) &&
+ (arg->tc & (RISCV_IOMMU_DC_TC_EN_ATS | RISCV_IOMMU_DC_TC_EN_PRI |
+ RISCV_IOMMU_DC_TC_PRPR)))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_EN_PRI) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_PRPR) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_PRI))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_T2GPA) &&
+ (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_T2GPA) ||
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS)))
+ return -EINVAL;
+
+ /*
+ * A/D update behavior on stage-2 PTEs is owned by the host,
+ * decide it's value from the AMO_HWAD capability.
+ */
+ arg->tc &= ~RISCV_IOMMU_DC_TC_GADE;
+ if (iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD)
+ arg->tc |= RISCV_IOMMU_DC_TC_GADE;
+
+ /*
+ * A/D update behavior on stage-1 PTEs is owned by the guest but
+ * needs AMO_HWAD support.
+ */
+ if ((arg->tc & RISCV_IOMMU_DC_TC_SADE) &&
+ !(iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD))
+ return -EOPNOTSUPP;
+
+ /* SBE must match the IOMMU byte order unless END is supported. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_END) &&
+ (!!(arg->tc & RISCV_IOMMU_DC_TC_SBE) !=
+ !!(iommu->fctl & RISCV_IOMMU_FCTL_BE)))
+ return -EINVAL;
+
+ /* Validate the stage-1 mode. */
+ mode = FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, arg->iosatp);
+ if (mode == RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ /* No stage-1 translation, root pointer is unused. */
+ arg->iosatp = 0;
+ return 0;
+ }
+ switch (mode) {
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!riscv_iommu_fsc_supported(iommu, mode))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static struct iommu_domain *
+riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_nested_domain *nested_domain;
+ struct iommu_hwpt_riscv arg;
+ int ret;
+
+ if (flags)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ ret = iommu_copy_struct_from_user(&arg, user_data,
+ IOMMU_HWPT_DATA_RISCV_S1, iosatp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = riscv_iommu_validate_vdc(rv_viommu->iommu, &arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ nested_domain = kzalloc_obj(*nested_domain, GFP_KERNEL_ACCOUNT);
+ if (!nested_domain)
+ return ERR_PTR(-ENOMEM);
+
+ nested_domain->domain.type = IOMMU_DOMAIN_NESTED;
+ nested_domain->domain.ops = &riscv_iommu_nested_ops;
+ nested_domain->viommu = rv_viommu;
+ nested_domain->tc = arg.tc;
+ nested_domain->iosatp = arg.iosatp;
+
+ return &nested_domain->domain;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
+ .alloc_domain_nested = riscv_viommu_alloc_domain_nested,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 05/12] iommu/riscv: Add nested domain allocation
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement alloc_domain_nested for the vIOMMU, which builds a nested
domain out of the stage-1 device context that the guest provides. The
context is sanitized before it is stored, since it is entirely user
controlled and bits this IOMMU or this host does not support would
otherwise be programmed into the hardware unchanged.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 146 ++++++++++++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index bf02cd984d86..8046cadefbd8 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1930,7 +1930,153 @@ struct riscv_viommu {
int gscid;
};
+struct riscv_iommu_nested_domain {
+ struct iommu_domain domain;
+ struct riscv_viommu *viommu;
+
+ u64 tc;
+ u64 iosatp;
+};
+
+#define to_riscv_iommu_nested_domain(domain) \
+ container_of(domain, struct riscv_iommu_nested_domain, domain)
+
+static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
+{
+ kfree(to_riscv_iommu_nested_domain(domain));
+}
+
+static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .free = riscv_iommu_domain_nested_free,
+};
+
+static int riscv_iommu_validate_vdc(struct riscv_iommu_device *iommu,
+ struct iommu_hwpt_riscv *arg)
+{
+ u64 mode;
+
+ if (!(arg->tc & RISCV_IOMMU_DC_TC_V)) {
+ arg->tc = 0;
+ arg->iosatp = 0;
+ return 0;
+ }
+
+ /*
+ * Reject reserved/custom bits, the physical IOMMU may treat the
+ * DC as misconfigured.
+ */
+ if (arg->tc & ~RISCV_IOMMU_DC_TC_DEFINED)
+ return -EINVAL;
+ if (arg->iosatp & ~(RISCV_IOMMU_DC_FSC_PPN | RISCV_IOMMU_DC_FSC_MODE))
+ return -EINVAL;
+
+ /* Process directory tables are not supported now. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_PDTV)
+ return -EOPNOTSUPP;
+
+ /* With PDTV=0 the DPE bit is reserved for future use. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_DPE)
+ return -EINVAL;
+
+ /* Only 64-bit (SXL=0) stage-1 is supported. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_SXL)
+ return -EOPNOTSUPP;
+
+ /* ATS/PRI/T2GPA/PRPR consistency. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) &&
+ (arg->tc & (RISCV_IOMMU_DC_TC_EN_ATS | RISCV_IOMMU_DC_TC_EN_PRI |
+ RISCV_IOMMU_DC_TC_PRPR)))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_EN_PRI) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_PRPR) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_PRI))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_T2GPA) &&
+ (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_T2GPA) ||
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS)))
+ return -EINVAL;
+
+ /*
+ * A/D update behavior on stage-2 PTEs is owned by the host,
+ * decide it's value from the AMO_HWAD capability.
+ */
+ arg->tc &= ~RISCV_IOMMU_DC_TC_GADE;
+ if (iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD)
+ arg->tc |= RISCV_IOMMU_DC_TC_GADE;
+
+ /*
+ * A/D update behavior on stage-1 PTEs is owned by the guest but
+ * needs AMO_HWAD support.
+ */
+ if ((arg->tc & RISCV_IOMMU_DC_TC_SADE) &&
+ !(iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD))
+ return -EOPNOTSUPP;
+
+ /* SBE must match the IOMMU byte order unless END is supported. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_END) &&
+ (!!(arg->tc & RISCV_IOMMU_DC_TC_SBE) !=
+ !!(iommu->fctl & RISCV_IOMMU_FCTL_BE)))
+ return -EINVAL;
+
+ /* Validate the stage-1 mode. */
+ mode = FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, arg->iosatp);
+ if (mode == RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ /* No stage-1 translation, root pointer is unused. */
+ arg->iosatp = 0;
+ return 0;
+ }
+ switch (mode) {
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!riscv_iommu_fsc_supported(iommu, mode))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static struct iommu_domain *
+riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_nested_domain *nested_domain;
+ struct iommu_hwpt_riscv arg;
+ int ret;
+
+ if (flags)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ ret = iommu_copy_struct_from_user(&arg, user_data,
+ IOMMU_HWPT_DATA_RISCV_S1, iosatp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = riscv_iommu_validate_vdc(rv_viommu->iommu, &arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ nested_domain = kzalloc_obj(*nested_domain, GFP_KERNEL_ACCOUNT);
+ if (!nested_domain)
+ return ERR_PTR(-ENOMEM);
+
+ nested_domain->domain.type = IOMMU_DOMAIN_NESTED;
+ nested_domain->domain.ops = &riscv_iommu_nested_ops;
+ nested_domain->viommu = rv_viommu;
+ nested_domain->tc = arg.tc;
+ nested_domain->iosatp = arg.iosatp;
+
+ return &nested_domain->domain;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
+ .alloc_domain_nested = riscv_viommu_alloc_domain_nested,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 05/12] iommu/riscv: Add nested domain allocation
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement alloc_domain_nested for the vIOMMU, which builds a nested
domain out of the stage-1 device context that the guest provides. The
context is sanitized before it is stored, since it is entirely user
controlled and bits this IOMMU or this host does not support would
otherwise be programmed into the hardware unchanged.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 146 ++++++++++++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index bf02cd984d86..8046cadefbd8 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1930,7 +1930,153 @@ struct riscv_viommu {
int gscid;
};
+struct riscv_iommu_nested_domain {
+ struct iommu_domain domain;
+ struct riscv_viommu *viommu;
+
+ u64 tc;
+ u64 iosatp;
+};
+
+#define to_riscv_iommu_nested_domain(domain) \
+ container_of(domain, struct riscv_iommu_nested_domain, domain)
+
+static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
+{
+ kfree(to_riscv_iommu_nested_domain(domain));
+}
+
+static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .free = riscv_iommu_domain_nested_free,
+};
+
+static int riscv_iommu_validate_vdc(struct riscv_iommu_device *iommu,
+ struct iommu_hwpt_riscv *arg)
+{
+ u64 mode;
+
+ if (!(arg->tc & RISCV_IOMMU_DC_TC_V)) {
+ arg->tc = 0;
+ arg->iosatp = 0;
+ return 0;
+ }
+
+ /*
+ * Reject reserved/custom bits, the physical IOMMU may treat the
+ * DC as misconfigured.
+ */
+ if (arg->tc & ~RISCV_IOMMU_DC_TC_DEFINED)
+ return -EINVAL;
+ if (arg->iosatp & ~(RISCV_IOMMU_DC_FSC_PPN | RISCV_IOMMU_DC_FSC_MODE))
+ return -EINVAL;
+
+ /* Process directory tables are not supported now. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_PDTV)
+ return -EOPNOTSUPP;
+
+ /* With PDTV=0 the DPE bit is reserved for future use. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_DPE)
+ return -EINVAL;
+
+ /* Only 64-bit (SXL=0) stage-1 is supported. */
+ if (arg->tc & RISCV_IOMMU_DC_TC_SXL)
+ return -EOPNOTSUPP;
+
+ /* ATS/PRI/T2GPA/PRPR consistency. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) &&
+ (arg->tc & (RISCV_IOMMU_DC_TC_EN_ATS | RISCV_IOMMU_DC_TC_EN_PRI |
+ RISCV_IOMMU_DC_TC_PRPR)))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_EN_PRI) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_PRPR) &&
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_PRI))
+ return -EINVAL;
+ if ((arg->tc & RISCV_IOMMU_DC_TC_T2GPA) &&
+ (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_T2GPA) ||
+ !(arg->tc & RISCV_IOMMU_DC_TC_EN_ATS)))
+ return -EINVAL;
+
+ /*
+ * A/D update behavior on stage-2 PTEs is owned by the host,
+ * decide it's value from the AMO_HWAD capability.
+ */
+ arg->tc &= ~RISCV_IOMMU_DC_TC_GADE;
+ if (iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD)
+ arg->tc |= RISCV_IOMMU_DC_TC_GADE;
+
+ /*
+ * A/D update behavior on stage-1 PTEs is owned by the guest but
+ * needs AMO_HWAD support.
+ */
+ if ((arg->tc & RISCV_IOMMU_DC_TC_SADE) &&
+ !(iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD))
+ return -EOPNOTSUPP;
+
+ /* SBE must match the IOMMU byte order unless END is supported. */
+ if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_END) &&
+ (!!(arg->tc & RISCV_IOMMU_DC_TC_SBE) !=
+ !!(iommu->fctl & RISCV_IOMMU_FCTL_BE)))
+ return -EINVAL;
+
+ /* Validate the stage-1 mode. */
+ mode = FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, arg->iosatp);
+ if (mode == RISCV_IOMMU_DC_FSC_MODE_BARE) {
+ /* No stage-1 translation, root pointer is unused. */
+ arg->iosatp = 0;
+ return 0;
+ }
+ switch (mode) {
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48:
+ case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!riscv_iommu_fsc_supported(iommu, mode))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static struct iommu_domain *
+riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
+ const struct iommu_user_data *user_data)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_nested_domain *nested_domain;
+ struct iommu_hwpt_riscv arg;
+ int ret;
+
+ if (flags)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ ret = iommu_copy_struct_from_user(&arg, user_data,
+ IOMMU_HWPT_DATA_RISCV_S1, iosatp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = riscv_iommu_validate_vdc(rv_viommu->iommu, &arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ nested_domain = kzalloc_obj(*nested_domain, GFP_KERNEL_ACCOUNT);
+ if (!nested_domain)
+ return ERR_PTR(-ENOMEM);
+
+ nested_domain->domain.type = IOMMU_DOMAIN_NESTED;
+ nested_domain->domain.ops = &riscv_iommu_nested_ops;
+ nested_domain->viommu = rv_viommu;
+ nested_domain->tc = arg.tc;
+ nested_domain->iosatp = arg.iosatp;
+
+ return &nested_domain->domain;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
+ .alloc_domain_nested = riscv_viommu_alloc_domain_nested,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 06/12] iommu/riscv: Add vIOMMU cache invalidation
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Implement cache_invalidate for the vIOMMU, which takes IOTINVAL commands
from user space in the struct iommu_viommu_riscv_invalidate format and
forwards them to the physical IOMMU command queue.
The uAPI payload is little-endian, so convert it to the native command
words the hardware queue expects. Only IOTINVAL.VMA is accepted;
reserved bits are rejected. The guest-owned GV, GSCID and PSCV/PSCID
operands are replaced with the ones the host actually programs, so a
guest cannot invalidate caches that belong to another guest.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 13 +++++
drivers/iommu/riscv/iommu.c | 93 ++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 2a8230a0c1bb..68190d6cc060 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -486,6 +486,19 @@ struct riscv_iommu_command {
/* dword1[61:10] is the 4K-aligned page address */
#define RISCV_IOMMU_CMD1_IOTINVAL_ADDR GENMASK_ULL(61, 10)
+/*
+ * All standard bits of the IOTINVAL command. The remaining bits are
+ * reserved for future standard use, forwarding them to the physical IOMMU
+ * may make it treat the command as illegal.
+ */
+#define RISCV_IOMMU_CMD0_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD0_OPCODE | RISCV_IOMMU_CMD0_FUNC | \
+ RISCV_IOMMU_CMD0_IOTINVAL_AV | RISCV_IOMMU_CMD0_IOTINVAL_PSCID | \
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV | RISCV_IOMMU_CMD0_IOTINVAL_GV | \
+ RISCV_IOMMU_CMD0_IOTINVAL_NL | RISCV_IOMMU_CMD0_IOTINVAL_GSCID)
+#define RISCV_IOMMU_CMD1_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD1_IOTINVAL_S | RISCV_IOMMU_CMD1_IOTINVAL_ADDR)
+
/* 3.1.2 IOMMU Command Queue Fences */
/* Fields on dword0 */
#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 8046cadefbd8..c34331bcd661 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2075,8 +2075,101 @@ riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
return &nested_domain->domain;
}
+/*
+ * One invalidation command, viewed as either the little-endian uAPI
+ * payload or the native command words.
+ */
+struct riscv_viommu_invalidation_cmd {
+ union {
+ struct riscv_iommu_command cmd;
+ struct iommu_viommu_riscv_invalidate ucmd;
+ };
+};
+
+static int riscv_viommu_cache_invalidate(struct iommufd_viommu *viommu,
+ struct iommu_user_data_array *array)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu = rv_viommu->iommu;
+ struct riscv_viommu_invalidation_cmd *cmds;
+ unsigned int i = 0;
+ int ret;
+
+ if (array->type != IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ return -EINVAL;
+
+ /* entry_num==0 is the data_type support probe */
+ if (!array->entry_num)
+ return 0;
+
+ static_assert(sizeof(*cmds) == 2 * sizeof(u64));
+
+ cmds = kcalloc(array->entry_num, sizeof(*cmds), GFP_KERNEL);
+ if (!cmds)
+ return -ENOMEM;
+
+ ret = iommu_copy_struct_from_full_user_array(cmds, sizeof(*cmds), array,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV);
+ if (ret)
+ goto out_free;
+
+ for (i = 0; i < array->entry_num; i++) {
+ struct riscv_iommu_command *cmd = &cmds[i].cmd;
+ u64 opcode, func;
+
+ /* The uAPI payload is little-endian */
+ cmd->dword0 = le64_to_cpu(cmds[i].ucmd.cmd[0]);
+ cmd->dword1 = le64_to_cpu(cmds[i].ucmd.cmd[1]);
+
+ opcode = FIELD_GET(RISCV_IOMMU_CMD0_OPCODE, cmd->dword0);
+ if (opcode != RISCV_IOMMU_CMD_IOTINVAL_OPCODE) {
+ /* Only page-table cache invalidation is forwarded */
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /* Reject reserved bits instead of forwarding them to the physical IOMMU */
+ if (cmd->dword0 & ~RISCV_IOMMU_CMD0_IOTINVAL_STANDARD ||
+ cmd->dword1 & ~RISCV_IOMMU_CMD1_IOTINVAL_STANDARD) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ func = FIELD_GET(RISCV_IOMMU_CMD0_FUNC, cmd->dword0);
+ if (func != RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /*
+ * The guest operates in its own GSCID/PSCID namespace.
+ * The physical IOMMU uses the host-assigned GSCID and
+ * PSCID=0. Enforce both for correct cache invalidation.
+ */
+ cmd->dword0 &= ~(RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ RISCV_IOMMU_CMD0_IOTINVAL_GSCID |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCID);
+ cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_GSCID,
+ rv_viommu->gscid) |
+ RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_PSCID, 0) |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV;
+
+ riscv_iommu_cmd_send(iommu, cmd);
+ }
+
+ riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
+
+out_free:
+ array->entry_num = i;
+ kfree(cmds);
+ return ret;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
.alloc_domain_nested = riscv_viommu_alloc_domain_nested,
+ .cache_invalidate = riscv_viommu_cache_invalidate,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 06/12] iommu/riscv: Add vIOMMU cache invalidation
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Implement cache_invalidate for the vIOMMU, which takes IOTINVAL commands
from user space in the struct iommu_viommu_riscv_invalidate format and
forwards them to the physical IOMMU command queue.
The uAPI payload is little-endian, so convert it to the native command
words the hardware queue expects. Only IOTINVAL.VMA is accepted;
reserved bits are rejected. The guest-owned GV, GSCID and PSCV/PSCID
operands are replaced with the ones the host actually programs, so a
guest cannot invalidate caches that belong to another guest.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 13 +++++
drivers/iommu/riscv/iommu.c | 93 ++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 2a8230a0c1bb..68190d6cc060 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -486,6 +486,19 @@ struct riscv_iommu_command {
/* dword1[61:10] is the 4K-aligned page address */
#define RISCV_IOMMU_CMD1_IOTINVAL_ADDR GENMASK_ULL(61, 10)
+/*
+ * All standard bits of the IOTINVAL command. The remaining bits are
+ * reserved for future standard use, forwarding them to the physical IOMMU
+ * may make it treat the command as illegal.
+ */
+#define RISCV_IOMMU_CMD0_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD0_OPCODE | RISCV_IOMMU_CMD0_FUNC | \
+ RISCV_IOMMU_CMD0_IOTINVAL_AV | RISCV_IOMMU_CMD0_IOTINVAL_PSCID | \
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV | RISCV_IOMMU_CMD0_IOTINVAL_GV | \
+ RISCV_IOMMU_CMD0_IOTINVAL_NL | RISCV_IOMMU_CMD0_IOTINVAL_GSCID)
+#define RISCV_IOMMU_CMD1_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD1_IOTINVAL_S | RISCV_IOMMU_CMD1_IOTINVAL_ADDR)
+
/* 3.1.2 IOMMU Command Queue Fences */
/* Fields on dword0 */
#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 8046cadefbd8..c34331bcd661 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2075,8 +2075,101 @@ riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
return &nested_domain->domain;
}
+/*
+ * One invalidation command, viewed as either the little-endian uAPI
+ * payload or the native command words.
+ */
+struct riscv_viommu_invalidation_cmd {
+ union {
+ struct riscv_iommu_command cmd;
+ struct iommu_viommu_riscv_invalidate ucmd;
+ };
+};
+
+static int riscv_viommu_cache_invalidate(struct iommufd_viommu *viommu,
+ struct iommu_user_data_array *array)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu = rv_viommu->iommu;
+ struct riscv_viommu_invalidation_cmd *cmds;
+ unsigned int i = 0;
+ int ret;
+
+ if (array->type != IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ return -EINVAL;
+
+ /* entry_num==0 is the data_type support probe */
+ if (!array->entry_num)
+ return 0;
+
+ static_assert(sizeof(*cmds) == 2 * sizeof(u64));
+
+ cmds = kcalloc(array->entry_num, sizeof(*cmds), GFP_KERNEL);
+ if (!cmds)
+ return -ENOMEM;
+
+ ret = iommu_copy_struct_from_full_user_array(cmds, sizeof(*cmds), array,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV);
+ if (ret)
+ goto out_free;
+
+ for (i = 0; i < array->entry_num; i++) {
+ struct riscv_iommu_command *cmd = &cmds[i].cmd;
+ u64 opcode, func;
+
+ /* The uAPI payload is little-endian */
+ cmd->dword0 = le64_to_cpu(cmds[i].ucmd.cmd[0]);
+ cmd->dword1 = le64_to_cpu(cmds[i].ucmd.cmd[1]);
+
+ opcode = FIELD_GET(RISCV_IOMMU_CMD0_OPCODE, cmd->dword0);
+ if (opcode != RISCV_IOMMU_CMD_IOTINVAL_OPCODE) {
+ /* Only page-table cache invalidation is forwarded */
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /* Reject reserved bits instead of forwarding them to the physical IOMMU */
+ if (cmd->dword0 & ~RISCV_IOMMU_CMD0_IOTINVAL_STANDARD ||
+ cmd->dword1 & ~RISCV_IOMMU_CMD1_IOTINVAL_STANDARD) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ func = FIELD_GET(RISCV_IOMMU_CMD0_FUNC, cmd->dword0);
+ if (func != RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /*
+ * The guest operates in its own GSCID/PSCID namespace.
+ * The physical IOMMU uses the host-assigned GSCID and
+ * PSCID=0. Enforce both for correct cache invalidation.
+ */
+ cmd->dword0 &= ~(RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ RISCV_IOMMU_CMD0_IOTINVAL_GSCID |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCID);
+ cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_GSCID,
+ rv_viommu->gscid) |
+ RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_PSCID, 0) |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV;
+
+ riscv_iommu_cmd_send(iommu, cmd);
+ }
+
+ riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
+
+out_free:
+ array->entry_num = i;
+ kfree(cmds);
+ return ret;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
.alloc_domain_nested = riscv_viommu_alloc_domain_nested,
+ .cache_invalidate = riscv_viommu_cache_invalidate,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 06/12] iommu/riscv: Add vIOMMU cache invalidation
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
Implement cache_invalidate for the vIOMMU, which takes IOTINVAL commands
from user space in the struct iommu_viommu_riscv_invalidate format and
forwards them to the physical IOMMU command queue.
The uAPI payload is little-endian, so convert it to the native command
words the hardware queue expects. Only IOTINVAL.VMA is accepted;
reserved bits are rejected. The guest-owned GV, GSCID and PSCV/PSCID
operands are replaced with the ones the host actually programs, so a
guest cannot invalidate caches that belong to another guest.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu-bits.h | 13 +++++
drivers/iommu/riscv/iommu.c | 93 ++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 2a8230a0c1bb..68190d6cc060 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -486,6 +486,19 @@ struct riscv_iommu_command {
/* dword1[61:10] is the 4K-aligned page address */
#define RISCV_IOMMU_CMD1_IOTINVAL_ADDR GENMASK_ULL(61, 10)
+/*
+ * All standard bits of the IOTINVAL command. The remaining bits are
+ * reserved for future standard use, forwarding them to the physical IOMMU
+ * may make it treat the command as illegal.
+ */
+#define RISCV_IOMMU_CMD0_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD0_OPCODE | RISCV_IOMMU_CMD0_FUNC | \
+ RISCV_IOMMU_CMD0_IOTINVAL_AV | RISCV_IOMMU_CMD0_IOTINVAL_PSCID | \
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV | RISCV_IOMMU_CMD0_IOTINVAL_GV | \
+ RISCV_IOMMU_CMD0_IOTINVAL_NL | RISCV_IOMMU_CMD0_IOTINVAL_GSCID)
+#define RISCV_IOMMU_CMD1_IOTINVAL_STANDARD \
+ (RISCV_IOMMU_CMD1_IOTINVAL_S | RISCV_IOMMU_CMD1_IOTINVAL_ADDR)
+
/* 3.1.2 IOMMU Command Queue Fences */
/* Fields on dword0 */
#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 8046cadefbd8..c34331bcd661 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2075,8 +2075,101 @@ riscv_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
return &nested_domain->domain;
}
+/*
+ * One invalidation command, viewed as either the little-endian uAPI
+ * payload or the native command words.
+ */
+struct riscv_viommu_invalidation_cmd {
+ union {
+ struct riscv_iommu_command cmd;
+ struct iommu_viommu_riscv_invalidate ucmd;
+ };
+};
+
+static int riscv_viommu_cache_invalidate(struct iommufd_viommu *viommu,
+ struct iommu_user_data_array *array)
+{
+ struct riscv_viommu *rv_viommu = container_of(viommu, struct riscv_viommu, core);
+ struct riscv_iommu_device *iommu = rv_viommu->iommu;
+ struct riscv_viommu_invalidation_cmd *cmds;
+ unsigned int i = 0;
+ int ret;
+
+ if (array->type != IOMMU_VIOMMU_INVALIDATE_DATA_RISCV)
+ return -EINVAL;
+
+ /* entry_num==0 is the data_type support probe */
+ if (!array->entry_num)
+ return 0;
+
+ static_assert(sizeof(*cmds) == 2 * sizeof(u64));
+
+ cmds = kcalloc(array->entry_num, sizeof(*cmds), GFP_KERNEL);
+ if (!cmds)
+ return -ENOMEM;
+
+ ret = iommu_copy_struct_from_full_user_array(cmds, sizeof(*cmds), array,
+ IOMMU_VIOMMU_INVALIDATE_DATA_RISCV);
+ if (ret)
+ goto out_free;
+
+ for (i = 0; i < array->entry_num; i++) {
+ struct riscv_iommu_command *cmd = &cmds[i].cmd;
+ u64 opcode, func;
+
+ /* The uAPI payload is little-endian */
+ cmd->dword0 = le64_to_cpu(cmds[i].ucmd.cmd[0]);
+ cmd->dword1 = le64_to_cpu(cmds[i].ucmd.cmd[1]);
+
+ opcode = FIELD_GET(RISCV_IOMMU_CMD0_OPCODE, cmd->dword0);
+ if (opcode != RISCV_IOMMU_CMD_IOTINVAL_OPCODE) {
+ /* Only page-table cache invalidation is forwarded */
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /* Reject reserved bits instead of forwarding them to the physical IOMMU */
+ if (cmd->dword0 & ~RISCV_IOMMU_CMD0_IOTINVAL_STANDARD ||
+ cmd->dword1 & ~RISCV_IOMMU_CMD1_IOTINVAL_STANDARD) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ func = FIELD_GET(RISCV_IOMMU_CMD0_FUNC, cmd->dword0);
+ if (func != RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /*
+ * The guest operates in its own GSCID/PSCID namespace.
+ * The physical IOMMU uses the host-assigned GSCID and
+ * PSCID=0. Enforce both for correct cache invalidation.
+ */
+ cmd->dword0 &= ~(RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ RISCV_IOMMU_CMD0_IOTINVAL_GSCID |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCID);
+ cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_GSCID,
+ rv_viommu->gscid) |
+ RISCV_IOMMU_CMD0_IOTINVAL_GV |
+ FIELD_PREP(RISCV_IOMMU_CMD0_IOTINVAL_PSCID, 0) |
+ RISCV_IOMMU_CMD0_IOTINVAL_PSCV;
+
+ riscv_iommu_cmd_send(iommu, cmd);
+ }
+
+ riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT);
+
+out_free:
+ array->entry_num = i;
+ kfree(cmds);
+ return ret;
+}
+
static const struct iommufd_viommu_ops riscv_viommu_ops = {
.alloc_domain_nested = riscv_viommu_alloc_domain_nested,
+ .cache_invalidate = riscv_viommu_cache_invalidate,
};
static size_t riscv_iommu_get_viommu_size(struct device *dev,
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
reports the RISC-V IOMMU Capabilities register through
IOMMU_GET_HW_INFO.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 36e6187bb34b..acfef0338cd1 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
__aligned_u64 efr2;
};
+/**
+ * struct iommu_hw_info_riscv - RISC-V IOMMU device info
+ * @capabilities: Value of RISC-V IOMMU Capabilities register
+ */
+struct iommu_hw_info_riscv {
+ __u64 capabilities;
+};
+
/**
* enum iommu_hw_info_type - IOMMU Hardware Info Types
* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware
@@ -726,6 +734,7 @@ struct iommu_hw_info_amd {
* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) info type
* @IOMMU_HW_INFO_TYPE_AMD: AMD IOMMU info type
+ * @IOMMU_HW_INFO_TYPE_RISCV: RISC-V IOMMU info type
*/
enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_NONE = 0,
@@ -734,6 +743,7 @@ enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_ARM_SMMUV3 = 2,
IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV = 3,
IOMMU_HW_INFO_TYPE_AMD = 4,
+ IOMMU_HW_INFO_TYPE_RISCV = 5,
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
reports the RISC-V IOMMU Capabilities register through
IOMMU_GET_HW_INFO.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 36e6187bb34b..acfef0338cd1 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
__aligned_u64 efr2;
};
+/**
+ * struct iommu_hw_info_riscv - RISC-V IOMMU device info
+ * @capabilities: Value of RISC-V IOMMU Capabilities register
+ */
+struct iommu_hw_info_riscv {
+ __u64 capabilities;
+};
+
/**
* enum iommu_hw_info_type - IOMMU Hardware Info Types
* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware
@@ -726,6 +734,7 @@ struct iommu_hw_info_amd {
* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) info type
* @IOMMU_HW_INFO_TYPE_AMD: AMD IOMMU info type
+ * @IOMMU_HW_INFO_TYPE_RISCV: RISC-V IOMMU info type
*/
enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_NONE = 0,
@@ -734,6 +743,7 @@ enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_ARM_SMMUV3 = 2,
IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV = 3,
IOMMU_HW_INFO_TYPE_AMD = 4,
+ IOMMU_HW_INFO_TYPE_RISCV = 5,
};
/**
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
reports the RISC-V IOMMU Capabilities register through
IOMMU_GET_HW_INFO.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
include/uapi/linux/iommufd.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 36e6187bb34b..acfef0338cd1 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
__aligned_u64 efr2;
};
+/**
+ * struct iommu_hw_info_riscv - RISC-V IOMMU device info
+ * @capabilities: Value of RISC-V IOMMU Capabilities register
+ */
+struct iommu_hw_info_riscv {
+ __u64 capabilities;
+};
+
/**
* enum iommu_hw_info_type - IOMMU Hardware Info Types
* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware
@@ -726,6 +734,7 @@ struct iommu_hw_info_amd {
* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM
* SMMUv3) info type
* @IOMMU_HW_INFO_TYPE_AMD: AMD IOMMU info type
+ * @IOMMU_HW_INFO_TYPE_RISCV: RISC-V IOMMU info type
*/
enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_NONE = 0,
@@ -734,6 +743,7 @@ enum iommu_hw_info_type {
IOMMU_HW_INFO_TYPE_ARM_SMMUV3 = 2,
IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV = 3,
IOMMU_HW_INFO_TYPE_AMD = 4,
+ IOMMU_HW_INFO_TYPE_RISCV = 5,
};
/**
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 08/12] iommu/riscv: Add riscv_iommu_hw_info
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the hw_info op, report the IOMMU Capabilities register value
to user space as IOMMU_HW_INFO_TYPE_RISCV so VMMs can discover the
hardware capabilities of the physical IOMMU.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index c34331bcd661..e59a6a97589e 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2220,9 +2220,27 @@ static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *h
iommu_dma_get_resv_regions(dev, head);
}
+static void *riscv_iommu_hw_info(struct device *dev, u32 *length,
+ enum iommu_hw_info_type *type)
+{
+ struct iommu_hw_info_riscv *info;
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ info = kzalloc_obj(*info);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->capabilities = iommu->caps;
+ *length = sizeof(*info);
+ *type = IOMMU_HW_INFO_TYPE_RISCV;
+
+ return info;
+}
+
static const struct iommu_ops riscv_iommu_ops = {
.of_xlate = riscv_iommu_of_xlate,
.capable = riscv_iommu_capable,
+ .hw_info = riscv_iommu_hw_info,
.identity_domain = &riscv_iommu_identity_domain,
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 08/12] iommu/riscv: Add riscv_iommu_hw_info
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the hw_info op, report the IOMMU Capabilities register value
to user space as IOMMU_HW_INFO_TYPE_RISCV so VMMs can discover the
hardware capabilities of the physical IOMMU.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index c34331bcd661..e59a6a97589e 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2220,9 +2220,27 @@ static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *h
iommu_dma_get_resv_regions(dev, head);
}
+static void *riscv_iommu_hw_info(struct device *dev, u32 *length,
+ enum iommu_hw_info_type *type)
+{
+ struct iommu_hw_info_riscv *info;
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ info = kzalloc_obj(*info);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->capabilities = iommu->caps;
+ *length = sizeof(*info);
+ *type = IOMMU_HW_INFO_TYPE_RISCV;
+
+ return info;
+}
+
static const struct iommu_ops riscv_iommu_ops = {
.of_xlate = riscv_iommu_of_xlate,
.capable = riscv_iommu_capable,
+ .hw_info = riscv_iommu_hw_info,
.identity_domain = &riscv_iommu_identity_domain,
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 08/12] iommu/riscv: Add riscv_iommu_hw_info
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Implement the hw_info op, report the IOMMU Capabilities register value
to user space as IOMMU_HW_INFO_TYPE_RISCV so VMMs can discover the
hardware capabilities of the physical IOMMU.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index c34331bcd661..e59a6a97589e 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -2220,9 +2220,27 @@ static void riscv_iommu_get_resv_regions(struct device *dev, struct list_head *h
iommu_dma_get_resv_regions(dev, head);
}
+static void *riscv_iommu_hw_info(struct device *dev, u32 *length,
+ enum iommu_hw_info_type *type)
+{
+ struct iommu_hw_info_riscv *info;
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+
+ info = kzalloc_obj(*info);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->capabilities = iommu->caps;
+ *length = sizeof(*info);
+ *type = IOMMU_HW_INFO_TYPE_RISCV;
+
+ return info;
+}
+
static const struct iommu_ops riscv_iommu_ops = {
.of_xlate = riscv_iommu_of_xlate,
.capable = riscv_iommu_capable,
+ .hw_info = riscv_iommu_hw_info,
.identity_domain = &riscv_iommu_identity_domain,
.blocked_domain = &riscv_iommu_blocking_domain,
.release_domain = &riscv_iommu_blocking_domain,
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 09/12] iommu/riscv: Add riscv_iommu_attach_dev_nested
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Attach a device to a nested domain by combining the guest-provided
stage-1 context (tc, iosatp) with the host-owned second-stage context
in the device directory entry.
The device is bonded to the stage-2 parent domain so that it shares the
parent's invalidation and interrupt-remapping state: the guest MSI page
table is allocated when missing, and an active table's MSI configuration
is preserved across the device context update. Since the iommu core
passes the nested domain object as the old domain while the bond lives
on the parent, resolve the bond-holding domain before unlinking.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 89 ++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index e59a6a97589e..a484bf97c2f5 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -871,6 +871,13 @@ PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
#define iommu_domain_to_riscv(iommu_domain) \
container_of(iommu_domain, struct riscv_iommu_domain, domain)
+/*
+ * Resolve the domain holding the device bond: when the previously attached
+ * domain is a nested domain, the device is bonded to its stage-2 parent,
+ * which also owns the MSI table.
+ */
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old);
+
struct riscv_iommu_msi_table *riscv_iommu_msi_table_rcu(struct riscv_iommu_info *info)
{
struct riscv_iommu_domain *domain;
@@ -1593,6 +1600,8 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
unsigned long flags;
int ret;
+ old = riscv_iommu_old_bond_domain(old);
+
pt_iommu_riscv_64_hw_info(&domain->riscvpt, &pt_info);
if (domain->gscid) {
@@ -1787,6 +1796,8 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = 0;
@@ -1816,6 +1827,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = RISCV_IOMMU_DC_TC_V;
@@ -1938,8 +1951,79 @@ struct riscv_iommu_nested_domain {
u64 iosatp;
};
-#define to_riscv_iommu_nested_domain(domain) \
- container_of(domain, struct riscv_iommu_nested_domain, domain)
+#define to_riscv_iommu_nested_domain(domain_ptr) \
+ container_of(domain_ptr, struct riscv_iommu_nested_domain, domain)
+
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old)
+{
+ if (old && old->type == IOMMU_DOMAIN_NESTED)
+ return &to_riscv_iommu_nested_domain(old)->viommu->s2_parent->domain;
+ return old;
+}
+
+static int riscv_iommu_attach_dev_nested(struct iommu_domain *domain,
+ struct device *dev,
+ struct iommu_domain *old_domain)
+{
+ struct riscv_iommu_nested_domain *nested_domain =
+ to_riscv_iommu_nested_domain(domain);
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+ struct riscv_iommu_domain *s2_parent = nested_domain->viommu->s2_parent;
+ struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
+ struct pt_iommu_riscv_64_hw_info pt_info;
+ struct iommu_domain *old = riscv_iommu_old_bond_domain(old_domain);
+ struct riscv_iommu_bond *bond;
+ struct riscv_iommu_dc dc = {0};
+ unsigned long flags;
+ int ret;
+
+ if (nested_domain->viommu->iommu != iommu)
+ return -EINVAL;
+
+ if (!s2_parent->nest_parent)
+ return -EINVAL;
+
+ pt_iommu_riscv_64_hw_info(&s2_parent->riscvpt, &pt_info);
+
+ dc.tc = nested_domain->tc;
+ dc.fsc = nested_domain->iosatp;
+
+ dc.iohgatp = FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_MODE, pt_info.iohgatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_PPN, pt_info.ppn) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_GSCID, s2_parent->gscid);
+
+ /* SVA/PASID are not supported now, keep PSCID at 0. */
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, 0);
+
+ ret = riscv_iommu_msi_table_alloc(s2_parent, iommu, info);
+ if (ret)
+ return ret;
+
+ bond = kzalloc_obj(*bond);
+ if (!bond)
+ return -ENOMEM;
+ bond->dev = dev;
+
+ flags = riscv_iommu_msi_tables_lock(old, &s2_parent->domain);
+ if (!riscv_iommu_can_attach_paging_domain(&s2_parent->domain, dev, old)) {
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+ kfree(bond);
+ return -EBUSY;
+ }
+
+ /* Keep an active guest MSI table published across the DC update. */
+ if (s2_parent->msi_table.nr_forwarded_irqs)
+ riscv_iommu_msi_table_set_dc(&s2_parent->msi_table, &dc, true);
+
+ info->dc = dc;
+ riscv_iommu_bond_link(s2_parent, bond);
+ riscv_iommu_iodir_update(dev, &info->dc);
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, s2_parent);
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+
+ return 0;
+}
static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
{
@@ -1947,6 +2031,7 @@ static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
}
static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .attach_dev = riscv_iommu_attach_dev_nested,
.free = riscv_iommu_domain_nested_free,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 09/12] iommu/riscv: Add riscv_iommu_attach_dev_nested
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Attach a device to a nested domain by combining the guest-provided
stage-1 context (tc, iosatp) with the host-owned second-stage context
in the device directory entry.
The device is bonded to the stage-2 parent domain so that it shares the
parent's invalidation and interrupt-remapping state: the guest MSI page
table is allocated when missing, and an active table's MSI configuration
is preserved across the device context update. Since the iommu core
passes the nested domain object as the old domain while the bond lives
on the parent, resolve the bond-holding domain before unlinking.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 89 ++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index e59a6a97589e..a484bf97c2f5 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -871,6 +871,13 @@ PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
#define iommu_domain_to_riscv(iommu_domain) \
container_of(iommu_domain, struct riscv_iommu_domain, domain)
+/*
+ * Resolve the domain holding the device bond: when the previously attached
+ * domain is a nested domain, the device is bonded to its stage-2 parent,
+ * which also owns the MSI table.
+ */
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old);
+
struct riscv_iommu_msi_table *riscv_iommu_msi_table_rcu(struct riscv_iommu_info *info)
{
struct riscv_iommu_domain *domain;
@@ -1593,6 +1600,8 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
unsigned long flags;
int ret;
+ old = riscv_iommu_old_bond_domain(old);
+
pt_iommu_riscv_64_hw_info(&domain->riscvpt, &pt_info);
if (domain->gscid) {
@@ -1787,6 +1796,8 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = 0;
@@ -1816,6 +1827,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = RISCV_IOMMU_DC_TC_V;
@@ -1938,8 +1951,79 @@ struct riscv_iommu_nested_domain {
u64 iosatp;
};
-#define to_riscv_iommu_nested_domain(domain) \
- container_of(domain, struct riscv_iommu_nested_domain, domain)
+#define to_riscv_iommu_nested_domain(domain_ptr) \
+ container_of(domain_ptr, struct riscv_iommu_nested_domain, domain)
+
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old)
+{
+ if (old && old->type == IOMMU_DOMAIN_NESTED)
+ return &to_riscv_iommu_nested_domain(old)->viommu->s2_parent->domain;
+ return old;
+}
+
+static int riscv_iommu_attach_dev_nested(struct iommu_domain *domain,
+ struct device *dev,
+ struct iommu_domain *old_domain)
+{
+ struct riscv_iommu_nested_domain *nested_domain =
+ to_riscv_iommu_nested_domain(domain);
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+ struct riscv_iommu_domain *s2_parent = nested_domain->viommu->s2_parent;
+ struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
+ struct pt_iommu_riscv_64_hw_info pt_info;
+ struct iommu_domain *old = riscv_iommu_old_bond_domain(old_domain);
+ struct riscv_iommu_bond *bond;
+ struct riscv_iommu_dc dc = {0};
+ unsigned long flags;
+ int ret;
+
+ if (nested_domain->viommu->iommu != iommu)
+ return -EINVAL;
+
+ if (!s2_parent->nest_parent)
+ return -EINVAL;
+
+ pt_iommu_riscv_64_hw_info(&s2_parent->riscvpt, &pt_info);
+
+ dc.tc = nested_domain->tc;
+ dc.fsc = nested_domain->iosatp;
+
+ dc.iohgatp = FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_MODE, pt_info.iohgatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_PPN, pt_info.ppn) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_GSCID, s2_parent->gscid);
+
+ /* SVA/PASID are not supported now, keep PSCID at 0. */
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, 0);
+
+ ret = riscv_iommu_msi_table_alloc(s2_parent, iommu, info);
+ if (ret)
+ return ret;
+
+ bond = kzalloc_obj(*bond);
+ if (!bond)
+ return -ENOMEM;
+ bond->dev = dev;
+
+ flags = riscv_iommu_msi_tables_lock(old, &s2_parent->domain);
+ if (!riscv_iommu_can_attach_paging_domain(&s2_parent->domain, dev, old)) {
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+ kfree(bond);
+ return -EBUSY;
+ }
+
+ /* Keep an active guest MSI table published across the DC update. */
+ if (s2_parent->msi_table.nr_forwarded_irqs)
+ riscv_iommu_msi_table_set_dc(&s2_parent->msi_table, &dc, true);
+
+ info->dc = dc;
+ riscv_iommu_bond_link(s2_parent, bond);
+ riscv_iommu_iodir_update(dev, &info->dc);
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, s2_parent);
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+
+ return 0;
+}
static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
{
@@ -1947,6 +2031,7 @@ static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
}
static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .attach_dev = riscv_iommu_attach_dev_nested,
.free = riscv_iommu_domain_nested_free,
};
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 09/12] iommu/riscv: Add riscv_iommu_attach_dev_nested
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
From: Wu Fei <wu.fei9@sanechips.com.cn>
Attach a device to a nested domain by combining the guest-provided
stage-1 context (tc, iosatp) with the host-owned second-stage context
in the device directory entry.
The device is bonded to the stage-2 parent domain so that it shares the
parent's invalidation and interrupt-remapping state: the guest MSI page
table is allocated when missing, and an active table's MSI configuration
is preserved across the device context update. Since the iommu core
passes the nested domain object as the old domain while the bond lives
on the parent, resolve the bond-holding domain before unlinking.
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 89 ++++++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index e59a6a97589e..a484bf97c2f5 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -871,6 +871,13 @@ PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
#define iommu_domain_to_riscv(iommu_domain) \
container_of(iommu_domain, struct riscv_iommu_domain, domain)
+/*
+ * Resolve the domain holding the device bond: when the previously attached
+ * domain is a nested domain, the device is bonded to its stage-2 parent,
+ * which also owns the MSI table.
+ */
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old);
+
struct riscv_iommu_msi_table *riscv_iommu_msi_table_rcu(struct riscv_iommu_info *info)
{
struct riscv_iommu_domain *domain;
@@ -1593,6 +1600,8 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
unsigned long flags;
int ret;
+ old = riscv_iommu_old_bond_domain(old);
+
pt_iommu_riscv_64_hw_info(&domain->riscvpt, &pt_info);
if (domain->gscid) {
@@ -1787,6 +1796,8 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = 0;
@@ -1816,6 +1827,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_dc dc = {0};
unsigned long flags;
+ old = riscv_iommu_old_bond_domain(old);
+
dc.fsc = RISCV_IOMMU_DC_FSC_MODE_BARE;
dc.tc = RISCV_IOMMU_DC_TC_V;
@@ -1938,8 +1951,79 @@ struct riscv_iommu_nested_domain {
u64 iosatp;
};
-#define to_riscv_iommu_nested_domain(domain) \
- container_of(domain, struct riscv_iommu_nested_domain, domain)
+#define to_riscv_iommu_nested_domain(domain_ptr) \
+ container_of(domain_ptr, struct riscv_iommu_nested_domain, domain)
+
+static struct iommu_domain *riscv_iommu_old_bond_domain(struct iommu_domain *old)
+{
+ if (old && old->type == IOMMU_DOMAIN_NESTED)
+ return &to_riscv_iommu_nested_domain(old)->viommu->s2_parent->domain;
+ return old;
+}
+
+static int riscv_iommu_attach_dev_nested(struct iommu_domain *domain,
+ struct device *dev,
+ struct iommu_domain *old_domain)
+{
+ struct riscv_iommu_nested_domain *nested_domain =
+ to_riscv_iommu_nested_domain(domain);
+ struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+ struct riscv_iommu_domain *s2_parent = nested_domain->viommu->s2_parent;
+ struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
+ struct pt_iommu_riscv_64_hw_info pt_info;
+ struct iommu_domain *old = riscv_iommu_old_bond_domain(old_domain);
+ struct riscv_iommu_bond *bond;
+ struct riscv_iommu_dc dc = {0};
+ unsigned long flags;
+ int ret;
+
+ if (nested_domain->viommu->iommu != iommu)
+ return -EINVAL;
+
+ if (!s2_parent->nest_parent)
+ return -EINVAL;
+
+ pt_iommu_riscv_64_hw_info(&s2_parent->riscvpt, &pt_info);
+
+ dc.tc = nested_domain->tc;
+ dc.fsc = nested_domain->iosatp;
+
+ dc.iohgatp = FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_MODE, pt_info.iohgatp_mode) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_PPN, pt_info.ppn) |
+ FIELD_PREP(RISCV_IOMMU_DC_IOHGATP_GSCID, s2_parent->gscid);
+
+ /* SVA/PASID are not supported now, keep PSCID at 0. */
+ dc.ta = FIELD_PREP(RISCV_IOMMU_DC_TA_PSCID, 0);
+
+ ret = riscv_iommu_msi_table_alloc(s2_parent, iommu, info);
+ if (ret)
+ return ret;
+
+ bond = kzalloc_obj(*bond);
+ if (!bond)
+ return -ENOMEM;
+ bond->dev = dev;
+
+ flags = riscv_iommu_msi_tables_lock(old, &s2_parent->domain);
+ if (!riscv_iommu_can_attach_paging_domain(&s2_parent->domain, dev, old)) {
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+ kfree(bond);
+ return -EBUSY;
+ }
+
+ /* Keep an active guest MSI table published across the DC update. */
+ if (s2_parent->msi_table.nr_forwarded_irqs)
+ riscv_iommu_msi_table_set_dc(&s2_parent->msi_table, &dc, true);
+
+ info->dc = dc;
+ riscv_iommu_bond_link(s2_parent, bond);
+ riscv_iommu_iodir_update(dev, &info->dc);
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, s2_parent);
+ riscv_iommu_msi_tables_unlock(old, &s2_parent->domain, flags);
+
+ return 0;
+}
static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
{
@@ -1947,6 +2031,7 @@ static void riscv_iommu_domain_nested_free(struct iommu_domain *domain)
}
static const struct iommu_domain_ops riscv_iommu_nested_ops = {
+ .attach_dev = riscv_iommu_attach_dev_nested,
.free = riscv_iommu_domain_nested_free,
};
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 10/12] RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass required the AIA to be in HWACCEL mode, while the KVM
default is AUTO, which publishes an IMSIC VS-file whenever one is
available and only falls back to the SW-file when the host has none
left. Rejecting AUTO leaves every assigned device on host MSI delivery,
which cannot work for a device attached to a nested domain because its
stage-1 page tables belong to the guest, so the device keeps the host
MSI address composed at vector activation and its MSIs fault in the
guest stage-1.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 37e27f28dc62..010f9a90f107 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -981,10 +981,13 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* MSI-X because pci_write_msi_msg() masks an MSI-X vector around the
* update, which conventional MSI cannot provide.
*/
- if (kvm->arch.aia.mode != KVM_DEV_RISCV_AIA_MODE_HWACCEL ||
- !imsic_irqfd_is_msix(irqfd))
+ if (!imsic_irqfd_is_msix(irqfd))
return -EOPNOTSUPP;
+ /*
+ * The IOMMU writes MSIs straight into the VS-file, so bypass is
+ * gated by the hardware backing checks below, not the AIA mode.
+ */
if (!imsic_targets_valid(&kvm->arch.aia)) {
pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
return -EOPNOTSUPP;
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 10/12] RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass required the AIA to be in HWACCEL mode, while the KVM
default is AUTO, which publishes an IMSIC VS-file whenever one is
available and only falls back to the SW-file when the host has none
left. Rejecting AUTO leaves every assigned device on host MSI delivery,
which cannot work for a device attached to a nested domain because its
stage-1 page tables belong to the guest, so the device keeps the host
MSI address composed at vector activation and its MSIs fault in the
guest stage-1.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 37e27f28dc62..010f9a90f107 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -981,10 +981,13 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* MSI-X because pci_write_msi_msg() masks an MSI-X vector around the
* update, which conventional MSI cannot provide.
*/
- if (kvm->arch.aia.mode != KVM_DEV_RISCV_AIA_MODE_HWACCEL ||
- !imsic_irqfd_is_msix(irqfd))
+ if (!imsic_irqfd_is_msix(irqfd))
return -EOPNOTSUPP;
+ /*
+ * The IOMMU writes MSIs straight into the VS-file, so bypass is
+ * gated by the hardware backing checks below, not the AIA mode.
+ */
if (!imsic_targets_valid(&kvm->arch.aia)) {
pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
return -EOPNOTSUPP;
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 10/12] RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass required the AIA to be in HWACCEL mode, while the KVM
default is AUTO, which publishes an IMSIC VS-file whenever one is
available and only falls back to the SW-file when the host has none
left. Rejecting AUTO leaves every assigned device on host MSI delivery,
which cannot work for a device attached to a nested domain because its
stage-1 page tables belong to the guest, so the device keeps the host
MSI address composed at vector activation and its MSIs fault in the
guest stage-1.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 37e27f28dc62..010f9a90f107 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -981,10 +981,13 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* MSI-X because pci_write_msi_msg() masks an MSI-X vector around the
* update, which conventional MSI cannot provide.
*/
- if (kvm->arch.aia.mode != KVM_DEV_RISCV_AIA_MODE_HWACCEL ||
- !imsic_irqfd_is_msix(irqfd))
+ if (!imsic_irqfd_is_msix(irqfd))
return -EOPNOTSUPP;
+ /*
+ * The IOMMU writes MSIs straight into the VS-file, so bypass is
+ * gated by the hardware backing checks below, not the AIA mode.
+ */
if (!imsic_targets_valid(&kvm->arch.aia)) {
pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
return -EOPNOTSUPP;
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 11/12] iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
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@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@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
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 11/12] iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
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@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@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
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 11/12] iommu/riscv: Accept unpublished interrupt files in IRQ forwarding
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
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@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@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
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 12/12] RISC-V: KVM: Forward MSIs for guests with a vIOMMU
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 6:52 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass names the target vCPU by matching the device MSI address
against the guest IMSIC addresses of the vCPUs, so it only works when the
guest programs the device with those addresses directly. A guest with a
vIOMMU programs an address from its own IOVA space instead, which the
IOMMU resolves through the guest stage-1 page tables before it looks the
address up in the MSI table, so no vCPU can be named at that point.
Falling back to host delivery is not an option either. The device would
keep the host IMSIC address composed at vector activation, and the
guest's own stage-1 page tables do not map it, so its MSIs fault instead
of reaching an interrupt file.
The MSI table already holds the VM-wide IMSIC topology, so the hardware
finds the target vCPU by itself once the address is translated. Forward
such IRQs for the whole VM and program the device with the MSI message
composed by the guest.
Such a producer can reach any vCPU of the VM, so unforward it whenever a
VS-file is released and retarget it whenever a vCPU migrates.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 67 +++++++++++++++++++++++++++-----------
include/linux/kvm_irqfd.h | 2 ++
2 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 010f9a90f107..862db53c66a5 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -758,7 +758,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
lockdep_assert_held(&kvm->irqfds.lock);
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
return 0;
irq_data = irq_get_irq_data(irqfd->producer->irq);
@@ -775,6 +775,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
return ret;
irqfd->irq_bypass_vcpu = NULL;
+ irqfd->irq_bypass_nested = false;
return 0;
}
@@ -788,7 +789,11 @@ static int imsic_vcpu_unforward(struct kvm_vcpu *vcpu)
guard(spinlock_irqsave)(&kvm->irqfds.lock);
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (irqfd->irq_bypass_vcpu != vcpu)
+ /*
+ * Nested-forwarded producers can target any vCPU of the VM,
+ * unforward them on any VS-file release.
+ */
+ if (!irqfd->irq_bypass_nested && irqfd->irq_bypass_vcpu != vcpu)
continue;
ret = kvm_riscv_irqfd_unforward(irqfd);
@@ -902,7 +907,7 @@ static int imsic_vsfile_target_replace(struct kvm_vcpu *vcpu, phys_addr_t vsfile
vcpu_info.target.type = RISCV_IOMMU_IR_TARGET_IMSIC;
vcpu_info.target.hpa = vsfile_pa;
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
continue;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
@@ -931,16 +936,10 @@ static bool imsic_targets_valid(struct kvm_aia *aia)
return true;
}
-static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm,
- struct kvm_kernel_irq_routing_entry *irq_entry)
+static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm, gpa_t target)
{
struct kvm_vcpu *vcpu;
unsigned long index;
- gpa_t target;
-
- target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
- if (target & (IMSIC_MMIO_PAGE_SZ - 1))
- return NULL;
kvm_for_each_vcpu(index, vcpu, kvm) {
if (target == vcpu->arch.aia_context.imsic_addr)
@@ -968,6 +967,9 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
.data = irq_entry->msi.data,
};
struct kvm_vcpu *vcpu;
+ gpa_t target, gpa;
+ unsigned int i;
+ bool nested = false;
int ret;
lockdep_assert_held(&kvm->irqfds.lock);
@@ -988,24 +990,51 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* The IOMMU writes MSIs straight into the VS-file, so bypass is
* gated by the hardware backing checks below, not the AIA mode.
*/
- if (!imsic_targets_valid(&kvm->arch.aia)) {
- pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
+ if (target & (IMSIC_MMIO_PAGE_SZ - 1))
return -EOPNOTSUPP;
- }
- /* Leave guest messages that name no vIMSIC to software injection. */
- vcpu = imsic_irqfd_route_vcpu(kvm, irq_entry);
- if (!vcpu)
- return -EOPNOTSUPP;
+ vcpu = imsic_irqfd_route_vcpu(kvm, target);
+ if (vcpu) {
+ /*
+ * The guest programmed a guest interrupt file address, so every
+ * vCPU of the VM must be hardware backed for the complete
+ * topology to be installable.
+ */
+ if (!imsic_targets_valid(aia)) {
+ pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ return -EOPNOTSUPP;
+ }
+ gpa = vcpu->arch.aia_context.imsic_addr;
+ } else {
+ /*
+ * A vIOMMU guest programs the device with an IOVA-space MSI
+ * address, which names no vCPU until the IOMMU translates it
+ * and resolves the target through its MSI table of published
+ * VS-files. Forward such IRQs for the whole VM. The address
+ * pattern comes from any published target, as only the
+ * mask-covered index bits differ between them.
+ */
+ for (i = 0; i < aia->nr_targets; i++)
+ if (aia->targets[i].type == RISCV_IOMMU_IR_TARGET_IMSIC)
+ break;
+ if (i == aia->nr_targets)
+ return -EOPNOTSUPP;
+ gpa = aia->targets[i].gpa;
+ nested = true;
+ }
- vcpu_info.msi_addr_pattern = (vcpu->arch.aia_context.imsic_addr >> IMSIC_MMIO_PAGE_SHIFT) &
+ vcpu_info.msi_addr_pattern = (gpa >> IMSIC_MMIO_PAGE_SHIFT) &
~vcpu_info.msi_addr_mask;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
if (ret)
return ret;
pci_write_msi_msg(irqfd->producer->irq, &msg);
- irqfd->irq_bypass_vcpu = vcpu;
+ if (nested)
+ irqfd->irq_bypass_nested = true;
+ else
+ irqfd->irq_bypass_vcpu = vcpu;
return 0;
}
diff --git a/include/linux/kvm_irqfd.h b/include/linux/kvm_irqfd.h
index ef8c134ded8a..39c73157e086 100644
--- a/include/linux/kvm_irqfd.h
+++ b/include/linux/kvm_irqfd.h
@@ -60,6 +60,8 @@ struct kvm_kernel_irqfd {
struct irq_bypass_producer *producer;
struct kvm_vcpu *irq_bypass_vcpu;
+ /* Forwarded to any vCPU of the VM (guest-controlled MSI target) */
+ bool irq_bypass_nested;
struct list_head vcpu_list;
void *irq_bypass_data;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 12/12] RISC-V: KVM: Forward MSIs for guests with a vIOMMU
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass names the target vCPU by matching the device MSI address
against the guest IMSIC addresses of the vCPUs, so it only works when the
guest programs the device with those addresses directly. A guest with a
vIOMMU programs an address from its own IOVA space instead, which the
IOMMU resolves through the guest stage-1 page tables before it looks the
address up in the MSI table, so no vCPU can be named at that point.
Falling back to host delivery is not an option either. The device would
keep the host IMSIC address composed at vector activation, and the
guest's own stage-1 page tables do not map it, so its MSIs fault instead
of reaching an interrupt file.
The MSI table already holds the VM-wide IMSIC topology, so the hardware
finds the target vCPU by itself once the address is translated. Forward
such IRQs for the whole VM and program the device with the MSI message
composed by the guest.
Such a producer can reach any vCPU of the VM, so unforward it whenever a
VS-file is released and retarget it whenever a vCPU migrates.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 67 +++++++++++++++++++++++++++-----------
include/linux/kvm_irqfd.h | 2 ++
2 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 010f9a90f107..862db53c66a5 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -758,7 +758,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
lockdep_assert_held(&kvm->irqfds.lock);
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
return 0;
irq_data = irq_get_irq_data(irqfd->producer->irq);
@@ -775,6 +775,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
return ret;
irqfd->irq_bypass_vcpu = NULL;
+ irqfd->irq_bypass_nested = false;
return 0;
}
@@ -788,7 +789,11 @@ static int imsic_vcpu_unforward(struct kvm_vcpu *vcpu)
guard(spinlock_irqsave)(&kvm->irqfds.lock);
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (irqfd->irq_bypass_vcpu != vcpu)
+ /*
+ * Nested-forwarded producers can target any vCPU of the VM,
+ * unforward them on any VS-file release.
+ */
+ if (!irqfd->irq_bypass_nested && irqfd->irq_bypass_vcpu != vcpu)
continue;
ret = kvm_riscv_irqfd_unforward(irqfd);
@@ -902,7 +907,7 @@ static int imsic_vsfile_target_replace(struct kvm_vcpu *vcpu, phys_addr_t vsfile
vcpu_info.target.type = RISCV_IOMMU_IR_TARGET_IMSIC;
vcpu_info.target.hpa = vsfile_pa;
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
continue;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
@@ -931,16 +936,10 @@ static bool imsic_targets_valid(struct kvm_aia *aia)
return true;
}
-static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm,
- struct kvm_kernel_irq_routing_entry *irq_entry)
+static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm, gpa_t target)
{
struct kvm_vcpu *vcpu;
unsigned long index;
- gpa_t target;
-
- target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
- if (target & (IMSIC_MMIO_PAGE_SZ - 1))
- return NULL;
kvm_for_each_vcpu(index, vcpu, kvm) {
if (target == vcpu->arch.aia_context.imsic_addr)
@@ -968,6 +967,9 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
.data = irq_entry->msi.data,
};
struct kvm_vcpu *vcpu;
+ gpa_t target, gpa;
+ unsigned int i;
+ bool nested = false;
int ret;
lockdep_assert_held(&kvm->irqfds.lock);
@@ -988,24 +990,51 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* The IOMMU writes MSIs straight into the VS-file, so bypass is
* gated by the hardware backing checks below, not the AIA mode.
*/
- if (!imsic_targets_valid(&kvm->arch.aia)) {
- pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
+ if (target & (IMSIC_MMIO_PAGE_SZ - 1))
return -EOPNOTSUPP;
- }
- /* Leave guest messages that name no vIMSIC to software injection. */
- vcpu = imsic_irqfd_route_vcpu(kvm, irq_entry);
- if (!vcpu)
- return -EOPNOTSUPP;
+ vcpu = imsic_irqfd_route_vcpu(kvm, target);
+ if (vcpu) {
+ /*
+ * The guest programmed a guest interrupt file address, so every
+ * vCPU of the VM must be hardware backed for the complete
+ * topology to be installable.
+ */
+ if (!imsic_targets_valid(aia)) {
+ pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ return -EOPNOTSUPP;
+ }
+ gpa = vcpu->arch.aia_context.imsic_addr;
+ } else {
+ /*
+ * A vIOMMU guest programs the device with an IOVA-space MSI
+ * address, which names no vCPU until the IOMMU translates it
+ * and resolves the target through its MSI table of published
+ * VS-files. Forward such IRQs for the whole VM. The address
+ * pattern comes from any published target, as only the
+ * mask-covered index bits differ between them.
+ */
+ for (i = 0; i < aia->nr_targets; i++)
+ if (aia->targets[i].type == RISCV_IOMMU_IR_TARGET_IMSIC)
+ break;
+ if (i == aia->nr_targets)
+ return -EOPNOTSUPP;
+ gpa = aia->targets[i].gpa;
+ nested = true;
+ }
- vcpu_info.msi_addr_pattern = (vcpu->arch.aia_context.imsic_addr >> IMSIC_MMIO_PAGE_SHIFT) &
+ vcpu_info.msi_addr_pattern = (gpa >> IMSIC_MMIO_PAGE_SHIFT) &
~vcpu_info.msi_addr_mask;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
if (ret)
return ret;
pci_write_msi_msg(irqfd->producer->irq, &msg);
- irqfd->irq_bypass_vcpu = vcpu;
+ if (nested)
+ irqfd->irq_bypass_nested = true;
+ else
+ irqfd->irq_bypass_vcpu = vcpu;
return 0;
}
diff --git a/include/linux/kvm_irqfd.h b/include/linux/kvm_irqfd.h
index ef8c134ded8a..39c73157e086 100644
--- a/include/linux/kvm_irqfd.h
+++ b/include/linux/kvm_irqfd.h
@@ -60,6 +60,8 @@ struct kvm_kernel_irqfd {
struct irq_bypass_producer *producer;
struct kvm_vcpu *irq_bypass_vcpu;
+ /* Forwarded to any vCPU of the VM (guest-controlled MSI target) */
+ bool irq_bypass_nested;
struct list_head vcpu_list;
void *irq_bypass_data;
};
--
2.53.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* [RFC PATCH 12/12] RISC-V: KVM: Forward MSIs for guests with a vIOMMU
@ 2026-10-15 6:52 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-15 6:52 UTC (permalink / raw)
To: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu
Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Jason Gunthorpe,
Kevin Tian, Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye,
Gong Shuai, Gong Shuai
The IRQ bypass names the target vCPU by matching the device MSI address
against the guest IMSIC addresses of the vCPUs, so it only works when the
guest programs the device with those addresses directly. A guest with a
vIOMMU programs an address from its own IOVA space instead, which the
IOMMU resolves through the guest stage-1 page tables before it looks the
address up in the MSI table, so no vCPU can be named at that point.
Falling back to host delivery is not an option either. The device would
keep the host IMSIC address composed at vector activation, and the
guest's own stage-1 page tables do not map it, so its MSIs fault instead
of reaching an interrupt file.
The MSI table already holds the VM-wide IMSIC topology, so the hardware
finds the target vCPU by itself once the address is translated. Forward
such IRQs for the whole VM and program the device with the MSI message
composed by the guest.
Such a producer can reach any vCPU of the VM, so unforward it whenever a
VS-file is released and retarget it whenever a vCPU migrates.
Co-developed-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
---
arch/riscv/kvm/aia_imsic.c | 67 +++++++++++++++++++++++++++-----------
include/linux/kvm_irqfd.h | 2 ++
2 files changed, 50 insertions(+), 19 deletions(-)
diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 010f9a90f107..862db53c66a5 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -758,7 +758,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
lockdep_assert_held(&kvm->irqfds.lock);
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
return 0;
irq_data = irq_get_irq_data(irqfd->producer->irq);
@@ -775,6 +775,7 @@ int kvm_riscv_irqfd_unforward(struct kvm_kernel_irqfd *irqfd)
return ret;
irqfd->irq_bypass_vcpu = NULL;
+ irqfd->irq_bypass_nested = false;
return 0;
}
@@ -788,7 +789,11 @@ static int imsic_vcpu_unforward(struct kvm_vcpu *vcpu)
guard(spinlock_irqsave)(&kvm->irqfds.lock);
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (irqfd->irq_bypass_vcpu != vcpu)
+ /*
+ * Nested-forwarded producers can target any vCPU of the VM,
+ * unforward them on any VS-file release.
+ */
+ if (!irqfd->irq_bypass_nested && irqfd->irq_bypass_vcpu != vcpu)
continue;
ret = kvm_riscv_irqfd_unforward(irqfd);
@@ -902,7 +907,7 @@ static int imsic_vsfile_target_replace(struct kvm_vcpu *vcpu, phys_addr_t vsfile
vcpu_info.target.type = RISCV_IOMMU_IR_TARGET_IMSIC;
vcpu_info.target.hpa = vsfile_pa;
list_for_each_entry(irqfd, &kvm->irqfds.items, list) {
- if (!irqfd->irq_bypass_vcpu)
+ if (!irqfd->irq_bypass_vcpu && !irqfd->irq_bypass_nested)
continue;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
@@ -931,16 +936,10 @@ static bool imsic_targets_valid(struct kvm_aia *aia)
return true;
}
-static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm,
- struct kvm_kernel_irq_routing_entry *irq_entry)
+static struct kvm_vcpu *imsic_irqfd_route_vcpu(struct kvm *kvm, gpa_t target)
{
struct kvm_vcpu *vcpu;
unsigned long index;
- gpa_t target;
-
- target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
- if (target & (IMSIC_MMIO_PAGE_SZ - 1))
- return NULL;
kvm_for_each_vcpu(index, vcpu, kvm) {
if (target == vcpu->arch.aia_context.imsic_addr)
@@ -968,6 +967,9 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
.data = irq_entry->msi.data,
};
struct kvm_vcpu *vcpu;
+ gpa_t target, gpa;
+ unsigned int i;
+ bool nested = false;
int ret;
lockdep_assert_held(&kvm->irqfds.lock);
@@ -988,24 +990,51 @@ static int imsic_irqfd_forward(struct kvm_kernel_irqfd *irqfd,
* The IOMMU writes MSIs straight into the VS-file, so bypass is
* gated by the hardware backing checks below, not the AIA mode.
*/
- if (!imsic_targets_valid(&kvm->arch.aia)) {
- pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ target = ((gpa_t)irq_entry->msi.address_hi << 32) | irq_entry->msi.address_lo;
+ if (target & (IMSIC_MMIO_PAGE_SZ - 1))
return -EOPNOTSUPP;
- }
- /* Leave guest messages that name no vIMSIC to software injection. */
- vcpu = imsic_irqfd_route_vcpu(kvm, irq_entry);
- if (!vcpu)
- return -EOPNOTSUPP;
+ vcpu = imsic_irqfd_route_vcpu(kvm, target);
+ if (vcpu) {
+ /*
+ * The guest programmed a guest interrupt file address, so every
+ * vCPU of the VM must be hardware backed for the complete
+ * topology to be installable.
+ */
+ if (!imsic_targets_valid(aia)) {
+ pr_debug("KVM: IMSIC IRQ bypass requires all VS-files\n");
+ return -EOPNOTSUPP;
+ }
+ gpa = vcpu->arch.aia_context.imsic_addr;
+ } else {
+ /*
+ * A vIOMMU guest programs the device with an IOVA-space MSI
+ * address, which names no vCPU until the IOMMU translates it
+ * and resolves the target through its MSI table of published
+ * VS-files. Forward such IRQs for the whole VM. The address
+ * pattern comes from any published target, as only the
+ * mask-covered index bits differ between them.
+ */
+ for (i = 0; i < aia->nr_targets; i++)
+ if (aia->targets[i].type == RISCV_IOMMU_IR_TARGET_IMSIC)
+ break;
+ if (i == aia->nr_targets)
+ return -EOPNOTSUPP;
+ gpa = aia->targets[i].gpa;
+ nested = true;
+ }
- vcpu_info.msi_addr_pattern = (vcpu->arch.aia_context.imsic_addr >> IMSIC_MMIO_PAGE_SHIFT) &
+ vcpu_info.msi_addr_pattern = (gpa >> IMSIC_MMIO_PAGE_SHIFT) &
~vcpu_info.msi_addr_mask;
ret = irq_set_vcpu_affinity(irqfd->producer->irq, &vcpu_info);
if (ret)
return ret;
pci_write_msi_msg(irqfd->producer->irq, &msg);
- irqfd->irq_bypass_vcpu = vcpu;
+ if (nested)
+ irqfd->irq_bypass_nested = true;
+ else
+ irqfd->irq_bypass_vcpu = vcpu;
return 0;
}
diff --git a/include/linux/kvm_irqfd.h b/include/linux/kvm_irqfd.h
index ef8c134ded8a..39c73157e086 100644
--- a/include/linux/kvm_irqfd.h
+++ b/include/linux/kvm_irqfd.h
@@ -60,6 +60,8 @@ struct kvm_kernel_irqfd {
struct irq_bypass_producer *producer;
struct kvm_vcpu *irq_bypass_vcpu;
+ /* Forwarded to any vCPU of the VM (guest-controlled MSI target) */
+ bool irq_bypass_nested;
struct list_head vcpu_list;
void *irq_bypass_data;
};
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 23:54 ` Jason Gunthorpe
-1 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:54 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:22PM +0800, Gong Shuai wrote:
> +/**
> + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> + * (IOMMU_HWPT_DATA_RISCV_S1)
> + * @tc: Guest device context translation control
> + * @iosatp: Guest device context stage-1 root page table pointer
> + */
> +struct iommu_hwpt_riscv {
> + __aligned_u64 tc;
> + __aligned_u64 iosatp;
> +};
Like the others you need a spec reference explaining exactly what
these fields are.
Usually it should be the entire guest structure, is it only 16 bytes?
But this looks broadly right otherwise
Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-15 23:54 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:54 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:22PM +0800, Gong Shuai wrote:
> +/**
> + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> + * (IOMMU_HWPT_DATA_RISCV_S1)
> + * @tc: Guest device context translation control
> + * @iosatp: Guest device context stage-1 root page table pointer
> + */
> +struct iommu_hwpt_riscv {
> + __aligned_u64 tc;
> + __aligned_u64 iosatp;
> +};
Like the others you need a spec reference explaining exactly what
these fields are.
Usually it should be the entire guest structure, is it only 16 bytes?
But this looks broadly right otherwise
Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-15 23:54 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:54 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:22PM +0800, Gong Shuai wrote:
> +/**
> + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> + * (IOMMU_HWPT_DATA_RISCV_S1)
> + * @tc: Guest device context translation control
> + * @iosatp: Guest device context stage-1 root page table pointer
> + */
> +struct iommu_hwpt_riscv {
> + __aligned_u64 tc;
> + __aligned_u64 iosatp;
> +};
Like the others you need a spec reference explaining exactly what
these fields are.
Usually it should be the entire guest structure, is it only 16 bytes?
But this looks broadly right otherwise
Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-15 23:55 ` Jason Gunthorpe
-1 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:55 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:27PM +0800, Gong Shuai wrote:
> From: Wu Fei <wu.fei9@sanechips.com.cn>
>
> Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
> reports the RISC-V IOMMU Capabilities register through
> IOMMU_GET_HW_INFO.
>
> Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
> Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
> ---
> include/uapi/linux/iommufd.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
> index 36e6187bb34b..acfef0338cd1 100644
> --- a/include/uapi/linux/iommufd.h
> +++ b/include/uapi/linux/iommufd.h
> @@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
> __aligned_u64 efr2;
> };
>
> +/**
> + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> + * @capabilities: Value of RISC-V IOMMU Capabilities register
> + */
> +struct iommu_hw_info_riscv {
> + __u64 capabilities;
> +};
> +
Same here, spec reference.
Also be careful to always use __aligned_u64, check all the patches.
JAson
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-15 23:55 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:55 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:27PM +0800, Gong Shuai wrote:
> From: Wu Fei <wu.fei9@sanechips.com.cn>
>
> Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
> reports the RISC-V IOMMU Capabilities register through
> IOMMU_GET_HW_INFO.
>
> Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
> Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
> ---
> include/uapi/linux/iommufd.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
> index 36e6187bb34b..acfef0338cd1 100644
> --- a/include/uapi/linux/iommufd.h
> +++ b/include/uapi/linux/iommufd.h
> @@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
> __aligned_u64 efr2;
> };
>
> +/**
> + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> + * @capabilities: Value of RISC-V IOMMU Capabilities register
> + */
> +struct iommu_hw_info_riscv {
> + __u64 capabilities;
> +};
> +
Same here, spec reference.
Also be careful to always use __aligned_u64, check all the patches.
JAson
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-15 23:55 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-15 23:55 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:27PM +0800, Gong Shuai wrote:
> From: Wu Fei <wu.fei9@sanechips.com.cn>
>
> Add IOMMU_HW_INFO_TYPE_RISCV and struct iommu_hw_info_riscv, which
> reports the RISC-V IOMMU Capabilities register through
> IOMMU_GET_HW_INFO.
>
> Signed-off-by: Wu Fei <wu.fei9@sanechips.com.cn>
> Signed-off-by: Gong Shuai <gong.shuai@sanechips.com.cn>
> ---
> include/uapi/linux/iommufd.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
> index 36e6187bb34b..acfef0338cd1 100644
> --- a/include/uapi/linux/iommufd.h
> +++ b/include/uapi/linux/iommufd.h
> @@ -716,6 +716,14 @@ struct iommu_hw_info_amd {
> __aligned_u64 efr2;
> };
>
> +/**
> + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> + * @capabilities: Value of RISC-V IOMMU Capabilities register
> + */
> +struct iommu_hw_info_riscv {
> + __u64 capabilities;
> +};
> +
Same here, spec reference.
Also be careful to always use __aligned_u64, check all the patches.
JAson
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
2026-10-15 6:52 ` Gong Shuai
(?)
@ 2026-10-16 0:00 ` Jason Gunthorpe
-1 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 0:00 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:20PM +0800, Gong Shuai wrote:
> Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> with its own vIOMMU can own the first stage of a device context while the
> host keeps the second stage, and add the interrupt support. This is an RFC
> and comments on the design are welcome.
The iommufd parts looked reasonable to me
I feel some mild skepticism about all the MSI parts, it would be good
to get more of the interrupt stuff actually landed before posting this
again.
Please try harder on the commit messages, do not use AI to write them
like this. They need to explain why this patch exists and what problem
it is solving not some inscrutible description of what it contains.
You'll need other riscv people to help you with reviewing it.
Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 0:00 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 0:00 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:20PM +0800, Gong Shuai wrote:
> Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> with its own vIOMMU can own the first stage of a device context while the
> host keeps the second stage, and add the interrupt support. This is an RFC
> and comments on the design are welcome.
The iommufd parts looked reasonable to me
I feel some mild skepticism about all the MSI parts, it would be good
to get more of the interrupt stuff actually landed before posting this
again.
Please try harder on the commit messages, do not use AI to write them
like this. They need to explain why this patch exists and what problem
it is solving not some inscrutible description of what it contains.
You'll need other riscv people to help you with reviewing it.
Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 0:00 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 0:00 UTC (permalink / raw)
To: Gong Shuai
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, iommu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Tomasz Jeznach, Joerg Roedel (AMD), Will Deacon,
Robin Murphy, Paolo Bonzini, Sean Christopherson, Kevin Tian,
Andrew Jones, Fangyu Yu, Wu Fei, Zhao Qingye, Gong Shuai
On Thu, Oct 15, 2026 at 02:52:20PM +0800, Gong Shuai wrote:
> Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> with its own vIOMMU can own the first stage of a device context while the
> host keeps the second stage, and add the interrupt support. This is an RFC
> and comments on the design are welcome.
The iommufd parts looked reasonable to me
I feel some mild skepticism about all the MSI parts, it would be good
to get more of the interrupt stuff actually landed before posting this
again.
Please try harder on the commit messages, do not use AI to write them
like this. They need to explain why this patch exists and what problem
it is solving not some inscrutible description of what it contains.
You'll need other riscv people to help you with reviewing it.
Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
2026-10-15 23:54 ` Jason Gunthorpe
(?)
@ 2026-10-16 7:30 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:30 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thank you for your review.
> > +/**
> > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > + * @tc: Guest device context translation control
> > + * @iosatp: Guest device context stage-1 root page table pointer
> > + */
> > +struct iommu_hwpt_riscv {
> > + __aligned_u64 tc;
> > + __aligned_u64 iosatp;
> > +};
>
> Like the others you need a spec reference explaining exactly what
> these fields are.
I'll add references to the device-context sections of the RISC-V IOMMU
specification ("Leaf DDT entry", "Device-context fields", "Translation
control (tc)", and "First-Stage context (fsc)"), and I'll also include
detailed field information, as ARM does.
Also, I'll rename the field from iosatp to fsc. It holds iosatp when
PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
two share the same layout, so the name should cover both interpretations
and the uAPI won't need to change when Process-Directory-Table (PDT)
support is added.
>
> Usually it should be the entire guest structure, is it only 16 bytes?
The RISC-V device-context is 32 bytes in base format and 64 bytes in
extended format, but it is not entirely guest-owned in a nested setup:
iohgatp, ta and the extended-format MSI fields are configured by the host.
The guest-owned part is therefore exactly tc and fsc fields, so 16 bytes
is all we take.
Thanks,
Shuai
>
> But this looks broadly right otherwise
>
> Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-16 7:30 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:30 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thank you for your review.
> > +/**
> > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > + * @tc: Guest device context translation control
> > + * @iosatp: Guest device context stage-1 root page table pointer
> > + */
> > +struct iommu_hwpt_riscv {
> > + __aligned_u64 tc;
> > + __aligned_u64 iosatp;
> > +};
>
> Like the others you need a spec reference explaining exactly what
> these fields are.
I'll add references to the device-context sections of the RISC-V IOMMU
specification ("Leaf DDT entry", "Device-context fields", "Translation
control (tc)", and "First-Stage context (fsc)"), and I'll also include
detailed field information, as ARM does.
Also, I'll rename the field from iosatp to fsc. It holds iosatp when
PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
two share the same layout, so the name should cover both interpretations
and the uAPI won't need to change when Process-Directory-Table (PDT)
support is added.
>
> Usually it should be the entire guest structure, is it only 16 bytes?
The RISC-V device-context is 32 bytes in base format and 64 bytes in
extended format, but it is not entirely guest-owned in a nested setup:
iohgatp, ta and the extended-format MSI fields are configured by the host.
The guest-owned part is therefore exactly tc and fsc fields, so 16 bytes
is all we take.
Thanks,
Shuai
>
> But this looks broadly right otherwise
>
> Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-16 7:30 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:30 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thank you for your review.
> > +/**
> > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > + * @tc: Guest device context translation control
> > + * @iosatp: Guest device context stage-1 root page table pointer
> > + */
> > +struct iommu_hwpt_riscv {
> > + __aligned_u64 tc;
> > + __aligned_u64 iosatp;
> > +};
>
> Like the others you need a spec reference explaining exactly what
> these fields are.
I'll add references to the device-context sections of the RISC-V IOMMU
specification ("Leaf DDT entry", "Device-context fields", "Translation
control (tc)", and "First-Stage context (fsc)"), and I'll also include
detailed field information, as ARM does.
Also, I'll rename the field from iosatp to fsc. It holds iosatp when
PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
two share the same layout, so the name should cover both interpretations
and the uAPI won't need to change when Process-Directory-Table (PDT)
support is added.
>
> Usually it should be the entire guest structure, is it only 16 bytes?
The RISC-V device-context is 32 bytes in base format and 64 bytes in
extended format, but it is not entirely guest-owned in a nested setup:
iohgatp, ta and the extended-format MSI fields are configured by the host.
The guest-owned part is therefore exactly tc and fsc fields, so 16 bytes
is all we take.
Thanks,
Shuai
>
> But this looks broadly right otherwise
>
> Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
2026-10-15 23:55 ` Jason Gunthorpe
(?)
@ 2026-10-16 7:43 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:43 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
> > +/**
> > + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> > + * @capabilities: Value of RISC-V IOMMU Capabilities register
> > + */
> > +struct iommu_hw_info_riscv {
> > + __u64 capabilities;
> > +};
> > +
>
> Same here, spec reference.
>
> Also be careful to always use __aligned_u64, check all the patches.
Will add the spec reference ("IOMMU capabilities (capabilities)") and
switch to __aligned_u64. I checked the uAPI structures touched by this
series, and this is the only place that used __u64.
Thanks,
Shuai
>
> JAson
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-16 7:43 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:43 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
> > +/**
> > + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> > + * @capabilities: Value of RISC-V IOMMU Capabilities register
> > + */
> > +struct iommu_hw_info_riscv {
> > + __u64 capabilities;
> > +};
> > +
>
> Same here, spec reference.
>
> Also be careful to always use __aligned_u64, check all the patches.
Will add the spec reference ("IOMMU capabilities (capabilities)") and
switch to __aligned_u64. I checked the uAPI structures touched by this
series, and this is the only place that used __u64.
Thanks,
Shuai
>
> JAson
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type
@ 2026-10-16 7:43 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 7:43 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
> > +/**
> > + * struct iommu_hw_info_riscv - RISC-V IOMMU device info
> > + * @capabilities: Value of RISC-V IOMMU Capabilities register
> > + */
> > +struct iommu_hw_info_riscv {
> > + __u64 capabilities;
> > +};
> > +
>
> Same here, spec reference.
>
> Also be careful to always use __aligned_u64, check all the patches.
Will add the spec reference ("IOMMU capabilities (capabilities)") and
switch to __aligned_u64. I checked the uAPI structures touched by this
series, and this is the only place that used __u64.
Thanks,
Shuai
>
> JAson
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
2026-10-16 0:00 ` Jason Gunthorpe
(?)
@ 2026-10-16 9:16 ` Gong Shuai
-1 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 9:16 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thanks for the review again.
> > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > with its own vIOMMU can own the first stage of a device context while the
> > host keeps the second stage, and add the interrupt support. This is an RFC
> > and comments on the design are welcome.
>
> The iommufd parts looked reasonable to me
>
> I feel some mild skepticism about all the MSI parts, it would be good
> to get more of the interrupt stuff actually landed before posting this
> again.
Agreed on the MSI parts. They are a working proof to exercise the
nested flow end to end, not a finished design. The reason they are
in this series at all is that the NVMe device we use for testing
depends on MSI interrupts. Without this support, DMA succeeds but
the MSIs fault, so the driver ends up polling for completions after
timeouts.
We will keep following the irqbypass groundwork as it evolves, and
continue this work once it has landed.
>
> Please try harder on the commit messages, do not use AI to write them
> like this. They need to explain why this patch exists and what problem
> it is solving not some inscrutible description of what it contains.
I will rewrite all of them.
Thanks,
Shuai
>
> You'll need other riscv people to help you with reviewing it.
>
> Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 9:16 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 9:16 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thanks for the review again.
> > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > with its own vIOMMU can own the first stage of a device context while the
> > host keeps the second stage, and add the interrupt support. This is an RFC
> > and comments on the design are welcome.
>
> The iommufd parts looked reasonable to me
>
> I feel some mild skepticism about all the MSI parts, it would be good
> to get more of the interrupt stuff actually landed before posting this
> again.
Agreed on the MSI parts. They are a working proof to exercise the
nested flow end to end, not a finished design. The reason they are
in this series at all is that the NVMe device we use for testing
depends on MSI interrupts. Without this support, DMA succeeds but
the MSIs fault, so the driver ends up polling for completions after
timeouts.
We will keep following the irqbypass groundwork as it evolves, and
continue this work once it has landed.
>
> Please try harder on the commit messages, do not use AI to write them
> like this. They need to explain why this patch exists and what problem
> it is solving not some inscrutible description of what it contains.
I will rewrite all of them.
Thanks,
Shuai
>
> You'll need other riscv people to help you with reviewing it.
>
> Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 9:16 ` Gong Shuai
0 siblings, 0 replies; 63+ messages in thread
From: Gong Shuai @ 2026-10-16 9:16 UTC (permalink / raw)
To: jgg
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gong.shuai,
gsh517025, iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
Hi Jason,
Thanks for the review again.
> > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > with its own vIOMMU can own the first stage of a device context while the
> > host keeps the second stage, and add the interrupt support. This is an RFC
> > and comments on the design are welcome.
>
> The iommufd parts looked reasonable to me
>
> I feel some mild skepticism about all the MSI parts, it would be good
> to get more of the interrupt stuff actually landed before posting this
> again.
Agreed on the MSI parts. They are a working proof to exercise the
nested flow end to end, not a finished design. The reason they are
in this series at all is that the NVMe device we use for testing
depends on MSI interrupts. Without this support, DMA succeeds but
the MSIs fault, so the driver ends up polling for completions after
timeouts.
We will keep following the irqbypass groundwork as it evolves, and
continue this work once it has landed.
>
> Please try harder on the commit messages, do not use AI to write them
> like this. They need to explain why this patch exists and what problem
> it is solving not some inscrutible description of what it contains.
I will rewrite all of them.
Thanks,
Shuai
>
> You'll need other riscv people to help you with reviewing it.
>
> Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
2026-10-16 9:16 ` Gong Shuai
(?)
@ 2026-10-16 14:25 ` Jason Gunthorpe
-1 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 14:25 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 05:16:10PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thanks for the review again.
>
> > > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > > with its own vIOMMU can own the first stage of a device context while the
> > > host keeps the second stage, and add the interrupt support. This is an RFC
> > > and comments on the design are welcome.
> >
> > The iommufd parts looked reasonable to me
> >
> > I feel some mild skepticism about all the MSI parts, it would be good
> > to get more of the interrupt stuff actually landed before posting this
> > again.
>
> Agreed on the MSI parts. They are a working proof to exercise the
> nested flow end to end, not a finished design. The reason they are
> in this series at all is that the NVMe device we use for testing
> depends on MSI interrupts. Without this support, DMA succeeds but
> the MSIs fault, so the driver ends up polling for completions after
> timeouts.
>
> We will keep following the irqbypass groundwork as it evolves, and
> continue this work once it has landed.
It seems to me the riscv interrupt architecture is a terrible fit for
Linux, so I would prefer you keep that out of a viommu series and try
to address interrupt support in VFIO through the other series.
viommu shouldn't change anything about how interrupts work..
Without the msi stuff I think you could get this merged without a big
trouble.
Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 14:25 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 14:25 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 05:16:10PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thanks for the review again.
>
> > > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > > with its own vIOMMU can own the first stage of a device context while the
> > > host keeps the second stage, and add the interrupt support. This is an RFC
> > > and comments on the design are welcome.
> >
> > The iommufd parts looked reasonable to me
> >
> > I feel some mild skepticism about all the MSI parts, it would be good
> > to get more of the interrupt stuff actually landed before posting this
> > again.
>
> Agreed on the MSI parts. They are a working proof to exercise the
> nested flow end to end, not a finished design. The reason they are
> in this series at all is that the NVMe device we use for testing
> depends on MSI interrupts. Without this support, DMA succeeds but
> the MSIs fault, so the driver ends up polling for completions after
> timeouts.
>
> We will keep following the irqbypass groundwork as it evolves, and
> continue this work once it has landed.
It seems to me the riscv interrupt architecture is a terrible fit for
Linux, so I would prefer you keep that out of a viommu series and try
to address interrupt support in VFIO through the other series.
viommu shouldn't change anything about how interrupts work..
Without the msi stuff I think you could get this merged without a big
trouble.
Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support
@ 2026-10-16 14:25 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 14:25 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 05:16:10PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thanks for the review again.
>
> > > Add nested translation support to the RISC-V IOMMU driver, so a KVM guest
> > > with its own vIOMMU can own the first stage of a device context while the
> > > host keeps the second stage, and add the interrupt support. This is an RFC
> > > and comments on the design are welcome.
> >
> > The iommufd parts looked reasonable to me
> >
> > I feel some mild skepticism about all the MSI parts, it would be good
> > to get more of the interrupt stuff actually landed before posting this
> > again.
>
> Agreed on the MSI parts. They are a working proof to exercise the
> nested flow end to end, not a finished design. The reason they are
> in this series at all is that the NVMe device we use for testing
> depends on MSI interrupts. Without this support, DMA succeeds but
> the MSIs fault, so the driver ends up polling for completions after
> timeouts.
>
> We will keep following the irqbypass groundwork as it evolves, and
> continue this work once it has landed.
It seems to me the riscv interrupt architecture is a terrible fit for
Linux, so I would prefer you keep that out of a viommu series and try
to address interrupt support in VFIO through the other series.
viommu shouldn't change anything about how interrupts work..
Without the msi stuff I think you could get this merged without a big
trouble.
Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
2026-10-16 7:30 ` Gong Shuai
(?)
@ 2026-10-16 15:00 ` Jason Gunthorpe
-1 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 15:00 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 03:30:20PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thank you for your review.
>
> > > +/**
> > > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > > + * @tc: Guest device context translation control
> > > + * @iosatp: Guest device context stage-1 root page table pointer
> > > + */
> > > +struct iommu_hwpt_riscv {
> > > + __aligned_u64 tc;
> > > + __aligned_u64 iosatp;
> > > +};
> >
> > Like the others you need a spec reference explaining exactly what
> > these fields are.
>
> I'll add references to the device-context sections of the RISC-V IOMMU
> specification ("Leaf DDT entry", "Device-context fields", "Translation
> control (tc)", and "First-Stage context (fsc)"), and I'll also include
> detailed field information, as ARM does.
>
> Also, I'll rename the field from iosatp to fsc. It holds iosatp when
> PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
> two share the same layout, so the name should cover both interpretations
> and the uAPI won't need to change when Process-Directory-Table (PDT)
> support is added.
You might be better off just to have a data[] array of the device
context. I prefer the fields are not parsed out in userspace..
Future specs may add more guest controlled bits and in other places?
Jason
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-16 15:00 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 15:00 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 03:30:20PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thank you for your review.
>
> > > +/**
> > > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > > + * @tc: Guest device context translation control
> > > + * @iosatp: Guest device context stage-1 root page table pointer
> > > + */
> > > +struct iommu_hwpt_riscv {
> > > + __aligned_u64 tc;
> > > + __aligned_u64 iosatp;
> > > +};
> >
> > Like the others you need a spec reference explaining exactly what
> > these fields are.
>
> I'll add references to the device-context sections of the RISC-V IOMMU
> specification ("Leaf DDT entry", "Device-context fields", "Translation
> control (tc)", and "First-Stage context (fsc)"), and I'll also include
> detailed field information, as ARM does.
>
> Also, I'll rename the field from iosatp to fsc. It holds iosatp when
> PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
> two share the same layout, so the name should cover both interpretations
> and the uAPI won't need to change when Process-Directory-Table (PDT)
> support is added.
You might be better off just to have a data[] array of the device
context. I prefer the fields are not parsed out in userspace..
Future specs may add more guest controlled bits and in other places?
Jason
^ permalink raw reply [flat|nested] 63+ messages in thread
* Re: [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types
@ 2026-10-16 15:00 ` Jason Gunthorpe
0 siblings, 0 replies; 63+ messages in thread
From: Jason Gunthorpe @ 2026-10-16 15:00 UTC (permalink / raw)
To: Gong Shuai
Cc: alex, andrew.jones, anup, aou, atish.patra, fangyu.yu, gsh517025,
iommu, joro, kevin.tian, kvm-riscv, kvm, linux-kernel,
linux-riscv, palmer, pbonzini, pjw, robin.murphy, seanjc,
tomasz.jeznach, will, wu.fei9, zhao.qingye
On Fri, Oct 16, 2026 at 03:30:20PM +0800, Gong Shuai wrote:
> Hi Jason,
>
> Thank you for your review.
>
> > > +/**
> > > + * struct iommu_hwpt_riscv - RISC-V IOMMU stage-1 page table data
> > > + * (IOMMU_HWPT_DATA_RISCV_S1)
> > > + * @tc: Guest device context translation control
> > > + * @iosatp: Guest device context stage-1 root page table pointer
> > > + */
> > > +struct iommu_hwpt_riscv {
> > > + __aligned_u64 tc;
> > > + __aligned_u64 iosatp;
> > > +};
> >
> > Like the others you need a spec reference explaining exactly what
> > these fields are.
>
> I'll add references to the device-context sections of the RISC-V IOMMU
> specification ("Leaf DDT entry", "Device-context fields", "Translation
> control (tc)", and "First-Stage context (fsc)"), and I'll also include
> detailed field information, as ARM does.
>
> Also, I'll rename the field from iosatp to fsc. It holds iosatp when
> PDTV=0 and process-directory-table pointer (pdtp) when PDTV=1, and the
> two share the same layout, so the name should cover both interpretations
> and the uAPI won't need to change when Process-Directory-Table (PDT)
> support is added.
You might be better off just to have a data[] array of the device
context. I prefer the fields are not parsed out in userspace..
Future specs may add more guest controlled bits and in other places?
Jason
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 63+ messages in thread
end of thread, other threads:[~2026-10-16 15:01 UTC | newest]
Thread overview: 63+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 6:52 [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 01/12] iommu/riscv: Use DC.tc.V as the device context valid bit Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 02/12] iommufd: Add RISC-V IOMMU hwpt and vIOMMU types Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 23:54 ` Jason Gunthorpe
2026-10-15 23:54 ` Jason Gunthorpe
2026-10-15 23:54 ` Jason Gunthorpe
2026-10-16 7:30 ` Gong Shuai
2026-10-16 7:30 ` Gong Shuai
2026-10-16 7:30 ` Gong Shuai
2026-10-16 15:00 ` Jason Gunthorpe
2026-10-16 15:00 ` Jason Gunthorpe
2026-10-16 15:00 ` Jason Gunthorpe
2026-10-15 6:52 ` [RFC PATCH 03/12] iommufd: Add RISC-V IOMMU cache invalidation data type Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 04/12] iommu/riscv: Add vIOMMU object support Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 05/12] iommu/riscv: Add nested domain allocation Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 06/12] iommu/riscv: Add vIOMMU cache invalidation Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 07/12] iommufd: Add RISC-V IOMMU hardware info type Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 23:55 ` Jason Gunthorpe
2026-10-15 23:55 ` Jason Gunthorpe
2026-10-15 23:55 ` Jason Gunthorpe
2026-10-16 7:43 ` Gong Shuai
2026-10-16 7:43 ` Gong Shuai
2026-10-16 7:43 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 08/12] iommu/riscv: Add riscv_iommu_hw_info Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 09/12] iommu/riscv: Add riscv_iommu_attach_dev_nested Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 10/12] RISC-V: KVM: Accept auto-mode interrupt files for IMSIC IRQ bypass Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 11/12] iommu/riscv: Accept unpublished interrupt files in IRQ forwarding Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` [RFC PATCH 12/12] RISC-V: KVM: Forward MSIs for guests with a vIOMMU Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-15 6:52 ` Gong Shuai
2026-10-16 0:00 ` [RFC PATCH 0/12] iommu/riscv: Add nested translation (vIOMMU) support Jason Gunthorpe
2026-10-16 0:00 ` Jason Gunthorpe
2026-10-16 0:00 ` Jason Gunthorpe
2026-10-16 9:16 ` Gong Shuai
2026-10-16 9:16 ` Gong Shuai
2026-10-16 9:16 ` Gong Shuai
2026-10-16 14:25 ` Jason Gunthorpe
2026-10-16 14:25 ` Jason Gunthorpe
2026-10-16 14:25 ` Jason Gunthorpe
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.