[PATCH v2 08/10] iommu/arm-smmu-v3: Introduce INV_TYPE_S2_VMID_VSMMU
From: Nicolin Chen <hidden>
Date: 2026-01-22 01:25:02
Also in:
linux-iommu, linux-patches, lkml
Subsystem:
arm smmu drivers, iommu subsystem, the rest · Maintainers:
Will Deacon, Joerg Roedel, Linus Torvalds
A VMID held by a vSMMU is required to setup hardware (e.g. tegra241-cmdqv) during its initialization. So, it should be allocated in the ->viommu_init callback. This makes the VMID lifecycle unique than a VMID allocated for a naked S2 attachment. Introduce an INV_TYPE_S2_VMID_VSMMU to accommodate this case. Note that a second device attaching to a nested domain associated with the same vSMMU instance will have an INV_TYPE_S2_VMID_VSMMU and reuse the VMID held by the vSMMU. Devices attaching directly to the nesting parent domain will have an INV_TYPE_S2_VMID and shouldn't resue the VMID from the vSMMU. Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Nicolin Chen <redacted> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 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 386ac75879c0..8365660282d5 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h@@ -656,6 +656,7 @@ struct arm_smmu_cmdq_batch { enum arm_smmu_inv_type { INV_TYPE_S1_ASID, INV_TYPE_S2_VMID, + INV_TYPE_S2_VMID_VSMMU, INV_TYPE_S2_VMID_S1_CLEAR, INV_TYPE_ATS, INV_TYPE_ATS_FULL,
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 8323f74c8923..6d3da3f82ec8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c@@ -1904,7 +1904,8 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target, u64 vtcr_val; struct arm_smmu_device *smmu = master->smmu; - WARN_ON(tag->type != INV_TYPE_S2_VMID); + WARN_ON(tag->type != INV_TYPE_S2_VMID && + tag->type != INV_TYPE_S2_VMID_VSMMU); memset(target, 0, sizeof(*target)); target->data[0] = cpu_to_le64(
@@ -2592,6 +2593,7 @@ static void __arm_smmu_domain_inv_range(struct arm_smmu_invs *invs, granule); break; case INV_TYPE_S2_VMID: + case INV_TYPE_S2_VMID_VSMMU: cmd.tlbi.vmid = cur->id; cmd.tlbi.leaf = leaf; arm_smmu_inv_to_cmdq_batch(cur, &cmds, &cmd, iova, size,
@@ -3149,7 +3151,10 @@ int arm_smmu_domain_get_iotlb_tag(struct arm_smmu_domain *smmu_domain, tag->type = INV_TYPE_S1_ASID; break; case ARM_SMMU_DOMAIN_S2: - tag->type = INV_TYPE_S2_VMID; + if (vsmmu) + tag->type = INV_TYPE_S2_VMID_VSMMU; + else + tag->type = INV_TYPE_S2_VMID; break; default: return -EINVAL;
@@ -3163,6 +3168,12 @@ int arm_smmu_domain_get_iotlb_tag(struct arm_smmu_domain *smmu_domain, return ret; /* Allocate a new IOTLB cache tag (users counter == 0) */ + if (tag->type == INV_TYPE_S2_VMID_VSMMU) { + /* Use the pre-allocated VMID from vSMMU */ + tag->id = vsmmu->vmid; + return 0; + } + lockdep_assert_held(&arm_smmu_asid_lock); if (tag->type == INV_TYPE_S1_ASID) {
@@ -3233,6 +3244,7 @@ arm_smmu_master_build_inv(struct arm_smmu_master *master, } break; case INV_TYPE_S2_VMID: + case INV_TYPE_S2_VMID_VSMMU: cur->size_opcode = CMDQ_OP_TLBI_S2_IPA; cur->nsize_opcode = CMDQ_OP_TLBI_S12_VMALL; break;
@@ -3280,7 +3292,7 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled, return NULL; /* All the nested S1 ASIDs have to be flushed when S2 parent changes */ - if (nesting) { + if (tag->type == INV_TYPE_S2_VMID_VSMMU) { if (!arm_smmu_master_build_inv(master, INV_TYPE_S2_VMID_S1_CLEAR, tag->id, IOMMU_NO_PASID, 0))
--
2.43.0