diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-30 11:10:12 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-30 11:10:12 -0400 |
| commit | 24a77daf3d80bddcece044e6dc3675e427eef3f3 (patch) | |
| tree | 2c5e0b0bea394d6fe62c5d5857c252e83e48ac48 /arch/powerpc/mm | |
| parent | e389f9aec689209724105ae80a6c91fd2e747bc9 (diff) | |
| parent | f900e9777fc9b65140cb9570438597bc8fae56ab (diff) | |
Merge branch 'for-2.6.22' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.22' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (255 commits)
[POWERPC] Remove dev_dbg redefinition in drivers/ps3/vuart.c
[POWERPC] remove kernel module option for booke wdt
[POWERPC] Avoid putting cpu node twice
[POWERPC] Spinlock initializer cleanup
[POWERPC] ppc4xx_sgdma needs dma-mapping.h
[POWERPC] arch/powerpc/sysdev/timer.c build fix
[POWERPC] get_property cleanups
[POWERPC] Remove the unused HTDMSOUND driver
[POWERPC] cell: cbe_cpufreq cleanup and crash fix
[POWERPC] Declare enable_kernel_spe in a header
[POWERPC] Add dt_xlate_addr() to bootwrapper
[POWERPC] bootwrapper: CONFIG_ -> CONFIG_DEVICE_TREE
[POWERPC] Don't define a custom bd_t for Xilixn Virtex based boards.
[POWERPC] Add sane defaults for Xilinx EDK generated xparameters files
[POWERPC] Add uartlite boot console driver for the zImage wrapper
[POWERPC] Stop using ppc_sys for Xilinx Virtex boards
[POWERPC] New registration for common Xilinx Virtex ppc405 platform devices
[POWERPC] Merge common virtex header files
[POWERPC] Rework Kconfig dependancies for Xilinx Virtex ppc405 platform
[POWERPC] Clean up cpufreq Kconfig dependencies
...
Diffstat (limited to 'arch/powerpc/mm')
| -rw-r--r-- | arch/powerpc/mm/hash_low_32.S | 22 | ||||
| -rw-r--r-- | arch/powerpc/mm/hash_low_64.S | 5 | ||||
| -rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 127 | ||||
| -rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 16 | ||||
| -rw-r--r-- | arch/powerpc/mm/init_32.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/mm/lmb.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/mm/mem.c | 3 | ||||
| -rw-r--r-- | arch/powerpc/mm/mmu_decl.h | 5 | ||||
| -rw-r--r-- | arch/powerpc/mm/numa.c | 24 | ||||
| -rw-r--r-- | arch/powerpc/mm/pgtable_32.c | 76 | ||||
| -rw-r--r-- | arch/powerpc/mm/ppc_mmu_32.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/mm/tlb_64.c | 68 |
13 files changed, 279 insertions, 81 deletions
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S index bd68df5fa78a..ddceefc06ecc 100644 --- a/arch/powerpc/mm/hash_low_32.S +++ b/arch/powerpc/mm/hash_low_32.S | |||
| @@ -283,6 +283,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64) | |||
| 283 | #define PTEG_SIZE 64 | 283 | #define PTEG_SIZE 64 |
| 284 | #define LG_PTEG_SIZE 6 | 284 | #define LG_PTEG_SIZE 6 |
| 285 | #define LDPTEu lwzu | 285 | #define LDPTEu lwzu |
| 286 | #define LDPTE lwz | ||
| 286 | #define STPTE stw | 287 | #define STPTE stw |
| 287 | #define CMPPTE cmpw | 288 | #define CMPPTE cmpw |
| 288 | #define PTE_H 0x40 | 289 | #define PTE_H 0x40 |
| @@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C) | |||
| 389 | * and we know there is a definite (although small) speed | 390 | * and we know there is a definite (although small) speed |
| 390 | * advantage to putting the PTE in the primary PTEG, we always | 391 | * advantage to putting the PTE in the primary PTEG, we always |
| 391 | * put the PTE in the primary PTEG. | 392 | * put the PTE in the primary PTEG. |
| 393 | * | ||
| 394 | * In addition, we skip any slot that is mapping kernel text in | ||
| 395 | * order to avoid a deadlock when not using BAT mappings if | ||
| 396 | * trying to hash in the kernel hash code itself after it has | ||
| 397 | * already taken the hash table lock. This works in conjunction | ||
| 398 | * with pre-faulting of the kernel text. | ||
| 399 | * | ||
| 400 | * If the hash table bucket is full of kernel text entries, we'll | ||
| 401 | * lockup here but that shouldn't happen | ||
| 392 | */ | 402 | */ |
| 393 | addis r4,r7,next_slot@ha | 403 | |
| 404 | 1: addis r4,r7,next_slot@ha /* get next evict slot */ | ||
| 394 | lwz r6,next_slot@l(r4) | 405 | lwz r6,next_slot@l(r4) |
| 395 | addi r6,r6,PTE_SIZE | 406 | addi r6,r6,PTE_SIZE /* search for candidate */ |
| 396 | andi. r6,r6,7*PTE_SIZE | 407 | andi. r6,r6,7*PTE_SIZE |
| 397 | stw r6,next_slot@l(r4) | 408 | stw r6,next_slot@l(r4) |
| 398 | add r4,r3,r6 | 409 | add r4,r3,r6 |
| 410 | LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */ | ||
| 411 | clrrwi r0,r0,12 | ||
| 412 | lis r6,etext@h | ||
| 413 | ori r6,r6,etext@l /* get etext */ | ||
| 414 | tophys(r6,r6) | ||
| 415 | cmpl cr0,r0,r6 /* compare and try again */ | ||
| 416 | blt 1b | ||
| 399 | 417 | ||
| 400 | #ifndef CONFIG_SMP | 418 | #ifndef CONFIG_SMP |
| 401 | /* Store PTE in PTEG */ | 419 | /* Store PTE in PTEG */ |
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 9bc0a9c2b9bc..e64ce3eec36e 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S | |||
| @@ -445,9 +445,12 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) | |||
| 445 | 445 | ||
| 446 | htab_insert_pte: | 446 | htab_insert_pte: |
| 447 | /* real page number in r5, PTE RPN value + index */ | 447 | /* real page number in r5, PTE RPN value + index */ |
| 448 | rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT | 448 | andis. r0,r31,_PAGE_4K_PFN@h |
| 449 | srdi r5,r31,PTE_RPN_SHIFT | ||
| 450 | bne- htab_special_pfn | ||
| 449 | sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT | 451 | sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT |
| 450 | add r5,r5,r25 | 452 | add r5,r5,r25 |
| 453 | htab_special_pfn: | ||
| 451 | sldi r5,r5,HW_PAGE_SHIFT | 454 | sldi r5,r5,HW_PAGE_SHIFT |
| 452 | 455 | ||
| 453 | /* Calculate primary group hash */ | 456 | /* Calculate primary group hash */ |
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 6f1016acdbf6..79aedaf36f2b 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
| @@ -505,7 +505,7 @@ static inline int tlb_batching_enabled(void) | |||
| 505 | int enabled = 1; | 505 | int enabled = 1; |
| 506 | 506 | ||
| 507 | if (root) { | 507 | if (root) { |
| 508 | const char *model = get_property(root, "model", NULL); | 508 | const char *model = of_get_property(root, "model", NULL); |
| 509 | if (model && !strcmp(model, "IBM,9076-N81")) | 509 | if (model && !strcmp(model, "IBM,9076-N81")) |
| 510 | enabled = 0; | 510 | enabled = 0; |
| 511 | of_node_put(root); | 511 | of_node_put(root); |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 3c7fe2c65b5a..49618461defb 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
| @@ -100,6 +100,11 @@ unsigned int HPAGE_SHIFT; | |||
| 100 | #ifdef CONFIG_PPC_64K_PAGES | 100 | #ifdef CONFIG_PPC_64K_PAGES |
| 101 | int mmu_ci_restrictions; | 101 | int mmu_ci_restrictions; |
| 102 | #endif | 102 | #endif |
| 103 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 104 | static u8 *linear_map_hash_slots; | ||
| 105 | static unsigned long linear_map_hash_count; | ||
| 106 | static spinlock_t linear_map_hash_lock; | ||
| 107 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
| 103 | 108 | ||
| 104 | /* There are definitions of page sizes arrays to be used when none | 109 | /* There are definitions of page sizes arrays to be used when none |
| 105 | * is provided by the firmware. | 110 | * is provided by the firmware. |
| @@ -152,11 +157,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
| 152 | 157 | ||
| 153 | for (vaddr = vstart, paddr = pstart; vaddr < vend; | 158 | for (vaddr = vstart, paddr = pstart; vaddr < vend; |
| 154 | vaddr += step, paddr += step) { | 159 | vaddr += step, paddr += step) { |
| 155 | unsigned long vpn, hash, hpteg; | 160 | unsigned long hash, hpteg; |
| 156 | unsigned long vsid = get_kernel_vsid(vaddr); | 161 | unsigned long vsid = get_kernel_vsid(vaddr); |
| 157 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | 162 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); |
| 158 | 163 | ||
| 159 | vpn = va >> shift; | ||
| 160 | tmp_mode = mode; | 164 | tmp_mode = mode; |
| 161 | 165 | ||
| 162 | /* Make non-kernel text non-executable */ | 166 | /* Make non-kernel text non-executable */ |
| @@ -174,6 +178,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
| 174 | 178 | ||
| 175 | if (ret < 0) | 179 | if (ret < 0) |
| 176 | break; | 180 | break; |
| 181 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 182 | if ((paddr >> PAGE_SHIFT) < linear_map_hash_count) | ||
| 183 | linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80; | ||
| 184 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
| 177 | } | 185 | } |
| 178 | return ret < 0 ? ret : 0; | 186 | return ret < 0 ? ret : 0; |
| 179 | } | 187 | } |
| @@ -281,6 +289,7 @@ static void __init htab_init_page_sizes(void) | |||
| 281 | memcpy(mmu_psize_defs, mmu_psize_defaults_gp, | 289 | memcpy(mmu_psize_defs, mmu_psize_defaults_gp, |
| 282 | sizeof(mmu_psize_defaults_gp)); | 290 | sizeof(mmu_psize_defaults_gp)); |
| 283 | found: | 291 | found: |
| 292 | #ifndef CONFIG_DEBUG_PAGEALLOC | ||
| 284 | /* | 293 | /* |
| 285 | * Pick a size for the linear mapping. Currently, we only support | 294 | * Pick a size for the linear mapping. Currently, we only support |
| 286 | * 16M, 1M and 4K which is the default | 295 | * 16M, 1M and 4K which is the default |
| @@ -289,6 +298,7 @@ static void __init htab_init_page_sizes(void) | |||
| 289 | mmu_linear_psize = MMU_PAGE_16M; | 298 | mmu_linear_psize = MMU_PAGE_16M; |
| 290 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) | 299 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) |
| 291 | mmu_linear_psize = MMU_PAGE_1M; | 300 | mmu_linear_psize = MMU_PAGE_1M; |
| 301 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
| 292 | 302 | ||
| 293 | #ifdef CONFIG_PPC_64K_PAGES | 303 | #ifdef CONFIG_PPC_64K_PAGES |
| 294 | /* | 304 | /* |
| @@ -303,12 +313,14 @@ static void __init htab_init_page_sizes(void) | |||
| 303 | if (mmu_psize_defs[MMU_PAGE_64K].shift) { | 313 | if (mmu_psize_defs[MMU_PAGE_64K].shift) { |
| 304 | mmu_virtual_psize = MMU_PAGE_64K; | 314 | mmu_virtual_psize = MMU_PAGE_64K; |
| 305 | mmu_vmalloc_psize = MMU_PAGE_64K; | 315 | mmu_vmalloc_psize = MMU_PAGE_64K; |
| 316 | if (mmu_linear_psize == MMU_PAGE_4K) | ||
| 317 | mmu_linear_psize = MMU_PAGE_64K; | ||
| 306 | if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) | 318 | if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) |
| 307 | mmu_io_psize = MMU_PAGE_64K; | 319 | mmu_io_psize = MMU_PAGE_64K; |
| 308 | else | 320 | else |
| 309 | mmu_ci_restrictions = 1; | 321 | mmu_ci_restrictions = 1; |
| 310 | } | 322 | } |
| 311 | #endif | 323 | #endif /* CONFIG_PPC_64K_PAGES */ |
| 312 | 324 | ||
| 313 | printk(KERN_DEBUG "Page orders: linear mapping = %d, " | 325 | printk(KERN_DEBUG "Page orders: linear mapping = %d, " |
| 314 | "virtual = %d, io = %d\n", | 326 | "virtual = %d, io = %d\n", |
| @@ -476,6 +488,13 @@ void __init htab_initialize(void) | |||
| 476 | 488 | ||
| 477 | mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; | 489 | mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; |
| 478 | 490 | ||
| 491 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 492 | linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT; | ||
| 493 | linear_map_hash_slots = __va(lmb_alloc_base(linear_map_hash_count, | ||
| 494 | 1, lmb.rmo_size)); | ||
| 495 | memset(linear_map_hash_slots, 0, linear_map_hash_count); | ||
| 496 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
| 497 | |||
| 479 | /* On U3 based machines, we need to reserve the DART area and | 498 | /* On U3 based machines, we need to reserve the DART area and |
| 480 | * _NOT_ map it to avoid cache paradoxes as it's remapped non | 499 | * _NOT_ map it to avoid cache paradoxes as it's remapped non |
| 481 | * cacheable later on | 500 | * cacheable later on |
| @@ -573,6 +592,27 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) | |||
| 573 | return pp; | 592 | return pp; |
| 574 | } | 593 | } |
| 575 | 594 | ||
| 595 | /* | ||
| 596 | * Demote a segment to using 4k pages. | ||
| 597 | * For now this makes the whole process use 4k pages. | ||
| 598 | */ | ||
| 599 | void demote_segment_4k(struct mm_struct *mm, unsigned long addr) | ||
| 600 | { | ||
| 601 | #ifdef CONFIG_PPC_64K_PAGES | ||
| 602 | if (mm->context.user_psize == MMU_PAGE_4K) | ||
| 603 | return; | ||
| 604 | mm->context.user_psize = MMU_PAGE_4K; | ||
| 605 | mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp; | ||
| 606 | get_paca()->context = mm->context; | ||
| 607 | slb_flush_and_rebolt(); | ||
| 608 | #ifdef CONFIG_SPE_BASE | ||
| 609 | spu_flush_all_slbs(mm); | ||
| 610 | #endif | ||
| 611 | #endif | ||
| 612 | } | ||
| 613 | |||
| 614 | EXPORT_SYMBOL_GPL(demote_segment_4k); | ||
| 615 | |||
| 576 | /* Result code is: | 616 | /* Result code is: |
| 577 | * 0 - handled | 617 | * 0 - handled |
| 578 | * 1 - normal page fault | 618 | * 1 - normal page fault |
| @@ -665,15 +705,19 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
| 665 | #ifndef CONFIG_PPC_64K_PAGES | 705 | #ifndef CONFIG_PPC_64K_PAGES |
| 666 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); | 706 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); |
| 667 | #else | 707 | #else |
| 708 | /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */ | ||
| 709 | if (pte_val(*ptep) & _PAGE_4K_PFN) { | ||
| 710 | demote_segment_4k(mm, ea); | ||
| 711 | psize = MMU_PAGE_4K; | ||
| 712 | } | ||
| 713 | |||
| 668 | if (mmu_ci_restrictions) { | 714 | if (mmu_ci_restrictions) { |
| 669 | /* If this PTE is non-cacheable, switch to 4k */ | 715 | /* If this PTE is non-cacheable, switch to 4k */ |
| 670 | if (psize == MMU_PAGE_64K && | 716 | if (psize == MMU_PAGE_64K && |
| 671 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { | 717 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { |
| 672 | if (user_region) { | 718 | if (user_region) { |
| 719 | demote_segment_4k(mm, ea); | ||
| 673 | psize = MMU_PAGE_4K; | 720 | psize = MMU_PAGE_4K; |
| 674 | mm->context.user_psize = MMU_PAGE_4K; | ||
| 675 | mm->context.sllp = SLB_VSID_USER | | ||
| 676 | mmu_psize_defs[MMU_PAGE_4K].sllp; | ||
| 677 | } else if (ea < VMALLOC_END) { | 721 | } else if (ea < VMALLOC_END) { |
| 678 | /* | 722 | /* |
| 679 | * some driver did a non-cacheable mapping | 723 | * some driver did a non-cacheable mapping |
| @@ -756,16 +800,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
| 756 | if (mmu_ci_restrictions) { | 800 | if (mmu_ci_restrictions) { |
| 757 | /* If this PTE is non-cacheable, switch to 4k */ | 801 | /* If this PTE is non-cacheable, switch to 4k */ |
| 758 | if (mm->context.user_psize == MMU_PAGE_64K && | 802 | if (mm->context.user_psize == MMU_PAGE_64K && |
| 759 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { | 803 | (pte_val(*ptep) & _PAGE_NO_CACHE)) |
| 760 | mm->context.user_psize = MMU_PAGE_4K; | 804 | demote_segment_4k(mm, ea); |
| 761 | mm->context.sllp = SLB_VSID_USER | | ||
| 762 | mmu_psize_defs[MMU_PAGE_4K].sllp; | ||
| 763 | get_paca()->context = mm->context; | ||
| 764 | slb_flush_and_rebolt(); | ||
| 765 | #ifdef CONFIG_SPE_BASE | ||
| 766 | spu_flush_all_slbs(mm); | ||
| 767 | #endif | ||
| 768 | } | ||
| 769 | } | 805 | } |
| 770 | if (mm->context.user_psize == MMU_PAGE_64K) | 806 | if (mm->context.user_psize == MMU_PAGE_64K) |
| 771 | __hash_page_64K(ea, access, vsid, ptep, trap, local); | 807 | __hash_page_64K(ea, access, vsid, ptep, trap, local); |
| @@ -825,3 +861,62 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address) | |||
| 825 | } | 861 | } |
| 826 | bad_page_fault(regs, address, SIGBUS); | 862 | bad_page_fault(regs, address, SIGBUS); |
| 827 | } | 863 | } |
| 864 | |||
| 865 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 866 | static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) | ||
| 867 | { | ||
| 868 | unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr); | ||
| 869 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | ||
| 870 | unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY | | ||
| 871 | _PAGE_COHERENT | PP_RWXX | HPTE_R_N; | ||
| 872 | int ret; | ||
| 873 | |||
| 874 | hash = hpt_hash(va, PAGE_SHIFT); | ||
| 875 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | ||
| 876 | |||
| 877 | ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), | ||
| 878 | mode, HPTE_V_BOLTED, mmu_linear_psize); | ||
| 879 | BUG_ON (ret < 0); | ||
| 880 | spin_lock(&linear_map_hash_lock); | ||
| 881 | BUG_ON(linear_map_hash_slots[lmi] & 0x80); | ||
| 882 | linear_map_hash_slots[lmi] = ret | 0x80; | ||
| 883 | spin_unlock(&linear_map_hash_lock); | ||
| 884 | } | ||
| 885 | |||
| 886 | static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) | ||
| 887 | { | ||
| 888 | unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr); | ||
| 889 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | ||
| 890 | |||
| 891 | hash = hpt_hash(va, PAGE_SHIFT); | ||
| 892 | spin_lock(&linear_map_hash_lock); | ||
| 893 | BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); | ||
| 894 | hidx = linear_map_hash_slots[lmi] & 0x7f; | ||
| 895 | linear_map_hash_slots[lmi] = 0; | ||
| 896 | spin_unlock(&linear_map_hash_lock); | ||
| 897 | if (hidx & _PTEIDX_SECONDARY) | ||
| 898 | hash = ~hash; | ||
| 899 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
| 900 | slot += hidx & _PTEIDX_GROUP_IX; | ||
| 901 | ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0); | ||
| 902 | } | ||
| 903 | |||
| 904 | void kernel_map_pages(struct page *page, int numpages, int enable) | ||
| 905 | { | ||
| 906 | unsigned long flags, vaddr, lmi; | ||
| 907 | int i; | ||
| 908 | |||
| 909 | local_irq_save(flags); | ||
| 910 | for (i = 0; i < numpages; i++, page++) { | ||
| 911 | vaddr = (unsigned long)page_address(page); | ||
| 912 | lmi = __pa(vaddr) >> PAGE_SHIFT; | ||
| 913 | if (lmi >= linear_map_hash_count) | ||
| 914 | continue; | ||
| 915 | if (enable) | ||
| 916 | kernel_map_linear_page(vaddr, lmi); | ||
| 917 | else | ||
| 918 | kernel_unmap_linear_page(vaddr, lmi); | ||
| 919 | } | ||
| 920 | local_irq_restore(flags); | ||
| 921 | } | ||
| 922 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index f6ffaaa7a5bf..8508f973d9cc 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
| @@ -316,12 +316,11 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 316 | { | 316 | { |
| 317 | if (pte_present(*ptep)) { | 317 | if (pte_present(*ptep)) { |
| 318 | /* We open-code pte_clear because we need to pass the right | 318 | /* We open-code pte_clear because we need to pass the right |
| 319 | * argument to hpte_update (huge / !huge) | 319 | * argument to hpte_need_flush (huge / !huge). Might not be |
| 320 | * necessary anymore if we make hpte_need_flush() get the | ||
| 321 | * page size from the slices | ||
| 320 | */ | 322 | */ |
| 321 | unsigned long old = pte_update(ptep, ~0UL); | 323 | pte_update(mm, addr & HPAGE_MASK, ptep, ~0UL, 1); |
| 322 | if (old & _PAGE_HASHPTE) | ||
| 323 | hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1); | ||
| 324 | flush_tlb_pending(); | ||
| 325 | } | 324 | } |
| 326 | *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); | 325 | *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); |
| 327 | } | 326 | } |
| @@ -329,12 +328,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
| 329 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | 328 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, |
| 330 | pte_t *ptep) | 329 | pte_t *ptep) |
| 331 | { | 330 | { |
| 332 | unsigned long old = pte_update(ptep, ~0UL); | 331 | unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1); |
| 333 | |||
| 334 | if (old & _PAGE_HASHPTE) | ||
| 335 | hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1); | ||
| 336 | *ptep = __pte(0); | ||
| 337 | |||
| 338 | return __pte(old); | 332 | return __pte(old); |
| 339 | } | 333 | } |
| 340 | 334 | ||
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 0e53ca8f02fb..5fce6ccecb8d 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
| @@ -115,6 +115,10 @@ void MMU_setup(void) | |||
| 115 | if (strstr(cmd_line, "noltlbs")) { | 115 | if (strstr(cmd_line, "noltlbs")) { |
| 116 | __map_without_ltlbs = 1; | 116 | __map_without_ltlbs = 1; |
| 117 | } | 117 | } |
| 118 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 119 | __map_without_bats = 1; | ||
| 120 | __map_without_ltlbs = 1; | ||
| 121 | #endif | ||
| 118 | } | 122 | } |
| 119 | 123 | ||
| 120 | /* | 124 | /* |
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c index 716a2906a24d..e3a1e8dc536a 100644 --- a/arch/powerpc/mm/lmb.c +++ b/arch/powerpc/mm/lmb.c | |||
| @@ -146,6 +146,10 @@ static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base, | |||
| 146 | unsigned long rgnbase = rgn->region[i].base; | 146 | unsigned long rgnbase = rgn->region[i].base; |
| 147 | unsigned long rgnsize = rgn->region[i].size; | 147 | unsigned long rgnsize = rgn->region[i].size; |
| 148 | 148 | ||
| 149 | if ((rgnbase == base) && (rgnsize == size)) | ||
| 150 | /* Already have this region, so we're done */ | ||
| 151 | return 0; | ||
| 152 | |||
| 149 | adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); | 153 | adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); |
| 150 | if ( adjacent > 0 ) { | 154 | if ( adjacent > 0 ) { |
| 151 | rgn->region[i].base -= size; | 155 | rgn->region[i].base -= size; |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 52f397c108a7..c4bcd7546424 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
| @@ -58,9 +58,6 @@ int init_bootmem_done; | |||
| 58 | int mem_init_done; | 58 | int mem_init_done; |
| 59 | unsigned long memory_limit; | 59 | unsigned long memory_limit; |
| 60 | 60 | ||
| 61 | extern void hash_preload(struct mm_struct *mm, unsigned long ea, | ||
| 62 | unsigned long access, unsigned long trap); | ||
| 63 | |||
| 64 | int page_is_ram(unsigned long pfn) | 61 | int page_is_ram(unsigned long pfn) |
| 65 | { | 62 | { |
| 66 | unsigned long paddr = (pfn << PAGE_SHIFT); | 63 | unsigned long paddr = (pfn << PAGE_SHIFT); |
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index bea2d21ac6f7..9c4538bb04b0 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h | |||
| @@ -19,9 +19,14 @@ | |||
| 19 | * 2 of the License, or (at your option) any later version. | 19 | * 2 of the License, or (at your option) any later version. |
| 20 | * | 20 | * |
| 21 | */ | 21 | */ |
| 22 | #include <linux/mm.h> | ||
| 22 | #include <asm/tlbflush.h> | 23 | #include <asm/tlbflush.h> |
| 23 | #include <asm/mmu.h> | 24 | #include <asm/mmu.h> |
| 24 | 25 | ||
| 26 | extern void hash_preload(struct mm_struct *mm, unsigned long ea, | ||
| 27 | unsigned long access, unsigned long trap); | ||
| 28 | |||
| 29 | |||
| 25 | #ifdef CONFIG_PPC32 | 30 | #ifdef CONFIG_PPC32 |
| 26 | extern void mapin_ram(void); | 31 | extern void mapin_ram(void); |
| 27 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); | 32 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); |
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index e86c37c82cfd..b3a592b25ab3 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
| @@ -74,7 +74,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) | |||
| 74 | 74 | ||
| 75 | while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) { | 75 | while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) { |
| 76 | /* Try interrupt server first */ | 76 | /* Try interrupt server first */ |
| 77 | interrupt_server = get_property(cpu_node, | 77 | interrupt_server = of_get_property(cpu_node, |
| 78 | "ibm,ppc-interrupt-server#s", &len); | 78 | "ibm,ppc-interrupt-server#s", &len); |
| 79 | 79 | ||
| 80 | len = len / sizeof(u32); | 80 | len = len / sizeof(u32); |
| @@ -85,7 +85,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) | |||
| 85 | return cpu_node; | 85 | return cpu_node; |
| 86 | } | 86 | } |
| 87 | } else { | 87 | } else { |
| 88 | reg = get_property(cpu_node, "reg", &len); | 88 | reg = of_get_property(cpu_node, "reg", &len); |
| 89 | if (reg && (len > 0) && (reg[0] == hw_cpuid)) | 89 | if (reg && (len > 0) && (reg[0] == hw_cpuid)) |
| 90 | return cpu_node; | 90 | return cpu_node; |
| 91 | } | 91 | } |
| @@ -97,7 +97,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu) | |||
| 97 | /* must hold reference to node during call */ | 97 | /* must hold reference to node during call */ |
| 98 | static const int *of_get_associativity(struct device_node *dev) | 98 | static const int *of_get_associativity(struct device_node *dev) |
| 99 | { | 99 | { |
| 100 | return get_property(dev, "ibm,associativity", NULL); | 100 | return of_get_property(dev, "ibm,associativity", NULL); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa | 103 | /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa |
| @@ -179,7 +179,7 @@ static int __init find_min_common_depth(void) | |||
| 179 | * configuration (should be all 0's) and the second is for a normal | 179 | * configuration (should be all 0's) and the second is for a normal |
| 180 | * NUMA configuration. | 180 | * NUMA configuration. |
| 181 | */ | 181 | */ |
| 182 | ref_points = get_property(rtas_root, | 182 | ref_points = of_get_property(rtas_root, |
| 183 | "ibm,associativity-reference-points", &len); | 183 | "ibm,associativity-reference-points", &len); |
| 184 | 184 | ||
| 185 | if ((len >= 1) && ref_points) { | 185 | if ((len >= 1) && ref_points) { |
| @@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) | |||
| 201 | if (!memory) | 201 | if (!memory) |
| 202 | panic("numa.c: No memory nodes found!"); | 202 | panic("numa.c: No memory nodes found!"); |
| 203 | 203 | ||
| 204 | *n_addr_cells = prom_n_addr_cells(memory); | 204 | *n_addr_cells = of_n_addr_cells(memory); |
| 205 | *n_size_cells = prom_n_size_cells(memory); | 205 | *n_size_cells = of_n_size_cells(memory); |
| 206 | of_node_put(memory); | 206 | of_node_put(memory); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| @@ -308,9 +308,9 @@ static void __init parse_drconf_memory(struct device_node *memory) | |||
| 308 | int nid, default_nid = 0; | 308 | int nid, default_nid = 0; |
| 309 | unsigned int start, ai, flags; | 309 | unsigned int start, ai, flags; |
| 310 | 310 | ||
| 311 | lm = get_property(memory, "ibm,lmb-size", &ls); | 311 | lm = of_get_property(memory, "ibm,lmb-size", &ls); |
| 312 | dm = get_property(memory, "ibm,dynamic-memory", &ld); | 312 | dm = of_get_property(memory, "ibm,dynamic-memory", &ld); |
| 313 | aa = get_property(memory, "ibm,associativity-lookup-arrays", &la); | 313 | aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la); |
| 314 | if (!lm || !dm || !aa || | 314 | if (!lm || !dm || !aa || |
| 315 | ls < sizeof(unsigned int) || ld < sizeof(unsigned int) || | 315 | ls < sizeof(unsigned int) || ld < sizeof(unsigned int) || |
| 316 | la < 2 * sizeof(unsigned int)) | 316 | la < 2 * sizeof(unsigned int)) |
| @@ -404,10 +404,10 @@ static int __init parse_numa_properties(void) | |||
| 404 | const unsigned int *memcell_buf; | 404 | const unsigned int *memcell_buf; |
| 405 | unsigned int len; | 405 | unsigned int len; |
| 406 | 406 | ||
| 407 | memcell_buf = get_property(memory, | 407 | memcell_buf = of_get_property(memory, |
| 408 | "linux,usable-memory", &len); | 408 | "linux,usable-memory", &len); |
| 409 | if (!memcell_buf || len <= 0) | 409 | if (!memcell_buf || len <= 0) |
| 410 | memcell_buf = get_property(memory, "reg", &len); | 410 | memcell_buf = of_get_property(memory, "reg", &len); |
| 411 | if (!memcell_buf || len <= 0) | 411 | if (!memcell_buf || len <= 0) |
| 412 | continue; | 412 | continue; |
| 413 | 413 | ||
| @@ -725,7 +725,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr) | |||
| 725 | const unsigned int *memcell_buf; | 725 | const unsigned int *memcell_buf; |
| 726 | unsigned int len; | 726 | unsigned int len; |
| 727 | 727 | ||
| 728 | memcell_buf = get_property(memory, "reg", &len); | 728 | memcell_buf = of_get_property(memory, "reg", &len); |
| 729 | if (!memcell_buf || len <= 0) | 729 | if (!memcell_buf || len <= 0) |
| 730 | continue; | 730 | continue; |
| 731 | 731 | ||
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index c284bdac9947..bca560374927 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c | |||
| @@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) | |||
| 183 | * mem_init() sets high_memory so only do the check after that. | 183 | * mem_init() sets high_memory so only do the check after that. |
| 184 | */ | 184 | */ |
| 185 | if (mem_init_done && (p < virt_to_phys(high_memory))) { | 185 | if (mem_init_done && (p < virt_to_phys(high_memory))) { |
| 186 | printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p, | 186 | printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n", |
| 187 | __builtin_return_address(0)); | 187 | (unsigned long long)p, __builtin_return_address(0)); |
| 188 | return NULL; | 188 | return NULL; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| @@ -266,9 +266,12 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) | |||
| 266 | pg = pte_alloc_kernel(pd, va); | 266 | pg = pte_alloc_kernel(pd, va); |
| 267 | if (pg != 0) { | 267 | if (pg != 0) { |
| 268 | err = 0; | 268 | err = 0; |
| 269 | set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags))); | 269 | /* The PTE should never be already set nor present in the |
| 270 | if (mem_init_done) | 270 | * hash table |
| 271 | flush_HPTE(0, va, pmd_val(*pd)); | 271 | */ |
| 272 | BUG_ON(pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)); | ||
| 273 | set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, | ||
| 274 | __pgprot(flags))); | ||
| 272 | } | 275 | } |
| 273 | return err; | 276 | return err; |
| 274 | } | 277 | } |
| @@ -279,16 +282,19 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) | |||
| 279 | void __init mapin_ram(void) | 282 | void __init mapin_ram(void) |
| 280 | { | 283 | { |
| 281 | unsigned long v, p, s, f; | 284 | unsigned long v, p, s, f; |
| 285 | int ktext; | ||
| 282 | 286 | ||
| 283 | s = mmu_mapin_ram(); | 287 | s = mmu_mapin_ram(); |
| 284 | v = KERNELBASE + s; | 288 | v = KERNELBASE + s; |
| 285 | p = PPC_MEMSTART + s; | 289 | p = PPC_MEMSTART + s; |
| 286 | for (; s < total_lowmem; s += PAGE_SIZE) { | 290 | for (; s < total_lowmem; s += PAGE_SIZE) { |
| 287 | if ((char *) v >= _stext && (char *) v < etext) | 291 | ktext = ((char *) v >= _stext && (char *) v < etext); |
| 288 | f = _PAGE_RAM_TEXT; | 292 | f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM; |
| 289 | else | ||
| 290 | f = _PAGE_RAM; | ||
| 291 | map_page(v, p, f); | 293 | map_page(v, p, f); |
| 294 | #ifdef CONFIG_PPC_STD_MMU_32 | ||
| 295 | if (ktext) | ||
| 296 | hash_preload(&init_mm, v, 0, 0x300); | ||
| 297 | #endif | ||
| 292 | v += PAGE_SIZE; | 298 | v += PAGE_SIZE; |
| 293 | p += PAGE_SIZE; | 299 | p += PAGE_SIZE; |
| 294 | } | 300 | } |
| @@ -445,3 +451,55 @@ exit: | |||
| 445 | return ret; | 451 | return ret; |
| 446 | } | 452 | } |
| 447 | 453 | ||
| 454 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 455 | |||
| 456 | static int __change_page_attr(struct page *page, pgprot_t prot) | ||
| 457 | { | ||
| 458 | pte_t *kpte; | ||
| 459 | pmd_t *kpmd; | ||
| 460 | unsigned long address; | ||
| 461 | |||
| 462 | BUG_ON(PageHighMem(page)); | ||
| 463 | address = (unsigned long)page_address(page); | ||
| 464 | |||
| 465 | if (v_mapped_by_bats(address) || v_mapped_by_tlbcam(address)) | ||
| 466 | return 0; | ||
| 467 | if (!get_pteptr(&init_mm, address, &kpte, &kpmd)) | ||
| 468 | return -EINVAL; | ||
| 469 | set_pte_at(&init_mm, address, kpte, mk_pte(page, prot)); | ||
| 470 | wmb(); | ||
| 471 | flush_HPTE(0, address, pmd_val(*kpmd)); | ||
| 472 | pte_unmap(kpte); | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* | ||
| 478 | * Change the page attributes of an page in the linear mapping. | ||
| 479 | * | ||
| 480 | * THIS CONFLICTS WITH BAT MAPPINGS, DEBUG USE ONLY | ||
| 481 | */ | ||
| 482 | static int change_page_attr(struct page *page, int numpages, pgprot_t prot) | ||
| 483 | { | ||
| 484 | int i, err = 0; | ||
| 485 | unsigned long flags; | ||
| 486 | |||
| 487 | local_irq_save(flags); | ||
| 488 | for (i = 0; i < numpages; i++, page++) { | ||
| 489 | err = __change_page_attr(page, prot); | ||
| 490 | if (err) | ||
| 491 | break; | ||
| 492 | } | ||
| 493 | local_irq_restore(flags); | ||
| 494 | return err; | ||
| 495 | } | ||
| 496 | |||
| 497 | |||
| 498 | void kernel_map_pages(struct page *page, int numpages, int enable) | ||
| 499 | { | ||
| 500 | if (PageHighMem(page)) | ||
| 501 | return; | ||
| 502 | |||
| 503 | change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0)); | ||
| 504 | } | ||
| 505 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | ||
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index 7cceb2c44cb9..05066674a7a0 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c | |||
| @@ -85,8 +85,10 @@ unsigned long __init mmu_mapin_ram(void) | |||
| 85 | unsigned long max_size = (256<<20); | 85 | unsigned long max_size = (256<<20); |
| 86 | unsigned long align; | 86 | unsigned long align; |
| 87 | 87 | ||
| 88 | if (__map_without_bats) | 88 | if (__map_without_bats) { |
| 89 | printk(KERN_DEBUG "RAM mapped without BATs\n"); | ||
| 89 | return 0; | 90 | return 0; |
| 91 | } | ||
| 90 | 92 | ||
| 91 | /* Set up BAT2 and if necessary BAT3 to cover RAM. */ | 93 | /* Set up BAT2 and if necessary BAT3 to cover RAM. */ |
| 92 | 94 | ||
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c index b58baa65c4a7..fd8d08c325eb 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_64.c | |||
| @@ -120,17 +120,20 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) | |||
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | /* | 122 | /* |
| 123 | * Update the MMU hash table to correspond with a change to | 123 | * A linux PTE was changed and the corresponding hash table entry |
| 124 | * a Linux PTE. If wrprot is true, it is permissible to | 124 | * neesd to be flushed. This function will either perform the flush |
| 125 | * change the existing HPTE to read-only rather than removing it | 125 | * immediately or will batch it up if the current CPU has an active |
| 126 | * (if we remove it we should clear the _PTE_HPTEFLAGS bits). | 126 | * batch on it. |
| 127 | * | ||
| 128 | * Must be called from within some kind of spinlock/non-preempt region... | ||
| 127 | */ | 129 | */ |
| 128 | void hpte_update(struct mm_struct *mm, unsigned long addr, | 130 | void hpte_need_flush(struct mm_struct *mm, unsigned long addr, |
| 129 | pte_t *ptep, unsigned long pte, int huge) | 131 | pte_t *ptep, unsigned long pte, int huge) |
| 130 | { | 132 | { |
| 131 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); | 133 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); |
| 132 | unsigned long vsid; | 134 | unsigned long vsid, vaddr; |
| 133 | unsigned int psize; | 135 | unsigned int psize; |
| 136 | real_pte_t rpte; | ||
| 134 | int i; | 137 | int i; |
| 135 | 138 | ||
| 136 | i = batch->index; | 139 | i = batch->index; |
| @@ -151,6 +154,26 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, | |||
| 151 | } else | 154 | } else |
| 152 | psize = pte_pagesize_index(pte); | 155 | psize = pte_pagesize_index(pte); |
| 153 | 156 | ||
| 157 | /* Build full vaddr */ | ||
| 158 | if (!is_kernel_addr(addr)) { | ||
| 159 | vsid = get_vsid(mm->context.id, addr); | ||
| 160 | WARN_ON(vsid == 0); | ||
| 161 | } else | ||
| 162 | vsid = get_kernel_vsid(addr); | ||
| 163 | vaddr = (vsid << 28 ) | (addr & 0x0fffffff); | ||
| 164 | rpte = __real_pte(__pte(pte), ptep); | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Check if we have an active batch on this CPU. If not, just | ||
| 168 | * flush now and return. For now, we don global invalidates | ||
| 169 | * in that case, might be worth testing the mm cpu mask though | ||
| 170 | * and decide to use local invalidates instead... | ||
| 171 | */ | ||
| 172 | if (!batch->active) { | ||
| 173 | flush_hash_page(vaddr, rpte, psize, 0); | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 154 | /* | 177 | /* |
| 155 | * This can happen when we are in the middle of a TLB batch and | 178 | * This can happen when we are in the middle of a TLB batch and |
| 156 | * we encounter memory pressure (eg copy_page_range when it tries | 179 | * we encounter memory pressure (eg copy_page_range when it tries |
| @@ -162,47 +185,42 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, | |||
| 162 | * batch | 185 | * batch |
| 163 | */ | 186 | */ |
| 164 | if (i != 0 && (mm != batch->mm || batch->psize != psize)) { | 187 | if (i != 0 && (mm != batch->mm || batch->psize != psize)) { |
| 165 | flush_tlb_pending(); | 188 | __flush_tlb_pending(batch); |
| 166 | i = 0; | 189 | i = 0; |
| 167 | } | 190 | } |
| 168 | if (i == 0) { | 191 | if (i == 0) { |
| 169 | batch->mm = mm; | 192 | batch->mm = mm; |
| 170 | batch->psize = psize; | 193 | batch->psize = psize; |
| 171 | } | 194 | } |
| 172 | if (!is_kernel_addr(addr)) { | 195 | batch->pte[i] = rpte; |
| 173 | vsid = get_vsid(mm->context.id, addr); | 196 | batch->vaddr[i] = vaddr; |
| 174 | WARN_ON(vsid == 0); | ||
| 175 | } else | ||
| 176 | vsid = get_kernel_vsid(addr); | ||
| 177 | batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff); | ||
| 178 | batch->pte[i] = __real_pte(__pte(pte), ptep); | ||
| 179 | batch->index = ++i; | 197 | batch->index = ++i; |
| 180 | if (i >= PPC64_TLB_BATCH_NR) | 198 | if (i >= PPC64_TLB_BATCH_NR) |
| 181 | flush_tlb_pending(); | 199 | __flush_tlb_pending(batch); |
| 182 | } | 200 | } |
| 183 | 201 | ||
| 202 | /* | ||
| 203 | * This function is called when terminating an mmu batch or when a batch | ||
| 204 | * is full. It will perform the flush of all the entries currently stored | ||
| 205 | * in a batch. | ||
| 206 | * | ||
| 207 | * Must be called from within some kind of spinlock/non-preempt region... | ||
| 208 | */ | ||
| 184 | void __flush_tlb_pending(struct ppc64_tlb_batch *batch) | 209 | void __flush_tlb_pending(struct ppc64_tlb_batch *batch) |
| 185 | { | 210 | { |
| 186 | int i; | ||
| 187 | int cpu; | ||
| 188 | cpumask_t tmp; | 211 | cpumask_t tmp; |
| 189 | int local = 0; | 212 | int i, local = 0; |
| 190 | 213 | ||
| 191 | BUG_ON(in_interrupt()); | ||
| 192 | |||
| 193 | cpu = get_cpu(); | ||
| 194 | i = batch->index; | 214 | i = batch->index; |
| 195 | tmp = cpumask_of_cpu(cpu); | 215 | tmp = cpumask_of_cpu(smp_processor_id()); |
| 196 | if (cpus_equal(batch->mm->cpu_vm_mask, tmp)) | 216 | if (cpus_equal(batch->mm->cpu_vm_mask, tmp)) |
| 197 | local = 1; | 217 | local = 1; |
| 198 | |||
| 199 | if (i == 1) | 218 | if (i == 1) |
| 200 | flush_hash_page(batch->vaddr[0], batch->pte[0], | 219 | flush_hash_page(batch->vaddr[0], batch->pte[0], |
| 201 | batch->psize, local); | 220 | batch->psize, local); |
| 202 | else | 221 | else |
| 203 | flush_hash_range(i, local); | 222 | flush_hash_range(i, local); |
| 204 | batch->index = 0; | 223 | batch->index = 0; |
| 205 | put_cpu(); | ||
| 206 | } | 224 | } |
| 207 | 225 | ||
| 208 | void pte_free_finish(void) | 226 | void pte_free_finish(void) |
