Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu: Remove sva handle list

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>

authored by

Lu Baolu and committed by
Will Deacon
3e7f57d1 14678219

+54 -12
+3
drivers/iommu/iommu-priv.h
··· 28 28 const struct bus_type *bus, 29 29 struct notifier_block *nb); 30 30 31 + struct iommu_attach_handle *iommu_attach_handle_get(struct iommu_group *group, 32 + ioasid_t pasid, 33 + unsigned int type); 31 34 #endif /* __LINUX_IOMMU_PRIV_H */
+20 -10
drivers/iommu/iommu-sva.c
··· 41 41 } 42 42 iommu_mm->pasid = pasid; 43 43 INIT_LIST_HEAD(&iommu_mm->sva_domains); 44 - INIT_LIST_HEAD(&iommu_mm->sva_handles); 45 44 /* 46 45 * Make sure the write to mm->iommu_mm is not reordered in front of 47 46 * initialization to iommu_mm fields. If it does, readers may see a ··· 68 69 */ 69 70 struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm) 70 71 { 72 + struct iommu_group *group = dev->iommu_group; 73 + struct iommu_attach_handle *attach_handle; 71 74 struct iommu_mm_data *iommu_mm; 72 75 struct iommu_domain *domain; 73 76 struct iommu_sva *handle; 74 77 int ret; 78 + 79 + if (!group) 80 + return ERR_PTR(-ENODEV); 75 81 76 82 mutex_lock(&iommu_sva_lock); 77 83 ··· 87 83 goto out_unlock; 88 84 } 89 85 90 - list_for_each_entry(handle, &mm->iommu_mm->sva_handles, handle_item) { 91 - if (handle->dev == dev) { 92 - refcount_inc(&handle->users); 93 - mutex_unlock(&iommu_sva_lock); 94 - return handle; 86 + /* A bond already exists, just take a reference`. */ 87 + attach_handle = iommu_attach_handle_get(group, iommu_mm->pasid, IOMMU_DOMAIN_SVA); 88 + if (!IS_ERR(attach_handle)) { 89 + handle = container_of(attach_handle, struct iommu_sva, handle); 90 + if (attach_handle->domain->mm != mm) { 91 + ret = -EBUSY; 92 + goto out_unlock; 95 93 } 94 + refcount_inc(&handle->users); 95 + mutex_unlock(&iommu_sva_lock); 96 + return handle; 97 + } 98 + 99 + if (PTR_ERR(attach_handle) != -ENOENT) { 100 + ret = PTR_ERR(attach_handle); 101 + goto out_unlock; 96 102 } 97 103 98 104 handle = kzalloc(sizeof(*handle), GFP_KERNEL); ··· 113 99 114 100 /* Search for an existing domain. */ 115 101 list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) { 116 - handle->handle.domain = domain; 117 102 ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid, 118 103 &handle->handle); 119 104 if (!ret) { ··· 128 115 goto out_free_handle; 129 116 } 130 117 131 - handle->handle.domain = domain; 132 118 ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid, 133 119 &handle->handle); 134 120 if (ret) ··· 137 125 138 126 out: 139 127 refcount_set(&handle->users, 1); 140 - list_add(&handle->handle_item, &mm->iommu_mm->sva_handles); 141 128 mutex_unlock(&iommu_sva_lock); 142 129 handle->dev = dev; 143 130 return handle; ··· 170 159 mutex_unlock(&iommu_sva_lock); 171 160 return; 172 161 } 173 - list_del(&handle->handle_item); 174 162 175 163 iommu_detach_device_pasid(domain, dev, iommu_mm->pasid); 176 164 if (--domain->users == 0) {
+31
drivers/iommu/iommu.c
··· 3486 3486 ida_free(&iommu_global_pasid_ida, pasid); 3487 3487 } 3488 3488 EXPORT_SYMBOL_GPL(iommu_free_global_pasid); 3489 + 3490 + /** 3491 + * iommu_attach_handle_get - Return the attach handle 3492 + * @group: the iommu group that domain was attached to 3493 + * @pasid: the pasid within the group 3494 + * @type: matched domain type, 0 for any match 3495 + * 3496 + * Return handle or ERR_PTR(-ENOENT) on none, ERR_PTR(-EBUSY) on mismatch. 3497 + * 3498 + * Return the attach handle to the caller. The life cycle of an iommu attach 3499 + * handle is from the time when the domain is attached to the time when the 3500 + * domain is detached. Callers are required to synchronize the call of 3501 + * iommu_attach_handle_get() with domain attachment and detachment. The attach 3502 + * handle can only be used during its life cycle. 3503 + */ 3504 + struct iommu_attach_handle * 3505 + iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int type) 3506 + { 3507 + struct iommu_attach_handle *handle; 3508 + 3509 + xa_lock(&group->pasid_array); 3510 + handle = xa_load(&group->pasid_array, pasid); 3511 + if (!handle) 3512 + handle = ERR_PTR(-ENOENT); 3513 + else if (type && handle->domain->type != type) 3514 + handle = ERR_PTR(-EBUSY); 3515 + xa_unlock(&group->pasid_array); 3516 + 3517 + return handle; 3518 + } 3519 + EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL);
-2
include/linux/iommu.h
··· 1005 1005 struct iommu_sva { 1006 1006 struct iommu_attach_handle handle; 1007 1007 struct device *dev; 1008 - struct list_head handle_item; 1009 1008 refcount_t users; 1010 1009 }; 1011 1010 1012 1011 struct iommu_mm_data { 1013 1012 u32 pasid; 1014 1013 struct list_head sva_domains; 1015 - struct list_head sva_handles; 1016 1014 }; 1017 1015 1018 1016 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,