2 * arch/arm/mm/consistent-nommu.c
3 * Based on arch/arm/mm/consistent.c
5 * Copyright (C) 2000-2004 Russell King
6 * Modified by Catalin Marinas for noMMU support
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * DMA uncached mapping support.
14 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <linux/errno.h>
18 #include <linux/list.h>
19 #include <linux/init.h>
20 #include <linux/device.h>
21 #include <linux/dma-mapping.h>
23 #include <asm/cacheflush.h>
27 #include "../../../mm/internal.h"
30 __dma_alloc(struct device
*dev
, size_t size
, dma_addr_t
*handle
, gfp_t gfp
,
36 u64 mask
= ISA_DMA_THRESHOLD
, limit
;
39 mask
= dev
->coherent_dma_mask
;
42 * Sanity check the DMA mask - it must be non-zero, and
43 * must be able to be satisfied by a DMA allocation.
46 dev_warn(dev
, "coherent DMA mask is unset\n");
50 if ((~mask
) & ISA_DMA_THRESHOLD
) {
51 dev_warn(dev
, "coherent DMA mask %#llx is smaller "
52 "than system GFP_DMA mask %#llx\n",
53 mask
, (unsigned long long)ISA_DMA_THRESHOLD
);
59 * Sanity check the allocation size.
61 size
= PAGE_ALIGN(size
);
62 limit
= (mask
+ 1) & ~mask
;
63 if (limit
&& size
>= limit
) {
64 printk(KERN_WARNING
"coherent allocation too big "
65 "(requested %#x mask %#llx)\n", size
, mask
);
69 order
= get_order(size
);
71 if (mask
!= 0xffffffff)
74 page
= alloc_pages(gfp
, order
);
79 * Invalidate any data that might be lurking in the
80 * kernel direct-mapped region for device DMA.
83 unsigned long kaddr
= (unsigned long)page_address(page
);
84 memset(page_address(page
), 0, size
);
85 dmac_flush_range(kaddr
, kaddr
+ size
);
89 * Set the "dma handle"
91 *handle
= page_to_dma(dev
, page
);
92 page_addr
= page_address(page
);
95 set_page_count(page
, 1);
97 * x86 does not mark the pages reserved...
99 SetPageReserved(page
);
101 } while (size
-= PAGE_SIZE
);
111 * Allocate DMA-coherent memory space and return both the kernel remapped
112 * virtual and bus address for that space.
115 dma_alloc_coherent(struct device
*dev
, size_t size
, dma_addr_t
*handle
, gfp_t gfp
)
117 return __dma_alloc(dev
, size
, handle
, gfp
,
118 pgprot_noncached(pgprot_kernel
));
120 EXPORT_SYMBOL(dma_alloc_coherent
);
123 * Allocate a writecombining region, in much the same way as
124 * dma_alloc_coherent above.
127 dma_alloc_writecombine(struct device
*dev
, size_t size
, dma_addr_t
*handle
, gfp_t gfp
)
129 return __dma_alloc(dev
, size
, handle
, gfp
,
130 pgprot_writecombine(pgprot_kernel
));
132 EXPORT_SYMBOL(dma_alloc_writecombine
);
134 static int dma_mmap(struct device
*dev
, struct vm_area_struct
*vma
,
135 void *cpu_addr
, dma_addr_t dma_addr
, size_t size
)
137 unsigned long user_size
;
140 user_size
= (vma
->vm_end
- vma
->vm_start
) >> PAGE_SHIFT
;
142 vma
->vm_flags
|= VM_RESERVED
;
144 /* Equivalent to: vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; */
145 ret
= remap_pfn_range(vma
, vma
->vm_start
, vma
->vm_pgoff
,
146 user_size
<< PAGE_SHIFT
, vma
->vm_page_prot
);
151 int dma_mmap_coherent(struct device
*dev
, struct vm_area_struct
*vma
,
152 void *cpu_addr
, dma_addr_t dma_addr
, size_t size
)
154 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
155 return dma_mmap(dev
, vma
, cpu_addr
, dma_addr
, size
);
157 EXPORT_SYMBOL(dma_mmap_coherent
);
159 int dma_mmap_writecombine(struct device
*dev
, struct vm_area_struct
*vma
,
160 void *cpu_addr
, dma_addr_t dma_addr
, size_t size
)
162 vma
->vm_page_prot
= pgprot_writecombine(vma
->vm_page_prot
);
163 return dma_mmap(dev
, vma
, cpu_addr
, dma_addr
, size
);
165 EXPORT_SYMBOL(dma_mmap_writecombine
);
168 * free a page as defined by the above mapping.
170 void dma_free_coherent(struct device
*dev
, size_t size
, void *cpu_addr
, dma_addr_t handle
)
174 size
= PAGE_ALIGN(size
);
176 page
= virt_to_page(cpu_addr
);
180 * x86 does not mark the pages reserved...
182 ClearPageReserved(page
);
186 } while (size
-= PAGE_SIZE
);
188 EXPORT_SYMBOL(dma_free_coherent
);
191 * Make an area consistent for devices.
193 void consistent_sync(void *vaddr
, size_t size
, int direction
)
195 unsigned long start
= (unsigned long)vaddr
;
196 unsigned long end
= start
+ size
;
199 case DMA_FROM_DEVICE
: /* invalidate only */
200 dmac_inv_range(start
, end
);
202 case DMA_TO_DEVICE
: /* writeback only */
203 dmac_clean_range(start
, end
);
205 case DMA_BIDIRECTIONAL
: /* writeback and invalidate */
206 dmac_flush_range(start
, end
);
212 EXPORT_SYMBOL(consistent_sync
);