@@ -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) {
@@ -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;
@@ -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;
new file mode 100644
@@ -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
@@ -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);
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