Re: [PATCH v3 4/7] iommu: Switch __iommu_domain_alloc() to device ops

From: Baolu Lu
Date: Mon Sep 18 2023 - 02:15:02 EST


On 9/16/23 12:58 AM, Robin Murphy wrote:
@@ -1997,16 +1995,13 @@ void iommu_set_fault_handler(struct iommu_domain *domain,
}
EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
-static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus,
+static struct iommu_domain *__iommu_domain_alloc(struct device *dev,
unsigned type)
{
- const struct iommu_ops *ops = bus ? bus->iommu_ops : NULL;
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
struct iommu_domain *domain;
unsigned int alloc_type = type & IOMMU_DOMAIN_ALLOC_FLAGS;
- if (!ops)
- return NULL;
-
domain = ops->domain_alloc(alloc_type);
if (!domain)
return NULL;
@@ -2030,9 +2025,28 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus,
return domain;
}
+static int __iommu_domain_alloc_dev(struct device *dev, void *data)
+{
+ struct device **alloc_dev = data;
+
+ if (!dev_has_iommu(dev))
+ return 0;
+
+ WARN_ONCE(*alloc_dev && dev_iommu_ops(dev) != dev_iommu_ops(*alloc_dev),
+ "Multiple IOMMU drivers present, which the public IOMMU API can't fully support yet. You may still need to disable one or more to get the expected result here, sorry!\n");
+
+ *alloc_dev = dev;
+ return 0;
+}
+
struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
{
- return __iommu_domain_alloc(bus, IOMMU_DOMAIN_UNMANAGED);
+ struct device *dev = NULL;
+
+ if (bus_for_each_dev(bus, NULL, &dev, __iommu_domain_alloc_dev))
+ return NULL;

__iommu_domain_alloc_dev() always returns 0. Hence above if condition
will never be true. Perhaps, in __iommu_domain_alloc_dev(),

if (WARN_ON(*alloc_dev && dev_iommu_ops(dev) !=
dev_iommu_ops(*alloc_dev))
return -EPERM;

?

+
+ return __iommu_domain_alloc(dev, IOMMU_DOMAIN_UNMANAGED);

Is it possible that all devices on this bus have dev_has_iommu() to be
false? If so, we probably need something like below:

if (!dev_has_iommu(dev))
return -ENODEV;

?

}
EXPORT_SYMBOL_GPL(iommu_domain_alloc);
@@ -3228,13 +3242,17 @@ static int __iommu_group_alloc_blocking_domain(struct iommu_group *group)
if (group->blocking_domain)
return 0;
- group->blocking_domain = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_BLOCKED);
+ /* noiommu groups should never be here */
+ if (WARN_ON(!dev_has_iommu(dev)))
+ return -ENODEV;
+
+ group->blocking_domain = __iommu_domain_alloc(dev, IOMMU_DOMAIN_BLOCKED);
if (!group->blocking_domain) {
/*
* For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED
* create an empty domain instead.
*/
- group->blocking_domain = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_UNMANAGED);
+ group->blocking_domain = __iommu_domain_alloc(dev, IOMMU_DOMAIN_UNMANAGED);
if (!group->blocking_domain)
return -EINVAL;
}

Best regards,
baolu