Skip to content

Commit

Permalink
iommu: Always register bus notifiers
Browse files Browse the repository at this point in the history
The number of bus types that the IOMMU subsystem deals with is small and
manageable, so pull that list into core code as a first step towards
cleaning up all the boilerplate bus-awareness from drivers. Calling
iommu_probe_device() before bus->iommu_ops is set will simply return
-ENODEV and not break the notifier call chain, so there should be no
harm in proactively registering all our bus notifiers at init time.

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com> # s390
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com> # s390
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/7462347bf938bd6eedb629a3a318434f6516e712.1660572783.git.robin.murphy@arm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
Robin Murphy authored and Joerg Roedel committed Sep 7, 2022
1 parent 927a5fd commit c13dbc1
Showing 1 changed file with 37 additions and 35 deletions.
72 changes: 37 additions & 35 deletions drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#define pr_fmt(fmt) "iommu: " fmt

#include <linux/amba/bus.h>
#include <linux/device.h>
#include <linux/dma-iommu.h>
#include <linux/kernel.h>
Expand All @@ -16,11 +17,13 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/host1x_context_bus.h>
#include <linux/iommu.h>
#include <linux/idr.h>
#include <linux/err.h>
#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/fsl/mc.h>
#include <linux/module.h>
Expand Down Expand Up @@ -75,6 +78,8 @@ static const char * const iommu_group_resv_type_string[] = {
#define IOMMU_CMD_LINE_DMA_API BIT(0)
#define IOMMU_CMD_LINE_STRICT BIT(1)

static int iommu_bus_notifier(struct notifier_block *nb,
unsigned long action, void *data);
static int iommu_alloc_default_domain(struct iommu_group *group,
struct device *dev);
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
Expand Down Expand Up @@ -103,6 +108,22 @@ struct iommu_group_attribute iommu_group_attr_##_name = \
static LIST_HEAD(iommu_device_list);
static DEFINE_SPINLOCK(iommu_device_lock);

static struct bus_type * const iommu_buses[] = {
&platform_bus_type,
#ifdef CONFIG_PCI
&pci_bus_type,
#endif
#ifdef CONFIG_ARM_AMBA
&amba_bustype,
#endif
#ifdef CONFIG_FSL_MC_BUS
&fsl_mc_bus_type,
#endif
#ifdef CONFIG_TEGRA_HOST1X_CONTEXT_BUS
&host1x_context_device_bus_type,
#endif
};

/*
* Use a function instead of an array here because the domain-type is a
* bit-field, so an array would waste memory.
Expand All @@ -126,6 +147,8 @@ static const char *iommu_domain_type_str(unsigned int t)

static int __init iommu_subsys_init(void)
{
struct notifier_block *nb;

if (!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API)) {
if (IS_ENABLED(CONFIG_IOMMU_DEFAULT_PASSTHROUGH))
iommu_set_default_passthrough(false);
Expand All @@ -152,6 +175,15 @@ static int __init iommu_subsys_init(void)
(iommu_cmd_line & IOMMU_CMD_LINE_STRICT) ?
"(set via kernel command line)" : "");

nb = kcalloc(ARRAY_SIZE(iommu_buses), sizeof(*nb), GFP_KERNEL);
if (!nb)
return -ENOMEM;

for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
nb[i].notifier_call = iommu_bus_notifier;
bus_register_notifier(iommu_buses[i], &nb[i]);
}

return 0;
}
subsys_initcall(iommu_subsys_init);
Expand Down Expand Up @@ -1774,39 +1806,6 @@ int bus_iommu_probe(struct bus_type *bus)
return ret;
}

static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
{
struct notifier_block *nb;
int err;

nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
if (!nb)
return -ENOMEM;

nb->notifier_call = iommu_bus_notifier;

err = bus_register_notifier(bus, nb);
if (err)
goto out_free;

err = bus_iommu_probe(bus);
if (err)
goto out_err;


return 0;

out_err:
/* Clean up */
bus_for_each_dev(bus, NULL, NULL, remove_iommu_group);
bus_unregister_notifier(bus, nb);

out_free:
kfree(nb);

return err;
}

/**
* bus_set_iommu - set iommu-callbacks for the bus
* @bus: bus.
Expand Down Expand Up @@ -1835,9 +1834,12 @@ int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
bus->iommu_ops = ops;

/* Do IOMMU specific setup for this bus-type */
err = iommu_bus_init(bus, ops);
if (err)
err = bus_iommu_probe(bus);
if (err) {
/* Clean up */
bus_for_each_dev(bus, NULL, NULL, remove_iommu_group);
bus->iommu_ops = NULL;
}

return err;
}
Expand Down

0 comments on commit c13dbc1

Please sign in to comment.