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

iommu: Introduce domain attachment handle

Currently, when attaching a domain to a device or its PASID, domain is
stored within the iommu group. It could be retrieved for use during the
window between attachment and detachment.

With new features introduced, there's a need to store more information
than just a domain pointer. This information essentially represents the
association between a domain and a device. For example, the SVA code
already has a custom struct iommu_sva which represents a bond between
sva domain and a PASID of a device. Looking forward, the IOMMUFD needs
a place to store the iommufd_device pointer in the core, so that the
device object ID could be quickly retrieved in the critical fault handling
path.

Introduce domain attachment handle that explicitly represents the
attachment relationship between a domain and a device or its PASID.

Co-developed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
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-2-baolu.lu@linux.intel.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Lu Baolu and committed by
Will Deacon
14678219 83a7eefe

+40 -19
+1 -1
drivers/dma/idxd/init.c
··· 584 584 * DMA domain is owned by the driver, it should support all valid 585 585 * types such as DMA-FQ, identity, etc. 586 586 */ 587 - ret = iommu_attach_device_pasid(domain, dev, pasid); 587 + ret = iommu_attach_device_pasid(domain, dev, pasid, NULL); 588 588 if (ret) { 589 589 dev_err(dev, "failed to attach device pasid %d, domain type %d", 590 590 pasid, domain->type);
+8 -5
drivers/iommu/iommu-sva.c
··· 99 99 100 100 /* Search for an existing domain. */ 101 101 list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) { 102 - ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid); 102 + handle->handle.domain = domain; 103 + ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid, 104 + &handle->handle); 103 105 if (!ret) { 104 106 domain->users++; 105 107 goto out; ··· 115 113 goto out_free_handle; 116 114 } 117 115 118 - ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid); 116 + handle->handle.domain = domain; 117 + ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid, 118 + &handle->handle); 119 119 if (ret) 120 120 goto out_free_domain; 121 121 domain->users = 1; ··· 128 124 list_add(&handle->handle_item, &mm->iommu_mm->sva_handles); 129 125 mutex_unlock(&iommu_sva_lock); 130 126 handle->dev = dev; 131 - handle->domain = domain; 132 127 return handle; 133 128 134 129 out_free_domain: ··· 150 147 */ 151 148 void iommu_sva_unbind_device(struct iommu_sva *handle) 152 149 { 153 - struct iommu_domain *domain = handle->domain; 150 + struct iommu_domain *domain = handle->handle.domain; 154 151 struct iommu_mm_data *iommu_mm = domain->mm->iommu_mm; 155 152 struct device *dev = handle->dev; 156 153 ··· 173 170 174 171 u32 iommu_sva_get_pasid(struct iommu_sva *handle) 175 172 { 176 - struct iommu_domain *domain = handle->domain; 173 + struct iommu_domain *domain = handle->handle.domain; 177 174 178 175 return mm_get_enqcmd_pasid(domain->mm); 179 176 }
+16 -10
drivers/iommu/iommu.c
··· 3352 3352 * @domain: the iommu domain. 3353 3353 * @dev: the attached device. 3354 3354 * @pasid: the pasid of the device. 3355 + * @handle: the attach handle. 3355 3356 * 3356 3357 * Return: 0 on success, or an error. 3357 3358 */ 3358 3359 int iommu_attach_device_pasid(struct iommu_domain *domain, 3359 - struct device *dev, ioasid_t pasid) 3360 + struct device *dev, ioasid_t pasid, 3361 + struct iommu_attach_handle *handle) 3360 3362 { 3361 3363 /* Caller must be a probed driver on dev */ 3362 3364 struct iommu_group *group = dev->iommu_group; 3363 3365 struct group_device *device; 3364 - void *curr; 3365 3366 int ret; 3366 3367 3367 3368 if (!domain->ops->set_dev_pasid) ··· 3383 3382 } 3384 3383 } 3385 3384 3386 - curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL); 3387 - if (curr) { 3388 - ret = xa_err(curr) ? : -EBUSY; 3385 + if (handle) 3386 + handle->domain = domain; 3387 + 3388 + ret = xa_insert(&group->pasid_array, pasid, handle, GFP_KERNEL); 3389 + if (ret) 3389 3390 goto out_unlock; 3390 - } 3391 3391 3392 3392 ret = __iommu_set_group_pasid(domain, group, pasid); 3393 3393 if (ret) ··· 3416 3414 3417 3415 mutex_lock(&group->mutex); 3418 3416 __iommu_remove_group_pasid(group, pasid, domain); 3419 - WARN_ON(xa_erase(&group->pasid_array, pasid) != domain); 3417 + xa_erase(&group->pasid_array, pasid); 3420 3418 mutex_unlock(&group->mutex); 3421 3419 } 3422 3420 EXPORT_SYMBOL_GPL(iommu_detach_device_pasid); ··· 3441 3439 { 3442 3440 /* Caller must be a probed driver on dev */ 3443 3441 struct iommu_group *group = dev->iommu_group; 3444 - struct iommu_domain *domain; 3442 + struct iommu_attach_handle *handle; 3443 + struct iommu_domain *domain = NULL; 3445 3444 3446 3445 if (!group) 3447 3446 return NULL; 3448 3447 3449 3448 xa_lock(&group->pasid_array); 3450 - domain = xa_load(&group->pasid_array, pasid); 3449 + handle = xa_load(&group->pasid_array, pasid); 3450 + if (handle) 3451 + domain = handle->domain; 3452 + 3451 3453 if (type && domain && domain->type != type) 3452 - domain = ERR_PTR(-EBUSY); 3454 + domain = NULL; 3453 3455 xa_unlock(&group->pasid_array); 3454 3456 3455 3457 return domain;
+15 -3
include/linux/iommu.h
··· 989 989 /* ATS is supported */ 990 990 #define IOMMU_FWSPEC_PCI_RC_ATS (1 << 0) 991 991 992 + /* 993 + * An iommu attach handle represents a relationship between an iommu domain 994 + * and a PASID or RID of a device. It is allocated and managed by the component 995 + * that manages the domain and is stored in the iommu group during the time the 996 + * domain is attached. 997 + */ 998 + struct iommu_attach_handle { 999 + struct iommu_domain *domain; 1000 + }; 1001 + 992 1002 /** 993 1003 * struct iommu_sva - handle to a device-mm bond 994 1004 */ 995 1005 struct iommu_sva { 1006 + struct iommu_attach_handle handle; 996 1007 struct device *dev; 997 - struct iommu_domain *domain; 998 1008 struct list_head handle_item; 999 1009 refcount_t users; 1000 1010 }; ··· 1062 1052 void iommu_device_release_dma_owner(struct device *dev); 1063 1053 1064 1054 int iommu_attach_device_pasid(struct iommu_domain *domain, 1065 - struct device *dev, ioasid_t pasid); 1055 + struct device *dev, ioasid_t pasid, 1056 + struct iommu_attach_handle *handle); 1066 1057 void iommu_detach_device_pasid(struct iommu_domain *domain, 1067 1058 struct device *dev, ioasid_t pasid); 1068 1059 struct iommu_domain * ··· 1399 1388 } 1400 1389 1401 1390 static inline int iommu_attach_device_pasid(struct iommu_domain *domain, 1402 - struct device *dev, ioasid_t pasid) 1391 + struct device *dev, ioasid_t pasid, 1392 + struct iommu_attach_handle *handle) 1403 1393 { 1404 1394 return -ENODEV; 1405 1395 }