Jason Gunthorpe
2023-Nov-29 00:47 UTC
[Nouveau] [PATCH 00/10] IOMMU related FW parsing cleanup
These are the patches from the from the prior series without the "fwspec polishing": https://lore.kernel.org/r/0-v2-36a0088ecaa7+22c6e-iommu_fwspec_jgg at nvidia.com Rebased onto Robin's patch: https://lore.kernel.org/all/16f433658661d7cadfea51e7c65da95826112a2b.1700071477.git.robin.murphy at arm.com/ Does a few things to prepare for the next: - Clean up the call chains around dma_configure so the iommu_ops isn't being exposed. - Add additional lockdep annotations now that we can. - Replace the iommu_device_lock with iommu_probe_device_lock. - Fix some missed places that need to call tegra_dev_iommu_get_stream_id() Jason Gunthorpe (10): iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops() iommmu/of: Do not return struct iommu_ops from of_iommu_configure() iommu/of: Use -ENODEV consistently in of_iommu_configure() iommu: Mark dev_iommu_get() with lockdep iommu: Mark dev_iommu_priv_set() with a lockdep iommu: Replace iommu_device_lock with iommu_probe_device_lock acpi: Do not return struct iommu_ops from acpi_iommu_configure_id() iommu/tegra: Use tegra_dev_iommu_get_stream_id() in the remaining places ACPI: IORT: Cast from ULL to phys_addr_t ACPI: IORT: Allow COMPILE_TEST of IORT arch/arc/mm/dma.c | 2 +- arch/arm/mm/dma-mapping-nommu.c | 2 +- arch/arm/mm/dma-mapping.c | 10 +-- arch/arm64/mm/dma-mapping.c | 4 +- arch/mips/mm/dma-noncoherent.c | 2 +- arch/riscv/mm/dma-noncoherent.c | 2 +- drivers/acpi/Kconfig | 2 - drivers/acpi/Makefile | 2 +- drivers/acpi/arm64/Kconfig | 1 + drivers/acpi/arm64/Makefile | 2 +- drivers/acpi/arm64/iort.c | 6 +- drivers/acpi/scan.c | 32 ++++++---- drivers/dma/tegra186-gpc-dma.c | 8 +-- .../gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c | 7 +- drivers/hv/hv_common.c | 2 +- drivers/iommu/Kconfig | 1 + drivers/iommu/amd/iommu.c | 2 - drivers/iommu/apple-dart.c | 1 - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 - drivers/iommu/arm/arm-smmu/arm-smmu.c | 1 - drivers/iommu/intel/iommu.c | 2 - drivers/iommu/iommu.c | 41 +++++++----- drivers/iommu/of_iommu.c | 64 ++++++++----------- drivers/iommu/omap-iommu.c | 1 - drivers/memory/tegra/tegra186.c | 12 ++-- drivers/of/device.c | 24 ++++--- include/linux/dma-map-ops.h | 4 +- include/linux/iommu.h | 5 +- include/linux/of_iommu.h | 13 ++-- 29 files changed, 124 insertions(+), 132 deletions(-) base-commit: 173ff345925a394284250bfa6e47d231e62031c7 -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:47 UTC
[Nouveau] [PATCH 01/10] iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops()
This is not being used to pass ops, it is just a way to tell if an iommu driver was probed. These days this can be detected directly via device_iommu_mapped(). Call device_iommu_mapped() in the two places that need to check it and remove the iommu parameter everywhere. Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com> Reviewed-by: Moritz Fischer <mdf at kernel.org> Acked-by: Christoph Hellwig <hch at lst.de> Acked-by: Rob Herring <robh at kernel.org> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- arch/arc/mm/dma.c | 2 +- arch/arm/mm/dma-mapping-nommu.c | 2 +- arch/arm/mm/dma-mapping.c | 10 +++++----- arch/arm64/mm/dma-mapping.c | 4 ++-- arch/mips/mm/dma-noncoherent.c | 2 +- arch/riscv/mm/dma-noncoherent.c | 2 +- drivers/acpi/scan.c | 3 +-- drivers/hv/hv_common.c | 2 +- drivers/of/device.c | 2 +- include/linux/dma-map-ops.h | 4 ++-- 10 files changed, 16 insertions(+), 17 deletions(-) diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index 2a7fbbb83b7056..197707bc765889 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -91,7 +91,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, * Plug in direct dma map ops. */ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { /* * IOC hardware snoops all DMA traffic keeping the caches consistent diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c index cfd9c933d2f09c..b94850b579952a 100644 --- a/arch/arm/mm/dma-mapping-nommu.c +++ b/arch/arm/mm/dma-mapping-nommu.c @@ -34,7 +34,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { if (IS_ENABLED(CONFIG_CPU_V7M)) { /* diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 5409225b4abc06..6c359a3af8d9c7 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1713,7 +1713,7 @@ void arm_iommu_detach_device(struct device *dev) EXPORT_SYMBOL_GPL(arm_iommu_detach_device); static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { struct dma_iommu_mapping *mapping; @@ -1748,7 +1748,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) #else static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { } @@ -1757,7 +1757,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { } #endif /* CONFIG_ARM_DMA_USE_IOMMU */ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { /* * Due to legacy code that sets the ->dma_coherent flag from a bus @@ -1776,8 +1776,8 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, if (dev->dma_ops) return; - if (iommu) - arm_setup_iommu_dma_ops(dev, dma_base, size, iommu, coherent); + if (device_iommu_mapped(dev)) + arm_setup_iommu_dma_ops(dev, dma_base, size, coherent); xen_setup_dma_ops(dev); dev->archdata.dma_ops_setup = true; diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 3cb101e8cb29ba..61886e43e3a10f 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -47,7 +47,7 @@ void arch_teardown_dma_ops(struct device *dev) #endif void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { int cls = cache_line_size_of_cpu(); @@ -58,7 +58,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, ARCH_DMA_MINALIGN, cls); dev->dma_coherent = coherent; - if (iommu) + if (device_iommu_mapped(dev)) iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1); xen_setup_dma_ops(dev); diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index 3c4fc97b9f394b..0f3cec663a12cd 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -138,7 +138,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { dev->dma_coherent = coherent; } diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c index 4e4e469b8dd66c..843107f834b231 100644 --- a/arch/riscv/mm/dma-noncoherent.c +++ b/arch/riscv/mm/dma-noncoherent.c @@ -129,7 +129,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN, TAINT_CPU_OUT_OF_SPEC, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 02bb2cce423f47..444a0b3c72f2d8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1641,8 +1641,7 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, if (PTR_ERR(iommu) == -EPROBE_DEFER) return -EPROBE_DEFER; - arch_setup_dma_ops(dev, 0, U64_MAX, - iommu, attr == DEV_DMA_COHERENT); + arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT); return 0; } diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 4372f5d146ab22..0285a74363b3d1 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -488,7 +488,7 @@ void hv_setup_dma_ops(struct device *dev, bool coherent) * Hyper-V does not offer a vIOMMU in the guest * VM, so pass 0/NULL for the IOMMU settings */ - arch_setup_dma_ops(dev, 0, 0, NULL, coherent); + arch_setup_dma_ops(dev, 0, 0, coherent); } EXPORT_SYMBOL_GPL(hv_setup_dma_ops); diff --git a/drivers/of/device.c b/drivers/of/device.c index 1ca42ad9dd159d..65c71be71a8d45 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -193,7 +193,7 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, dev_dbg(dev, "device is%sbehind an iommu\n", iommu ? " " : " not "); - arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); + arch_setup_dma_ops(dev, dma_start, size, coherent); if (!iommu) of_dma_set_restricted_buffer(dev, np); diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h index a52e508d1869f6..e9cc317e9d7de6 100644 --- a/include/linux/dma-map-ops.h +++ b/include/linux/dma-map-ops.h @@ -427,10 +427,10 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg, #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent); + bool coherent); #else static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, - u64 size, const struct iommu_ops *iommu, bool coherent) + u64 size, bool coherent) { } #endif /* CONFIG_ARCH_HAS_SETUP_DMA_OPS */ -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:47 UTC
[Nouveau] [PATCH 02/10] iommmu/of: Do not return struct iommu_ops from of_iommu_configure()
Nothing needs this pointer. Return a normal error code with the usual IOMMU semantic that ENODEV means 'there is no IOMMU driver'. Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Acked-by: Rob Herring <robh at kernel.org> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/iommu/of_iommu.c | 31 +++++++++++++++++++------------ drivers/of/device.c | 22 +++++++++++++++------- include/linux/of_iommu.h | 13 ++++++------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 5ecca53847d325..c6510d7e7b241b 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -107,16 +107,22 @@ static int of_iommu_configure_device(struct device_node *master_np, of_iommu_configure_dev(master_np, dev); } -const struct iommu_ops *of_iommu_configure(struct device *dev, - struct device_node *master_np, - const u32 *id) +/* + * Returns: + * 0 on success, an iommu was configured + * -ENODEV if the device does not have any IOMMU + * -EPROBEDEFER if probing should be tried again + * -errno fatal errors + */ +int of_iommu_configure(struct device *dev, struct device_node *master_np, + const u32 *id) { const struct iommu_ops *ops = NULL; struct iommu_fwspec *fwspec; int err = NO_IOMMU; if (!master_np) - return NULL; + return -ENODEV; /* Serialise to make dev->iommu stable under our potential fwspec */ mutex_lock(&iommu_probe_device_lock); @@ -124,7 +130,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, if (fwspec) { if (fwspec->ops) { mutex_unlock(&iommu_probe_device_lock); - return fwspec->ops; + return 0; } /* In the deferred case, start again from scratch */ iommu_fwspec_free(dev); @@ -169,14 +175,15 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, err = iommu_probe_device(dev); /* Ignore all other errors apart from EPROBE_DEFER */ - if (err == -EPROBE_DEFER) { - ops = ERR_PTR(err); - } else if (err < 0) { - dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); - ops = NULL; + if (err < 0) { + if (err == -EPROBE_DEFER) + return err; + dev_dbg(dev, "Adding to IOMMU failed: %pe\n", ERR_PTR(err)); + return err; } - - return ops; + if (!ops) + return -ENODEV; + return 0; } static enum iommu_resv_type __maybe_unused diff --git a/drivers/of/device.c b/drivers/of/device.c index 65c71be71a8d45..873d933e8e6d1d 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -93,12 +93,12 @@ of_dma_set_restricted_buffer(struct device *dev, struct device_node *np) int of_dma_configure_id(struct device *dev, struct device_node *np, bool force_dma, const u32 *id) { - const struct iommu_ops *iommu; const struct bus_dma_region *map = NULL; struct device_node *bus_np; u64 dma_start = 0; u64 mask, end, size = 0; bool coherent; + int iommu_ret; int ret; if (np == dev->of_node) @@ -181,21 +181,29 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, dev_dbg(dev, "device is%sdma coherent\n", coherent ? " " : " not "); - iommu = of_iommu_configure(dev, np, id); - if (PTR_ERR(iommu) == -EPROBE_DEFER) { + iommu_ret = of_iommu_configure(dev, np, id); + if (iommu_ret == -EPROBE_DEFER) { /* Don't touch range map if it wasn't set from a valid dma-ranges */ if (!ret) dev->dma_range_map = NULL; kfree(map); return -EPROBE_DEFER; - } + } else if (iommu_ret == -ENODEV) { + dev_dbg(dev, "device is not behind an iommu\n"); + } else if (iommu_ret) { + dev_err(dev, "iommu configuration for device failed with %pe\n", + ERR_PTR(iommu_ret)); - dev_dbg(dev, "device is%sbehind an iommu\n", - iommu ? " " : " not "); + /* + * Historically this routine doesn't fail driver probing + * due to errors in of_iommu_configure() + */ + } else + dev_dbg(dev, "device is behind an iommu\n"); arch_setup_dma_ops(dev, dma_start, size, coherent); - if (!iommu) + if (iommu_ret) of_dma_set_restricted_buffer(dev, np); return 0; diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index 9a5e6b410dd2fb..e61cbbe12dac6f 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -8,20 +8,19 @@ struct iommu_ops; #ifdef CONFIG_OF_IOMMU -extern const struct iommu_ops *of_iommu_configure(struct device *dev, - struct device_node *master_np, - const u32 *id); +extern int of_iommu_configure(struct device *dev, struct device_node *master_np, + const u32 *id); extern void of_iommu_get_resv_regions(struct device *dev, struct list_head *list); #else -static inline const struct iommu_ops *of_iommu_configure(struct device *dev, - struct device_node *master_np, - const u32 *id) +static inline int of_iommu_configure(struct device *dev, + struct device_node *master_np, + const u32 *id) { - return NULL; + return -ENODEV; } static inline void of_iommu_get_resv_regions(struct device *dev, -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:47 UTC
[Nouveau] [PATCH 03/10] iommu/of: Use -ENODEV consistently in of_iommu_configure()
Instead of returning 1 and trying to handle positive error codes just stick to the convention of returning -ENODEV. Remove references to ops from of_iommu_configure(), a NULL ops will already generate an error code. There is no reason to check dev->bus, if err=0 at this point then the called configure functions thought there was an iommu and we should try to probe it. Remove it. Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/iommu/of_iommu.c | 49 ++++++++++++---------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index c6510d7e7b241b..164317bfb8a81f 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -17,8 +17,6 @@ #include <linux/slab.h> #include <linux/fsl/mc.h> -#define NO_IOMMU 1 - static int of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec) { @@ -29,7 +27,7 @@ static int of_iommu_xlate(struct device *dev, ops = iommu_ops_from_fwnode(fwnode); if ((ops && !ops->of_xlate) || !of_device_is_available(iommu_spec->np)) - return NO_IOMMU; + return -ENODEV; ret = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops); if (ret) @@ -61,7 +59,7 @@ static int of_iommu_configure_dev_id(struct device_node *master_np, "iommu-map-mask", &iommu_spec.np, iommu_spec.args); if (err) - return err == -ENODEV ? NO_IOMMU : err; + return err; err = of_iommu_xlate(dev, &iommu_spec); of_node_put(iommu_spec.np); @@ -72,7 +70,7 @@ static int of_iommu_configure_dev(struct device_node *master_np, struct device *dev) { struct of_phandle_args iommu_spec; - int err = NO_IOMMU, idx = 0; + int err = -ENODEV, idx = 0; while (!of_parse_phandle_with_args(master_np, "iommus", "#iommu-cells", @@ -117,9 +115,8 @@ static int of_iommu_configure_device(struct device_node *master_np, int of_iommu_configure(struct device *dev, struct device_node *master_np, const u32 *id) { - const struct iommu_ops *ops = NULL; struct iommu_fwspec *fwspec; - int err = NO_IOMMU; + int err; if (!master_np) return -ENODEV; @@ -153,37 +150,21 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np, } else { err = of_iommu_configure_device(master_np, dev, id); } - - /* - * Two success conditions can be represented by non-negative err here: - * >0 : there is no IOMMU, or one was unavailable for non-fatal reasons - * 0 : we found an IOMMU, and dev->fwspec is initialised appropriately - * <0 : any actual error - */ - if (!err) { - /* The fwspec pointer changed, read it again */ - fwspec = dev_iommu_fwspec_get(dev); - ops = fwspec->ops; - } mutex_unlock(&iommu_probe_device_lock); - /* - * If we have reason to believe the IOMMU driver missed the initial - * probe for dev, replay it to get things in order. - */ - if (!err && dev->bus) - err = iommu_probe_device(dev); - - /* Ignore all other errors apart from EPROBE_DEFER */ - if (err < 0) { - if (err == -EPROBE_DEFER) - return err; - dev_dbg(dev, "Adding to IOMMU failed: %pe\n", ERR_PTR(err)); + if (err == -ENODEV || err == -EPROBE_DEFER) return err; - } - if (!ops) - return -ENODEV; + if (err) + goto err_log; + + err = iommu_probe_device(dev); + if (err) + goto err_log; return 0; + +err_log: + dev_dbg(dev, "Adding to IOMMU failed: %pe\n", ERR_PTR(err)); + return err; } static enum iommu_resv_type __maybe_unused -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 04/10] iommu: Mark dev_iommu_get() with lockdep
Allocation of dev->iommu must be done under the iommu_probe_device_lock. Mark this with lockdep to discourage future mistakes. Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/iommu/iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0d25468d53a68a..4323b6276e977f 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -334,6 +334,8 @@ static struct dev_iommu *dev_iommu_get(struct device *dev) { struct dev_iommu *param = dev->iommu; + lockdep_assert_held(&iommu_probe_device_lock); + if (param) return param; -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 05/10] iommu: Mark dev_iommu_priv_set() with a lockdep
A perfect driver would only call dev_iommu_priv_set() from its probe callback. We've made it functionally correct to call it from the of_xlate by adding a lock around that call. lockdep assert that iommu_probe_device_lock is held to discourage misuse. Exclude PPC kernels with CONFIG_FSL_PAMU turned on because FSL_PAMU uses a global static for its priv and abuses priv for its domain. Remove the pointless stores of NULL, all these are on paths where the core code will free dev->iommu after the op returns. Reviewed-by: Lu Baolu <baolu.lu at linux.intel.com> Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/iommu/amd/iommu.c | 2 -- drivers/iommu/apple-dart.c | 1 - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 - drivers/iommu/arm/arm-smmu/arm-smmu.c | 1 - drivers/iommu/intel/iommu.c | 2 -- drivers/iommu/iommu.c | 9 +++++++++ drivers/iommu/omap-iommu.c | 1 - include/linux/iommu.h | 5 +---- 8 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 9f706436082833..be58644a6fa518 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -551,8 +551,6 @@ static void amd_iommu_uninit_device(struct device *dev) if (dev_data->domain) detach_device(dev); - dev_iommu_priv_set(dev, NULL); - /* * We keep dev_data around for unplugged devices and reuse it when the * device is re-plugged - not doing so would introduce a ton of races. diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 7438e9c82ba982..25135440b5dd54 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -743,7 +743,6 @@ static void apple_dart_release_device(struct device *dev) { struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev); - dev_iommu_priv_set(dev, NULL); kfree(cfg); } diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index fc4317c25b6d53..1855d3892b15f8 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2695,7 +2695,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) err_free_master: kfree(master); - dev_iommu_priv_set(dev, NULL); return ERR_PTR(ret); } diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 4d09c004789274..adc7937fd8a3a3 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1420,7 +1420,6 @@ static void arm_smmu_release_device(struct device *dev) arm_smmu_rpm_put(cfg->smmu); - dev_iommu_priv_set(dev, NULL); kfree(cfg); } diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 897159dba47de4..511589341074f0 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4461,7 +4461,6 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) ret = intel_pasid_alloc_table(dev); if (ret) { dev_err(dev, "PASID table allocation failed\n"); - dev_iommu_priv_set(dev, NULL); kfree(info); return ERR_PTR(ret); } @@ -4479,7 +4478,6 @@ static void intel_iommu_release_device(struct device *dev) dmar_remove_one_dev_info(dev); intel_pasid_free_table(dev); intel_iommu_debugfs_remove_dev(info); - dev_iommu_priv_set(dev, NULL); kfree(info); set_dma_ops(dev, NULL); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 4323b6276e977f..08f29a1dfcd5f8 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -387,6 +387,15 @@ static u32 dev_iommu_get_max_pasids(struct device *dev) return min_t(u32, max_pasids, dev->iommu->iommu_dev->max_pasids); } +void dev_iommu_priv_set(struct device *dev, void *priv) +{ + /* FSL_PAMU does something weird */ + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + lockdep_assert_held(&iommu_probe_device_lock); + dev->iommu->priv = priv; +} +EXPORT_SYMBOL_GPL(dev_iommu_priv_set); + /* * Init the dev->iommu and dev->iommu_group in the struct device and get the * driver probed diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index c66b070841dd41..c9528065a59afa 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1719,7 +1719,6 @@ static void omap_iommu_release_device(struct device *dev) if (!dev->of_node || !arch_data) return; - dev_iommu_priv_set(dev, NULL); kfree(arch_data); } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c7394b39599c84..c24933a1d0d643 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -840,10 +840,7 @@ static inline void *dev_iommu_priv_get(struct device *dev) return NULL; } -static inline void dev_iommu_priv_set(struct device *dev, void *priv) -{ - dev->iommu->priv = priv; -} +void dev_iommu_priv_set(struct device *dev, void *priv); extern struct mutex iommu_probe_device_lock; int iommu_probe_device(struct device *dev); -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 06/10] iommu: Replace iommu_device_lock with iommu_probe_device_lock
The iommu_device_lock protects the iommu_device_list which is only read by iommu_ops_from_fwnode(). This is now always called under the iommu_probe_device_lock, so we don't need to double lock the linked list. Use the iommu_probe_device_lock on the write side too. Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/iommu/iommu.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 08f29a1dfcd5f8..9557c2ec08d915 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -146,7 +146,6 @@ struct iommu_group_attribute iommu_group_attr_##_name = \ container_of(_kobj, struct iommu_group, kobj) static LIST_HEAD(iommu_device_list); -static DEFINE_SPINLOCK(iommu_device_lock); static const struct bus_type * const iommu_buses[] = { &platform_bus_type, @@ -262,9 +261,9 @@ int iommu_device_register(struct iommu_device *iommu, if (hwdev) iommu->fwnode = dev_fwnode(hwdev); - spin_lock(&iommu_device_lock); + mutex_lock(&iommu_probe_device_lock); list_add_tail(&iommu->list, &iommu_device_list); - spin_unlock(&iommu_device_lock); + mutex_unlock(&iommu_probe_device_lock); for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++) err = bus_iommu_probe(iommu_buses[i]); @@ -279,9 +278,9 @@ void iommu_device_unregister(struct iommu_device *iommu) for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) bus_for_each_dev(iommu_buses[i], NULL, iommu, remove_iommu_group); - spin_lock(&iommu_device_lock); + mutex_lock(&iommu_probe_device_lock); list_del(&iommu->list); - spin_unlock(&iommu_device_lock); + mutex_unlock(&iommu_probe_device_lock); /* Pairs with the alloc in generic_single_device_group() */ iommu_group_put(iommu->singleton_group); @@ -316,9 +315,9 @@ int iommu_device_register_bus(struct iommu_device *iommu, if (err) return err; - spin_lock(&iommu_device_lock); + mutex_lock(&iommu_probe_device_lock); list_add_tail(&iommu->list, &iommu_device_list); - spin_unlock(&iommu_device_lock); + mutex_unlock(&iommu_probe_device_lock); err = bus_iommu_probe(bus); if (err) { @@ -2033,9 +2032,9 @@ bool iommu_present(const struct bus_type *bus) for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) { if (iommu_buses[i] == bus) { - spin_lock(&iommu_device_lock); + mutex_lock(&iommu_probe_device_lock); ret = !list_empty(&iommu_device_list); - spin_unlock(&iommu_device_lock); + mutex_unlock(&iommu_probe_device_lock); } } return ret; @@ -2980,17 +2979,14 @@ EXPORT_SYMBOL_GPL(iommu_default_passthrough); const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode) { - const struct iommu_ops *ops = NULL; struct iommu_device *iommu; - spin_lock(&iommu_device_lock); + lockdep_assert_held(&iommu_probe_device_lock); + list_for_each_entry(iommu, &iommu_device_list, list) - if (iommu->fwnode == fwnode) { - ops = iommu->ops; - break; - } - spin_unlock(&iommu_device_lock); - return ops; + if (iommu->fwnode == fwnode) + return iommu->ops; + return NULL; } int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode, -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 07/10] acpi: Do not return struct iommu_ops from acpi_iommu_configure_id()
Nothing needs this pointer. Return a normal error code with the usual IOMMU semantic that ENODEV means 'there is no IOMMU driver'. Acked-by: Rafael J. Wysocki <rafael.j.wysocki at intel.com> Reviewed-by: Jerry Snitselaar <jsnitsel at redhat.com> Tested-by: Hector Martin <marcan at marcan.st> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/acpi/scan.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 444a0b3c72f2d8..340ba720c72129 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1562,8 +1562,7 @@ static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev) return fwspec ? fwspec->ops : NULL; } -static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, - const u32 *id_in) +static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) { int err; const struct iommu_ops *ops; @@ -1577,7 +1576,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, ops = acpi_iommu_fwspec_ops(dev); if (ops) { mutex_unlock(&iommu_probe_device_lock); - return ops; + return 0; } err = iort_iommu_configure_id(dev, id_in); @@ -1594,12 +1593,14 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, /* Ignore all other errors apart from EPROBE_DEFER */ if (err == -EPROBE_DEFER) { - return ERR_PTR(err); + return err; } else if (err) { dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); - return NULL; + return -ENODEV; } - return acpi_iommu_fwspec_ops(dev); + if (!acpi_iommu_fwspec_ops(dev)) + return -ENODEV; + return 0; } #else /* !CONFIG_IOMMU_API */ @@ -1611,10 +1612,9 @@ int acpi_iommu_fwspec_init(struct device *dev, u32 id, return -ENODEV; } -static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, - const u32 *id_in) +static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) { - return NULL; + return -ENODEV; } #endif /* !CONFIG_IOMMU_API */ @@ -1628,7 +1628,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, const u32 *input_id) { - const struct iommu_ops *iommu; + int ret; if (attr == DEV_DMA_NOT_SUPPORTED) { set_dma_ops(dev, &dma_dummy_ops); @@ -1637,10 +1637,15 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, acpi_arch_dma_setup(dev); - iommu = acpi_iommu_configure_id(dev, input_id); - if (PTR_ERR(iommu) == -EPROBE_DEFER) + ret = acpi_iommu_configure_id(dev, input_id); + if (ret == -EPROBE_DEFER) return -EPROBE_DEFER; + /* + * Historically this routine doesn't fail driver probing due to errors + * in acpi_iommu_configure_id() + */ + arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT); return 0; -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 08/10] iommu/tegra: Use tegra_dev_iommu_get_stream_id() in the remaining places
This API was defined to formalize the access to internal iommu details on some Tegra SOCs, but a few callers got missed. Add them. The helper already masks by 0xFFFF so remove this code from the callers. Suggested-by: Thierry Reding <thierry.reding at gmail.com> Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/dma/tegra186-gpc-dma.c | 8 +++----- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c | 7 ++----- drivers/memory/tegra/tegra186.c | 12 ++++++------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index fa4d4142a68a21..88547a23825b18 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -1348,8 +1348,8 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id) static int tegra_dma_probe(struct platform_device *pdev) { const struct tegra_dma_chip_data *cdata = NULL; - struct iommu_fwspec *iommu_spec; - unsigned int stream_id, i; + unsigned int i; + u32 stream_id; struct tegra_dma *tdma; int ret; @@ -1378,12 +1378,10 @@ static int tegra_dma_probe(struct platform_device *pdev) tdma->dma_dev.dev = &pdev->dev; - iommu_spec = dev_iommu_fwspec_get(&pdev->dev); - if (!iommu_spec) { + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) { dev_err(&pdev->dev, "Missing iommu stream-id\n"); return -EINVAL; } - stream_id = iommu_spec->ids[0] & 0xffff; ret = device_property_read_u32(&pdev->dev, "dma-channel-mask", &tdma->chan_mask); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c index e7e8fdf3adab7a..b40fd1dbb21617 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c @@ -28,16 +28,13 @@ static void gp10b_ltc_init(struct nvkm_ltc *ltc) { struct nvkm_device *device = ltc->subdev.device; - struct iommu_fwspec *spec; + u32 sid; nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); nvkm_wr32(device, 0x17e000, ltc->ltc_nr); nvkm_wr32(device, 0x100800, ltc->ltc_nr); - spec = dev_iommu_fwspec_get(device->dev); - if (spec) { - u32 sid = spec->ids[0] & 0xffff; - + if (tegra_dev_iommu_get_stream_id(device->dev, &sid)) { /* stream ID */ nvkm_wr32(device, 0x160000, sid << 2); } diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 533f85a4b2bdb7..3e4fbe94dd666e 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -111,21 +111,21 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc, static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) { #if IS_ENABLED(CONFIG_IOMMU_API) - struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); struct of_phandle_args args; unsigned int i, index = 0; + u32 sid; + WARN_ON(!tegra_dev_iommu_get_stream_id(dev, &sid)); while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells", index, &args)) { if (args.np == mc->dev->of_node && args.args_count != 0) { for (i = 0; i < mc->soc->num_clients; i++) { const struct tegra_mc_client *client = &mc->soc->clients[i]; - if (client->id == args.args[0]) { - u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK; - - tegra186_mc_client_sid_override(mc, client, sid); - } + if (client->id == args.args[0]) + tegra186_mc_client_sid_override( + mc, client, + sid & MC_SID_STREAMID_OVERRIDE_MASK); } } -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 09/10] ACPI: IORT: Cast from ULL to phys_addr_t
gcc on i386 (when compile testing) warns: drivers/acpi/arm64/iort.c:2014:18: warning: implicit conversion from 'unsigned long long' to 'phys_addr_t' (aka 'unsigned int') changes value from 18446744073709551615 to 4294967295 [-Wconstant-conversion] local_limit = DMA_BIT_MASK(ncomp->memory_address_limit); Because DMA_BIT_MASK returns a large ULL constant. Explicitly truncate it to phys_addr_t. Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/acpi/arm64/iort.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 6496ff5a6ba20d..bdaf9256870d92 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -2011,7 +2011,8 @@ phys_addr_t __init acpi_iort_dma_get_max_cpu_address(void) case ACPI_IORT_NODE_NAMED_COMPONENT: ncomp = (struct acpi_iort_named_component *)node->node_data; - local_limit = DMA_BIT_MASK(ncomp->memory_address_limit); + local_limit = (phys_addr_t)DMA_BIT_MASK( + ncomp->memory_address_limit); limit = min_not_zero(limit, local_limit); break; @@ -2020,7 +2021,8 @@ phys_addr_t __init acpi_iort_dma_get_max_cpu_address(void) break; rc = (struct acpi_iort_root_complex *)node->node_data; - local_limit = DMA_BIT_MASK(rc->memory_address_limit); + local_limit = (phys_addr_t)DMA_BIT_MASK( + rc->memory_address_limit); limit = min_not_zero(limit, local_limit); break; } -- 2.42.0
Jason Gunthorpe
2023-Nov-29 00:48 UTC
[Nouveau] [PATCH 10/10] ACPI: IORT: Allow COMPILE_TEST of IORT
The arm-smmu driver can COMPILE_TEST on x86, so expand this to also enable the IORT code so it can be COMPILE_TEST'd too. Signed-off-by: Jason Gunthorpe <jgg at nvidia.com> --- drivers/acpi/Kconfig | 2 -- drivers/acpi/Makefile | 2 +- drivers/acpi/arm64/Kconfig | 1 + drivers/acpi/arm64/Makefile | 2 +- drivers/iommu/Kconfig | 1 + 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f819e760ff195a..3b7f77b227d13a 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -541,9 +541,7 @@ config ACPI_PFRUT To compile the drivers as modules, choose M here: the modules will be called pfr_update and pfr_telemetry. -if ARM64 source "drivers/acpi/arm64/Kconfig" -endif config ACPI_PPTT bool diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index eaa09bf52f1760..4e77ae37b80726 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -127,7 +127,7 @@ obj-y += pmic/ video-objs += acpi_video.o video_detect.o obj-y += dptf/ -obj-$(CONFIG_ARM64) += arm64/ +obj-y += arm64/ obj-$(CONFIG_ACPI_VIOT) += viot.o diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index b3ed6212244c1e..537d49d8ace69e 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -11,6 +11,7 @@ config ACPI_GTDT config ACPI_AGDI bool "Arm Generic Diagnostic Dump and Reset Device Interface" + depends on ARM64 depends on ARM_SDE_INTERFACE help Arm Generic Diagnostic Dump and Reset Device Interface (AGDI) is diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 143debc1ba4a9d..71d0e635599390 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_ACPI_IORT) += iort.o obj-$(CONFIG_ACPI_GTDT) += gtdt.o obj-$(CONFIG_ACPI_APMT) += apmt.o obj-$(CONFIG_ARM_AMBA) += amba.o -obj-y += dma.o init.o +obj-$(CONFIG_ARM64) += dma.o init.o diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 7673bb82945b6c..309378e76a9bc9 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -318,6 +318,7 @@ config ARM_SMMU select IOMMU_API select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU if ARM + select ACPI_IORT if ACPI help Support for implementations of the ARM System MMU architecture versions 1 and 2. -- 2.42.0