diff options
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/hash_low_64.S | 5 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 43 |
2 files changed, 34 insertions, 14 deletions
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_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 3c7fe2c65b5a..aae085317018 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -573,6 +573,27 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) | |||
573 | return pp; | 573 | return pp; |
574 | } | 574 | } |
575 | 575 | ||
576 | /* | ||
577 | * Demote a segment to using 4k pages. | ||
578 | * For now this makes the whole process use 4k pages. | ||
579 | */ | ||
580 | void demote_segment_4k(struct mm_struct *mm, unsigned long addr) | ||
581 | { | ||
582 | #ifdef CONFIG_PPC_64K_PAGES | ||
583 | if (mm->context.user_psize == MMU_PAGE_4K) | ||
584 | return; | ||
585 | mm->context.user_psize = MMU_PAGE_4K; | ||
586 | mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp; | ||
587 | get_paca()->context = mm->context; | ||
588 | slb_flush_and_rebolt(); | ||
589 | #ifdef CONFIG_SPE_BASE | ||
590 | spu_flush_all_slbs(mm); | ||
591 | #endif | ||
592 | #endif | ||
593 | } | ||
594 | |||
595 | EXPORT_SYMBOL_GPL(demote_segment_4k); | ||
596 | |||
576 | /* Result code is: | 597 | /* Result code is: |
577 | * 0 - handled | 598 | * 0 - handled |
578 | * 1 - normal page fault | 599 | * 1 - normal page fault |
@@ -665,15 +686,19 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
665 | #ifndef CONFIG_PPC_64K_PAGES | 686 | #ifndef CONFIG_PPC_64K_PAGES |
666 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); | 687 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); |
667 | #else | 688 | #else |
689 | /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */ | ||
690 | if (pte_val(*ptep) & _PAGE_4K_PFN) { | ||
691 | demote_segment_4k(mm, ea); | ||
692 | psize = MMU_PAGE_4K; | ||
693 | } | ||
694 | |||
668 | if (mmu_ci_restrictions) { | 695 | if (mmu_ci_restrictions) { |
669 | /* If this PTE is non-cacheable, switch to 4k */ | 696 | /* If this PTE is non-cacheable, switch to 4k */ |
670 | if (psize == MMU_PAGE_64K && | 697 | if (psize == MMU_PAGE_64K && |
671 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { | 698 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { |
672 | if (user_region) { | 699 | if (user_region) { |
700 | demote_segment_4k(mm, ea); | ||
673 | psize = MMU_PAGE_4K; | 701 | 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) { | 702 | } else if (ea < VMALLOC_END) { |
678 | /* | 703 | /* |
679 | * some driver did a non-cacheable mapping | 704 | * some driver did a non-cacheable mapping |
@@ -756,16 +781,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
756 | if (mmu_ci_restrictions) { | 781 | if (mmu_ci_restrictions) { |
757 | /* If this PTE is non-cacheable, switch to 4k */ | 782 | /* If this PTE is non-cacheable, switch to 4k */ |
758 | if (mm->context.user_psize == MMU_PAGE_64K && | 783 | if (mm->context.user_psize == MMU_PAGE_64K && |
759 | (pte_val(*ptep) & _PAGE_NO_CACHE)) { | 784 | (pte_val(*ptep) & _PAGE_NO_CACHE)) |
760 | mm->context.user_psize = MMU_PAGE_4K; | 785 | 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 | } | 786 | } |
770 | if (mm->context.user_psize == MMU_PAGE_64K) | 787 | if (mm->context.user_psize == MMU_PAGE_64K) |
771 | __hash_page_64K(ea, access, vsid, ptep, trap, local); | 788 | __hash_page_64K(ea, access, vsid, ptep, trap, local); |