diff options
Diffstat (limited to 'arch/arm/mm/mmu.c')
| -rw-r--r-- | arch/arm/mm/mmu.c | 73 |
1 files changed, 48 insertions, 25 deletions
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 6e1c4f6a2b3f..e2335811c02e 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/nodemask.h> | 15 | #include <linux/nodemask.h> |
| 16 | #include <linux/memblock.h> | 16 | #include <linux/memblock.h> |
| 17 | #include <linux/sort.h> | 17 | #include <linux/sort.h> |
| 18 | #include <linux/fs.h> | ||
| 18 | 19 | ||
| 19 | #include <asm/cputype.h> | 20 | #include <asm/cputype.h> |
| 20 | #include <asm/sections.h> | 21 | #include <asm/sections.h> |
| @@ -246,6 +247,9 @@ static struct mem_type mem_types[] = { | |||
| 246 | .domain = DOMAIN_USER, | 247 | .domain = DOMAIN_USER, |
| 247 | }, | 248 | }, |
| 248 | [MT_MEMORY] = { | 249 | [MT_MEMORY] = { |
| 250 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | ||
| 251 | L_PTE_USER | L_PTE_EXEC, | ||
| 252 | .prot_l1 = PMD_TYPE_TABLE, | ||
| 249 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, | 253 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, |
| 250 | .domain = DOMAIN_KERNEL, | 254 | .domain = DOMAIN_KERNEL, |
| 251 | }, | 255 | }, |
| @@ -254,6 +258,9 @@ static struct mem_type mem_types[] = { | |||
| 254 | .domain = DOMAIN_KERNEL, | 258 | .domain = DOMAIN_KERNEL, |
| 255 | }, | 259 | }, |
| 256 | [MT_MEMORY_NONCACHED] = { | 260 | [MT_MEMORY_NONCACHED] = { |
| 261 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | ||
| 262 | L_PTE_USER | L_PTE_EXEC | L_PTE_MT_BUFFERABLE, | ||
| 263 | .prot_l1 = PMD_TYPE_TABLE, | ||
| 257 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, | 264 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, |
| 258 | .domain = DOMAIN_KERNEL, | 265 | .domain = DOMAIN_KERNEL, |
| 259 | }, | 266 | }, |
| @@ -303,9 +310,8 @@ static void __init build_mem_type_table(void) | |||
| 303 | cachepolicy = CPOLICY_WRITEBACK; | 310 | cachepolicy = CPOLICY_WRITEBACK; |
| 304 | ecc_mask = 0; | 311 | ecc_mask = 0; |
| 305 | } | 312 | } |
| 306 | #ifdef CONFIG_SMP | 313 | if (is_smp()) |
| 307 | cachepolicy = CPOLICY_WRITEALLOC; | 314 | cachepolicy = CPOLICY_WRITEALLOC; |
| 308 | #endif | ||
| 309 | 315 | ||
| 310 | /* | 316 | /* |
| 311 | * Strip out features not present on earlier architectures. | 317 | * Strip out features not present on earlier architectures. |
| @@ -399,21 +405,22 @@ static void __init build_mem_type_table(void) | |||
| 399 | cp = &cache_policies[cachepolicy]; | 405 | cp = &cache_policies[cachepolicy]; |
| 400 | vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; | 406 | vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; |
| 401 | 407 | ||
| 402 | #ifndef CONFIG_SMP | ||
| 403 | /* | 408 | /* |
| 404 | * Only use write-through for non-SMP systems | 409 | * Only use write-through for non-SMP systems |
| 405 | */ | 410 | */ |
| 406 | if (cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH) | 411 | if (!is_smp() && cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH) |
| 407 | vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte; | 412 | vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte; |
| 408 | #endif | ||
| 409 | 413 | ||
| 410 | /* | 414 | /* |
| 411 | * Enable CPU-specific coherency if supported. | 415 | * Enable CPU-specific coherency if supported. |
| 412 | * (Only available on XSC3 at the moment.) | 416 | * (Only available on XSC3 at the moment.) |
| 413 | */ | 417 | */ |
| 414 | if (arch_is_coherent() && cpu_is_xsc3()) | 418 | if (arch_is_coherent() && cpu_is_xsc3()) { |
| 415 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; | 419 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; |
| 416 | 420 | mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED; | |
| 421 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; | ||
| 422 | mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED; | ||
| 423 | } | ||
| 417 | /* | 424 | /* |
| 418 | * ARMv6 and above have extended page tables. | 425 | * ARMv6 and above have extended page tables. |
| 419 | */ | 426 | */ |
| @@ -426,20 +433,23 @@ static void __init build_mem_type_table(void) | |||
| 426 | mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; | 433 | mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; |
| 427 | mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; | 434 | mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; |
| 428 | 435 | ||
| 429 | #ifdef CONFIG_SMP | 436 | if (is_smp()) { |
| 430 | /* | 437 | /* |
| 431 | * Mark memory with the "shared" attribute for SMP systems | 438 | * Mark memory with the "shared" attribute |
| 432 | */ | 439 | * for SMP systems |
| 433 | user_pgprot |= L_PTE_SHARED; | 440 | */ |
| 434 | kern_pgprot |= L_PTE_SHARED; | 441 | user_pgprot |= L_PTE_SHARED; |
| 435 | vecs_pgprot |= L_PTE_SHARED; | 442 | kern_pgprot |= L_PTE_SHARED; |
| 436 | mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S; | 443 | vecs_pgprot |= L_PTE_SHARED; |
| 437 | mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED; | 444 | mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S; |
| 438 | mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S; | 445 | mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED; |
| 439 | mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; | 446 | mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S; |
| 440 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; | 447 | mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; |
| 441 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; | 448 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; |
| 442 | #endif | 449 | mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED; |
| 450 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; | ||
| 451 | mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED; | ||
| 452 | } | ||
| 443 | } | 453 | } |
| 444 | 454 | ||
| 445 | /* | 455 | /* |
| @@ -475,6 +485,8 @@ static void __init build_mem_type_table(void) | |||
| 475 | mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask; | 485 | mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask; |
| 476 | mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; | 486 | mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; |
| 477 | mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd; | 487 | mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd; |
| 488 | mem_types[MT_MEMORY].prot_pte |= kern_pgprot; | ||
| 489 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= ecc_mask; | ||
| 478 | mem_types[MT_ROM].prot_sect |= cp->pmd; | 490 | mem_types[MT_ROM].prot_sect |= cp->pmd; |
| 479 | 491 | ||
| 480 | switch (cp->pmd) { | 492 | switch (cp->pmd) { |
| @@ -498,6 +510,19 @@ static void __init build_mem_type_table(void) | |||
| 498 | } | 510 | } |
| 499 | } | 511 | } |
| 500 | 512 | ||
| 513 | #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE | ||
| 514 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | ||
| 515 | unsigned long size, pgprot_t vma_prot) | ||
| 516 | { | ||
| 517 | if (!pfn_valid(pfn)) | ||
| 518 | return pgprot_noncached(vma_prot); | ||
| 519 | else if (file->f_flags & O_SYNC) | ||
| 520 | return pgprot_writecombine(vma_prot); | ||
| 521 | return vma_prot; | ||
| 522 | } | ||
| 523 | EXPORT_SYMBOL(phys_mem_access_prot); | ||
| 524 | #endif | ||
| 525 | |||
| 501 | #define vectors_base() (vectors_high() ? 0xffff0000 : 0) | 526 | #define vectors_base() (vectors_high() ? 0xffff0000 : 0) |
| 502 | 527 | ||
| 503 | static void __init *early_alloc(unsigned long sz) | 528 | static void __init *early_alloc(unsigned long sz) |
| @@ -802,8 +827,7 @@ static void __init sanity_check_meminfo(void) | |||
| 802 | * rather difficult. | 827 | * rather difficult. |
| 803 | */ | 828 | */ |
| 804 | reason = "with VIPT aliasing cache"; | 829 | reason = "with VIPT aliasing cache"; |
| 805 | #ifdef CONFIG_SMP | 830 | } else if (is_smp() && tlb_ops_need_broadcast()) { |
| 806 | } else if (tlb_ops_need_broadcast()) { | ||
| 807 | /* | 831 | /* |
| 808 | * kmap_high needs to occasionally flush TLB entries, | 832 | * kmap_high needs to occasionally flush TLB entries, |
| 809 | * however, if the TLB entries need to be broadcast | 833 | * however, if the TLB entries need to be broadcast |
| @@ -813,7 +837,6 @@ static void __init sanity_check_meminfo(void) | |||
| 813 | * (must not be called with irqs off) | 837 | * (must not be called with irqs off) |
| 814 | */ | 838 | */ |
| 815 | reason = "without hardware TLB ops broadcasting"; | 839 | reason = "without hardware TLB ops broadcasting"; |
| 816 | #endif | ||
| 817 | } | 840 | } |
| 818 | if (reason) { | 841 | if (reason) { |
| 819 | printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n", | 842 | printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n", |
