aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/dma-noncoherent.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/mm/dma-noncoherent.c')
-rw-r--r--arch/powerpc/mm/dma-noncoherent.c108
1 files changed, 41 insertions, 67 deletions
diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c
index b7dc4c19f582..36692f5c9a76 100644
--- a/arch/powerpc/mm/dma-noncoherent.c
+++ b/arch/powerpc/mm/dma-noncoherent.c
@@ -32,20 +32,21 @@
32 32
33#include <asm/tlbflush.h> 33#include <asm/tlbflush.h>
34 34
35#include "mmu_decl.h"
36
35/* 37/*
36 * This address range defaults to a value that is safe for all 38 * This address range defaults to a value that is safe for all
37 * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It 39 * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It
38 * can be further configured for specific applications under 40 * can be further configured for specific applications under
39 * the "Advanced Setup" menu. -Matt 41 * the "Advanced Setup" menu. -Matt
40 */ 42 */
41#define CONSISTENT_BASE (CONFIG_CONSISTENT_START) 43#define CONSISTENT_BASE (IOREMAP_TOP)
42#define CONSISTENT_END (CONFIG_CONSISTENT_START + CONFIG_CONSISTENT_SIZE) 44#define CONSISTENT_END (CONSISTENT_BASE + CONFIG_CONSISTENT_SIZE)
43#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) 45#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
44 46
45/* 47/*
46 * This is the page table (2MB) covering uncached, DMA consistent allocations 48 * This is the page table (2MB) covering uncached, DMA consistent allocations
47 */ 49 */
48static pte_t *consistent_pte;
49static DEFINE_SPINLOCK(consistent_lock); 50static DEFINE_SPINLOCK(consistent_lock);
50 51
51/* 52/*
@@ -148,22 +149,38 @@ static struct ppc_vm_region *ppc_vm_region_find(struct ppc_vm_region *head, unsi
148 * virtual and bus address for that space. 149 * virtual and bus address for that space.
149 */ 150 */
150void * 151void *
151__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) 152__dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
152{ 153{
153 struct page *page; 154 struct page *page;
154 struct ppc_vm_region *c; 155 struct ppc_vm_region *c;
155 unsigned long order; 156 unsigned long order;
156 u64 mask = 0x00ffffff, limit; /* ISA default */ 157 u64 mask = ISA_DMA_THRESHOLD, limit;
157 158
158 if (!consistent_pte) { 159 if (dev) {
159 printk(KERN_ERR "%s: not initialised\n", __func__); 160 mask = dev->coherent_dma_mask;
160 dump_stack(); 161
161 return NULL; 162 /*
163 * Sanity check the DMA mask - it must be non-zero, and
164 * must be able to be satisfied by a DMA allocation.
165 */
166 if (mask == 0) {
167 dev_warn(dev, "coherent DMA mask is unset\n");
168 goto no_page;
169 }
170
171 if ((~mask) & ISA_DMA_THRESHOLD) {
172 dev_warn(dev, "coherent DMA mask %#llx is smaller "
173 "than system GFP_DMA mask %#llx\n",
174 mask, (unsigned long long)ISA_DMA_THRESHOLD);
175 goto no_page;
176 }
162 } 177 }
163 178
179
164 size = PAGE_ALIGN(size); 180 size = PAGE_ALIGN(size);
165 limit = (mask + 1) & ~mask; 181 limit = (mask + 1) & ~mask;
166 if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) { 182 if ((limit && size >= limit) ||
183 size >= (CONSISTENT_END - CONSISTENT_BASE)) {
167 printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", 184 printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n",
168 size, mask); 185 size, mask);
169 return NULL; 186 return NULL;
@@ -171,6 +188,7 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
171 188
172 order = get_order(size); 189 order = get_order(size);
173 190
191 /* Might be useful if we ever have a real legacy DMA zone... */
174 if (mask != 0xffffffff) 192 if (mask != 0xffffffff)
175 gfp |= GFP_DMA; 193 gfp |= GFP_DMA;
176 194
@@ -195,7 +213,6 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
195 gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); 213 gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
196 if (c) { 214 if (c) {
197 unsigned long vaddr = c->vm_start; 215 unsigned long vaddr = c->vm_start;
198 pte_t *pte = consistent_pte + CONSISTENT_OFFSET(vaddr);
199 struct page *end = page + (1 << order); 216 struct page *end = page + (1 << order);
200 217
201 split_page(page, order); 218 split_page(page, order);
@@ -206,13 +223,10 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
206 *handle = page_to_phys(page); 223 *handle = page_to_phys(page);
207 224
208 do { 225 do {
209 BUG_ON(!pte_none(*pte));
210
211 SetPageReserved(page); 226 SetPageReserved(page);
212 set_pte_at(&init_mm, vaddr, 227 map_page(vaddr, page_to_phys(page),
213 pte, mk_pte(page, pgprot_noncached(PAGE_KERNEL))); 228 pgprot_noncached(PAGE_KERNEL));
214 page++; 229 page++;
215 pte++;
216 vaddr += PAGE_SIZE; 230 vaddr += PAGE_SIZE;
217 } while (size -= PAGE_SIZE); 231 } while (size -= PAGE_SIZE);
218 232
@@ -241,8 +255,7 @@ void __dma_free_coherent(size_t size, void *vaddr)
241{ 255{
242 struct ppc_vm_region *c; 256 struct ppc_vm_region *c;
243 unsigned long flags, addr; 257 unsigned long flags, addr;
244 pte_t *ptep; 258
245
246 size = PAGE_ALIGN(size); 259 size = PAGE_ALIGN(size);
247 260
248 spin_lock_irqsave(&consistent_lock, flags); 261 spin_lock_irqsave(&consistent_lock, flags);
@@ -258,29 +271,26 @@ void __dma_free_coherent(size_t size, void *vaddr)
258 size = c->vm_end - c->vm_start; 271 size = c->vm_end - c->vm_start;
259 } 272 }
260 273
261 ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
262 addr = c->vm_start; 274 addr = c->vm_start;
263 do { 275 do {
264 pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); 276 pte_t *ptep;
265 unsigned long pfn; 277 unsigned long pfn;
266 278
267 ptep++; 279 ptep = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(addr),
268 addr += PAGE_SIZE; 280 addr),
269 281 addr),
270 if (!pte_none(pte) && pte_present(pte)) { 282 addr);
271 pfn = pte_pfn(pte); 283 if (!pte_none(*ptep) && pte_present(*ptep)) {
272 284 pfn = pte_pfn(*ptep);
285 pte_clear(&init_mm, addr, ptep);
273 if (pfn_valid(pfn)) { 286 if (pfn_valid(pfn)) {
274 struct page *page = pfn_to_page(pfn); 287 struct page *page = pfn_to_page(pfn);
275 ClearPageReserved(page);
276 288
289 ClearPageReserved(page);
277 __free_page(page); 290 __free_page(page);
278 continue;
279 } 291 }
280 } 292 }
281 293 addr += PAGE_SIZE;
282 printk(KERN_CRIT "%s: bad page in kernel page table\n",
283 __func__);
284 } while (size -= PAGE_SIZE); 294 } while (size -= PAGE_SIZE);
285 295
286 flush_tlb_kernel_range(c->vm_start, c->vm_end); 296 flush_tlb_kernel_range(c->vm_start, c->vm_end);
@@ -301,42 +311,6 @@ void __dma_free_coherent(size_t size, void *vaddr)
301EXPORT_SYMBOL(__dma_free_coherent); 311EXPORT_SYMBOL(__dma_free_coherent);
302 312
303/* 313/*
304 * Initialise the consistent memory allocation.
305 */
306static int __init dma_alloc_init(void)
307{
308 pgd_t *pgd;
309 pud_t *pud;
310 pmd_t *pmd;
311 pte_t *pte;
312 int ret = 0;
313
314 do {
315 pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
316 pud = pud_alloc(&init_mm, pgd, CONSISTENT_BASE);
317 pmd = pmd_alloc(&init_mm, pud, CONSISTENT_BASE);
318 if (!pmd) {
319 printk(KERN_ERR "%s: no pmd tables\n", __func__);
320 ret = -ENOMEM;
321 break;
322 }
323
324 pte = pte_alloc_kernel(pmd, CONSISTENT_BASE);
325 if (!pte) {
326 printk(KERN_ERR "%s: no pte tables\n", __func__);
327 ret = -ENOMEM;
328 break;
329 }
330
331 consistent_pte = pte;
332 } while (0);
333
334 return ret;
335}
336
337core_initcall(dma_alloc_init);
338
339/*
340 * make an area consistent. 314 * make an area consistent.
341 */ 315 */
342void __dma_sync(void *vaddr, size_t size, int direction) 316void __dma_sync(void *vaddr, size_t size, int direction)