diff options
author | Sricharan R <sricharan@codeaurora.org> | 2017-04-10 07:21:01 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2017-04-20 10:31:06 -0400 |
commit | 09515ef5ddad71c7820e5e428da418b709feeb26 (patch) | |
tree | 3786792035e575e806a629cbf02ac3c96f5ebe53 | |
parent | efc8551a276faab19d85079da02c5fb602b0dcbe (diff) |
of/acpi: Configure dma operations at probe time for platform/amba/pci bus devices
Configuring 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 to probe time for
both OF and ACPI based platform/amba/pci bus devices.
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> (drivers/pci part)
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/acpi/glue.c | 5 | ||||
-rw-r--r-- | drivers/base/dd.c | 9 | ||||
-rw-r--r-- | drivers/base/dma-mapping.c | 40 | ||||
-rw-r--r-- | drivers/of/platform.c | 5 | ||||
-rw-r--r-- | drivers/pci/probe.c | 28 | ||||
-rw-r--r-- | include/linux/dma-mapping.h | 12 |
6 files changed, 62 insertions, 37 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index fb19e1cdb641..c05f24107bfc 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) | |||
176 | struct list_head *physnode_list; | 176 | struct list_head *physnode_list; |
177 | unsigned int node_id; | 177 | unsigned int node_id; |
178 | int retval = -EINVAL; | 178 | int retval = -EINVAL; |
179 | enum dev_dma_attr attr; | ||
180 | 179 | ||
181 | if (has_acpi_companion(dev)) { | 180 | if (has_acpi_companion(dev)) { |
182 | if (acpi_dev) { | 181 | if (acpi_dev) { |
@@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) | |||
233 | if (!has_acpi_companion(dev)) | 232 | if (!has_acpi_companion(dev)) |
234 | ACPI_COMPANION_SET(dev, acpi_dev); | 233 | ACPI_COMPANION_SET(dev, acpi_dev); |
235 | 234 | ||
236 | attr = acpi_get_dma_attr(acpi_dev); | ||
237 | if (attr != DEV_DMA_NOT_SUPPORTED) | ||
238 | acpi_dma_configure(dev, attr); | ||
239 | |||
240 | acpi_physnode_link_name(physical_node_name, node_id); | 235 | acpi_physnode_link_name(physical_node_name, node_id); |
241 | retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, | 236 | retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, |
242 | physical_node_name); | 237 | physical_node_name); |
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a1fbf55c4d3a..4882f06d12df 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
23 | #include <linux/kthread.h> | 24 | #include <linux/kthread.h> |
24 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
@@ -356,6 +357,10 @@ re_probe: | |||
356 | if (ret) | 357 | if (ret) |
357 | goto pinctrl_bind_failed; | 358 | goto pinctrl_bind_failed; |
358 | 359 | ||
360 | ret = dma_configure(dev); | ||
361 | if (ret) | ||
362 | goto dma_failed; | ||
363 | |||
359 | if (driver_sysfs_add(dev)) { | 364 | if (driver_sysfs_add(dev)) { |
360 | printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", | 365 | printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", |
361 | __func__, dev_name(dev)); | 366 | __func__, dev_name(dev)); |
@@ -417,6 +422,8 @@ re_probe: | |||
417 | goto done; | 422 | goto done; |
418 | 423 | ||
419 | probe_failed: | 424 | probe_failed: |
425 | dma_deconfigure(dev); | ||
426 | dma_failed: | ||
420 | if (dev->bus) | 427 | if (dev->bus) |
421 | blocking_notifier_call_chain(&dev->bus->p->bus_notifier, | 428 | blocking_notifier_call_chain(&dev->bus->p->bus_notifier, |
422 | BUS_NOTIFY_DRIVER_NOT_BOUND, dev); | 429 | BUS_NOTIFY_DRIVER_NOT_BOUND, dev); |
@@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent) | |||
826 | drv->remove(dev); | 833 | drv->remove(dev); |
827 | 834 | ||
828 | device_links_driver_cleanup(dev); | 835 | device_links_driver_cleanup(dev); |
836 | dma_deconfigure(dev); | ||
837 | |||
829 | devres_release_all(dev); | 838 | devres_release_all(dev); |
830 | dev->driver = NULL; | 839 | dev->driver = NULL; |
831 | dev_set_drvdata(dev, NULL); | 840 | dev_set_drvdata(dev, NULL); |
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index efd71cf4fdea..449b948c7427 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c | |||
@@ -7,9 +7,11 @@ | |||
7 | * This file is released under the GPLv2. | 7 | * This file is released under the GPLv2. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/acpi.h> | ||
10 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
11 | #include <linux/export.h> | 12 | #include <linux/export.h> |
12 | #include <linux/gfp.h> | 13 | #include <linux/gfp.h> |
14 | #include <linux/of_device.h> | ||
13 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
14 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
15 | 17 | ||
@@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) | |||
341 | vunmap(cpu_addr); | 343 | vunmap(cpu_addr); |
342 | } | 344 | } |
343 | #endif | 345 | #endif |
346 | |||
347 | /* | ||
348 | * Common configuration to enable DMA API use for a device | ||
349 | */ | ||
350 | #include <linux/pci.h> | ||
351 | |||
352 | int dma_configure(struct device *dev) | ||
353 | { | ||
354 | struct device *bridge = NULL, *dma_dev = dev; | ||
355 | enum dev_dma_attr attr; | ||
356 | |||
357 | if (dev_is_pci(dev)) { | ||
358 | bridge = pci_get_host_bridge_device(to_pci_dev(dev)); | ||
359 | dma_dev = bridge; | ||
360 | if (IS_ENABLED(CONFIG_OF) && dma_dev->parent && | ||
361 | dma_dev->parent->of_node) | ||
362 | dma_dev = dma_dev->parent; | ||
363 | } | ||
364 | |||
365 | if (dma_dev->of_node) { | ||
366 | of_dma_configure(dev, dma_dev->of_node); | ||
367 | } else if (has_acpi_companion(dma_dev)) { | ||
368 | attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode)); | ||
369 | if (attr != DEV_DMA_NOT_SUPPORTED) | ||
370 | acpi_dma_configure(dev, attr); | ||
371 | } | ||
372 | |||
373 | if (bridge) | ||
374 | pci_put_host_bridge_device(bridge); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | void dma_deconfigure(struct device *dev) | ||
380 | { | ||
381 | of_dma_deconfigure(dev); | ||
382 | acpi_dma_deconfigure(dev); | ||
383 | } | ||
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 5344db50aa65..2aa4ebbde9cd 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
24 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
25 | #include <linux/of_iommu.h> | ||
25 | #include <linux/of_irq.h> | 26 | #include <linux/of_irq.h> |
26 | #include <linux/of_platform.h> | 27 | #include <linux/of_platform.h> |
27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
@@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata( | |||
186 | 187 | ||
187 | dev->dev.bus = &platform_bus_type; | 188 | dev->dev.bus = &platform_bus_type; |
188 | dev->dev.platform_data = platform_data; | 189 | dev->dev.platform_data = platform_data; |
189 | of_dma_configure(&dev->dev, dev->dev.of_node); | ||
190 | of_msi_configure(&dev->dev, dev->dev.of_node); | 190 | of_msi_configure(&dev->dev, dev->dev.of_node); |
191 | 191 | ||
192 | if (of_device_add(dev) != 0) { | 192 | if (of_device_add(dev) != 0) { |
193 | of_dma_deconfigure(&dev->dev); | ||
194 | platform_device_put(dev); | 193 | platform_device_put(dev); |
195 | goto err_clear_flag; | 194 | goto err_clear_flag; |
196 | } | 195 | } |
@@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node, | |||
248 | dev_set_name(&dev->dev, "%s", bus_id); | 247 | dev_set_name(&dev->dev, "%s", bus_id); |
249 | else | 248 | else |
250 | of_device_make_bus_id(&dev->dev); | 249 | of_device_make_bus_id(&dev->dev); |
251 | of_dma_configure(&dev->dev, dev->dev.of_node); | ||
252 | 250 | ||
253 | /* Allow the HW Peripheral ID to be overridden */ | 251 | /* Allow the HW Peripheral ID to be overridden */ |
254 | prop = of_get_property(node, "arm,primecell-periphid", NULL); | 252 | prop = of_get_property(node, "arm,primecell-periphid", NULL); |
@@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data) | |||
542 | amba_device_unregister(to_amba_device(dev)); | 540 | amba_device_unregister(to_amba_device(dev)); |
543 | #endif | 541 | #endif |
544 | 542 | ||
545 | of_dma_deconfigure(dev); | ||
546 | of_node_clear_flag(dev->of_node, OF_POPULATED); | 543 | of_node_clear_flag(dev->of_node, OF_POPULATED); |
547 | of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); | 544 | of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); |
548 | return 0; | 545 | return 0; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dfc9a2794141..5a8dd43db336 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1893,33 +1893,6 @@ static void pci_set_msi_domain(struct pci_dev *dev) | |||
1893 | dev_set_msi_domain(&dev->dev, d); | 1893 | dev_set_msi_domain(&dev->dev, d); |
1894 | } | 1894 | } |
1895 | 1895 | ||
1896 | /** | ||
1897 | * pci_dma_configure - Setup DMA configuration | ||
1898 | * @dev: ptr to pci_dev struct of the PCI device | ||
1899 | * | ||
1900 | * Function to update PCI devices's DMA configuration using the same | ||
1901 | * info from the OF node or ACPI node of host bridge's parent (if any). | ||
1902 | */ | ||
1903 | static void pci_dma_configure(struct pci_dev *dev) | ||
1904 | { | ||
1905 | struct device *bridge = pci_get_host_bridge_device(dev); | ||
1906 | |||
1907 | if (IS_ENABLED(CONFIG_OF) && | ||
1908 | bridge->parent && bridge->parent->of_node) { | ||
1909 | of_dma_configure(&dev->dev, bridge->parent->of_node); | ||
1910 | } else if (has_acpi_companion(bridge)) { | ||
1911 | struct acpi_device *adev = to_acpi_device_node(bridge->fwnode); | ||
1912 | enum dev_dma_attr attr = acpi_get_dma_attr(adev); | ||
1913 | |||
1914 | if (attr == DEV_DMA_NOT_SUPPORTED) | ||
1915 | dev_warn(&dev->dev, "DMA not supported.\n"); | ||
1916 | else | ||
1917 | acpi_dma_configure(&dev->dev, attr); | ||
1918 | } | ||
1919 | |||
1920 | pci_put_host_bridge_device(bridge); | ||
1921 | } | ||
1922 | |||
1923 | void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | 1896 | void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) |
1924 | { | 1897 | { |
1925 | int ret; | 1898 | int ret; |
@@ -1933,7 +1906,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
1933 | dev->dev.dma_mask = &dev->dma_mask; | 1906 | dev->dev.dma_mask = &dev->dma_mask; |
1934 | dev->dev.dma_parms = &dev->dma_parms; | 1907 | dev->dev.dma_parms = &dev->dma_parms; |
1935 | dev->dev.coherent_dma_mask = 0xffffffffull; | 1908 | dev->dev.coherent_dma_mask = 0xffffffffull; |
1936 | pci_dma_configure(dev); | ||
1937 | 1909 | ||
1938 | pci_set_dma_max_seg_size(dev, 65536); | 1910 | pci_set_dma_max_seg_size(dev, 65536); |
1939 | pci_set_dma_seg_boundary(dev, 0xffffffff); | 1911 | pci_set_dma_seg_boundary(dev, 0xffffffff); |
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 0977317c6835..4f3eecedca2d 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h | |||
@@ -728,6 +728,18 @@ dma_mark_declared_memory_occupied(struct device *dev, | |||
728 | } | 728 | } |
729 | #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ | 729 | #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ |
730 | 730 | ||
731 | #ifdef CONFIG_HAS_DMA | ||
732 | int dma_configure(struct device *dev); | ||
733 | void dma_deconfigure(struct device *dev); | ||
734 | #else | ||
735 | static inline int dma_configure(struct device *dev) | ||
736 | { | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static inline void dma_deconfigure(struct device *dev) {} | ||
741 | #endif | ||
742 | |||
731 | /* | 743 | /* |
732 | * Managed DMA API | 744 | * Managed DMA API |
733 | */ | 745 | */ |