diff options
| -rw-r--r-- | arch/powerpc/Kconfig | 13 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/dma-mapping.h | 6 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/pgtable-ppc32.h | 4 | ||||
| -rw-r--r-- | arch/powerpc/kernel/dma.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/mm/dma-noncoherent.c | 108 | ||||
| -rw-r--r-- | arch/powerpc/mm/mem.c | 4 |
6 files changed, 54 insertions, 83 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 3bb43adce44d..cdc9a6ff4be8 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
| @@ -868,19 +868,6 @@ config TASK_SIZE | |||
| 868 | default "0x80000000" if PPC_PREP || PPC_8xx | 868 | default "0x80000000" if PPC_PREP || PPC_8xx |
| 869 | default "0xc0000000" | 869 | default "0xc0000000" |
| 870 | 870 | ||
| 871 | config CONSISTENT_START_BOOL | ||
| 872 | bool "Set custom consistent memory pool address" | ||
| 873 | depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE | ||
| 874 | help | ||
| 875 | This option allows you to set the base virtual address | ||
| 876 | of the consistent memory pool. This pool of virtual | ||
| 877 | memory is used to make consistent memory allocations. | ||
| 878 | |||
| 879 | config CONSISTENT_START | ||
| 880 | hex "Base virtual address of consistent memory pool" if CONSISTENT_START_BOOL | ||
| 881 | default "0xfd000000" if (NOT_COHERENT_CACHE && 8xx) | ||
| 882 | default "0xff100000" if NOT_COHERENT_CACHE | ||
| 883 | |||
| 884 | config CONSISTENT_SIZE_BOOL | 871 | config CONSISTENT_SIZE_BOOL |
| 885 | bool "Set custom consistent memory pool size" | 872 | bool "Set custom consistent memory pool size" |
| 886 | depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE | 873 | depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE |
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index c69f2b5f0cc4..cb448d68452c 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h | |||
| @@ -26,7 +26,9 @@ | |||
| 26 | * allocate the space "normally" and use the cache management functions | 26 | * allocate the space "normally" and use the cache management functions |
| 27 | * to ensure it is consistent. | 27 | * to ensure it is consistent. |
| 28 | */ | 28 | */ |
| 29 | extern void *__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp); | 29 | struct device; |
| 30 | extern void *__dma_alloc_coherent(struct device *dev, size_t size, | ||
| 31 | dma_addr_t *handle, gfp_t gfp); | ||
| 30 | extern void __dma_free_coherent(size_t size, void *vaddr); | 32 | extern void __dma_free_coherent(size_t size, void *vaddr); |
| 31 | extern void __dma_sync(void *vaddr, size_t size, int direction); | 33 | extern void __dma_sync(void *vaddr, size_t size, int direction); |
| 32 | extern void __dma_sync_page(struct page *page, unsigned long offset, | 34 | extern void __dma_sync_page(struct page *page, unsigned long offset, |
| @@ -37,7 +39,7 @@ extern void __dma_sync_page(struct page *page, unsigned long offset, | |||
| 37 | * Cache coherent cores. | 39 | * Cache coherent cores. |
| 38 | */ | 40 | */ |
| 39 | 41 | ||
| 40 | #define __dma_alloc_coherent(gfp, size, handle) NULL | 42 | #define __dma_alloc_coherent(dev, gfp, size, handle) NULL |
| 41 | #define __dma_free_coherent(size, addr) ((void)0) | 43 | #define __dma_free_coherent(size, addr) ((void)0) |
| 42 | #define __dma_sync(addr, size, rw) ((void)0) | 44 | #define __dma_sync(addr, size, rw) ((void)0) |
| 43 | #define __dma_sync_page(pg, off, sz, rw) ((void)0) | 45 | #define __dma_sync_page(pg, off, sz, rw) ((void)0) |
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index 28fe9d4bae35..c9ff9d75990e 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h | |||
| @@ -71,7 +71,11 @@ extern int icache_44x_need_flush; | |||
| 71 | * until mem_init() at which point this becomes the top of the vmalloc | 71 | * until mem_init() at which point this becomes the top of the vmalloc |
| 72 | * and ioremap space | 72 | * and ioremap space |
| 73 | */ | 73 | */ |
| 74 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
| 75 | #define IOREMAP_TOP ((KVIRT_TOP - CONFIG_CONSISTENT_SIZE) & PAGE_MASK) | ||
| 76 | #else | ||
| 74 | #define IOREMAP_TOP KVIRT_TOP | 77 | #define IOREMAP_TOP KVIRT_TOP |
| 78 | #endif | ||
| 75 | 79 | ||
| 76 | /* | 80 | /* |
| 77 | * Just any arbitrary offset to the start of the vmalloc VM area: the | 81 | * Just any arbitrary offset to the start of the vmalloc VM area: the |
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 53c7788cba78..6b02793dc75b 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c | |||
| @@ -32,7 +32,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size, | |||
| 32 | { | 32 | { |
| 33 | void *ret; | 33 | void *ret; |
| 34 | #ifdef CONFIG_NOT_COHERENT_CACHE | 34 | #ifdef CONFIG_NOT_COHERENT_CACHE |
| 35 | ret = __dma_alloc_coherent(size, dma_handle, flag); | 35 | ret = __dma_alloc_coherent(dev, size, dma_handle, flag); |
| 36 | if (ret == NULL) | 36 | if (ret == NULL) |
| 37 | return NULL; | 37 | return NULL; |
| 38 | *dma_handle += get_dma_direct_offset(dev); | 38 | *dma_handle += get_dma_direct_offset(dev); |
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 | */ |
| 48 | static pte_t *consistent_pte; | ||
| 49 | static DEFINE_SPINLOCK(consistent_lock); | 50 | static 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 | */ |
| 150 | void * | 151 | void * |
| 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) | |||
| 301 | EXPORT_SYMBOL(__dma_free_coherent); | 311 | EXPORT_SYMBOL(__dma_free_coherent); |
| 302 | 312 | ||
| 303 | /* | 313 | /* |
| 304 | * Initialise the consistent memory allocation. | ||
| 305 | */ | ||
| 306 | static 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 | |||
| 337 | core_initcall(dma_alloc_init); | ||
| 338 | |||
| 339 | /* | ||
| 340 | * make an area consistent. | 314 | * make an area consistent. |
| 341 | */ | 315 | */ |
| 342 | void __dma_sync(void *vaddr, size_t size, int direction) | 316 | void __dma_sync(void *vaddr, size_t size, int direction) |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index d3a4e67561fa..579382c163a9 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
| @@ -387,6 +387,10 @@ void __init mem_init(void) | |||
| 387 | pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n", | 387 | pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n", |
| 388 | PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP)); | 388 | PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP)); |
| 389 | #endif /* CONFIG_HIGHMEM */ | 389 | #endif /* CONFIG_HIGHMEM */ |
| 390 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
| 391 | pr_info(" * 0x%08lx..0x%08lx : consistent mem\n", | ||
| 392 | IOREMAP_TOP, IOREMAP_TOP + CONFIG_CONSISTENT_SIZE); | ||
| 393 | #endif /* CONFIG_NOT_COHERENT_CACHE */ | ||
| 390 | pr_info(" * 0x%08lx..0x%08lx : early ioremap\n", | 394 | pr_info(" * 0x%08lx..0x%08lx : early ioremap\n", |
| 391 | ioremap_bot, IOREMAP_TOP); | 395 | ioremap_bot, IOREMAP_TOP); |
| 392 | pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n", | 396 | pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n", |
