summaryrefslogtreecommitdiff
path: root/drivers/iommu/iommu.c
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2023-06-06 03:59:39 +0300
committerJoerg Roedel <jroedel@suse.de>2023-07-14 17:14:12 +0300
commit6eb4da8cf54537992fc9843be8b2af4f83f717e0 (patch)
treefdc31f8e6f8122fd41993dc2e71e995d88555155 /drivers/iommu/iommu.c
parent06c2afb862f9da8dc5efa4b6076a0e48c3fbaaa5 (diff)
downloadlinux-6eb4da8cf54537992fc9843be8b2af4f83f717e0.tar.xz
iommu: Have __iommu_probe_device() check for already probed devices
This is a step toward making __iommu_probe_device() self contained. It should, under proper locking, check if the device is already associated with an iommu driver and resolve parallel probes. All but one of the callers open code this test using two different means, but they all rely on dev->iommu_group. Currently the bus_iommu_probe()/probe_iommu_group() and probe_acpi_namespace_devices() rejects already probed devices with an unlocked read of dev->iommu_group. The OF and ACPI "replay" functions use device_iommu_mapped() which is the same read without the pointless refcount. Move this test into __iommu_probe_device() and put it under the iommu_probe_device_lock. The store to dev->iommu_group is in iommu_group_add_device() which is also called under this lock for iommu driver devices, making it properly locked. The only path that didn't have this check is the hotplug path triggered by BUS_NOTIFY_ADD_DEVICE. The only way to get dev->iommu_group assigned outside the probe path is via iommu_group_add_device(). Today the only caller is VFIO no-iommu which never associates with an iommu driver. Thus adding this additional check is safe. Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/1-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/iommu.c')
-rw-r--r--drivers/iommu/iommu.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index da340f11c5f5..bdc5ce884b7b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -351,9 +351,16 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
* but for now enforcing a simple global ordering is fine.
*/
mutex_lock(&iommu_probe_device_lock);
+
+ /* Device is probed already if in a group */
+ if (dev->iommu_group) {
+ ret = 0;
+ goto out_unlock;
+ }
+
if (!dev_iommu_get(dev)) {
ret = -ENOMEM;
- goto err_unlock;
+ goto out_unlock;
}
if (!try_module_get(ops->owner)) {
@@ -399,7 +406,7 @@ out_module_put:
err_free:
dev_iommu_free(dev);
-err_unlock:
+out_unlock:
mutex_unlock(&iommu_probe_device_lock);
return ret;
@@ -1711,16 +1718,8 @@ struct iommu_domain *iommu_group_default_domain(struct iommu_group *group)
static int probe_iommu_group(struct device *dev, void *data)
{
struct list_head *group_list = data;
- struct iommu_group *group;
int ret;
- /* Device is probed already if in a group */
- group = iommu_group_get(dev);
- if (group) {
- iommu_group_put(group);
- return 0;
- }
-
ret = __iommu_probe_device(dev, group_list);
if (ret == -ENODEV)
ret = 0;