Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad...
[pandora-kernel.git] / arch / arm / mm / dma-mapping.c
index 13fa536..c704eed 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/sizes.h>
 
-/* Sanity check size */
-#if (CONSISTENT_DMA_SIZE % SZ_2M)
-#error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
-#endif
-
-#define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
-#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
-#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
-
 static u64 get_coherent_dma_mask(struct device *dev)
 {
        u64 mask = ISA_DMA_THRESHOLD;
@@ -123,6 +114,15 @@ static void __dma_free_buffer(struct page *page, size_t size)
 }
 
 #ifdef CONFIG_MMU
+/* Sanity check size */
+#if (CONSISTENT_DMA_SIZE % SZ_2M)
+#error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
+#endif
+
+#define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
+#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
+#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+
 /*
  * These are the page tables (2MB each) covering uncached, DMA consistent allocations
  */
@@ -183,6 +183,8 @@ static void *
 __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
 {
        struct arm_vmregion *c;
+       size_t align;
+       int bit;
 
        if (!consistent_pte[0]) {
                printk(KERN_ERR "%s: not initialised\n", __func__);
@@ -190,10 +192,21 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
                return NULL;
        }
 
+       /*
+        * Align the virtual region allocation - maximum alignment is
+        * a section size, minimum is a page size.  This helps reduce
+        * fragmentation of the DMA space, and also prevents allocations
+        * smaller than a section from crossing a section boundary.
+        */
+       bit = fls(size - 1) + 1;
+       if (bit > SECTION_SHIFT)
+               bit = SECTION_SHIFT;
+       align = 1 << bit;
+
        /*
         * Allocate a virtual address in the consistent mapping region.
         */
-       c = arm_vmregion_alloc(&consistent_head, size,
+       c = arm_vmregion_alloc(&consistent_head, align, size,
                            gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
        if (c) {
                pte_t *pte;