On systems with multiple IOMMUs, bus-level granularity can be too
coarse, particularly on the platform "bus", where the hardware may
actually warrant multiple different iommu_ops, which we currently have
no way at all to accommodate. As an initial step towards the necessary
flexibility, allow the device-focused API calls to use the ops provided
by the device-specific IOMMU instance data (when present) in preference
to the bus ops.

Signed-off-by: Robin Murphy <robin.mur...@arm.com>
---
 drivers/iommu/iommu.c | 56 +++++++++++++++++++++++++--------------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9a2f1960873b..eab883e6c5a9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -37,10 +37,6 @@
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
 
-struct iommu_callback_data {
-       const struct iommu_ops *ops;
-};
-
 struct iommu_group {
        struct kobject kobj;
        struct kobject *devices_kobj;
@@ -77,7 +73,7 @@ struct iommu_group_attribute iommu_group_attr_##_name =       
        \
 #define to_iommu_group(_kobj)          \
        container_of(_kobj, struct iommu_group, kobj)
 
-static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
+static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
                                                 unsigned type);
 static int __iommu_attach_device(struct iommu_domain *domain,
                                 struct device *dev);
@@ -801,6 +797,14 @@ struct iommu_group *pci_device_group(struct device *dev)
        return group;
 }
 
+static const struct iommu_ops *dev_iommu_ops(struct device *dev)
+{
+       if (dev->iommu_fwspec && dev->iommu_fwspec->ops)
+               return dev->iommu_fwspec->ops;
+
+       return dev->bus->iommu_ops;
+}
+
 /**
  * iommu_group_get_for_dev - Find or create the IOMMU group for a device
  * @dev: target device
@@ -813,7 +817,7 @@ struct iommu_group *pci_device_group(struct device *dev)
  */
 struct iommu_group *iommu_group_get_for_dev(struct device *dev)
 {
-       const struct iommu_ops *ops = dev->bus->iommu_ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
        struct iommu_group *group;
        int ret;
 
@@ -834,7 +838,7 @@ struct iommu_group *iommu_group_get_for_dev(struct device 
*dev)
         * IOMMU driver.
         */
        if (!group->default_domain) {
-               group->default_domain = __iommu_domain_alloc(dev->bus,
+               group->default_domain = __iommu_domain_alloc(ops,
                                                             IOMMU_DOMAIN_DMA);
                if (!group->domain)
                        group->domain = group->default_domain;
@@ -856,8 +860,7 @@ struct iommu_domain *iommu_group_default_domain(struct 
iommu_group *group)
 
 static int add_iommu_group(struct device *dev, void *data)
 {
-       struct iommu_callback_data *cb = data;
-       const struct iommu_ops *ops = cb->ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
        int ret;
 
        if (!ops->add_device)
@@ -880,8 +883,7 @@ static int add_iommu_group(struct device *dev, void *data)
 
 static int remove_iommu_group(struct device *dev, void *data)
 {
-       struct iommu_callback_data *cb = data;
-       const struct iommu_ops *ops = cb->ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
 
        if (ops->remove_device && dev->iommu_group)
                ops->remove_device(dev);
@@ -893,7 +895,7 @@ static int iommu_bus_notifier(struct notifier_block *nb,
                              unsigned long action, void *data)
 {
        struct device *dev = data;
-       const struct iommu_ops *ops = dev->bus->iommu_ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
        struct iommu_group *group;
        unsigned long group_action = 0;
 
@@ -946,9 +948,6 @@ static int iommu_bus_init(struct bus_type *bus, const 
struct iommu_ops *ops)
 {
        int err;
        struct notifier_block *nb;
-       struct iommu_callback_data cb = {
-               .ops = ops,
-       };
 
        nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
        if (!nb)
@@ -960,7 +959,7 @@ static int iommu_bus_init(struct bus_type *bus, const 
struct iommu_ops *ops)
        if (err)
                goto out_free;
 
-       err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
+       err = bus_for_each_dev(bus, NULL, NULL, add_iommu_group);
        if (err)
                goto out_err;
 
@@ -969,7 +968,7 @@ static int iommu_bus_init(struct bus_type *bus, const 
struct iommu_ops *ops)
 
 out_err:
        /* Clean up */
-       bus_for_each_dev(bus, NULL, &cb, remove_iommu_group);
+       bus_for_each_dev(bus, NULL, NULL, remove_iommu_group);
        bus_unregister_notifier(bus, nb);
 
 out_free:
@@ -1047,29 +1046,29 @@ void iommu_set_fault_handler(struct iommu_domain 
*domain,
 }
 EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
 
-static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
+static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
                                                 unsigned type)
 {
        struct iommu_domain *domain;
 
-       if (bus == NULL || bus->iommu_ops == NULL)
-               return NULL;
-
-       domain = bus->iommu_ops->domain_alloc(type);
+       domain = ops->domain_alloc(type);
        if (!domain)
                return NULL;
 
-       domain->ops  = bus->iommu_ops;
+       domain->ops  = ops;
        domain->type = type;
        /* Assume all sizes by default; the driver may override this later */
-       domain->pgsize_bitmap  = bus->iommu_ops->pgsize_bitmap;
+       domain->pgsize_bitmap  = ops->pgsize_bitmap;
 
        return domain;
 }
 
 struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
 {
-       return __iommu_domain_alloc(bus, IOMMU_DOMAIN_UNMANAGED);
+       if (bus == NULL || bus->iommu_ops == NULL)
+               return NULL;
+
+       return __iommu_domain_alloc(bus->iommu_ops, IOMMU_DOMAIN_UNMANAGED);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_alloc);
 
@@ -1548,7 +1547,7 @@ int iommu_domain_set_attr(struct iommu_domain *domain,
 
 void iommu_get_dm_regions(struct device *dev, struct list_head *list)
 {
-       const struct iommu_ops *ops = dev->bus->iommu_ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
 
        if (ops && ops->get_dm_regions)
                ops->get_dm_regions(dev, list);
@@ -1556,7 +1555,7 @@ void iommu_get_dm_regions(struct device *dev, struct 
list_head *list)
 
 void iommu_put_dm_regions(struct device *dev, struct list_head *list)
 {
-       const struct iommu_ops *ops = dev->bus->iommu_ops;
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
 
        if (ops && ops->put_dm_regions)
                ops->put_dm_regions(dev, list);
@@ -1565,6 +1564,7 @@ void iommu_put_dm_regions(struct device *dev, struct 
list_head *list)
 /* Request that a device is direct mapped by the IOMMU */
 int iommu_request_dm_for_dev(struct device *dev)
 {
+       const struct iommu_ops *ops = dev_iommu_ops(dev);
        struct iommu_domain *dm_domain;
        struct iommu_group *group;
        int ret;
@@ -1589,7 +1589,7 @@ int iommu_request_dm_for_dev(struct device *dev)
 
        /* Allocate a direct mapped domain */
        ret = -ENOMEM;
-       dm_domain = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_IDENTITY);
+       dm_domain = __iommu_domain_alloc(ops, IOMMU_DOMAIN_IDENTITY);
        if (!dm_domain)
                goto out;
 
-- 
1.9.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to