Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
[sfrench/cifs-2.6.git] / arch / mips / mm / dma-default.c
index 44b6dff5aba2a09e92715aab976c2ac37619e729..33ba3c558fe4ff31a0693457ea28a71ae4b5fafa 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/cache.h>
 #include <asm/cpu-type.h>
@@ -128,23 +129,30 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
        dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
 {
        void *ret;
+       struct page *page = NULL;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
                return ret;
 
        gfp = massage_gfp_flags(dev, gfp);
 
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-
-       if (ret) {
-               memset(ret, 0, size);
-               *dma_handle = plat_map_dma_mem(dev, ret, size);
-
-               if (!plat_device_is_coherent(dev)) {
-                       dma_cache_wback_inv((unsigned long) ret, size);
-                       if (!hw_coherentio)
-                               ret = UNCAC_ADDR(ret);
-               }
+       if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC))
+               page = dma_alloc_from_contiguous(dev,
+                                       count, get_order(size));
+       if (!page)
+               page = alloc_pages(gfp, get_order(size));
+
+       if (!page)
+               return NULL;
+
+       ret = page_address(page);
+       memset(ret, 0, size);
+       *dma_handle = plat_map_dma_mem(dev, ret, size);
+       if (!plat_device_is_coherent(dev)) {
+               dma_cache_wback_inv((unsigned long) ret, size);
+               if (!hw_coherentio)
+                       ret = UNCAC_ADDR(ret);
        }
 
        return ret;
@@ -164,6 +172,8 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 {
        unsigned long addr = (unsigned long) vaddr;
        int order = get_order(size);
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = NULL;
 
        if (dma_release_from_coherent(dev, order, vaddr))
                return;
@@ -173,7 +183,10 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
        if (!plat_device_is_coherent(dev) && !hw_coherentio)
                addr = CAC_ADDR(addr);
 
-       free_pages(addr, get_order(size));
+       page = virt_to_page((void *) addr);
+
+       if (!dma_release_from_contiguous(dev, page, count))
+               __free_pages(page, get_order(size));
 }
 
 static inline void __dma_sync_virtual(void *addr, size_t size,