IOMMU probe deferral support
Subsystems (11)
v6 cover IOMMU probe deferral support
This series calls the dma ops configuration for the devices at a generic place so that it works for all busses. The dma_configure_ops for a device is now called during the device_attach callback just before the probe of the bus/driver is called. Similarly dma_deconfigure is called during device/driver_detach path.
pci_bus_add_devices (platform/amba)(_device_create/driver_register)
| |
pci_bus_add_device (device_add/driver_register)
| |
device_attach device_initial_probe
| |
__device_attach_driver __device_attach_driver
|
driver_probe_device
|
really_probe
|dma_configure
Similarly on the device/driver_unregister path __device_release_driver is called which inturn calls dma_deconfigure.
Took the reworked patches [2] from Robin's branch and rebased on top of Lorenzo's ACPI IORT ARM support series [3].
* Tested with platform and pci devices for probe deferral and reprobe on arm64 based platform.
* Need help for testing with ACPI.
Previous post of this series [6].
[V6]
* Fixed a bug in dma_configure function pointed out by Robin.
* Reordered the patches as per comments from Robin and Lorenzo.
* Added Tags.
[V5]
* Reworked the pci configuration code hanging outside and pushed it to dma_configure as in PATCH#5,6,7. Also added a couple of patches that Lorenzo provided for correcting the Probe deferring mechanism in case of ACPI devices from here [5].
[V4]
* Took the reworked patches [2] from Robin's branch and rebased on top of Lorenzo's ACPI IORT ARM support series [3].
* Added the patches for moving the dma ops configuration of acpi based devices to probe time as well.
[V3]
* Removed the patch to split dma_masks/dma_ops configuration separately based on review comments that both masks and ops are required only during the device probe time.
* Reworked the series based on Generic DT bindings series.
* Added call to iommu's remove_device in the cleanup path for arm and arm64.
* Removed the notifier trick in arm64 to handle early device registration.
* Added reset of dma_ops in cleanup path for arm based on comments.
* Fixed the pci_iommu_configure path and tested with PCI device as well.
* Fixed a bug to return the correct iommu_ops from patch 7 [4] in last post.
* Fixed few other cosmetic comments.
[V2]
* Updated the Initial post to call dma_configure/deconfigure from generic code
* Added iommu add_device callback from of_iommu_configure path
[V1]
* Initial post from Laurent Pinchart [1]
[1] http://lists.linuxfoundation.org/pipermail/iommu/2015-May/013016.html
[2] http://www.linux-arm.org/git?p=linux-rm.git;a=shortlog;h=refs/heads/iommu/defer
[3] https://lkml.org/lkml/2016/11/21/141
[4] https://www.mail-archive.com/iommu at lists.linux-foundation.org/msg13940.html
[5] git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git iommu/probe-deferral
[6] https://www.spinics.net/lists/arm-kernel/msg556134.html
Laurent Pinchart (3):
of: dma: Move range size workaround to of_dma_get_range()
of: dma: Make of_dma_deconfigure() public
iommu: of: Handle IOMMU lookup failure with deferred probing or error
Lorenzo Pieralisi (2):
ACPI/IORT: Add function to check SMMUs drivers presence ACPI/IORT: Remove linker section for IORT entries probing
Robin Murphy (3):
iommu/of: Refactor of_iommu_configure() for error handling iommu/of: Prepare for deferred IOMMU configuration iommu/arm-smmu: Clean up early-probing workarounds
Sricharan R (3):
drivers: platform: Configure dma operations at probe time
drivers: acpi: Handle IOMMU lookup failure with deferred probing or
error
arm64: dma-mapping: Remove the notifier trick to handle early setting
of dma_ops
arch/arm64/mm/dma-mapping.c | 132 ++++---------------------------------- drivers/acpi/arm64/iort.c | 40 +++++++++++- drivers/acpi/glue.c | 5 -- drivers/acpi/scan.c | 7 +- drivers/base/dd.c | 9 +++ drivers/base/dma-mapping.c | 41 ++++++++++++ drivers/iommu/arm-smmu-v3.c | 46 +------------ drivers/iommu/arm-smmu.c | 58 +++-------------- drivers/iommu/of_iommu.c | 114 +++++++++++++++++++++++--------- drivers/of/address.c | 20 +++++- drivers/of/device.c | 36 ++++++----- drivers/of/platform.c | 10 +-- drivers/pci/probe.c | 28 -------- include/acpi/acpi_bus.h | 2 +- include/asm-generic/vmlinux.lds.h | 1 - include/linux/acpi.h | 7 +- include/linux/acpi_iort.h | 3 - include/linux/dma-mapping.h | 3 + include/linux/of_device.h | 10 ++- 19 files changed, 252 insertions(+), 320 deletions(-)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 1/11 iommu/of: Refactor of_iommu_configure() for error handling
From: Robin Murphy <[email protected]>
In preparation for some upcoming cleverness, rework the control flow in of_iommu_configure() to minimise duplication and improve the propogation of errors. It's also as good a time as any to switch over from the now-just-a-compatibility-wrapper of_iommu_get_ops() to using the generic IOMMU instance interface directly.
--- drivers/iommu/of_iommu.c | 83 +++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 30 deletions(-)
drivers/iommu/of_iommu.c +53 -30
@@ -96,6 +96,28 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, }EXPORT_SYMBOL_GPL (of_get_dma_window); +static const struct iommu_ops +*of_iommu_xlate (struct device *dev,struct of_phandle_args *iommu_spec) +{ +const struct iommu_ops *ops; +struct fwnode_handle *fwnode = &iommu_spec->np->fwnode; +int err; + + ops =iommu_get_instance (fwnode); +if (!ops || !ops->of_xlate) +return NULL ; + + err =iommu_fwspec_init (dev, &iommu_spec->np->fwnode, ops); +if (err) +return ERR_PTR (err); + + err = ops->of_xlate (dev, iommu_spec); +if (err) +return ERR_PTR (err); + +return ops; +} +static int __get_pci_rid (struct pci_dev *pdev,u16 alias,void *data) {struct of_phandle_args *iommu_spec = data;
@@ -105,10 +127,11 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) }static const struct iommu_ops -*of_pci_iommu_configure (struct pci_dev *pdev,struct device_node *bridge_np) +*of_pci_iommu_init (struct pci_dev *pdev,struct device_node *bridge_np) {const struct iommu_ops *ops;struct of_phandle_args iommu_spec; +int err;/* * Start by tracing the RID alias down the PCI topology as
@@ -123,56 +146,56 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)* bus into the system beyond, and which IOMMU it ends up at. */ iommu_spec.np =NULL ; -if (of_pci_map_rid (bridge_np, iommu_spec.args[0 ],"iommu-map" , -"iommu-map-mask" , &iommu_spec.np, iommu_spec.args)) -return NULL ; + err =of_pci_map_rid (bridge_np, iommu_spec.args[0 ],"iommu-map" , +"iommu-map-mask" , &iommu_spec.np, + iommu_spec.args); +if (err) +return ERR_PTR (err); - ops =of_iommu_get_ops (iommu_spec.np); -if (!ops || !ops->of_xlate || -iommu_fwspec_init (&pdev->dev, &iommu_spec.np->fwnode, ops) || - ops->of_xlate (&pdev->dev, &iommu_spec)) - ops =NULL ; + ops =of_iommu_xlate (&pdev->dev, &iommu_spec);of_node_put (iommu_spec.np);return ops; } -const struct iommu_ops *of_iommu_configure (struct device *dev, -struct device_node *master_np) +static const struct iommu_ops +*of_platform_iommu_init (struct device *dev,struct device_node *np) {struct of_phandle_args iommu_spec; -struct device_node *np;const struct iommu_ops *ops =NULL ;int idx =0 ; -if (dev_is_pci (dev)) -return of_pci_iommu_configure (to_pci_dev (dev), master_np); -/* * We don't currently walk up the tree looking for a parent IOMMU. * See the `Notes:' section of * Documentation/devicetree/bindings/iommu/iommu.txt */ -while (!of_parse_phandle_with_args (master_np,"iommus" , -"#iommu-cells" , idx, - &iommu_spec)) { - np = iommu_spec.np; - ops =of_iommu_get_ops (np); - -if (!ops || !ops->of_xlate || -iommu_fwspec_init (dev, &np->fwnode, ops) || - ops->of_xlate (dev, &iommu_spec)) - goto err_put_node; - -of_node_put (np); +while (!of_parse_phandle_with_args (np,"iommus" ,"#iommu-cells" , + idx, &iommu_spec)) { + ops =of_iommu_xlate (dev, &iommu_spec); +of_node_put (iommu_spec.np); idx++; +if (IS_ERR_OR_NULL (ops)) +break ; }return ops; +} + +const struct iommu_ops *of_iommu_configure (struct device *dev, +struct device_node *master_np) +{ +const struct iommu_ops *ops; + +if (!master_np) +return NULL ; + +if (dev_is_pci (dev)) + ops =of_pci_iommu_init (to_pci_dev (dev), master_np); +else + ops =of_platform_iommu_init (dev, master_np); -err_put_node: -of_node_put (np); -return NULL ; +return IS_ERR (ops) ?NULL : ops; }static int __init of_iommu_init (void )
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 2/11 iommu/of: Prepare for deferred IOMMU configuration
In reply to Sricharan RFrom: Robin Murphy <[email protected]>
IOMMU configuration represents unchanging properties of the hardware, and as such should only need happen once in a device's lifetime, but the necessary interaction with the IOMMU device and driver complicates exactly when that point should be.
Since the only reasonable tool available for handling the inter-device dependency is probe deferral, we need to prepare of_iommu_configure() to run later than it is currently called (i.e. at driver probe rather than device creation), to handle being retried, and to tell whether a not-yet present IOMMU should be waited for or skipped (by virtue of having declared a built-in driver or not).
--- drivers/iommu/of_iommu.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-)
drivers/iommu/of_iommu.c +29 -1
@@ -104,12 +104,20 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index,int err; ops =iommu_get_instance (fwnode); -if (!ops || !ops->of_xlate) +if ((ops && !ops->of_xlate) || + (!ops && !of_match_node (&__iommu_of_table, iommu_spec->np)))return NULL ; err =iommu_fwspec_init (dev, &iommu_spec->np->fwnode, ops);if (err)return ERR_PTR (err); +/* +* The otherwise-empty fwspec handily serves to indicate the specific +* IOMMU device we're waiting for, which will be useful if we ever get +* a proper probe-ordering dependency mechanism in future. +*/ +if (!ops) +return ERR_PTR (-EPROBE_DEFER ); err = ops->of_xlate (dev, iommu_spec);if (err)
@@ -186,14 +194,34 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np) {const struct iommu_ops *ops; +struct iommu_fwspec *fwspec = dev->iommu_fwspec;if (!master_np)return NULL ; +if (fwspec) { +if (fwspec->ops) +return fwspec->ops; + +/* In the deferred case, start again from scratch */ +iommu_fwspec_free (dev); + } +if (dev_is_pci (dev)) ops =of_pci_iommu_init (to_pci_dev (dev), master_np);else ops =of_platform_iommu_init (dev, master_np); +/* +* If we have reason to believe the IOMMU driver missed the initial +* add_device callback for dev, replay it to get things in order. +*/ +if (!IS_ERR_OR_NULL (ops) && ops->add_device && + dev->bus && !dev->iommu_group) { +int err = ops->add_device (dev); + +if (err) + ops =ERR_PTR (err); + }return IS_ERR (ops) ?NULL : ops; }
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 3/11 of: dma: Move range size workaround to of_dma_get_range()
In reply to Sricharan RFrom: Laurent Pinchart <[email protected]>
Invalid dma-ranges values should be worked around when retrieving the DMA range in of_dma_get_range(), not by all callers of the function. This isn't much of a problem now that we have a single caller, but that situation will change when moving DMA configuration to device probe time.
--- drivers/of/address.c | 20 ++++++++++++++++++-- drivers/of/device.c | 15 --------------- 2 files changed, 18 insertions(+), 17 deletions(-)
drivers/of/address.c +18 -2
@@ -819,8 +819,8 @@ void __iomem *of_io_request_and_map(struct device_node *np, int index,* CPU addr (phys_addr_t) : pna cells * size : nsize cells * -* It returns -ENODEV if "dma-ranges" property was not found -* for this device in DT. +* Return 0 on success, -ENODEV if the "dma-ranges" property was not found for +* this device in DT, or -EINVAL if the CPU address or size is invalid. */ int of_dma_get_range (struct device_node *np,u64 *dma_addr,u64 *paddr,u64 *size) {
@@ -880,6 +880,22 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz *dma_addr = dmaaddr; *size =of_read_number (ranges + naddr + pna, nsize); +/* +* DT nodes sometimes incorrectly set the size as a mask. Work around +* those incorrect DT by computing the size as mask + 1. +*/ +if (*size &1 ) { +pr_warn ("%s: size 0x%llx for dma-range in node(%s) set as mask\n" , + __func__, *size, np->full_name); + *size = *size +1 ; + } + +if (!*size) { +pr_err ("%s: invalid size zero for dma-range in node(%s)\n" , + __func__, np->full_name); + ret = -EINVAL ; + goto out; + }pr_debug ("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n" , *dma_addr, *paddr, *size);
drivers/of/device.c +0 -15
@@ -110,21 +110,6 @@ void of_dma_configure(struct device *dev, struct device_node *np) size = dev->coherent_dma_mask +1 ; }else { offset =PFN_DOWN (paddr - dma_addr); - -/* -* Add a work around to treat the size as mask + 1 in case -* it is defined in DT as a mask. -*/ -if (size &1 ) { -dev_warn (dev,"Invalid size 0x%llx for dma-range\n" , - size); - size = size +1 ; - } - -if (!size) { -dev_err (dev,"Adjusted size 0x%llx invalid\n" , size); -return ; - }dev_dbg (dev,"dma_pfn_offset(%#08lx)\n" , offset); }
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 4/11 of: dma: Make of_dma_deconfigure() public
In reply to Sricharan RFrom: Laurent Pinchart <[email protected]>
As part of moving DMA initializing to probe time the of_dma_deconfigure() function will need to be called from different source files. Make it public and move it to drivers/of/device.c where the of_dma_configure() function is.
--- drivers/of/device.c | 12 ++++++++++++ drivers/of/platform.c | 5 ----- include/linux/of_device.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-)
drivers/of/device.c +12 -0
@@ -136,6 +136,18 @@ void of_dma_configure(struct device *dev, struct device_node *np) }EXPORT_SYMBOL_GPL (of_dma_configure); +/** +* of_dma_deconfigure - Clean up DMA configuration +* @dev: Device for which to clean up DMA configuration +* +* Clean up all configuration performed by of_dma_configure_ops() and free all +* resources that have been allocated. +*/ +void of_dma_deconfigure (struct device *dev) +{ +arch_teardown_dma_ops (dev); +} +int of_device_register (struct platform_device *pdev) {device_initialize (&pdev->dev);
drivers/of/platform.c +0 -5
@@ -158,11 +158,6 @@ struct platform_device *of_device_alloc(struct device_node *np, }EXPORT_SYMBOL (of_device_alloc); -static void of_dma_deconfigure (struct device *dev) -{ -arch_teardown_dma_ops (dev); -} -/** * of_platform_device_create_pdata - Alloc, initialize and register an of_device * @np: pointer to node to create device for
include/linux/of_device.h +3 -0
@@ -56,6 +56,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) }void of_dma_configure (struct device *dev,struct device_node *np); +void of_dma_deconfigure (struct device *dev);#else /* CONFIG_OF */ static inline int of_driver_match_device(struct device *dev,
@@ -100,6 +101,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) }static inline void of_dma_configure (struct device *dev,struct device_node *np) {} +static inline void of_dma_deconfigure (struct device *dev) +{}#endif /* CONFIG_OF */ #endif /* _LINUX_OF_DEVICE_H */
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 5/11 ACPI/IORT: Add function to check SMMUs drivers presence
In reply to Sricharan RFrom: Lorenzo Pieralisi <[email protected]>
The IOMMU probe deferral implementation requires a mechanism to detect if drivers for SMMU components are built-in in the kernel to detect whether IOMMU configuration for a given device should be deferred (ie SMMU drivers present but still not probed) or not (drivers not present).
Add a simple function to IORT to detect if SMMU drivers for SMMU components managed by IORT are built-in in the kernel.
--- drivers/acpi/arm64/iort.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/acpi/arm64/iort.c +13 -0
@@ -523,6 +523,19 @@ static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,return ret; } +static inline bool iort_iommu_driver_enabled (u8 type) +{ +switch (type) { +case ACPI_IORT_NODE_SMMU_V3 : +return IS_BUILTIN (CONFIG_ARM_SMMU_V3 ); +case ACPI_IORT_NODE_SMMU : +return IS_BUILTIN (CONFIG_ARM_SMMU ); +default : +pr_warn ("IORT node type %u does not describe an SMMU\n" , type); +return false; + } +} +static const struct iommu_ops *iort_iommu_xlate (struct device *dev,struct acpi_iort_node *node,u32 streamid)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 6/11 drivers: platform: Configure dma operations at probe time
In reply to Sricharan RConfiguring DMA ops at probe time will allow deferring device probe when the IOMMU isn't available yet. The dma_configure for the device is now called from the generic device_attach callback just before the bus/driver probe is called. This way, configuring the DMA ops for the device would be called at the same place for all bus_types, hence the deferred probing mechanism should work for all buses as well.
pci_bus_add_devices (platform/amba)(_device_create/driver_register)
| |
pci_bus_add_device (device_add/driver_register)
| |
device_attach device_initial_probe
| |
__device_attach_driver __device_attach_driver
|
driver_probe_device
|
really_probe
|dma_configure
Similarly on the device/driver_unregister path __device_release_driver is called which inturn calls dma_deconfigure.
This patch changes the dma ops configuration time to probe time for both OF and ACPI based devices.
---
[V5 .. V6]
* Squashed in patch 10 for configuring the dma ops of ACPI device at probe time from previous post.
* Fixed a bug in dma_configure pointed out by Robin.
drivers/acpi/glue.c | 5 ----- drivers/base/dd.c | 9 +++++++++ drivers/base/dma-mapping.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 5 +---- drivers/pci/probe.c | 28 ---------------------------- include/linux/dma-mapping.h | 3 +++ 6 files changed, 53 insertions(+), 37 deletions(-)
drivers/acpi/glue.c +0 -5
@@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)struct list_head *physnode_list;unsigned int node_id;int retval = -EINVAL ; -enum dev_dma_attr attr;if (has_acpi_companion (dev)) {if (acpi_dev) {
@@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)if (!has_acpi_companion (dev))ACPI_COMPANION_SET (dev, acpi_dev); - attr =acpi_get_dma_attr (acpi_dev); -if (attr !=DEV_DMA_NOT_SUPPORTED ) -acpi_dma_configure (dev, attr); -acpi_physnode_link_name (physical_node_name, node_id); retval =sysfs_create_link (&acpi_dev->dev.kobj, &dev->kobj, physical_node_name);
drivers/base/dd.c +9 -0
@@ -19,6 +19,7 @@#include <linux/device.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/kthread.h> #include <linux/wait.h>
@@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)if (ret) goto pinctrl_bind_failed; + ret =dma_configure (dev); +if (ret) + goto dma_failed; +if (driver_sysfs_add (dev)) {printk (KERN_ERR "%s: driver_sysfs_add(%s) failed\n" , __func__,dev_name (dev));
@@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto done; probe_failed: +dma_deconfigure (dev); +dma_failed:if (dev->bus)blocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_DRIVER_NOT_BOUND , dev);
@@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) drv->remove (dev);device_links_driver_cleanup (dev); +dma_deconfigure (dev); +devres_release_all (dev); dev->driver =NULL ;dev_set_drvdata (dev,NULL );
drivers/base/dma-mapping.c +40 -0
@@ -7,9 +7,11 @@* This file is released under the GPLv2. */ +#include <linux/acpi.h> #include <linux/dma-mapping.h> #include <linux/export.h> #include <linux/gfp.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/vmalloc.h>
@@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)vunmap (cpu_addr); }#endif + +/* +* Common configuration to enable DMA API use for a device +*/ +#include <linux/pci.h> + +int dma_configure (struct device *dev) +{ +struct device *bridge =NULL , *dma_dev = dev; +enum dev_dma_attr attr; + +if (dev_is_pci (dev)) { + bridge =pci_get_host_bridge_device (to_pci_dev (dev)); + dma_dev = bridge; +if (IS_ENABLED (CONFIG_OF ) && dma_dev->parent && + dma_dev->parent->of_node) + dma_dev = dma_dev->parent; + } + +if (dma_dev->of_node) { +of_dma_configure (dev, dma_dev->of_node); + }else if (has_acpi_companion (dma_dev)) { + attr =acpi_get_dma_attr (to_acpi_device_node (dma_dev->fwnode)); +if (attr !=DEV_DMA_NOT_SUPPORTED ) +acpi_dma_configure (dev, attr); + } + +if (bridge) +pci_put_host_bridge_device (bridge); + +return 0 ; +} + +void dma_deconfigure (struct device *dev) +{ +of_dma_deconfigure (dev); +acpi_dma_deconfigure (dev); +}
drivers/of/platform.c +1 -4
@@ -22,6 +22,7 @@#include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_iommu.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h>
@@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; -of_dma_configure (&dev->dev, dev->dev.of_node);of_msi_configure (&dev->dev, dev->dev.of_node);if (of_device_add (dev) !=0 ) { -of_dma_deconfigure (&dev->dev);platform_device_put (dev); goto err_clear_flag; }
@@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,dev_set_name (&dev->dev,"%s" , bus_id); else of_device_make_bus_id(&dev->dev); -of_dma_configure (&dev->dev, dev->dev.of_node);/* Allow the HW Peripheral ID to be overridden */ prop =of_get_property (node,"arm,primecell-periphid" ,NULL );
@@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)amba_device_unregister (to_amba_device (dev));#endif -of_dma_deconfigure (dev);of_node_clear_flag (dev->of_node,OF_POPULATED );of_node_clear_flag (dev->of_node,OF_POPULATED_BUS );return 0 ;
drivers/pci/probe.c +0 -28
@@ -1864,33 +1864,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)dev_set_msi_domain (&dev->dev, d); } -/** -* pci_dma_configure - Setup DMA configuration -* @dev: ptr to pci_dev struct of the PCI device -* -* Function to update PCI devices's DMA configuration using the same -* info from the OF node or ACPI node of host bridge's parent (if any). -*/ -static void pci_dma_configure (struct pci_dev *dev) -{ -struct device *bridge =pci_get_host_bridge_device (dev); - -if (IS_ENABLED (CONFIG_OF ) && - bridge->parent && bridge->parent->of_node) { -of_dma_configure (&dev->dev, bridge->parent->of_node); - }else if (has_acpi_companion (bridge)) { -struct acpi_device *adev =to_acpi_device_node (bridge->fwnode); -enum dev_dma_attr attr =acpi_get_dma_attr (adev); - -if (attr ==DEV_DMA_NOT_SUPPORTED ) -dev_warn (&dev->dev,"DMA not supported.\n" ); -else -acpi_dma_configure (&dev->dev, attr); - } - -pci_put_host_bridge_device (bridge); -} -void pci_device_add (struct pci_dev *dev,struct pci_bus *bus) {int ret;
@@ -1904,7 +1877,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask =0xffffffffull ; -pci_dma_configure (dev);pci_set_dma_max_seg_size (dev,65536 );pci_set_dma_seg_boundary (dev,0xffffffff );
include/linux/dma-mapping.h +3 -0
@@ -708,6 +708,9 @@ void *dma_mark_declared_memory_occupied(struct device *dev, }#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ +int dma_configure (struct device *dev); +void dma_deconfigure (struct device *dev); +/* * Managed DMA API */
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 6/11 drivers: platform: Configure dma operations at probe time
[+bjorn]
Quoted 19 lines · Sricharan R
Configuring DMA ops at probe time will allow deferring device probe when the IOMMU isn't available yet. The
dma_configurefor the device is now called from the genericdevice_attachcallback just before the bus/driver probe is called. This way, configuring the DMA ops for the device would be called at the same place for allbus_types, hence the deferred probing mechanism should work for all buses as well.
pci_bus_add_devices(platform/amba)(_device_create/driver_register)| | pci_bus_add_device (device_add/driver_register) | | device_attach device_initial_probe | | __device_attach_driver __device_attach_driver | driver_probe_device | really_probe |
Quoted 7 lines
dma_configureSimilarly on the device/driver_unregister path
__device_release_driveris called which inturn callsdma_deconfigure.This patch changes the dma ops configuration time to probe time for both OF and ACPI based devices.
For all device types, inclusive of PCI, so please you have to:
- Update the $SUBJECT
- Copy linux-pci at vger.kernel.org
- Copy linux-acpi at vger.kernel org (on the series)
Thanks,
Lorenzo
Quoted 240 lines
Signed-off-by Sricharan R <[email protected]>---
[V5 .. V6]
* Squashed in patch 10 for configuring the dma ops of ACPI device at probe time from previous post.
* Fixed a bug indma_configurepointed out by Robin.drivers/acpi/glue.c | 5 ----- drivers/base/dd.c | 9 +++++++++ drivers/base/dma-mapping.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 5 +---- drivers/pci/probe.c | 28 ---------------------------- include/linux/dma-mapping.h | 3 +++ 6 files changed, 53 insertions(+), 37 deletions(-)drivers/acpi/glue.c +0
-5@@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)struct list_head *physnode_list;unsigned int node_id;int retval = -EINVAL ; -enum dev_dma_attr attr;if (has_acpi_companion (dev)) {if (acpi_dev) {@@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)if (!has_acpi_companion (dev))ACPI_COMPANION_SET (dev, acpi_dev); - attr =acpi_get_dma_attr (acpi_dev); -if (attr !=DEV_DMA_NOT_SUPPORTED ) -acpi_dma_configure (dev, attr); -acpi_physnode_link_name (physical_node_name, node_id); retval =sysfs_create_link (&acpi_dev->dev.kobj, &dev->kobj, physical_node_name);drivers/base/dd.c +9
-0@@ -19,6 +19,7 @@#include <linux/device.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/kthread.h> #include <linux/wait.h> @@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)if (ret) goto pinctrl_bind_failed; + ret =dma_configure (dev); +if (ret) + goto dma_failed; +if (driver_sysfs_add (dev)) {printk (KERN_ERR "%s: driver_sysfs_add(%s) failed\n" , __func__,dev_name (dev));@@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto done; probe_failed: +dma_deconfigure (dev); +dma_failed:if (dev->bus)blocking_notifier_call_chain (&dev->bus->p->bus_notifier,BUS_NOTIFY_DRIVER_NOT_BOUND , dev);@@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) drv->remove (dev);device_links_driver_cleanup (dev); +dma_deconfigure (dev); +devres_release_all (dev); dev->driver =NULL ;dev_set_drvdata (dev,NULL );drivers/base/dma-mapping.c +40
-0@@ -7,9 +7,11 @@* This file is released under the GPLv2. */ +#include <linux/acpi.h> #include <linux/dma-mapping.h> #include <linux/export.h> #include <linux/gfp.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)vunmap (cpu_addr); }#endif + +/* +* Common configuration to enable DMA API use for a device +*/ +#include <linux/pci.h> + +int dma_configure (struct device *dev) +{ +struct device *bridge =NULL , *dma_dev = dev; +enum dev_dma_attr attr; + +if (dev_is_pci (dev)) { + bridge =pci_get_host_bridge_device (to_pci_dev (dev)); + dma_dev = bridge; +if (IS_ENABLED (CONFIG_OF ) && dma_dev->parent && + dma_dev->parent->of_node) + dma_dev = dma_dev->parent; + } + +if (dma_dev->of_node) { +of_dma_configure (dev, dma_dev->of_node); + }else if (has_acpi_companion (dma_dev)) { + attr =acpi_get_dma_attr (to_acpi_device_node (dma_dev->fwnode)); +if (attr !=DEV_DMA_NOT_SUPPORTED ) +acpi_dma_configure (dev, attr); + } + +if (bridge) +pci_put_host_bridge_device (bridge); + +return 0 ; +} + +void dma_deconfigure (struct device *dev) +{ +of_dma_deconfigure (dev); +acpi_dma_deconfigure (dev); +}drivers/of/platform.c +1
-4@@ -22,6 +22,7 @@#include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_iommu.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; -of_dma_configure (&dev->dev, dev->dev.of_node);of_msi_configure (&dev->dev, dev->dev.of_node);if (of_device_add (dev) !=0 ) { -of_dma_deconfigure (&dev->dev);platform_device_put (dev); goto err_clear_flag; }@@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,dev_set_name (&dev->dev,"%s" , bus_id); else of_device_make_bus_id(&dev->dev); -of_dma_configure (&dev->dev, dev->dev.of_node);/* Allow the HW Peripheral ID to be overridden */ prop =of_get_property (node,"arm,primecell-periphid" ,NULL );@@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)amba_device_unregister (to_amba_device (dev));#endif -of_dma_deconfigure (dev);of_node_clear_flag (dev->of_node,OF_POPULATED );of_node_clear_flag (dev->of_node,OF_POPULATED_BUS );return 0 ;drivers/pci/probe.c +0
-28@@ -1864,33 +1864,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)dev_set_msi_domain (&dev->dev, d); } -/** -* pci_dma_configure - Setup DMA configuration -* @dev: ptr to pci_dev struct of the PCI device -* -* Function to update PCI devices's DMA configuration using the same -* info from the OF node or ACPI node of host bridge's parent (if any). -*/ -static void pci_dma_configure (struct pci_dev *dev) -{ -struct device *bridge =pci_get_host_bridge_device (dev); - -if (IS_ENABLED (CONFIG_OF ) && - bridge->parent && bridge->parent->of_node) { -of_dma_configure (&dev->dev, bridge->parent->of_node); - }else if (has_acpi_companion (bridge)) { -struct acpi_device *adev =to_acpi_device_node (bridge->fwnode); -enum dev_dma_attr attr =acpi_get_dma_attr (adev); - -if (attr ==DEV_DMA_NOT_SUPPORTED ) -dev_warn (&dev->dev,"DMA not supported.\n" ); -else -acpi_dma_configure (&dev->dev, attr); - } - -pci_put_host_bridge_device (bridge); -} -void pci_device_add (struct pci_dev *dev,struct pci_bus *bus) {int ret;@@ -1904,7 +1877,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask =0xffffffffull ; -pci_dma_configure (dev);pci_set_dma_max_seg_size (dev,65536 );pci_set_dma_seg_boundary (dev,0xffffffff );include/linux/dma-mapping.h +3
-0@@ -708,6 +708,9 @@ void *dma_mark_declared_memory_occupied(struct device *dev, }#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ +int dma_configure (struct device *dev); +void dma_deconfigure (struct device *dev); +/* * Managed DMA API */ Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 6/11 drivers: platform: Configure dma operations at probe time
Hi Lorenzo,
Quoted 35 lines
-----Original Message-----
From: Lorenzo Pieralisi [mailto:lorenzo.pieralisi at arm.com]
Sent: Monday, January 23, 2017 5:37 PM
To: Sricharan R <[email protected]>
Cc: robin.murphy at arm.com; will.deacon at arm.com; joro at 8bytes.org; iommu at lists.linux-foundation.org; linux-arm- kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; m.szyprowski at samsung.com; bhelgaas at google.com
Subject: Re: [PATCH V6 06/11] drivers: platform: Configure dma operations at probe time[+bjorn]
Quoted 24 lines · Sricharan R
Configuring DMA ops at probe time will allow deferring device probe when the IOMMU isn't available yet. The
dma_configurefor the device is now called from the genericdevice_attachcallback just before the bus/driver probe is called. This way, configuring the DMA ops for the device would be called at the same place for allbus_types, hence the deferred probing mechanism should work for all buses as well.
pci_bus_add_devices(platform/amba)(_device_create/driver_register)| | pci_bus_add_device (device_add/driver_register) | | device_attach device_initial_probe | | __device_attach_driver __device_attach_driver | driver_probe_device | really_probe |
dma_configureSimilarly on the device/driver_unregister path
__device_release_driveris called which inturn callsdma_deconfigure.
Quoted 8 lines
Quoted 2 lines
This patch changes the dma ops configuration time to probe time for both OF and ACPI based devices.
For all device types, inclusive of PCI, so please you have to:
- Update the $SUBJECT
- Copy linux-pci at vger.kernel.org
- Copy linux-acpi at vger.kernel org (on the series)
Sure, i will just see till tomorrow for any further comments and repost with $SUBJECT modified and the lists
Regards,
Sricharan
PATCH v6 6/11 drivers: platform: Configure dma operations at probe time
In reply to Lorenzo PieralisiHi Lorenzo,
Quoted 30 lines
Quoted 30 lines
[+bjorn]
Quoted 26 lines · Sricharan R
Configuring DMA ops at probe time will allow deferring device probe when the IOMMU isn't available yet. The
dma_configurefor the device is now called from the genericdevice_attachcallback just before the bus/driver probe is called. This way, configuring the DMA ops for the device would be called at the same place for allbus_types, hence the deferred probing mechanism should work for all buses as well.
pci_bus_add_devices(platform/amba)(_device_create/driver_register)| | pci_bus_add_device (device_add/driver_register) | | device_attach device_initial_probe | | __device_attach_driver __device_attach_driver | driver_probe_device | really_probe |
dma_configureSimilarly on the device/driver_unregister path
__device_release_driveris called which inturn callsdma_deconfigure.This patch changes the dma ops configuration time to probe time for both OF and ACPI based devices.
Quoted 8 lines
Quoted 5 lines
For all device types, inclusive of PCI, so please you have to:
- Update the $SUBJECT
- Copy linux-pci at vger.kernel.org
- Copy linux-acpi at vger.kernel org (on the series)Sure, i will just see till tomorrow for any further comments and repost with $SUBJECT modified and the lists
Infact just reposted with $SUB updated and the additional lists.
Regards,
Sricharan
PATCH v6 7/11 iommu: of: Handle IOMMU lookup failure with deferred probing or error
In reply to Sricharan RFrom: Laurent Pinchart <[email protected]>
Failures to look up an IOMMU when parsing the DT iommus property need to be handled separately from the .of_xlate() failures to support deferred probing.
The lack of a registered IOMMU can be caused by the lack of a driver for the IOMMU, the IOMMU device probe not having been performed yet, having been deferred, or having failed.
The first case occurs when the device tree describes the bus master and IOMMU topology correctly but no device driver exists for the IOMMU yet or the device driver has not been compiled in. Return NULL, the caller will configure the device without an IOMMU.
The second and third cases are handled by deferring the probe of the bus master device which will eventually get reprobed after the IOMMU.
The last case is currently handled by deferring the probe of the bus master device as well. A mechanism to either configure the bus master device without an IOMMU or to fail the bus master device probe depending on whether the IOMMU is optional or mandatory would be a good enhancement.
--- drivers/base/dma-mapping.c | 5 +++-- drivers/iommu/of_iommu.c | 5 +++-- drivers/of/device.c | 9 +++++++-- include/linux/of_device.h | 9 ++++++--- 4 files changed, 19 insertions(+), 9 deletions(-)
drivers/base/dma-mapping.c +3 -2
@@ -353,6 +353,7 @@ int dma_configure(struct device *dev) {struct device *bridge =NULL , *dma_dev = dev;enum dev_dma_attr attr; +int ret =0 ;if (dev_is_pci (dev)) { bridge =pci_get_host_bridge_device (to_pci_dev (dev));
@@ -363,7 +364,7 @@ int dma_configure(struct device *dev) }if (dma_dev->of_node) { -of_dma_configure (dev, dma_dev->of_node); + ret =of_dma_configure (dev, dma_dev->of_node); }else if (has_acpi_companion (dma_dev)) { attr =acpi_get_dma_attr (to_acpi_device_node (dma_dev->fwnode));if (attr !=DEV_DMA_NOT_SUPPORTED )
@@ -373,7 +374,7 @@ int dma_configure(struct device *dev)if (bridge)pci_put_host_bridge_device (bridge); -return 0 ; +return ret; }void dma_deconfigure (struct device *dev)
drivers/iommu/of_iommu.c +3 -2
@@ -23,6 +23,7 @@#include <linux/of.h> #include <linux/of_iommu.h> #include <linux/of_pci.h> +#include <linux/pci.h> #include <linux/slab.h> static const struct of_device_id __iommu_of_table_sentinel
@@ -223,7 +224,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, ops =ERR_PTR (err); } -return IS_ERR (ops) ?NULL : ops; +return ops; }static int __init of_iommu_init (void )
@@ -234,7 +235,7 @@ static int __init of_iommu_init(void)for_each_matching_node_and_match (np, matches, &match) {const of_iommu_init_fn init_fn = match->data; -if (init_fn (np)) +if (init_fn &&init_fn (np))pr_err ("Failed to initialise IOMMU %s\n" ,of_node_full_name (np)); }
drivers/of/device.c +7 -2
@@ -82,7 +82,7 @@ int of_device_add(struct platform_device *ofdev)* can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events * to fix up DMA configuration. */ -void of_dma_configure (struct device *dev,struct device_node *np) +int of_dma_configure (struct device *dev,struct device_node *np) {u64 dma_addr, paddr, size;int ret;
@@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np) ret =of_dma_get_range (np, &dma_addr, &paddr, &size);if (ret <0 ) { dma_addr = offset =0 ; - size = dev->coherent_dma_mask +1 ; + size =max (dev->coherent_dma_mask, dev->coherent_dma_mask +1 ); }else { offset =PFN_DOWN (paddr - dma_addr);dev_dbg (dev,"dma_pfn_offset(%#08lx)\n" , offset);
@@ -129,10 +129,15 @@ void of_dma_configure(struct device *dev, struct device_node *np) coherent ? " " : " not "); iommu =of_iommu_configure (dev, np); +if (IS_ERR (iommu)) +return PTR_ERR (iommu); +dev_dbg (dev,"device is%sbehind an iommu\n" , iommu ?" " :" not " );arch_setup_dma_ops (dev, dma_addr, size, iommu, coherent); + +return 0 ; }EXPORT_SYMBOL_GPL (of_dma_configure);
include/linux/of_device.h +6 -3
@@ -55,7 +55,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) return of_node_get(cpu_dev->of_node); } -void of_dma_configure (struct device *dev,struct device_node *np); +int of_dma_configure (struct device *dev,struct device_node *np);void of_dma_deconfigure (struct device *dev);#else /* CONFIG_OF */
@@ -99,8 +99,11 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) {return NULL ; } -static inline void of_dma_configure (struct device *dev,struct device_node *np) -{} + +static inline int of_dma_configure (struct device *dev,struct device_node *np) +{ +return 0 ; +}static inline void of_dma_deconfigure (struct device *dev) {}#endif /* CONFIG_OF */
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 8/11 drivers: acpi: Handle IOMMU lookup failure with deferred probing or error
In reply to Sricharan RThis is an equivalent to the DT's handling of the iommu master's probe with deferred probing when the corrsponding iommu is not probed yet. The lack of a registered IOMMU can be caused by the lack of a driver for the IOMMU, the IOMMU device probe not having been performed yet, having been deferred, or having failed.
The first case occurs when the firmware describes the bus master and IOMMU topology correctly but no device driver exists for the IOMMU yet or the device driver has not been compiled in. Return NULL, the caller will configure the device without an IOMMU.
The second and third cases are handled by deferring the probe of the bus master device which will eventually get reprobed after the IOMMU.
The last case is currently handled by deferring the probe of the bus master device as well. A mechanism to either configure the bus master device without an IOMMU or to fail the bus master device probe depending on whether the IOMMU is optional or mandatory would be a good enhancement.
--- drivers/acpi/arm64/iort.c | 25 ++++++++++++++++++++++++- drivers/acpi/scan.c | 7 +++++-- drivers/base/dma-mapping.c | 2 +- include/acpi/acpi_bus.h | 2 +- include/linux/acpi.h | 7 +++++-- 5 files changed, 36 insertions(+), 7 deletions(-)
drivers/acpi/arm64/iort.c +24 -1
@@ -550,8 +550,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,return NULL ; ops =iommu_get_instance (iort_fwnode); +/* +* If the ops look-up fails, this means that either +* the SMMU drivers have not been probed yet or that +* the SMMU drivers are not built in the kernel; +* Depending on whether the SMMU drivers are built-in +* in the kernel or not, defer the IOMMU configuration +* or just abort it. +*/ if (!ops) -return NULL ; +return iort_iommu_driver_enabled (node->type) ? +ERR_PTR (-EPROBE_DEFER ) :NULL ; ret =arm_smmu_iort_xlate (dev, streamid, iort_fwnode, ops); }
@@ -625,12 +634,26 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)while (parent) { ops =iort_iommu_xlate (dev, parent, streamid); +if (IS_ERR_OR_NULL (ops)) +return ops; parent =iort_node_get_id (node, &streamid,IORT_IOMMU_TYPE , i++); } } +/* +* If we have reason to believe the IOMMU driver missed the initial +* add_device callback for dev, replay it to get things in order. +*/ +if (!IS_ERR_OR_NULL (ops) && ops->add_device && + dev->bus && !dev->iommu_group) { +int err = ops->add_device (dev); + +if (err) + ops =ERR_PTR (err); + } +return ops; }
drivers/acpi/scan.c +5 -2
@@ -1373,20 +1373,23 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)* @dev: The pointer to the device * @attr: device dma attributes */ -void acpi_dma_configure (struct device *dev,enum dev_dma_attr attr) +int acpi_dma_configure (struct device *dev,enum dev_dma_attr attr) {const struct iommu_ops *iommu;iort_set_dma_mask (dev); iommu =iort_iommu_configure (dev); - +if (IS_ERR (iommu)) +return PTR_ERR (iommu);/* * Assume dma valid range starts at 0 and covers the whole * coherent_dma_mask. */ arch_setup_dma_ops (dev,0 , dev->coherent_dma_mask +1 , iommu, attr ==DEV_DMA_COHERENT ); + +return 0 ; }EXPORT_SYMBOL_GPL (acpi_dma_configure);
drivers/base/dma-mapping.c +1 -1
@@ -368,7 +368,7 @@ int dma_configure(struct device *dev) }else if (has_acpi_companion (dma_dev)) { attr =acpi_get_dma_attr (to_acpi_device_node (dma_dev->fwnode));if (attr !=DEV_DMA_NOT_SUPPORTED ) -acpi_dma_configure (dev, attr); + ret =acpi_dma_configure (dev, attr); }if (bridge)
include/acpi/acpi_bus.h +1 -1
@@ -573,7 +573,7 @@ struct acpi_pci_root {bool acpi_dma_supported (struct acpi_device *adev);enum dev_dma_attr acpi_get_dma_attr (struct acpi_device *adev); -void acpi_dma_configure (struct device *dev,enum dev_dma_attr attr); +int acpi_dma_configure (struct device *dev,enum dev_dma_attr attr);void acpi_dma_deconfigure (struct device *dev); struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
include/linux/acpi.h +5 -2
@@ -764,8 +764,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)return DEV_DMA_NOT_SUPPORTED ; } -static inline void acpi_dma_configure (struct device *dev, -enum dev_dma_attr attr) { } +static inline int acpi_dma_configure (struct device *dev, +enum dev_dma_attr attr) +{ +return 0 ; +}static inline void acpi_dma_deconfigure (struct device *dev) { }
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 9/11 arm64: dma-mapping: Remove the notifier trick to handle early setting of dma_ops
In reply to Sricharan RWith arch_setup_dma_ops now being called late during device's probe after the device's iommu is probed, the notifier trick required to handle the early setup of dma_ops before the iommu group gets created is not required. So removing the notifier's here.
--- arch/arm64/mm/dma-mapping.c | 132 ++++---------------------------------------- 1 file changed, 12 insertions(+), 120 deletions(-)
arch/arm64/mm/dma-mapping.c +12 -120
@@ -803,140 +803,32 @@ static void __iommu_unmap_sg_attrs(struct device *dev, .mapping_error = iommu_dma_mapping_error, }; -/* -* TODO: Right now __iommu_setup_dma_ops() gets called too early to do -* everything it needs to - the device is only partially created and the -* IOMMU driver hasn't seen it yet, so it can't have a group. Thus we -* need this delayed attachment dance. Once IOMMU probe ordering is sorted -* to move the arch_setup_dma_ops() call later, all the notifier bits below -* become unnecessary, and will go away. -*/ -struct iommu_dma_notifier_data { -struct list_head list; -struct device *dev; -const struct iommu_ops *ops; -u64 dma_base; -u64 size; -}; -static LIST_HEAD (iommu_dma_masters); -static DEFINE_MUTEX (iommu_dma_notifier_lock); - -static bool do_iommu_attach (struct device *dev,const struct iommu_ops *ops, -u64 dma_base,u64 size) -{ -struct iommu_domain *domain =iommu_get_domain_for_dev (dev); - -/* -* If the IOMMU driver has the DMA domain support that we require, -* then the IOMMU core will have already configured a group for this -* device, and allocated the default domain for that group. -*/ -if (!domain ||iommu_dma_init_domain (domain, dma_base, size, dev)) { -pr_warn ("Failed to set up IOMMU for device %s; retaining platform DMA ops\n" , -dev_name (dev)); -return false; - } - - dev->archdata.dma_ops = &iommu_dma_ops; -return true; -} - -static void queue_iommu_attach (struct device *dev,const struct iommu_ops *ops, -u64 dma_base,u64 size) -{ -struct iommu_dma_notifier_data *iommudata; - - iommudata =kzalloc (sizeof (*iommudata),GFP_KERNEL ); -if (!iommudata) -return ; - - iommudata->dev = dev; - iommudata->ops = ops; - iommudata->dma_base = dma_base; - iommudata->size = size; - -mutex_lock (&iommu_dma_notifier_lock); -list_add (&iommudata->list, &iommu_dma_masters); -mutex_unlock (&iommu_dma_notifier_lock); -} - -static int __iommu_attach_notifier (struct notifier_block *nb, -unsigned long action,void *data) -{ -struct iommu_dma_notifier_data *master, *tmp; - -if (action !=BUS_NOTIFY_BIND_DRIVER ) -return 0 ; - -mutex_lock (&iommu_dma_notifier_lock); -list_for_each_entry_safe (master, tmp, &iommu_dma_masters, list) { -if (data == master->dev &&do_iommu_attach (master->dev, - master->ops, master->dma_base, master->size)) { -list_del (&master->list); -kfree (master); -break ; - } - } -mutex_unlock (&iommu_dma_notifier_lock); -return 0 ; -} - -static int __init register_iommu_dma_ops_notifier (struct bus_type *bus) -{ -struct notifier_block *nb =kzalloc (sizeof (*nb),GFP_KERNEL ); -int ret; - -if (!nb) -return -ENOMEM ; - - nb->notifier_call = __iommu_attach_notifier; - - ret =bus_register_notifier (bus, nb); -if (ret) { -pr_warn ("Failed to register DMA domain notifier; IOMMU DMA ops unavailable on bus '%s'\n" , - bus->name); -kfree (nb); - } -return ret; -} -static int __init __iommu_dma_init (void ) { -int ret; - - ret =iommu_dma_init (); -if (!ret) - ret =register_iommu_dma_ops_notifier (&platform_bus_type); -if (!ret) - ret =register_iommu_dma_ops_notifier (&amba_bustype); -#ifdef CONFIG_PCI -if (!ret) - ret =register_iommu_dma_ops_notifier (&pci_bus_type); -#endif -return ret; +return iommu_dma_init (); }arch_initcall (__iommu_dma_init);static void __iommu_setup_dma_ops (struct device *dev,u64 dma_base,u64 size,const struct iommu_ops *ops) { -struct iommu_group *group; +struct iommu_domain *domain;if (!ops)return ; +/* -* TODO: As a concession to the future, we're ready to handle being -* called both early and late (i.e. after bus_add_device). Once all -* the platform bus code is reworked to call us late and the notifier -* junk above goes away, move the body of do_iommu_attach here. +* The IOMMU core code allocates the default DMA domain, which the +* underlying IOMMU driver needs to support via the dma-iommu layer. */ - group =iommu_group_get (dev); -if (group) { -do_iommu_attach (dev, ops, dma_base, size); -iommu_group_put (group); - }else { -queue_iommu_attach (dev, ops, dma_base, size); + domain =iommu_get_domain_for_dev (dev); +if (!domain ||iommu_dma_init_domain (domain, dma_base, size, dev)) { +pr_warn ("Failed to set up IOMMU for device %s; retaining platform DMA ops\n" , +dev_name (dev)); +return ; } + + dev->archdata.dma_ops = &iommu_dma_ops; }void arch_teardown_dma_ops (struct device *dev)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 10/11 iommu/arm-smmu: Clean up early-probing workarounds
In reply to Sricharan RFrom: Robin Murphy <[email protected]>
Now that the appropriate ordering is enforced via profe-deferral of masters in core code, rip it all out and bask in the simplicity.
--- drivers/iommu/arm-smmu-v3.c | 46 ++--------------------------------- drivers/iommu/arm-smmu.c | 58 +++++++-------------------------------------- 2 files changed, 10 insertions(+), 94 deletions(-)
drivers/iommu/arm-smmu-v3.c +2 -44
@@ -2729,51 +2729,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev) .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, }; +module_platform_driver (arm_smmu_driver); -static int __init arm_smmu_init (void ) -{ -static bool registered; -int ret =0 ; - -if (!registered) { - ret =platform_driver_register (&arm_smmu_driver); - registered = !ret; - } -return ret; -} - -static void __exit arm_smmu_exit(void) -{ -return platform_driver_unregister (&arm_smmu_driver); -} - -subsys_initcall (arm_smmu_init); -module_exit (arm_smmu_exit); - -static int __init arm_smmu_of_init (struct device_node *np) -{ -int ret =arm_smmu_init (); - -if (ret) -return ret; - -if (!of_platform_device_create (np,NULL , platform_bus_type.dev_root)) -return -ENODEV ; - -return 0 ; -} -IOMMU_OF_DECLARE (arm_smmuv3,"arm,smmu-v3" , arm_smmu_of_init); - -#ifdef CONFIG_ACPI -static int __init acpi_smmu_v3_init (struct acpi_table_header *table) -{ -if (iort_node_match (ACPI_IORT_NODE_SMMU_V3 )) -return arm_smmu_init (); - -return 0 ; -} -IORT_ACPI_DECLARE (arm_smmu_v3,ACPI_SIG_IORT , acpi_smmu_v3_init); -#endif +IOMMU_OF_DECLARE (arm_smmuv3,"arm,smmu-v3" ,NULL );MODULE_DESCRIPTION ("IOMMU API for ARM architected SMMUv3 implementations" );MODULE_AUTHOR ("Will Deacon <[email protected]>" );
drivers/iommu/arm-smmu.c +8 -50
64 lines not on this page · raw message
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v6 11/11 ACPI/IORT: Remove linker section for IORT entries probing
In reply to Sricharan RFrom: Lorenzo Pieralisi <[email protected]>
The IORT linker section introduced by commit 34ceea275f62 ("ACPI/IORT: Introduce linker section for IORT entries probing") was needed to make sure SMMU drivers are registered (and therefore probed) in the kernel before devices using the SMMU have a chance to probe in turn.
Through the introduction of deferred IOMMU configuration the linker section based IORT probing infrastructure is not needed any longer, in that device/SMMU probe dependencies are managed through the probe deferral mechanism, making the IORT linker section infrastructure unused, so that it can be removed.
Remove the unused IORT linker section probing infrastructure from the kernel to complete the ACPI IORT IOMMU configure probe deferral mechanism implementation.
--- drivers/acpi/arm64/iort.c | 2 -- include/asm-generic/vmlinux.lds.h | 1 - include/linux/acpi_iort.h | 3 --- 3 files changed, 6 deletions(-)
drivers/acpi/arm64/iort.c +0 -2
@@ -992,6 +992,4 @@ void __init acpi_iort_init(void) }iort_init_platform_devices (); - -acpi_probe_device_table (iort); }
include/asm-generic/vmlinux.lds.h +0 -1
@@ -566,7 +566,6 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(clksrc) \ - ACPI_PROBE_TABLE(iort) \ EARLYCON_TABLE()#define INIT_TEXT \
include/linux/acpi_iort.h +0 -3
@@ -52,7 +52,4 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) {return NULL ; }#endif -#define IORT_ACPI_DECLARE (name, table_id, fn) \ - ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn) -#endif /* __ACPI_IORT_H__ */
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation