aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mm/consistent.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 0513ed1b2fcf..c2ee18d2075e 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -20,15 +20,25 @@
20 20
21#include <asm/cacheflush.h> 21#include <asm/cacheflush.h>
22#include <asm/tlbflush.h> 22#include <asm/tlbflush.h>
23#include <asm/sizes.h>
24
25/* Sanity check size */
26#if (CONSISTENT_DMA_SIZE % SZ_2M)
27#error "CONSISTENT_DMA_SIZE must be multiple of 2MiB"
28#endif
23 29
24#define CONSISTENT_BASE (0xffc00000)
25#define CONSISTENT_END (0xffe00000) 30#define CONSISTENT_END (0xffe00000)
31#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE)
32
26#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) 33#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
34#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
35#define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
36
27 37
28/* 38/*
29 * This is the page table (2MB) covering uncached, DMA consistent allocations 39 * These are the page tables (2MB each) covering uncached, DMA consistent allocations
30 */ 40 */
31static pte_t *consistent_pte; 41static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
32static DEFINE_SPINLOCK(consistent_lock); 42static DEFINE_SPINLOCK(consistent_lock);
33 43
34/* 44/*
@@ -142,7 +152,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
142 unsigned long order; 152 unsigned long order;
143 u64 mask = ISA_DMA_THRESHOLD, limit; 153 u64 mask = ISA_DMA_THRESHOLD, limit;
144 154
145 if (!consistent_pte) { 155 if (!consistent_pte[0]) {
146 printk(KERN_ERR "%s: not initialised\n", __func__); 156 printk(KERN_ERR "%s: not initialised\n", __func__);
147 dump_stack(); 157 dump_stack();
148 return NULL; 158 return NULL;
@@ -205,9 +215,12 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
205 c = vm_region_alloc(&consistent_head, size, 215 c = vm_region_alloc(&consistent_head, size,
206 gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); 216 gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
207 if (c) { 217 if (c) {
208 pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); 218 pte_t *pte;
209 struct page *end = page + (1 << order); 219 struct page *end = page + (1 << order);
220 int idx = CONSISTENT_PTE_INDEX(c->vm_start);
221 u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
210 222
223 pte = consistent_pte[idx] + off;
211 c->vm_pages = page; 224 c->vm_pages = page;
212 225
213 /* 226 /*
@@ -226,6 +239,11 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
226 set_pte(pte, mk_pte(page, prot)); 239 set_pte(pte, mk_pte(page, prot));
227 page++; 240 page++;
228 pte++; 241 pte++;
242 off++;
243 if (off >= PTRS_PER_PTE) {
244 off = 0;
245 pte = consistent_pte[++idx];
246 }
229 } while (size -= PAGE_SIZE); 247 } while (size -= PAGE_SIZE);
230 248
231 /* 249 /*
@@ -327,6 +345,8 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
327 struct vm_region *c; 345 struct vm_region *c;
328 unsigned long flags, addr; 346 unsigned long flags, addr;
329 pte_t *ptep; 347 pte_t *ptep;
348 int idx;
349 u32 off;
330 350
331 WARN_ON(irqs_disabled()); 351 WARN_ON(irqs_disabled());
332 352
@@ -347,7 +367,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
347 size = c->vm_end - c->vm_start; 367 size = c->vm_end - c->vm_start;
348 } 368 }
349 369
350 ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start); 370 idx = CONSISTENT_PTE_INDEX(c->vm_start);
371 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
372 ptep = consistent_pte[idx] + off;
351 addr = c->vm_start; 373 addr = c->vm_start;
352 do { 374 do {
353 pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); 375 pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
@@ -355,6 +377,11 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
355 377
356 ptep++; 378 ptep++;
357 addr += PAGE_SIZE; 379 addr += PAGE_SIZE;
380 off++;
381 if (off >= PTRS_PER_PTE) {
382 off = 0;
383 ptep = consistent_pte[++idx];
384 }
358 385
359 if (!pte_none(pte) && pte_present(pte)) { 386 if (!pte_none(pte) && pte_present(pte)) {
360 pfn = pte_pfn(pte); 387 pfn = pte_pfn(pte);
@@ -401,11 +428,12 @@ static int __init consistent_init(void)
401 pgd_t *pgd; 428 pgd_t *pgd;
402 pmd_t *pmd; 429 pmd_t *pmd;
403 pte_t *pte; 430 pte_t *pte;
404 int ret = 0; 431 int ret = 0, i = 0;
432 u32 base = CONSISTENT_BASE;
405 433
406 do { 434 do {
407 pgd = pgd_offset(&init_mm, CONSISTENT_BASE); 435 pgd = pgd_offset(&init_mm, base);
408 pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); 436 pmd = pmd_alloc(&init_mm, pgd, base);
409 if (!pmd) { 437 if (!pmd) {
410 printk(KERN_ERR "%s: no pmd tables\n", __func__); 438 printk(KERN_ERR "%s: no pmd tables\n", __func__);
411 ret = -ENOMEM; 439 ret = -ENOMEM;
@@ -413,15 +441,16 @@ static int __init consistent_init(void)
413 } 441 }
414 WARN_ON(!pmd_none(*pmd)); 442 WARN_ON(!pmd_none(*pmd));
415 443
416 pte = pte_alloc_kernel(pmd, CONSISTENT_BASE); 444 pte = pte_alloc_kernel(pmd, base);
417 if (!pte) { 445 if (!pte) {
418 printk(KERN_ERR "%s: no pte tables\n", __func__); 446 printk(KERN_ERR "%s: no pte tables\n", __func__);
419 ret = -ENOMEM; 447 ret = -ENOMEM;
420 break; 448 break;
421 } 449 }
422 450
423 consistent_pte = pte; 451 consistent_pte[i++] = pte;
424 } while (0); 452 base += (1 << PGDIR_SHIFT);
453 } while (base < CONSISTENT_END);
425 454
426 return ret; 455 return ret;
427} 456}