Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sricharan R and committed by
Joerg Roedel
09515ef5 efc8551a

+62 -37
-5
drivers/acpi/glue.c
··· 176 176 struct list_head *physnode_list; 177 177 unsigned int node_id; 178 178 int retval = -EINVAL; 179 - enum dev_dma_attr attr; 180 179 181 180 if (has_acpi_companion(dev)) { 182 181 if (acpi_dev) { ··· 231 232 232 233 if (!has_acpi_companion(dev)) 233 234 ACPI_COMPANION_SET(dev, acpi_dev); 234 - 235 - attr = acpi_get_dma_attr(acpi_dev); 236 - if (attr != DEV_DMA_NOT_SUPPORTED) 237 - acpi_dma_configure(dev, attr); 238 235 239 236 acpi_physnode_link_name(physical_node_name, node_id); 240 237 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+9
drivers/base/dd.c
··· 19 19 20 20 #include <linux/device.h> 21 21 #include <linux/delay.h> 22 + #include <linux/dma-mapping.h> 22 23 #include <linux/module.h> 23 24 #include <linux/kthread.h> 24 25 #include <linux/wait.h> ··· 357 356 if (ret) 358 357 goto pinctrl_bind_failed; 359 358 359 + ret = dma_configure(dev); 360 + if (ret) 361 + goto dma_failed; 362 + 360 363 if (driver_sysfs_add(dev)) { 361 364 printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", 362 365 __func__, dev_name(dev)); ··· 422 417 goto done; 423 418 424 419 probe_failed: 420 + dma_deconfigure(dev); 421 + dma_failed: 425 422 if (dev->bus) 426 423 blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 427 424 BUS_NOTIFY_DRIVER_NOT_BOUND, dev); ··· 833 826 drv->remove(dev); 834 827 835 828 device_links_driver_cleanup(dev); 829 + dma_deconfigure(dev); 830 + 836 831 devres_release_all(dev); 837 832 dev->driver = NULL; 838 833 dev_set_drvdata(dev, NULL);
+40
drivers/base/dma-mapping.c
··· 7 7 * This file is released under the GPLv2. 8 8 */ 9 9 10 + #include <linux/acpi.h> 10 11 #include <linux/dma-mapping.h> 11 12 #include <linux/export.h> 12 13 #include <linux/gfp.h> 14 + #include <linux/of_device.h> 13 15 #include <linux/slab.h> 14 16 #include <linux/vmalloc.h> 15 17 ··· 343 341 vunmap(cpu_addr); 344 342 } 345 343 #endif 344 + 345 + /* 346 + * Common configuration to enable DMA API use for a device 347 + */ 348 + #include <linux/pci.h> 349 + 350 + int dma_configure(struct device *dev) 351 + { 352 + struct device *bridge = NULL, *dma_dev = dev; 353 + enum dev_dma_attr attr; 354 + 355 + if (dev_is_pci(dev)) { 356 + bridge = pci_get_host_bridge_device(to_pci_dev(dev)); 357 + dma_dev = bridge; 358 + if (IS_ENABLED(CONFIG_OF) && dma_dev->parent && 359 + dma_dev->parent->of_node) 360 + dma_dev = dma_dev->parent; 361 + } 362 + 363 + if (dma_dev->of_node) { 364 + of_dma_configure(dev, dma_dev->of_node); 365 + } else if (has_acpi_companion(dma_dev)) { 366 + attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode)); 367 + if (attr != DEV_DMA_NOT_SUPPORTED) 368 + acpi_dma_configure(dev, attr); 369 + } 370 + 371 + if (bridge) 372 + pci_put_host_bridge_device(bridge); 373 + 374 + return 0; 375 + } 376 + 377 + void dma_deconfigure(struct device *dev) 378 + { 379 + of_dma_deconfigure(dev); 380 + acpi_dma_deconfigure(dev); 381 + }
+1 -4
drivers/of/platform.c
··· 22 22 #include <linux/slab.h> 23 23 #include <linux/of_address.h> 24 24 #include <linux/of_device.h> 25 + #include <linux/of_iommu.h> 25 26 #include <linux/of_irq.h> 26 27 #include <linux/of_platform.h> 27 28 #include <linux/platform_device.h> ··· 187 186 188 187 dev->dev.bus = &platform_bus_type; 189 188 dev->dev.platform_data = platform_data; 190 - of_dma_configure(&dev->dev, dev->dev.of_node); 191 189 of_msi_configure(&dev->dev, dev->dev.of_node); 192 190 193 191 if (of_device_add(dev) != 0) { 194 - of_dma_deconfigure(&dev->dev); 195 192 platform_device_put(dev); 196 193 goto err_clear_flag; 197 194 } ··· 247 248 dev_set_name(&dev->dev, "%s", bus_id); 248 249 else 249 250 of_device_make_bus_id(&dev->dev); 250 - of_dma_configure(&dev->dev, dev->dev.of_node); 251 251 252 252 /* Allow the HW Peripheral ID to be overridden */ 253 253 prop = of_get_property(node, "arm,primecell-periphid", NULL); ··· 540 542 amba_device_unregister(to_amba_device(dev)); 541 543 #endif 542 544 543 - of_dma_deconfigure(dev); 544 545 of_node_clear_flag(dev->of_node, OF_POPULATED); 545 546 of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); 546 547 return 0;
-28
drivers/pci/probe.c
··· 1893 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 1896 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) 1924 1897 { 1925 1898 int ret; ··· 1906 1933 dev->dev.dma_mask = &dev->dma_mask; 1907 1934 dev->dev.dma_parms = &dev->dma_parms; 1908 1935 dev->dev.coherent_dma_mask = 0xffffffffull; 1909 - pci_dma_configure(dev); 1910 1936 1911 1937 pci_set_dma_max_seg_size(dev, 65536); 1912 1938 pci_set_dma_seg_boundary(dev, 0xffffffff);
+12
include/linux/dma-mapping.h
··· 728 728 } 729 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 744 * Managed DMA API 733 745 */