diff mbox series

[05/30] iommu: Add iommu_probe_info

Message ID 5-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com
State New
Headers show
Series Make a new API for drivers to use to get their FW | expand

Commit Message

Jason Gunthorpe Nov. 30, 2023, 1:10 a.m. UTC
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 <jgg@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 mbox series

Patch

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);