]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
base: dma-coherent: add dma exact size alloc/release functions
authorVandana Salve <vsalve@nvidia.com>
Thu, 21 Nov 2013 11:11:15 +0000 (16:41 +0530)
committerHiroshi Doyu <hdoyu@nvidia.com>
Fri, 29 Nov 2013 07:01:33 +0000 (23:01 -0800)
Add functions dma_alloc_from_coherent_attr and
dma_release_from_coherent_attr. use attribute
DMA_ATTR_ALLOC_EXACT_SIZE to allocate/release
memory of exact size rather than order of 2^pages to
reduce internal fragmentation

bug 1380639

Change-Id: Ia7f560bf94960dfa9570f5be597f7f25b49150e1
Signed-off-by: Vandana Salve <vsalve@nvidia.com>
Reviewed-on: http://git-master/r/333986
Reviewed-by: Hiroshi Doyu <hdoyu@nvidia.com>
Tested-by: Hiroshi Doyu <hdoyu@nvidia.com>
drivers/base/dma-coherent.c
include/asm-generic/dma-coherent.h

index 8ca472af251b4903daed1be8a7abbf63f691d6fe..10c73a1f8bcf477e0f0c47ac0b4fecff0fb0af05 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-attrs.h>
 
 struct dma_coherent_mem {
        void            *virt_base;
@@ -107,26 +108,30 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
 EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
 
 /**
- * dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area
+ * dma_alloc_from_coherent_attr() - try to allocate memory from the per-device
+ * coherent area
  *
  * @dev:       device from which we allocate memory
  * @size:      size of requested memory area
  * @dma_handle:        This will be filled with the correct dma handle
  * @ret:       This pointer will be filled with the virtual address
  *             to allocated area.
- *
+ * @attrs:     DMA Attribute
  * This function should be only called from per-arch dma_alloc_coherent()
  * to support allocation from per-device coherent memory pools.
  *
- * Returns 0 if dma_alloc_coherent should continue with allocating from
+ * Returns 0 if dma_alloc_coherent_attr should continue with allocating from
  * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
  */
-int dma_alloc_from_coherent(struct device *dev, ssize_t size,
-                                      dma_addr_t *dma_handle, void **ret)
+int dma_alloc_from_coherent_attr(struct device *dev, ssize_t size,
+                                      dma_addr_t *dma_handle, void **ret,
+                                      struct dma_attrs *attrs)
 {
        struct dma_coherent_mem *mem;
        int order = get_order(size);
        int pageno;
+       unsigned int count;
+       unsigned long align;
 
        if (!dev)
                return 0;
@@ -139,10 +144,22 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
        if (unlikely(size > (mem->size << PAGE_SHIFT)))
                goto err;
 
-       pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
-       if (unlikely(pageno < 0))
+       if (dma_get_attr(DMA_ATTR_ALLOC_EXACT_SIZE, attrs)) {
+               align = 0;
+               count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       } else  {
+               align = (1 << order) - 1;
+               count = 1 << order;
+       }
+
+       pageno = bitmap_find_next_zero_area(mem->bitmap, mem->size,
+                       0, count, align);
+
+       if (pageno >= mem->size)
                goto err;
 
+       bitmap_set(mem->bitmap, pageno, count);
+
        /*
         * Memory was found in the per-device area.
         */
@@ -162,25 +179,30 @@ err:
         */
        return mem->flags & DMA_MEMORY_EXCLUSIVE;
 }
-EXPORT_SYMBOL(dma_alloc_from_coherent);
+EXPORT_SYMBOL(dma_alloc_from_coherent_attr);
 
 /**
- * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
+ * dma_release_from_coherent_attr() - try to free the memory allocated from
+ * per-device coherent memory pool
  * @dev:       device from which the memory was allocated
- * @order:     the order of pages allocated
+ * @size:      size of the memory area to free
  * @vaddr:     virtual address of allocated pages
+ * @attrs:     DMA Attribute
  *
  * This checks whether the memory was allocated from the per-device
  * coherent memory pool and if so, releases that memory.
  *
  * Returns 1 if we correctly released the memory, or 0 if
- * dma_release_coherent() should proceed with releasing memory from
+ * dma_release_coherent_attr() should proceed with releasing memory from
  * generic pools.
  */
-int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
+int dma_release_from_coherent_attr(struct device *dev, size_t size, void *vaddr,
+                               struct dma_attrs *attrs)
 {
        struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
        void *mem_addr;
+       unsigned int count;
+       unsigned int pageno;
 
        if (!mem)
                return 0;
@@ -190,16 +212,24 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
        else
                mem_addr =  mem->virt_base;
 
+
        if (mem && vaddr >= mem_addr &&
            vaddr - mem_addr < mem->size << PAGE_SHIFT) {
 
-               int page = (vaddr - mem_addr) >> PAGE_SHIFT;
-               bitmap_release_region(mem->bitmap, page, order);
+               pageno = (vaddr - mem_addr) >> PAGE_SHIFT;
+
+               if (dma_get_attr(DMA_ATTR_ALLOC_EXACT_SIZE, attrs))
+                       count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+               else
+                       count = 1 << get_order(size);
+
+               bitmap_clear(mem->bitmap, pageno, count);
+
                return 1;
        }
        return 0;
 }
-EXPORT_SYMBOL(dma_release_from_coherent);
+EXPORT_SYMBOL(dma_release_from_coherent_attr);
 
 /**
  * dma_mmap_from_coherent() - try to mmap the memory allocated from
index 2be8a2dbc868f86f84e90c0e79a755c1f51e672b..c28cb3576f452264f3bfb1a2b181530d662beaf3 100644 (file)
@@ -6,9 +6,15 @@
  * These three functions are only for dma allocator.
  * Don't use them in device drivers.
  */
-int dma_alloc_from_coherent(struct device *dev, ssize_t size,
-                                      dma_addr_t *dma_handle, void **ret);
-int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
+int dma_alloc_from_coherent_attr(struct device *dev, ssize_t size,
+                                      dma_addr_t *dma_handle, void **ret,
+                                      struct dma_attrs *attrs);
+int dma_release_from_coherent_attr(struct device *dev, size_t size, void *vaddr,
+                                      struct dma_attrs *attrs);
+#define dma_alloc_from_coherent(d, s, h, r) \
+        dma_alloc_from_coherent_attr(d, s, h, r, NULL)
+#define dma_release_from_coherent(d, s, v) \
+        dma_release_from_coherent_attr(d, s, v, NULL)
 
 int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
                            void *cpu_addr, size_t size, int *ret);
@@ -27,6 +33,8 @@ extern void *
 dma_mark_declared_memory_occupied(struct device *dev,
                                  dma_addr_t device_addr, size_t size);
 #else
+#define dma_alloc_from_coherent_attr(dev, size, handle, ret, attr) (0)
+#define dma_release_from_coherent_attr(dev, size, vaddr, attr) (0)
 #define dma_alloc_from_coherent(dev, size, handle, ret) (0)
 #define dma_release_from_coherent(dev, order, vaddr) (0)
 #define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0)