[PATCH v5 19/27] iommu/arm-smmu-v3: Keep track of arm_smmu_master_domain for SVA
Michael Shavit
mshavit at google.com
Thu Mar 21 03:47:41 PDT 2024
On Tue, Mar 5, 2024 at 7:44 AM Jason Gunthorpe <jgg at nvidia.com> wrote:
>
> Currently the smmu_domain->devices list is unused for SVA domains.
> Fill it in with the SSID and master of every arm_smmu_set_pasid()
> using the same logic as the RID attach.
>
> Tested-by: Nicolin Chen <nicolinc at nvidia.com>
> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
> ---
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 23 +++++++++++++++++++--
> 1 file changed, 21 insertions(+), 2 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 2db2b822292a87..6d15fe3a160acf 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2603,7 +2603,8 @@ to_smmu_domain_devices(struct iommu_domain *domain)
> /* The domain can be NULL only when processing the first attach */
> if (!domain)
> return NULL;
> - if (domain->type & __IOMMU_DOMAIN_PAGING)
> + if ((domain->type & __IOMMU_DOMAIN_PAGING) ||
> + domain->type == IOMMU_DOMAIN_SVA)
> return to_smmu_domain(domain);
> return NULL;
> }
> @@ -2813,7 +2814,9 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
> struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
> const struct arm_smmu_cd *cd)
> {
> + struct attach_state state = {.ssid = pasid};
> struct arm_smmu_cd *cdptr;
> + int ret;
>
> if (!arm_smmu_is_s1_domain(iommu_get_domain_for_dev(master->dev)))
> return -ENODEV;
> @@ -2821,14 +2824,30 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
> cdptr = arm_smmu_get_cd_ptr(master, pasid);
> if (!cdptr)
> return -ENOMEM;
> +
> + mutex_lock(&arm_smmu_asid_lock);
> + ret = arm_smmu_attach_prepare(master, &smmu_domain->domain, &state);
> + if (ret)
> + goto out_unlock;
> +
> arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
> - return 0;
> +
> + arm_smmu_attach_commit(master, &state);
> +
> +out_unlock:
> + mutex_unlock(&arm_smmu_asid_lock);
> + return ret;
> }
arm_smmu_attach_commit tries to remove the master_domain entry from
the previous domain that this master was attached to. It gets a
pointer to the previous domain from the iommu framework with
iommu_get_domain_for_dev().
But in this path, arm_smmu_attach_prepare is creating a master_domain
entry for the pasid domain, which may be different from the one
returned by iommu_get_domain_for_dev() on the next attach.
I think this ended up being safe in the end because afaict the iommu
framework requires detaching the previous pasid domain before
attaching a new one. But nonetheless this is pretty fragile and
doesn't look intentional.
>
> void arm_smmu_remove_pasid(struct arm_smmu_master *master,
> struct arm_smmu_domain *smmu_domain, ioasid_t pasid)
> {
> + mutex_lock(&arm_smmu_asid_lock);
> arm_smmu_clear_cd(master, pasid);
> + if (master->ats_enabled)
> + arm_smmu_atc_inv_master(master, pasid);
> + arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
> + mutex_unlock(&arm_smmu_asid_lock);
> }
>
> static int arm_smmu_attach_dev_ste(struct iommu_domain *domain,
> --
> 2.43.2
>
>
More information about the linux-arm-kernel
mailing list