]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
iommu: Remove sva handle list
authorLu Baolu <baolu.lu@linux.intel.com>
Tue, 2 Jul 2024 06:34:36 +0000 (14:34 +0800)
committerWill Deacon <will@kernel.org>
Thu, 4 Jul 2024 12:46:18 +0000 (13:46 +0100)
The struct sva_iommu represents an association between an SVA domain and
a PASID of a device. It's stored in the iommu group's pasid array and also
tracked by a list in the per-mm data structure. Removes duplicate tracking
of sva_iommu by eliminating the list.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240702063444.105814-3-baolu.lu@linux.intel.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/iommu-priv.h
drivers/iommu/iommu-sva.c
drivers/iommu/iommu.c
include/linux/iommu.h

index 5f731d994803c6bb644ad8b078da026be1c51f28..f1536a5ebb0dc9d523b170f82b64e7f6bbf270d7 100644 (file)
@@ -28,4 +28,7 @@ void iommu_device_unregister_bus(struct iommu_device *iommu,
                                 const struct bus_type *bus,
                                 struct notifier_block *nb);
 
+struct iommu_attach_handle *iommu_attach_handle_get(struct iommu_group *group,
+                                                   ioasid_t pasid,
+                                                   unsigned int type);
 #endif /* __LINUX_IOMMU_PRIV_H */
index 0fb9232540626e64e7436fd6b952a17be666d81a..9b7f625174195c5339334468762d27431e265524 100644 (file)
@@ -41,7 +41,6 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
        }
        iommu_mm->pasid = pasid;
        INIT_LIST_HEAD(&iommu_mm->sva_domains);
-       INIT_LIST_HEAD(&iommu_mm->sva_handles);
        /*
         * Make sure the write to mm->iommu_mm is not reordered in front of
         * initialization to iommu_mm fields. If it does, readers may see a
@@ -69,11 +68,16 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
  */
 struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
 {
+       struct iommu_group *group = dev->iommu_group;
+       struct iommu_attach_handle *attach_handle;
        struct iommu_mm_data *iommu_mm;
        struct iommu_domain *domain;
        struct iommu_sva *handle;
        int ret;
 
+       if (!group)
+               return ERR_PTR(-ENODEV);
+
        mutex_lock(&iommu_sva_lock);
 
        /* Allocate mm->pasid if necessary. */
@@ -83,12 +87,22 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
                goto out_unlock;
        }
 
-       list_for_each_entry(handle, &mm->iommu_mm->sva_handles, handle_item) {
-               if (handle->dev == dev) {
-                       refcount_inc(&handle->users);
-                       mutex_unlock(&iommu_sva_lock);
-                       return handle;
+       /* A bond already exists, just take a reference`. */
+       attach_handle = iommu_attach_handle_get(group, iommu_mm->pasid, IOMMU_DOMAIN_SVA);
+       if (!IS_ERR(attach_handle)) {
+               handle = container_of(attach_handle, struct iommu_sva, handle);
+               if (attach_handle->domain->mm != mm) {
+                       ret = -EBUSY;
+                       goto out_unlock;
                }
+               refcount_inc(&handle->users);
+               mutex_unlock(&iommu_sva_lock);
+               return handle;
+       }
+
+       if (PTR_ERR(attach_handle) != -ENOENT) {
+               ret = PTR_ERR(attach_handle);
+               goto out_unlock;
        }
 
        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
@@ -99,7 +113,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
 
        /* Search for an existing domain. */
        list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) {
-               handle->handle.domain = domain;
                ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid,
                                                &handle->handle);
                if (!ret) {
@@ -115,7 +128,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
                goto out_free_handle;
        }
 
-       handle->handle.domain = domain;
        ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid,
                                        &handle->handle);
        if (ret)
@@ -125,7 +137,6 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
 
 out:
        refcount_set(&handle->users, 1);
-       list_add(&handle->handle_item, &mm->iommu_mm->sva_handles);
        mutex_unlock(&iommu_sva_lock);
        handle->dev = dev;
        return handle;
@@ -159,7 +170,6 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
                mutex_unlock(&iommu_sva_lock);
                return;
        }
-       list_del(&handle->handle_item);
 
        iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
        if (--domain->users == 0) {
index a712b0cc3a1d3772997a7c64a4280f6461d8ed5b..7890bd21dff6d95cc3c2899582213fa05272726f 100644 (file)
@@ -3486,3 +3486,34 @@ void iommu_free_global_pasid(ioasid_t pasid)
        ida_free(&iommu_global_pasid_ida, pasid);
 }
 EXPORT_SYMBOL_GPL(iommu_free_global_pasid);
+
+/**
+ * iommu_attach_handle_get - Return the attach handle
+ * @group: the iommu group that domain was attached to
+ * @pasid: the pasid within the group
+ * @type: matched domain type, 0 for any match
+ *
+ * Return handle or ERR_PTR(-ENOENT) on none, ERR_PTR(-EBUSY) on mismatch.
+ *
+ * Return the attach handle to the caller. The life cycle of an iommu attach
+ * handle is from the time when the domain is attached to the time when the
+ * domain is detached. Callers are required to synchronize the call of
+ * iommu_attach_handle_get() with domain attachment and detachment. The attach
+ * handle can only be used during its life cycle.
+ */
+struct iommu_attach_handle *
+iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int type)
+{
+       struct iommu_attach_handle *handle;
+
+       xa_lock(&group->pasid_array);
+       handle = xa_load(&group->pasid_array, pasid);
+       if (!handle)
+               handle = ERR_PTR(-ENOENT);
+       else if (type && handle->domain->type != type)
+               handle = ERR_PTR(-EBUSY);
+       xa_unlock(&group->pasid_array);
+
+       return handle;
+}
+EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL);
index afc5af0069bb342c14be65d29595d67e2b5f41d1..87ebcc29020e91dc958352445884b9af19a04e29 100644 (file)
@@ -1005,14 +1005,12 @@ struct iommu_attach_handle {
 struct iommu_sva {
        struct iommu_attach_handle      handle;
        struct device                   *dev;
-       struct list_head                handle_item;
        refcount_t                      users;
 };
 
 struct iommu_mm_data {
        u32                     pasid;
        struct list_head        sva_domains;
-       struct list_head        sva_handles;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,