[PATCH v3 01/13] iommu/arm-smmu-v3: Add arm_smmu_attach_release()

Jonathan Cameron jonathan.cameron at oss.qualcomm.com
Thu Sep 3 12:18:33 PDT 2026


> The IOPF teardown is done in arm_smmu_remove_master_domain() when releasing
> the master_domain on detach, under the global arm_smmu_asid_lock mutex. But
> the teardown must drain any in-flight IOPF (for the old domain), before the
> master_domain is freed via iopf_queue_flush_dev() calling flush_workqueue()
> that can block on user-faulting page-fault handlers. Doing so while holding
> the arm_smmu_asid_lock would stall any unrelated attachment in the system.
> 
> Split the teardown out of arm_smmu_remove_master_domain(), to a new helper
> arm_smmu_attach_release() that runs after arm_smmu_asid_lock is released.
> 
> Since no other device would use the old master_domain that is being freed,
> it's safe to move out of arm_smmu_asid_lock (still under the protection of
> iommu_group->mutex).

This is a lot of text if the next bit about being a refactor only
is accurate.  Seems that not blocking attachments is the issue and
to me that is a functional and useful change. However, is that
in this patch?  Anyhow to me this needs a rewrite to focus on just
what is actually changing here rather than the eventual picture.


> 
> Note: this is a pure refactor; no functional change.
> 
> Signed-off-by: Nicolin Chen <nicolinc at nvidia.com>
>
> 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 25982bdbcbd9..fce026efa44f 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
> @@ -194,6 +194,7 @@ static int arm_smmu_attach_dev_nested(struct iommu_domain *domain,
>  	arm_smmu_install_ste_for_dev(master, &ste);
>  	arm_smmu_attach_commit(&state);
>  	mutex_unlock(&arm_smmu_asid_lock);
> +	arm_smmu_attach_release(&state);
>  	return 0;
>  }
>  
> 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 5732f3ba0122..99baa59b39c9 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -3285,9 +3285,9 @@ arm_smmu_master_build_invs(struct arm_smmu_master *master, bool ats_enabled,
>  	return master->build_invs;
>  }
>  
> -static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
> -					  struct iommu_domain *domain,
> -					  ioasid_t ssid)
> +static struct arm_smmu_master_domain *
> +arm_smmu_remove_master_domain(struct arm_smmu_master *master,
> +			      struct iommu_domain *domain, ioasid_t ssid)
>  {
>  	struct arm_smmu_domain *smmu_domain = to_smmu_domain_devices(domain);
>  	struct arm_smmu_master_domain *master_domain;
> @@ -3295,7 +3295,7 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
>  	unsigned long flags;
>  
>  	if (!smmu_domain)
> -		return;
> +		return NULL;
>  
>  	if (domain->type == IOMMU_DOMAIN_NESTED)
>  		nested_ats_flush = to_smmu_nested_domain(domain)->enable_ats;
> @@ -3310,8 +3310,23 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
>  	}
>  	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
>  
> +	/* arm_smmu_attach_release() will free it */
> +	return master_domain;
> +}
> +
> +/* Release the old master_domain detached by arm_smmu_remove_master_domain() */
> +void arm_smmu_attach_release(struct arm_smmu_attach_state *state)
> +{
> +	struct arm_smmu_master_domain *master_domain = state->old_master_domain;
> +	struct arm_smmu_master *master = state->master;
> +
> +	iommu_group_mutex_assert(master->dev);
> +
> +	if (!master_domain)

I guess this makes sense in later patches, but for now the local
variable seems more confusing than anything.

> +		return;

I'd add a blank line here to separate the sanity checks from bulk
code.


>  	arm_smmu_disable_iopf(master, master_domain);
>  	kfree(master_domain);
> +	state->old_master_domain = NULL;
>  }
>  

> @@ -3784,6 +3801,7 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
>
This path is hit from a failure of arm_smmu_attach_prepare()
At that point the old domain hasn't been detached.

Now it doesn't matter because of what is currently done in release,
but from a code flow / what that function is documented to be for
this seems wrong to me.  I'd separate the good and the bad
paths in the function.

-- 
Jonathan Cameron <jonathan.cameron at oss.qualcomm.com>



More information about the linux-arm-kernel mailing list