On Thu, Mar 14, 2024 at 03:41:23PM +0800, Baolu Lu wrote: > The whole cookie mechanism aims to address two things: > > - Extend the domain lifetime until all pending page faults are > resolved. Like you answered, I think the flush is a simpler scheme.. > - Associate information about the iommu device with each attachment of > the domain so that the iommufd device object ID could be quickly > retrieved in the fault delivering path. > > I see we also need to stick a pointer in the domain for iommufd to get > > back to the hwpt, but that doesn't seem to need such a big system to > > accomplish - just add a void *. It would make sense for the domain to > > have some optional pointer to a struct for all the fault related data > > that becomes allocated when a PRI domain is created.. > > It's not getting back hwpt from domain, just getting the iommufd_device > in the fault delivering path. The iommufd_device is not per-domain, but > per-domain-attachment. It does make sense you'd need that, but I think something like this is a more direct way to get it. Caller allocates the handle struct. The iopf will provide the handle from the XA to the callback. container_of() not void * is used to in the caller's API. diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 68e648b5576706..0d29d8f0847cd9 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -46,6 +46,8 @@ static unsigned int iommu_def_domain_type __read_mostly; static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT); static u32 iommu_cmd_line __read_mostly; +enum { IOMMU_PASID_ARRAY_DOMAIN, IOMMU_PASID_ARRAY_HANDLE }; + struct iommu_group { struct kobject kobj; struct kobject *devices_kobj; @@ -3516,18 +3518,20 @@ static void __iommu_remove_group_pasid(struct iommu_group *group, } /* - * iommu_attach_device_pasid() - Attach a domain to pasid of device + * __iommu_attach_device_pasid() - Attach a domain to pasid of device * @domain: the iommu domain. * @dev: the attached device. * @pasid: the pasid of the device. * * Return: 0 on success, or an error. */ -int iommu_attach_device_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid) +int __iommu_attach_device_pasid(struct iommu_domain *domain, struct device *dev, + ioasid_t pasid, + struct iommu_pasid_handle *handle) { /* Caller must be a probed driver on dev */ struct iommu_group *group = dev->iommu_group; + void *xa_entry; void *curr; int ret; @@ -3541,9 +3545,14 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, return -EINVAL; mutex_lock(&group->mutex); - curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL); + if (handle) + xa_entry = xa_tag_pointer(handle, IOMMU_PASID_ARRAY_HANDLE); + else + xa_entry = xa_tag_pointer(domain, IOMMU_PASID_ARRAY_DOMAIN); + curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, xa_entry, + GFP_KERNEL); if (curr) { - ret = xa_err(curr) ? : -EBUSY; + ret = xa_err(curr) ?: -EBUSY; goto out_unlock; } @@ -3556,7 +3565,7 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, mutex_unlock(&group->mutex); return ret; } -EXPORT_SYMBOL_GPL(iommu_attach_device_pasid); +EXPORT_SYMBOL_GPL(__iommu_attach_device_pasid); /* * iommu_detach_device_pasid() - Detach the domain from pasid of device @@ -3600,13 +3609,23 @@ struct iommu_domain *iommu_get_domain_for_dev_pasid(struct device *dev, { /* Caller must be a probed driver on dev */ struct iommu_group *group = dev->iommu_group; + struct iommu_pasid_handle *handle; struct iommu_domain *domain; + void *xa_entry; if (!group) return NULL; xa_lock(&group->pasid_array); - domain = xa_load(&group->pasid_array, pasid); + xa_entry = xa_load(&group->pasid_array, pasid); + if (xa_pointer_tag(xa_entry) == IOMMU_PASID_ARRAY_HANDLE) { + handle = xa_untag_pointer(xa_entry); + domain = handle->domain; + } else if (xa_pointer_tag(xa_entry) == IOMMU_PASID_ARRAY_DOMAIN) { + domain = xa_untag_pointer(xa_entry); + } else { + domain = NULL; + } if (type && domain && domain->type != type) domain = ERR_PTR(-EBUSY); xa_unlock(&group->pasid_array); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 1ea2a820e1eb03..47c121d4e13f65 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -947,8 +947,27 @@ void iommu_device_release_dma_owner(struct device *dev); struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm); -int iommu_attach_device_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid); + +struct iommu_pasid_handle { + struct iommu_domain *domain; +}; + +int __iommu_attach_device_pasid(struct iommu_domain *domain, struct device *dev, + ioasid_t pasid, + struct iommu_pasid_handle *handle); + +static inline int iommu_attach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + return __iommu_attach_device_pasid(domain, dev, pasid, NULL); +} +static inline int +iommu_attach_device_pasid_handle(struct iommu_pasid_handle *handle, + struct device *dev, ioasid_t pasid) +{ + return __iommu_attach_device_pasid(handle->domain, dev, pasid, handle); +} + void iommu_detach_device_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid); struct iommu_domain *