[RFC PATCH v2 4/9] iommu/riscv: Add vIOMMU object support
From: Gong Shuai
Date: Thu Oct 29 2026 - 02:17:17 EST
From: Wu Fei <wu.fei9@xxxxxxxxxxxxxxxx>
Allow iommufd to allocate a RISC-V vIOMMU when the physical IOMMU
supports both translation stages.
Nested translation needs to associate guest-owned stage 1 contexts
with a host-owned stage 2 parent domain. A vIOMMU provides this
association and retains the parent GSCID needed to program device
contexts and target IOTINVAL commands at the correct guest.
Signed-off-by: Wu Fei <wu.fei9@xxxxxxxxxxxxxxxx>
Signed-off-by: Gong Shuai <gong.shuai@xxxxxxxxxxxxxxxx>
---
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 554361dd3159..a8c19c9e45d4 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/kernel.h>
#include <linux/pci.h>
@@ -856,6 +857,7 @@ struct riscv_iommu_domain {
spinlock_t lock; /* protect bonds list updates. */
int pscid;
int gscid;
+ bool nest_parent;
};
PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);
@@ -1342,6 +1344,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_attach_paging_domain(struct iommu_domain *iommu_domain,
struct device *dev,
struct iommu_domain *old)
@@ -1488,6 +1504,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);
cfg.common.features |= BIT(PT_FEAT_RISCV_S2);
if (iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD)
domain->domain.dirty_ops = &riscv_iommu_dirty_ops;
@@ -1638,6 +1655,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 const struct iommu_ops riscv_iommu_ops = {
.of_xlate = riscv_iommu_of_xlate,
.capable = riscv_iommu_capable,
@@ -1645,6 +1703,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