dma-mapping: move dma configuration to bus infrastructure
authorNipun Gupta <nipun.gupta@nxp.com>
Sat, 28 Apr 2018 02:51:58 +0000 (08:21 +0530)
committerChristoph Hellwig <hch@lst.de>
Thu, 3 May 2018 14:22:18 +0000 (16:22 +0200)
ACPI/OF support for configuration of DMA is a bus specific aspect, and
thus should be configured by the bus.  Introduces a 'dma_configure' bus
method so that busses can control their DMA capabilities.

Also update the PCI, Platform, ACPI and host1x buses to use the new
method.

Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # PCI parts
Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[hch: simplified host1x_dma_configure based on a comment from Thierry,
      rewrote changelog]
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/amba/bus.c
drivers/base/dma-mapping.c
drivers/base/platform.c
drivers/gpu/host1x/bus.c
drivers/pci/pci-driver.c
include/linux/device.h
include/linux/platform_device.h

index 4a3ac31..b1f41f7 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sizes.h>
 #include <linux/limits.h>
 #include <linux/clk/clk-conf.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 
@@ -193,12 +194,15 @@ static const struct dev_pm_ops amba_pm = {
 /*
  * Primecells are part of the Advanced Microcontroller Bus Architecture,
  * so we call the bus "amba".
+ * DMA configuration for platform and AMBA bus is same. So here we reuse
+ * platform's DMA config routine.
  */
 struct bus_type amba_bustype = {
        .name           = "amba",
        .dev_groups     = amba_dev_groups,
        .match          = amba_match,
        .uevent         = amba_uevent,
+       .dma_configure  = platform_dma_configure,
        .pm             = &amba_pm,
        .force_dma      = true,
 };
index d82566d..f831a58 100644 (file)
@@ -329,36 +329,13 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
 #endif
 
 /*
- * Common configuration to enable DMA API use for a device
+ * enables 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;
-       int ret = 0;
-
-       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) {
-               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)
-                       ret = acpi_dma_configure(dev, attr);
-       }
-
-       if (bridge)
-               pci_put_host_bridge_device(bridge);
-
-       return ret;
+       if (dev->bus->dma_configure)
+               return dev->bus->dma_configure(dev);
+       return 0;
 }
 
 void dma_deconfigure(struct device *dev)
index 8075ddc..638d42e 100644 (file)
@@ -1130,6 +1130,22 @@ int platform_pm_restore(struct device *dev)
 
 #endif /* CONFIG_HIBERNATE_CALLBACKS */
 
+int platform_dma_configure(struct device *dev)
+{
+       enum dev_dma_attr attr;
+       int ret = 0;
+
+       if (dev->of_node) {
+               ret = of_dma_configure(dev, dev->of_node);
+       } else if (has_acpi_companion(dev)) {
+               attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
+               if (attr != DEV_DMA_NOT_SUPPORTED)
+                       ret = acpi_dma_configure(dev, attr);
+       }
+
+       return ret;
+}
+
 static const struct dev_pm_ops platform_dev_pm_ops = {
        .runtime_suspend = pm_generic_runtime_suspend,
        .runtime_resume = pm_generic_runtime_resume,
@@ -1141,6 +1157,7 @@ struct bus_type platform_bus_type = {
        .dev_groups     = platform_dev_groups,
        .match          = platform_match,
        .uevent         = platform_uevent,
+       .dma_configure  = platform_dma_configure,
        .pm             = &platform_dev_pm_ops,
        .force_dma      = true,
 };
index 88a3558..0c79baf 100644 (file)
@@ -314,6 +314,11 @@ static int host1x_device_match(struct device *dev, struct device_driver *drv)
        return strcmp(dev_name(dev), drv->name) == 0;
 }
 
+static int host1x_dma_configure(struct device *dev)
+{
+       return of_dma_configure(dev, dev->of_node);
+}
+
 static const struct dev_pm_ops host1x_device_pm_ops = {
        .suspend = pm_generic_suspend,
        .resume = pm_generic_resume,
@@ -326,6 +331,7 @@ static const struct dev_pm_ops host1x_device_pm_ops = {
 struct bus_type host1x_bus_type = {
        .name = "host1x",
        .match = host1x_device_match,
+       .dma_configure  = host1x_dma_configure,
        .pm = &host1x_device_pm_ops,
        .force_dma = true,
 };
index b9a1311..ba8c6b4 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
 #include <linux/kexec.h>
+#include <linux/of_device.h>
+#include <linux/acpi.h>
 #include "pci.h"
 #include "pcie/portdrv.h"
 
@@ -1577,6 +1579,35 @@ static int pci_bus_num_vf(struct device *dev)
        return pci_num_vf(to_pci_dev(dev));
 }
 
+/**
+ * pci_dma_configure - Setup DMA configuration
+ * @dev: ptr to dev structure
+ *
+ * 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 int pci_dma_configure(struct device *dev)
+{
+       struct device *bridge;
+       int ret = 0;
+
+       bridge = pci_get_host_bridge_device(to_pci_dev(dev));
+
+       if (IS_ENABLED(CONFIG_OF) && bridge->parent &&
+           bridge->parent->of_node) {
+               ret = of_dma_configure(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)
+                       ret = acpi_dma_configure(dev, attr);
+       }
+
+       pci_put_host_bridge_device(bridge);
+       return ret;
+}
+
 struct bus_type pci_bus_type = {
        .name           = "pci",
        .match          = pci_bus_match,
@@ -1589,6 +1620,7 @@ struct bus_type pci_bus_type = {
        .drv_groups     = pci_drv_groups,
        .pm             = PCI_PM_OPS_PTR,
        .num_vf         = pci_bus_num_vf,
+       .dma_configure  = pci_dma_configure,
        .force_dma      = true,
 };
 EXPORT_SYMBOL(pci_bus_type);
index 4779569..63aa672 100644 (file)
@@ -88,6 +88,8 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
  * @resume:    Called to bring a device on this bus out of sleep mode.
  * @num_vf:    Called to find out how many virtual functions a device on this
  *             bus supports.
+ * @dma_configure:     Called to setup DMA configuration on a device on
+                       this bus.
  * @pm:                Power management operations of this bus, callback the specific
  *             device driver's pm-ops.
  * @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU
@@ -130,6 +132,8 @@ struct bus_type {
 
        int (*num_vf)(struct device *dev);
 
+       int (*dma_configure)(struct device *dev);
+
        const struct dev_pm_ops *pm;
 
        const struct iommu_ops *iommu_ops;
index 49f634d..3097c94 100644 (file)
@@ -356,6 +356,8 @@ extern int platform_pm_restore(struct device *dev);
 #define platform_pm_restore            NULL
 #endif
 
+extern int platform_dma_configure(struct device *dev);
+
 #ifdef CONFIG_PM_SLEEP
 #define USE_PLATFORM_PM_SLEEP_OPS \
        .suspend = platform_pm_suspend, \