arm64: Align CMA sizes to PAGE_SIZE
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / mm / dma-mapping.c
index 4bd7579ec9e6029746cb0fc485a255056fbaf2ff..fbd76785c5db640bf511a9647380ebb1ae29b3ef 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
 #include <linux/vmalloc.h>
 #include <linux/swiotlb.h>
 
@@ -33,17 +34,48 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size,
                                          dma_addr_t *dma_handle, gfp_t flags,
                                          struct dma_attrs *attrs)
 {
+       if (dev == NULL) {
+               WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
+               return NULL;
+       }
+
        if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
            dev->coherent_dma_mask <= DMA_BIT_MASK(32))
                flags |= GFP_DMA32;
-       return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+       if (IS_ENABLED(CONFIG_DMA_CMA)) {
+               struct page *page;
+
+               size = PAGE_ALIGN(size);
+               page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
+                                                       get_order(size));
+               if (!page)
+                       return NULL;
+
+               *dma_handle = phys_to_dma(dev, page_to_phys(page));
+               return page_address(page);
+       } else {
+               return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+       }
 }
 
 static void arm64_swiotlb_free_coherent(struct device *dev, size_t size,
                                        void *vaddr, dma_addr_t dma_handle,
                                        struct dma_attrs *attrs)
 {
-       swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+       if (dev == NULL) {
+               WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
+               return;
+       }
+
+       if (IS_ENABLED(CONFIG_DMA_CMA)) {
+               phys_addr_t paddr = dma_to_phys(dev, dma_handle);
+
+               dma_release_from_contiguous(dev,
+                                       phys_to_page(paddr),
+                                       size >> PAGE_SHIFT);
+       } else {
+               swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+       }
 }
 
 static struct dma_map_ops arm64_swiotlb_dma_ops = {