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

Nicolin Chen posted 10 patches 2 weeks, 3 days ago
[PATCH v2 07/10] iommu/arm-smmu-v3: Pass in vsmmu to arm_smmu_domain_get_iotlb_tag()
Posted by Nicolin Chen 2 weeks, 3 days ago
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
Re: [PATCH v2 07/10] iommu/arm-smmu-v3: Pass in vsmmu to arm_smmu_domain_get_iotlb_tag()
Posted by Jason Gunthorpe 1 week, 5 days ago
On Wed, Jan 21, 2026 at 05:24:25PM -0800, Nicolin Chen wrote:
> 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;

This all seems too complicated, the domain passed in should have been
a iommu_domain, not a smmu_domain, then you can just do

if (domain->Type == IOMMU_DOMAIN_NESTED) {
  struct arm_smmu_nested_domain *nested = to_smmu_nested_domain(domain);
   tag->type = INV_TYPE_S2_VMID_VSMMU;
   tag->id = nested->vsmmu->vmid;
   tag->smmu = nested->vsmmu->smmu;
   return 0;
}

Here and everything is simple.

Jason
Re: [PATCH v2 07/10] iommu/arm-smmu-v3: Pass in vsmmu to arm_smmu_domain_get_iotlb_tag()
Posted by Nicolin Chen 1 week, 5 days ago
On Mon, Jan 26, 2026 at 05:20:00PM -0400, Jason Gunthorpe wrote:
> On Wed, Jan 21, 2026 at 05:24:25PM -0800, Nicolin Chen wrote:
> > 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;
> 
> This all seems too complicated, the domain passed in should have been
> a iommu_domain, not a smmu_domain, then you can just do
> 
> if (domain->Type == IOMMU_DOMAIN_NESTED) {
>   struct arm_smmu_nested_domain *nested = to_smmu_nested_domain(domain);
>    tag->type = INV_TYPE_S2_VMID_VSMMU;
>    tag->id = nested->vsmmu->vmid;
>    tag->smmu = nested->vsmmu->smmu;
>    return 0;
> }
> 
> Here and everything is simple.

Hmm, should have squashed this in the base series v10 that I just
sent. Anyway, I can change this in v3.

Thanks
Nicolin