[PATCH v2 07/10] iommu/arm-smmu-v3: Pass in vsmmu to arm_smmu_domain_get_iotlb_tag()

Nicolin Chen
2026-01-22T01:25:06Z

When a device attaches to a nested domain, VMID is held by its associated
vSMMU instance. So arm_smmu_domain_get_iotlb_tag() should return the VMID
from the vSMMU instance rather than allocating a new one. Pass in a vsmmu
pointer to arm_smmu_domain_get_iotlb_tag(), to prepare for this.

Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 9 +++++++++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 1 +
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 4 ++--
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 7 +++++--
4 files changed, 17 insertions(+), 4 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 8aecdbceb974..386ac75879c0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1124,6 +1124,7 @@ struct arm_smmu_attach_state {
/* Inputs */
struct iommu_domain *old_domain;
struct arm_smmu_master *master;
+ struct arm_vsmmu *vsmmu;
bool cd_needs_ats;
bool disable_ats;
ioasid_t ssid;
@@ -1136,6 +1137,7 @@ struct arm_smmu_attach_state {

int arm_smmu_domain_get_iotlb_tag(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_device *smmu,
+ struct arm_vsmmu *vsmmu,
struct arm_smmu_inv *tag, bool alloc);

int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
@@ -1182,6 +1184,13 @@ struct arm_vsmmu {
u16 vmid;
};

+static inline struct arm_vsmmu *to_vsmmu(struct iommu_domain *domain)
+{
+ if (domain->type == IOMMU_DOMAIN_NESTED)
+ return to_smmu_nested_domain(domain)->vsmmu;
+ return NULL;
+}
+
#if IS_ENABLED(CONFIG_ARM_SMMU_V3_IOMMUFD)
void *arm_smmu_hw_info(struct device *dev, u32 *length,
enum iommu_hw_info_type *type);
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 9998871f69a0..33b336d494c3 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
@@ -162,6 +162,7 @@ static int arm_smmu_attach_dev_nested(struct iommu_domain *domain,
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
struct arm_smmu_attach_state state = {
.master = master,
+ .vsmmu = nested_domain->vsmmu,
.old_domain = old_domain,
.ssid = IOMMU_NO_PASID,
};
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 5c8960d31a9b..461ccf4bdb03 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -31,7 +31,7 @@ arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain)
continue;

if (WARN_ON(arm_smmu_domain_get_iotlb_tag(
- smmu_domain, master->smmu, &tag, false)))
+ smmu_domain, master->smmu, NULL, &tag, false)))
continue;
if (WARN_ON(tag.type != INV_TYPE_S1_ASID))
continue;
@@ -171,7 +171,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
continue;

if (WARN_ON(arm_smmu_domain_get_iotlb_tag(
- smmu_domain, master->smmu, &tag, false)))
+ smmu_domain, master->smmu, NULL, &tag, false)))
continue;
if (WARN_ON(tag.type != INV_TYPE_S1_ASID))
continue;
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 5a7032081553..8323f74c8923 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3137,6 +3137,7 @@ static int __arm_smmu_domain_get_iotlb_tag(struct arm_smmu_domain *smmu_domain,

int arm_smmu_domain_get_iotlb_tag(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_device *smmu,
+ struct arm_vsmmu *vsmmu,
struct arm_smmu_inv *tag, bool alloc)
{
int ret;
@@ -3360,6 +3361,7 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
*/
if (new_smmu_domain) {
struct arm_smmu_inv_state *invst = &state->new_domain_invst;
+ struct arm_vsmmu *vsmmu = state->vsmmu;
struct arm_smmu_invs *build_invs;

invst->invs_ptr = &new_smmu_domain->invs;
@@ -3368,7 +3370,7 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
lockdep_is_held(&arm_smmu_asid_lock));

ret = arm_smmu_domain_get_iotlb_tag(new_smmu_domain, smmu,
- &invst->tag, true);
+ vsmmu, &invst->tag, true);
if (ret)
return ret;

@@ -3387,6 +3389,7 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,

if (old_smmu_domain) {
struct arm_smmu_inv_state *invst = &state->old_domain_invst;
+ struct arm_vsmmu *vsmmu = to_vsmmu(state->old_domain);

invst->invs_ptr = &old_smmu_domain->invs;
/* A re-attach case might have a different ats_enabled state */
@@ -3398,7 +3401,7 @@ static int arm_smmu_attach_prepare_invs(struct arm_smmu_attach_state *state,
lockdep_is_held(&arm_smmu_asid_lock));

ret = arm_smmu_domain_get_iotlb_tag(old_smmu_domain, smmu,
- &invst->tag, false);
+ vsmmu, &invst->tag, false);
if (WARN_ON(ret))
return ret;

--
2.43.0