powerpc/64: Honor swiotlb limit in coherent allocations
authorScott Wood <scottwood@freescale.com>
Fri, 8 Aug 2014 23:40:43 +0000 (18:40 -0500)
committerScott Wood <scottwood@freescale.com>
Wed, 3 Sep 2014 22:58:22 +0000 (17:58 -0500)
FSL PCI cannot directly address the whole lower 4 GiB due to
conflicts with PCICSRBAR and outbound windows, and thus
max_direct_dma_addr is less than 4GiB.  Honor that limit in
dma_direct_alloc_coherent().

Note that setting the DMA mask to 31 bits is not an option, since many
PCI drivers would fail if we reject 32-bit DMA in dma_supported(), and
we have no control over the setting of coherent_dma_mask if
dma_supported() returns true.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Cc: Shaohui Xie <Shaohui.Xie@freescale.com>
arch/powerpc/kernel/dma.c

index dfd99ef8c63d088e878dfbb3fd4639b9ba4bb40c..a7b0156586dd40f63342326ad74a4acd2cfcb1d4 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/vio.h>
 #include <asm/bug.h>
 #include <asm/machdep.h>
+#include <asm/swiotlb.h>
 
 /*
  * Generic direct DMA implementation
  * default the offset is PCI_DRAM_OFFSET.
  */
 
+static u64 __maybe_unused get_pfn_limit(struct device *dev)
+{
+       u64 pfn = (dev->coherent_dma_mask >> PAGE_SHIFT) + 1;
+       struct dev_archdata __maybe_unused *sd = &dev->archdata;
+
+#ifdef CONFIG_SWIOTLB
+       if (sd->max_direct_dma_addr && sd->dma_ops == &swiotlb_dma_ops)
+               pfn = min_t(u64, pfn, sd->max_direct_dma_addr >> PAGE_SHIFT);
+#endif
+
+       return pfn;
+}
 
 void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                                dma_addr_t *dma_handle, gfp_t flag,
@@ -40,7 +53,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 #else
        struct page *page;
        int node = dev_to_node(dev);
-       u64 pfn = (dev->coherent_dma_mask >> PAGE_SHIFT) + 1;
+       u64 pfn = get_pfn_limit(dev);
        int zone;
 
        zone = dma_pfn_limit_to_zone(pfn);