[RFC PATCH v2 9/9] iommu/riscv: Add riscv_iommu_attach_dev_nested
Gong Shuai
gong.shuai at sanechips.com.cn
Wed Oct 28 23:11:31 PDT 2026
From: Wu Fei <wu.fei9 at sanechips.com.cn>
Attach a device to a nested domain by combining the guest provided
stage 1 context with the host-owned stage 2 context in the device
directory entry. This allows the physical IOMMU to translate device
DMA through both stages.
The device is bonded to the stage 2 parent domain so that it shares
the parent's invalidation state.
Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
Co-developed-by: Gong Shuai <gong.shuai at sanechips.com.cn>
Signed-off-by: Gong Shuai <gong.shuai at sanechips.com.cn>
---
drivers/iommu/riscv/iommu.c | 41 +++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 44fab79110ac..a103c0465e62 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1673,12 +1673,53 @@ struct riscv_iommu_nested_domain {
#define to_riscv_iommu_nested_domain(domain) \
container_of(domain, struct riscv_iommu_nested_domain, domain)
+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 riscv_iommu_dc dc = {0};
+
+ 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);
+
+ if (riscv_iommu_bond_link(s2_parent, dev))
+ return -ENOMEM;
+
+ riscv_iommu_iodir_update(iommu, dev, &dc);
+ riscv_iommu_bond_unlink(info->domain, dev);
+ info->domain = s2_parent;
+
+ return 0;
+}
+
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 = {
+ .attach_dev = riscv_iommu_attach_dev_nested,
.free = riscv_iommu_domain_nested_free,
};
--
2.53.0
More information about the kvm-riscv
mailing list