diff mbox series

[v5,09/27] iommu/arm-smmu-v3: Allocate the CD table entry in advance

Message ID 9-v5-9a37e0c884ce+31e3-smmuv3_newapi_p2_jgg@nvidia.com (mailing list archive)
State New, archived
Headers show
Series Update SMMUv3 to the modern iommu API (part 2/3) | expand

Commit Message

Jason Gunthorpe March 4, 2024, 11:43 p.m. UTC
Avoid arm_smmu_attach_dev() having to undo the changes to the
smmu_domain->devices list, acquire the cdptr earlier so we don't need to
handle that error.

Now there is a clear break in arm_smmu_attach_dev() where all the
prep-work has been done non-disruptively and we commit to making the HW
change, which cannot fail.

This completes transforming arm_smmu_attach_dev() so that it does not
disturb the HW if it fails.

Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 24 +++++++--------------
 1 file changed, 8 insertions(+), 16 deletions(-)

Comments

Michael Shavit March 13, 2024, 12:17 p.m. UTC | #1
On Tue, Mar 5, 2024 at 7:44 AM Jason Gunthorpe <jgg@nvidia.com> wrote:
>
> Avoid arm_smmu_attach_dev() having to undo the changes to the
> smmu_domain->devices list, acquire the cdptr earlier so we don't need to
> handle that error.
>
> Now there is a clear break in arm_smmu_attach_dev() where all the
> prep-work has been done non-disruptively and we commit to making the HW
> change, which cannot fail.
>
> This completes transforming arm_smmu_attach_dev() so that it does not
> disturb the HW if it fails.
>
> Tested-by: Nicolin Chen <nicolinc@nvidia.com>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 24 +++++++--------------
>  1 file changed, 8 insertions(+), 16 deletions(-)
>
> 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 2dd6cb17112e98..39081d828a2132 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2676,6 +2676,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>         struct arm_smmu_device *smmu;
>         struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>         struct arm_smmu_master *master;
> +       struct arm_smmu_cd *cdptr;
>
>         if (!fwspec)
>                 return -ENOENT;
> @@ -2704,6 +2705,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>         if (ret)
>                 return ret;
>
> +       if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
> +               cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
> +               if (!cdptr)
> +                       return -ENOMEM;
> +       }
> +
>         /*
>          * Prevent arm_smmu_share_asid() from trying to change the ASID
>          * of either the old or new domain while we are working on it.
> @@ -2723,13 +2730,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>         switch (smmu_domain->stage) {
>         case ARM_SMMU_DOMAIN_S1: {
>                 struct arm_smmu_cd target_cd;
> -               struct arm_smmu_cd *cdptr;
> -
> -               cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
> -               if (!cdptr) {
> -                       ret = -ENOMEM;
> -                       goto out_list_del;
> -               }
>
>                 arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
>                 arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
> @@ -2746,16 +2746,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>         }
>
>         arm_smmu_enable_ats(master, smmu_domain);
> -       goto out_unlock;
> -
> -out_list_del:
> -       spin_lock_irqsave(&smmu_domain->devices_lock, flags);
> -       list_del_init(&master->domain_head);
> -       spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
> -
> -out_unlock:
>         mutex_unlock(&arm_smmu_asid_lock);
> -       return ret;
> +       return 0;
>  }
>
>  static int arm_smmu_attach_dev_ste(struct device *dev,
> --
> 2.43.2
>
Reviewed-by: Michael Shavit <mshavit@google.com>
Nicolin Chen March 16, 2024, 4:16 a.m. UTC | #2
On Mon, Mar 04, 2024 at 07:43:57PM -0400, Jason Gunthorpe wrote:
> Avoid arm_smmu_attach_dev() having to undo the changes to the
> smmu_domain->devices list, acquire the cdptr earlier so we don't need to
> handle that error.

I should probably mention this in the other patch, yet PATCH-14
adding arm_smmu_attach_prepare() to this function doesn't have a
rollback for CD table allocation. I assume we're fine with that?

> Now there is a clear break in arm_smmu_attach_dev() where all the
> prep-work has been done non-disruptively and we commit to making the HW
> change, which cannot fail.
> 
> This completes transforming arm_smmu_attach_dev() so that it does not
> disturb the HW if it fails.
> 
> Tested-by: Nicolin Chen <nicolinc@nvidia.com>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
 
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Jason Gunthorpe March 18, 2024, 6:14 p.m. UTC | #3
On Fri, Mar 15, 2024 at 09:16:14PM -0700, Nicolin Chen wrote:
> On Mon, Mar 04, 2024 at 07:43:57PM -0400, Jason Gunthorpe wrote:
> > Avoid arm_smmu_attach_dev() having to undo the changes to the
> > smmu_domain->devices list, acquire the cdptr earlier so we don't need to
> > handle that error.
> 
> I should probably mention this in the other patch, yet PATCH-14
> adding arm_smmu_attach_prepare() to this function doesn't have a
> rollback for CD table allocation. I assume we're fine with that?

Yeah, I think so. The CD table leafs are never freed by anything, so
even if you did succeed to attach a PASID and then detach the leaf
will still hang around.

If we care we could try to clean it up by consulting the PASID xarray
and checking if the entire leaf is unused.

Thanks,
Jason
Mostafa Saleh March 22, 2024, 7:15 p.m. UTC | #4
Hi Jason,

On Mon, Mar 04, 2024 at 07:43:57PM -0400, Jason Gunthorpe wrote:
> Avoid arm_smmu_attach_dev() having to undo the changes to the
> smmu_domain->devices list, acquire the cdptr earlier so we don't need to
> handle that error.
> 
> Now there is a clear break in arm_smmu_attach_dev() where all the
> prep-work has been done non-disruptively and we commit to making the HW
> change, which cannot fail.
> 
> This completes transforming arm_smmu_attach_dev() so that it does not
> disturb the HW if it fails.
> 
> Tested-by: Nicolin Chen <nicolinc@nvidia.com>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 24 +++++++--------------
>  1 file changed, 8 insertions(+), 16 deletions(-)
> 
> 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 2dd6cb17112e98..39081d828a2132 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2676,6 +2676,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	struct arm_smmu_device *smmu;
>  	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
>  	struct arm_smmu_master *master;
> +	struct arm_smmu_cd *cdptr;
>  
>  	if (!fwspec)
>  		return -ENOENT;
> @@ -2704,6 +2705,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	if (ret)
>  		return ret;
>  
> +	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
> +		cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
> +		if (!cdptr)
> +			return -ENOMEM;
> +	}
> +
>  	/*
>  	 * Prevent arm_smmu_share_asid() from trying to change the ASID
>  	 * of either the old or new domain while we are working on it.
> @@ -2723,13 +2730,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	switch (smmu_domain->stage) {
>  	case ARM_SMMU_DOMAIN_S1: {
>  		struct arm_smmu_cd target_cd;
> -		struct arm_smmu_cd *cdptr;
> -
> -		cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
> -		if (!cdptr) {
> -			ret = -ENOMEM;
> -			goto out_list_del;
> -		}
>  
>  		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
>  		arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
> @@ -2746,16 +2746,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
>  	}
>  
>  	arm_smmu_enable_ats(master, smmu_domain);
> -	goto out_unlock;
> -
> -out_list_del:
> -	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
> -	list_del_init(&master->domain_head);
> -	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
> -
> -out_unlock:
>  	mutex_unlock(&arm_smmu_asid_lock);
> -	return ret;
> +	return 0;
>  }
>  
>  static int arm_smmu_attach_dev_ste(struct device *dev,
> -- 
> 2.43.2
>
I believe this is fine, I couldn’t break it. With the comment on the previous
patch, where we explicitly allocate the CD here and not inside
arm_smmu_get_cd_ptr().

Reviewed-by: Mostafa Saleh <smostafa@google.com>


Thanks,
Mostafa
diff mbox series

Patch

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 2dd6cb17112e98..39081d828a2132 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2676,6 +2676,7 @@  static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	struct arm_smmu_device *smmu;
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 	struct arm_smmu_master *master;
+	struct arm_smmu_cd *cdptr;
 
 	if (!fwspec)
 		return -ENOENT;
@@ -2704,6 +2705,12 @@  static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	if (ret)
 		return ret;
 
+	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
+		cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
+		if (!cdptr)
+			return -ENOMEM;
+	}
+
 	/*
 	 * Prevent arm_smmu_share_asid() from trying to change the ASID
 	 * of either the old or new domain while we are working on it.
@@ -2723,13 +2730,6 @@  static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	switch (smmu_domain->stage) {
 	case ARM_SMMU_DOMAIN_S1: {
 		struct arm_smmu_cd target_cd;
-		struct arm_smmu_cd *cdptr;
-
-		cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
-		if (!cdptr) {
-			ret = -ENOMEM;
-			goto out_list_del;
-		}
 
 		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
 		arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
@@ -2746,16 +2746,8 @@  static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 	}
 
 	arm_smmu_enable_ats(master, smmu_domain);
-	goto out_unlock;
-
-out_list_del:
-	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
-	list_del_init(&master->domain_head);
-	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
-
-out_unlock:
 	mutex_unlock(&arm_smmu_asid_lock);
-	return ret;
+	return 0;
 }
 
 static int arm_smmu_attach_dev_ste(struct device *dev,