This is a stack structure that is passed around all the parts of probe to
allow them to exchange data.

With the new design this will be a place for the FW logic to cache data to
avoid reparsing and a to convey the currently active call path for probe
while we work on restructuring parts of it.

Place this in a new header "iommu-driver.h" which is intended to help
isolate APIs that are only for use by the drivers away from the consumers
of the IOMMU API.

Signed-off-by: Jason Gunthorpe <j...@nvidia.com>
---
 drivers/acpi/scan.c          |  7 +++++-
 drivers/iommu/iommu.c        | 42 ++++++++++++++++++++++++++----------
 drivers/iommu/of_iommu.c     |  6 +++++-
 include/linux/iommu-driver.h | 25 +++++++++++++++++++++
 include/linux/iommu.h        |  3 +++
 5 files changed, 70 insertions(+), 13 deletions(-)
 create mode 100644 include/linux/iommu-driver.h

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 340ba720c72129..9c13df632aa5e0 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1543,6 +1543,8 @@ int acpi_dma_get_range(struct device *dev, const struct 
bus_dma_region **map)
 }
 
 #ifdef CONFIG_IOMMU_API
+#include <linux/iommu-driver.h>
+
 int acpi_iommu_fwspec_init(struct device *dev, u32 id,
                           struct fwnode_handle *fwnode,
                           const struct iommu_ops *ops)
@@ -1566,6 +1568,9 @@ static int acpi_iommu_configure_id(struct device *dev, 
const u32 *id_in)
 {
        int err;
        const struct iommu_ops *ops;
+       struct iommu_probe_info pinf = {
+               .dev = dev,
+       };
 
        /* Serialise to make dev->iommu stable under our potential fwspec */
        mutex_lock(&iommu_probe_device_lock);
@@ -1589,7 +1594,7 @@ static int acpi_iommu_configure_id(struct device *dev, 
const u32 *id_in)
         * iommu_probe_device() call for dev, replay it to get things in order.
         */
        if (!err && dev->bus)
-               err = iommu_probe_device(dev);
+               err = iommu_probe_device_pinf(&pinf);
 
        /* Ignore all other errors apart from EPROBE_DEFER */
        if (err == -EPROBE_DEFER) {
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 9557c2ec08d915..76b245973cfafc 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/host1x_context_bus.h>
 #include <linux/iommu.h>
+#include <linux/iommu-driver.h>
 #include <linux/idr.h>
 #include <linux/err.h>
 #include <linux/pci.h>
@@ -399,8 +400,10 @@ EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
  * Init the dev->iommu and dev->iommu_group in the struct device and get the
  * driver probed
  */
-static int iommu_init_device(struct device *dev, const struct iommu_ops *ops)
+static int iommu_init_device(struct iommu_probe_info *pinf,
+                            const struct iommu_ops *ops)
 {
+       struct device *dev = pinf->dev;
        struct iommu_device *iommu_dev;
        struct iommu_group *group;
        int ret;
@@ -413,7 +416,10 @@ static int iommu_init_device(struct device *dev, const 
struct iommu_ops *ops)
                goto err_free;
        }
 
-       iommu_dev = ops->probe_device(dev);
+       if (ops->probe_device_pinf)
+               iommu_dev = ops->probe_device_pinf(pinf);
+       else
+               iommu_dev = ops->probe_device(dev);
        if (IS_ERR(iommu_dev)) {
                ret = PTR_ERR(iommu_dev);
                goto err_module_put;
@@ -496,8 +502,9 @@ static void iommu_deinit_device(struct device *dev)
 
 DEFINE_MUTEX(iommu_probe_device_lock);
 
-static int __iommu_probe_device(struct device *dev, struct list_head 
*group_list)
+static int __iommu_probe_device(struct iommu_probe_info *pinf)
 {
+       struct device *dev = pinf->dev;
        const struct iommu_ops *ops;
        struct iommu_fwspec *fwspec;
        struct iommu_group *group;
@@ -533,7 +540,7 @@ static int __iommu_probe_device(struct device *dev, struct 
list_head *group_list
        if (dev->iommu_group)
                return 0;
 
-       ret = iommu_init_device(dev, ops);
+       ret = iommu_init_device(pinf, ops);
        if (ret)
                return ret;
 
@@ -557,7 +564,7 @@ static int __iommu_probe_device(struct device *dev, struct 
list_head *group_list
                ret = __iommu_device_set_domain(group, dev, group->domain, 0);
                if (ret)
                        goto err_remove_gdev;
-       } else if (!group->default_domain && !group_list) {
+       } else if (!group->default_domain && !pinf->defer_setup) {
                ret = iommu_setup_default_domain(group, 0);
                if (ret)
                        goto err_remove_gdev;
@@ -568,7 +575,7 @@ static int __iommu_probe_device(struct device *dev, struct 
list_head *group_list
                 * that need further setup.
                 */
                if (list_empty(&group->entry))
-                       list_add_tail(&group->entry, group_list);
+                       list_add_tail(&group->entry, pinf->deferred_group_list);
        }
        mutex_unlock(&group->mutex);
 
@@ -588,13 +595,14 @@ static int __iommu_probe_device(struct device *dev, 
struct list_head *group_list
        return ret;
 }
 
-int iommu_probe_device(struct device *dev)
+int iommu_probe_device_pinf(struct iommu_probe_info *pinf)
 {
+       struct device *dev = pinf->dev;
        const struct iommu_ops *ops;
        int ret;
 
        mutex_lock(&iommu_probe_device_lock);
-       ret = __iommu_probe_device(dev, NULL);
+       ret = __iommu_probe_device(pinf);
        mutex_unlock(&iommu_probe_device_lock);
        if (ret)
                return ret;
@@ -606,6 +614,13 @@ int iommu_probe_device(struct device *dev)
        return 0;
 }
 
+int iommu_probe_device(struct device *dev)
+{
+       struct iommu_probe_info pinf = {.dev = dev};
+
+       return iommu_probe_device_pinf(&pinf);
+}
+
 static void __iommu_group_free_device(struct iommu_group *group,
                                      struct group_device *grp_dev)
 {
@@ -1830,11 +1845,12 @@ 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_probe_info *pinf = data;
        int ret;
 
+       pinf->dev = dev;
        mutex_lock(&iommu_probe_device_lock);
-       ret = __iommu_probe_device(dev, group_list);
+       ret = __iommu_probe_device(pinf);
        mutex_unlock(&iommu_probe_device_lock);
        if (ret == -ENODEV)
                ret = 0;
@@ -1977,9 +1993,13 @@ int bus_iommu_probe(const struct bus_type *bus)
 {
        struct iommu_group *group, *next;
        LIST_HEAD(group_list);
+       struct iommu_probe_info pinf = {
+               .deferred_group_list = &group_list,
+               .defer_setup = true,
+       };
        int ret;
 
-       ret = bus_for_each_dev(bus, NULL, &group_list, probe_iommu_group);
+       ret = bus_for_each_dev(bus, NULL, &pinf, probe_iommu_group);
        if (ret)
                return ret;
 
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 3d4580f1fbb378..fb743ddd239e0b 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -7,6 +7,7 @@
 
 #include <linux/export.h>
 #include <linux/iommu.h>
+#include <linux/iommu-driver.h>
 #include <linux/limits.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -139,6 +140,9 @@ static int of_iommu_for_each_id(struct device *dev,
 int of_iommu_configure(struct device *dev, struct device_node *master_np,
                       const u32 *id)
 {
+       struct iommu_probe_info pinf = {
+               .dev = dev,
+       };
        struct iommu_fwspec *fwspec;
        int err;
 
@@ -167,7 +171,7 @@ int of_iommu_configure(struct device *dev, struct 
device_node *master_np,
        if (err)
                goto err_log;
 
-       err = iommu_probe_device(dev);
+       err = iommu_probe_device_pinf(&pinf);
        if (err)
                goto err_log;
        return 0;
diff --git a/include/linux/iommu-driver.h b/include/linux/iommu-driver.h
new file mode 100644
index 00000000000000..b85c9f15cf478b
--- /dev/null
+++ b/include/linux/iommu-driver.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES
+ *
+ * This file should ONLY be included by iommu drivers. These API
+ * calls are NOT to be used generally.
+ */
+#ifndef __LINUX_IOMMU_DRIVER_H
+#define __LINUX_IOMMU_DRIVER_H
+
+#ifndef CONFIG_IOMMU_API
+#error "CONFIG_IOMMU_API is not set, should this header be included?"
+#endif
+
+#include <linux/types.h>
+
+struct iommu_probe_info {
+       struct device *dev;
+       struct list_head *deferred_group_list;
+       bool defer_setup : 1;
+};
+
+int iommu_probe_device_pinf(struct iommu_probe_info *pinf);
+
+#endif
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index c24933a1d0d643..cf578b8e0b59a4 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -43,6 +43,7 @@ struct notifier_block;
 struct iommu_sva;
 struct iommu_fault_event;
 struct iommu_dma_cookie;
+struct iommu_probe_info;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ       0x0
@@ -347,6 +348,7 @@ static inline int __iommu_copy_struct_from_user(
  * @domain_alloc_paging: Allocate an iommu_domain that can be used for
  *                       UNMANAGED, DMA, and DMA_FQ domain types.
  * @probe_device: Add device to iommu driver handling
+ * @probe_device_pinf: New API for probe_device
  * @release_device: Remove device from iommu driver handling
  * @probe_finalize: Do final setup work after the device is added to an IOMMU
  *                  group and attached to the groups domain
@@ -388,6 +390,7 @@ struct iommu_ops {
        struct iommu_domain *(*domain_alloc_paging)(struct device *dev);
 
        struct iommu_device *(*probe_device)(struct device *dev);
+       struct iommu_device *(*probe_device_pinf)(struct iommu_probe_info 
*pinf);
        void (*release_device)(struct device *dev);
        void (*probe_finalize)(struct device *dev);
        struct iommu_group *(*device_group)(struct device *dev);
-- 
2.42.0


Reply via email to