[PATCH v5 19/27] iommu/arm-smmu-v3: Keep track of arm_smmu_master_domain for SVA

Jason Gunthorpe jgg at nvidia.com
Thu Mar 21 06:55:51 PDT 2024


On Thu, Mar 21, 2024 at 06:47:41PM +0800, Michael Shavit wrote:
> 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.

Oh yeah, this is a mistake!

Commit needs to take in the old domain from the caller which knows
what it actually is.

Thanks,
Jason



More information about the linux-arm-kernel mailing list