[PATCH v2 10/11] iommu/arm-smmu-v3: Decouple vmid from S2 nest_parent domain
From: Nicolin Chen
Date: Tue Apr 15 2025 - 01:00:50 EST
Now the new S2 invalidation routines in arm-smmu-v3-iommufd are ready to
support a shared S2 nest_parent domain across multiple vSMMU instances.
Move the vmid allocation/releasing to the vSMMU allocator/destroyer too.
Then, move the vsmmus list next to s2_cfg in the struct arm_smmu_domain,
as they can be exclusive now.
Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 12 ++++++------
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 15 ++++++++++++---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++++++---
3 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 477d4d2f19a6..dfb9d5f935e4 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -857,13 +857,13 @@ struct arm_smmu_domain {
enum arm_smmu_domain_stage stage;
union {
- struct arm_smmu_ctx_desc cd;
- struct arm_smmu_s2_cfg s2_cfg;
+ struct arm_smmu_ctx_desc cd; /* S1 */
+ struct arm_smmu_s2_cfg s2_cfg; /* S2 && !nest_parent */
+ struct { /* S2 && nest_parent */
+ struct list_head list;
+ spinlock_t lock;
+ } vsmmus;
};
- struct {
- struct list_head list;
- spinlock_t lock;
- } vsmmus;
struct iommu_domain domain;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
index 491f2b88e30b..5d05f8a78215 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -118,6 +118,7 @@ static void arm_vsmmu_destroy(struct iommufd_viommu *viommu)
/* Must flush S2 vmid after delinking vSMMU */
arm_smmu_tlb_inv_vmid(vsmmu->smmu, vsmmu->vmid);
arm_vsmmu_atc_inv_domain(vsmmu, 0, 0);
+ ida_free(&vsmmu->smmu->vmid_map, vsmmu->vmid);
}
static void arm_smmu_make_nested_cd_table_ste(
@@ -511,6 +512,7 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
struct arm_smmu_domain *s2_parent = to_smmu_domain(parent);
struct arm_vsmmu *vsmmu;
unsigned long flags;
+ int vmid;
if (viommu_type != IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
return ERR_PTR(-EOPNOTSUPP);
@@ -541,15 +543,22 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
!(smmu->features & ARM_SMMU_FEAT_S2FWB))
return ERR_PTR(-EOPNOTSUPP);
+ vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
+ GFP_KERNEL);
+ if (vmid < 0)
+ return ERR_PTR(vmid);
+
vsmmu = iommufd_viommu_alloc(ictx, struct arm_vsmmu, core,
&arm_vsmmu_ops);
- if (IS_ERR(vsmmu))
+ if (IS_ERR(vsmmu)) {
+ ida_free(&smmu->vmid_map, vmid);
return ERR_CAST(vsmmu);
+ }
vsmmu->smmu = smmu;
+ vsmmu->vmid = (u16)vmid;
vsmmu->s2_parent = s2_parent;
- /* FIXME Move VMID allocation from the S2 domain allocation to here */
- vsmmu->vmid = s2_parent->s2_cfg.vmid;
+
spin_lock_irqsave(&s2_parent->vsmmus.lock, flags);
list_add_tail(&vsmmu->vsmmus_elm, &s2_parent->vsmmus.list);
spin_unlock_irqrestore(&s2_parent->vsmmus.lock, flags);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 4b9cdfb177ca..8047b60ec024 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2474,7 +2474,7 @@ static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
mutex_lock(&arm_smmu_asid_lock);
xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
mutex_unlock(&arm_smmu_asid_lock);
- } else {
+ } else if (!smmu_domain->nest_parent) {
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
if (cfg->vmid)
ida_free(&smmu->vmid_map, cfg->vmid);
@@ -2503,7 +2503,10 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_device *smmu,
struct arm_smmu_domain *smmu_domain)
{
int vmid;
- struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
+
+ /* nest_parent stores vmid in vSMMU instead of a shared S2 domain */
+ if (smmu_domain->nest_parent)
+ return 0;
/* Reserve VMID 0 for stage-2 bypass STEs */
vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
@@ -2511,7 +2514,7 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_device *smmu,
if (vmid < 0)
return vmid;
- cfg->vmid = (u16)vmid;
+ smmu_domain->s2_cfg.vmid = (u16)vmid;
return 0;
}
--
2.43.0