diff options
| author | Kevin Hilman <kevin@hilman.org> | 2006-01-12 11:12:21 -0500 | 
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-12 11:12:21 -0500 | 
| commit | 37134cd55d57e95d3f606c6f2a57fa496bdad333 (patch) | |
| tree | 0c5c3bb4a52550613eb5f171c5954725b51a1915 | |
| parent | a3e49436867e6c7acc1b5eed21d30c88d156825b (diff) | |
[ARM] 3209/1: Configurable DMA-consistent memory region
Patch from Kevin Hilman
This patch increase available DMA-consistent memory allocated by dma_coherent_alloc(). The default remains at 2M (defined in asm/memory.h) and each platform has the ability to override in asm/arch-foo/memory.h.
Signed-off-by: Kevin Hilman <kevin@hilman.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
| -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. | 
