dma-mapping: detect and configure IOMMU in of_dma_configure
authorWill Deacon <will.deacon@arm.com>
Wed, 27 Aug 2014 15:24:20 +0000 (16:24 +0100)
committerWill Deacon <will.deacon@arm.com>
Mon, 1 Dec 2014 16:50:45 +0000 (16:50 +0000)
This patch extends of_dma_configure so that it sets up the IOMMU for a
device, as well as the coherent/non-coherent DMA mapping ops.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm/include/asm/dma-mapping.h
drivers/of/platform.c
include/linux/dma-mapping.h

index dc3420e777581437089a23a6e37635db0182f20e..f3c0d953f6a210c6612b03aad7ff6d33b1fc74ef 100644 (file)
@@ -121,7 +121,9 @@ static inline unsigned long dma_max_pfn(struct device *dev)
 }
 #define dma_max_pfn(dev) dma_max_pfn(dev)
 
-static inline void arch_setup_dma_ops(struct device *dev, bool coherent)
+static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
+                                     u64 size, struct iommu_ops *iommu,
+                                     bool coherent)
 {
        if (coherent)
                set_dma_ops(dev, &arm_coherent_dma_ops);
index ff1f4e9afccb10d68d32fe2b04b5a31d4bb858e0..b89caf8c7586268b7aec6414be9c58d03382b78c 100644 (file)
@@ -19,6 +19,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>
@@ -166,6 +167,7 @@ static void of_dma_configure(struct device *dev)
        int ret;
        bool coherent;
        unsigned long offset;
+       struct iommu_ops *iommu;
 
        /*
         * Set default dma-mask to 32 bit. Drivers are expected to setup
@@ -194,7 +196,16 @@ static void of_dma_configure(struct device *dev)
        dev_dbg(dev, "device is%sdma coherent\n",
                coherent ? " " : " not ");
 
-       arch_setup_dma_ops(dev, coherent);
+       iommu = of_iommu_configure(dev);
+       dev_dbg(dev, "device is%sbehind an iommu\n",
+               iommu ? " " : " not ");
+
+       arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
+}
+
+static void of_dma_deconfigure(struct device *dev)
+{
+       arch_teardown_dma_ops(dev);
 }
 
 /**
@@ -223,16 +234,12 @@ static struct platform_device *of_platform_device_create_pdata(
        if (!dev)
                goto err_clear_flag;
 
-       of_dma_configure(&dev->dev);
        dev->dev.bus = &platform_bus_type;
        dev->dev.platform_data = platform_data;
-
-       /* We do not fill the DMA ops for platform devices by default.
-        * This is currently the responsibility of the platform code
-        * to do such, possibly using a device notifier
-        */
+       of_dma_configure(&dev->dev);
 
        if (of_device_add(dev) != 0) {
+               of_dma_deconfigure(&dev->dev);
                platform_device_put(dev);
                goto err_clear_flag;
        }
index 8a1560f95d4ab92636d5034aa52d2c76ecff89f7..c3007cb4bfa66fda55b2883f4e08f3fc341176ab 100644 (file)
@@ -130,7 +130,13 @@ static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask)
 extern u64 dma_get_required_mask(struct device *dev);
 
 #ifndef arch_setup_dma_ops
-static inline void arch_setup_dma_ops(struct device *dev, bool coherent) { }
+static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
+                                     u64 size, struct iommu_ops *iommu,
+                                     bool coherent) { }
+#endif
+
+#ifndef arch_teardown_dma_ops
+static inline void arch_teardown_dma_ops(struct device *dev) { }
 #endif
 
 static inline unsigned int dma_get_max_seg_size(struct device *dev)