diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9dd41386fe413d9be06f08c587a4a9761d2865d7..ee885238a72ee8b933b3cfef7a7ec7c1bfd0e98b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3067,6 +3067,55 @@ int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) } EXPORT_SYMBOL_GPL(iommu_aux_get_pasid); +struct iommu_sva_bind_group_data { + struct mm_struct *mm; + struct iommu_sva *handle; + void *drvdata; +}; + +static int iommu_group_do_bind_dev(struct device *dev, void *data) +{ + struct iommu_sva_bind_group_data *bind = data; + const struct iommu_ops *ops = dev->bus->iommu_ops; + + if (!ops || !ops->sva_bind) + return -ENODEV; + + bind->handle = ops->sva_bind(dev, bind->mm, bind->drvdata); + return PTR_ERR_OR_ZERO(bind->handle); +} + +struct iommu_sva * +iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm, + void *drvdata) +{ + int ret = -EINVAL; + struct iommu_sva_bind_group_data data = { + .mm = mm, + .drvdata = drvdata, + }; + + /* Ensure device count and domain don't change while we're binding */ + mutex_lock(&group->mutex); + + /* + * To keep things simple, SVA currently doesn't support IOMMU groups + * with more than one device. Existing SVA-capable systems are not + * affected by the problems that required IOMMU groups (lack of ACS + * isolation, device ID aliasing and other hardware issues). + */ + if (iommu_group_device_count(group) != 1) + goto out_unlock; + + ret = __iommu_group_for_each_dev(group, &data, + iommu_group_do_bind_dev); +out_unlock: + mutex_unlock(&group->mutex); + + return ret ? ERR_PTR(ret) : data.handle; +} +EXPORT_SYMBOL_GPL(iommu_sva_bind_group); + /** * iommu_sva_bind_device() - Bind a process address space to a device * @dev: the device @@ -3085,33 +3134,14 @@ EXPORT_SYMBOL_GPL(iommu_aux_get_pasid); struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata) { + struct iommu_sva *handle; struct iommu_group *group; - struct iommu_sva *handle = ERR_PTR(-EINVAL); - const struct iommu_ops *ops = dev->bus->iommu_ops; - - if (!ops || !ops->sva_bind) - return ERR_PTR(-ENODEV); group = iommu_group_get(dev); if (!group) return ERR_PTR(-ENODEV); - /* Ensure device count and domain don't change while we're binding */ - mutex_lock(&group->mutex); - - /* - * To keep things simple, SVA currently doesn't support IOMMU groups - * with more than one device. Existing SVA-capable systems are not - * affected by the problems that required IOMMU groups (lack of ACS - * isolation, device ID aliasing and other hardware issues). - */ - if (iommu_group_device_count(group) != 1) - goto out_unlock; - - handle = ops->sva_bind(dev, mm, drvdata); - -out_unlock: - mutex_unlock(&group->mutex); + handle = iommu_sva_bind_group(group, mm, drvdata); iommu_group_put(group); return handle; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index aa453c9dd032d67e7a06e89307806ab719cd12e8..30795e2b15a5c2bfee767d634e5033930e3f9a74 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -666,6 +666,9 @@ int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev); struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata); +extern struct iommu_sva * +iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm, + void *drvdata); void iommu_sva_unbind_device(struct iommu_sva *handle); u32 iommu_sva_get_pasid(struct iommu_sva *handle); @@ -1107,6 +1110,13 @@ int iommu_attach_pasid_table(struct iommu_domain *domain, static inline void iommu_detach_pasid_table(struct iommu_domain *domain) {} +static inline struct iommu_sva * +iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm, + void *drvdata) +{ + return -ENODEV; +} + #endif /* CONFIG_IOMMU_API */ /**