diff options
-rw-r--r-- | arch/arm/mm/consistent.c | 53 | ||||
-rw-r--r-- | include/asm-arm/memory.h | 9 |
2 files changed, 50 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 | */ |
31 | static pte_t *consistent_pte; | 41 | static pte_t *consistent_pte[NUM_CONSISTENT_PTES]; |
32 | static DEFINE_SPINLOCK(consistent_lock); | 42 | static 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 | } |
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h index 3d7f08bd9030..b4e1146ab682 100644 --- a/include/asm-arm/memory.h +++ b/include/asm-arm/memory.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/config.h> | 25 | #include <linux/config.h> |
26 | #include <linux/compiler.h> | 26 | #include <linux/compiler.h> |
27 | #include <asm/arch/memory.h> | 27 | #include <asm/arch/memory.h> |
28 | #include <asm/sizes.h> | ||
28 | 29 | ||
29 | #ifndef TASK_SIZE | 30 | #ifndef TASK_SIZE |
30 | /* | 31 | /* |
@@ -48,6 +49,14 @@ | |||
48 | #endif | 49 | #endif |
49 | 50 | ||
50 | /* | 51 | /* |
52 | * Size of DMA-consistent memory region. Must be multiple of 2M, | ||
53 | * between 2MB and 14MB inclusive. | ||
54 | */ | ||
55 | #ifndef CONSISTENT_DMA_SIZE | ||
56 | #define CONSISTENT_DMA_SIZE SZ_2M | ||
57 | #endif | ||
58 | |||
59 | /* | ||
51 | * Physical vs virtual RAM address space conversion. These are | 60 | * Physical vs virtual RAM address space conversion. These are |
52 | * private definitions which should NOT be used outside memory.h | 61 | * private definitions which should NOT be used outside memory.h |
53 | * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. | 62 | * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. |