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@xxxxxxxxxx> --- 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