aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-05-08 02:27:27 -0400
committerPaul Mackerras <paulus@samba.org>2007-05-09 02:35:00 -0400
commit16f1c746755836aa823658000493cdab8ce7b098 (patch)
tree32f534c771b69400839f5795f979c47eac51f923 /arch/powerpc/mm
parentb15f792fafb7e0524907ddd9e035d73dddeed89c (diff)
[POWERPC] Small fixes & cleanups in segment page size demotion
The code for demoting segments to 4K had some issues, like for example, when using _PAGE_4K_PFN flag, the first CPU to hit it would do the demotion, but other CPUs hitting the same page wouldn't properly flush their SLBs if mmu_ci_restriction isn't set. There are also potential issues with hash_preload not handling _PAGE_4K_PFN. All of these are non issues on current hardware but might bite us in the future. This patch thus fixes it by: - Taking the test comparing the mm and current CPU context page sizes to decide to flush SLBs out of the mmu_ci_restrictions test since that can also be triggered by _PAGE_4K_PFN pages - Due to the above being done all the time, demote_segment_4k doesn't need update the context and flush the SLB - demote_segment_4k can be static and doesn't need an EXPORT_SYMBOL - Making hash_preload ignore anything that has either _PAGE_4K_PFN or _PAGE_NO_CACHE set, thus avoiding duplication of the complicated logic in hash_page() (and possibly making hash_preload a little bit faster for the normal case). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/hash_utils_64.c87
1 files changed, 46 insertions, 41 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 9b226fa7006f..71092c2f65cd 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -596,22 +596,18 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
596 * Demote a segment to using 4k pages. 596 * Demote a segment to using 4k pages.
597 * For now this makes the whole process use 4k pages. 597 * For now this makes the whole process use 4k pages.
598 */ 598 */
599void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
600{
601#ifdef CONFIG_PPC_64K_PAGES 599#ifdef CONFIG_PPC_64K_PAGES
600static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
601{
602 if (mm->context.user_psize == MMU_PAGE_4K) 602 if (mm->context.user_psize == MMU_PAGE_4K)
603 return; 603 return;
604 mm->context.user_psize = MMU_PAGE_4K; 604 mm->context.user_psize = MMU_PAGE_4K;
605 mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp; 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 606#ifdef CONFIG_SPE_BASE
609 spu_flush_all_slbs(mm); 607 spu_flush_all_slbs(mm);
610#endif 608#endif
611#endif
612} 609}
613 610#endif /* CONFIG_PPC_64K_PAGES */
614EXPORT_SYMBOL_GPL(demote_segment_4k);
615 611
616/* Result code is: 612/* Result code is:
617 * 0 - handled 613 * 0 - handled
@@ -711,40 +707,42 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
711 psize = MMU_PAGE_4K; 707 psize = MMU_PAGE_4K;
712 } 708 }
713 709
714 if (mmu_ci_restrictions) { 710 /* If this PTE is non-cacheable and we have restrictions on
715 /* If this PTE is non-cacheable, switch to 4k */ 711 * using non cacheable large pages, then we switch to 4k
716 if (psize == MMU_PAGE_64K && 712 */
717 (pte_val(*ptep) & _PAGE_NO_CACHE)) { 713 if (mmu_ci_restrictions && psize == MMU_PAGE_64K &&
718 if (user_region) { 714 (pte_val(*ptep) & _PAGE_NO_CACHE)) {
719 demote_segment_4k(mm, ea); 715 if (user_region) {
720 psize = MMU_PAGE_4K; 716 demote_segment_4k(mm, ea);
721 } else if (ea < VMALLOC_END) { 717 psize = MMU_PAGE_4K;
722 /* 718 } else if (ea < VMALLOC_END) {
723 * some driver did a non-cacheable mapping 719 /*
724 * in vmalloc space, so switch vmalloc 720 * some driver did a non-cacheable mapping
725 * to 4k pages 721 * in vmalloc space, so switch vmalloc
726 */ 722 * to 4k pages
727 printk(KERN_ALERT "Reducing vmalloc segment " 723 */
728 "to 4kB pages because of " 724 printk(KERN_ALERT "Reducing vmalloc segment "
729 "non-cacheable mapping\n"); 725 "to 4kB pages because of "
730 psize = mmu_vmalloc_psize = MMU_PAGE_4K; 726 "non-cacheable mapping\n");
731 } 727 psize = mmu_vmalloc_psize = MMU_PAGE_4K;
732#ifdef CONFIG_SPE_BASE 728#ifdef CONFIG_SPE_BASE
733 spu_flush_all_slbs(mm); 729 spu_flush_all_slbs(mm);
734#endif 730#endif
735 } 731 }
736 if (user_region) { 732 }
737 if (psize != get_paca()->context.user_psize) { 733 if (user_region) {
738 get_paca()->context = mm->context; 734 if (psize != get_paca()->context.user_psize) {
739 slb_flush_and_rebolt(); 735 get_paca()->context.user_psize =
740 } 736 mm->context.user_psize;
741 } else if (get_paca()->vmalloc_sllp !=
742 mmu_psize_defs[mmu_vmalloc_psize].sllp) {
743 get_paca()->vmalloc_sllp =
744 mmu_psize_defs[mmu_vmalloc_psize].sllp;
745 slb_flush_and_rebolt(); 737 slb_flush_and_rebolt();
746 } 738 }
739 } else if (get_paca()->vmalloc_sllp !=
740 mmu_psize_defs[mmu_vmalloc_psize].sllp) {
741 get_paca()->vmalloc_sllp =
742 mmu_psize_defs[mmu_vmalloc_psize].sllp;
743 slb_flush_and_rebolt();
747 } 744 }
745
748 if (psize == MMU_PAGE_64K) 746 if (psize == MMU_PAGE_64K)
749 rc = __hash_page_64K(ea, access, vsid, ptep, trap, local); 747 rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
750 else 748 else
@@ -780,13 +778,26 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
780 DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx," 778 DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
781 " trap=%lx\n", mm, mm->pgd, ea, access, trap); 779 " trap=%lx\n", mm, mm->pgd, ea, access, trap);
782 780
783 /* Get PTE, VSID, access mask */ 781 /* Get Linux PTE if available */
784 pgdir = mm->pgd; 782 pgdir = mm->pgd;
785 if (pgdir == NULL) 783 if (pgdir == NULL)
786 return; 784 return;
787 ptep = find_linux_pte(pgdir, ea); 785 ptep = find_linux_pte(pgdir, ea);
788 if (!ptep) 786 if (!ptep)
789 return; 787 return;
788
789#ifdef CONFIG_PPC_64K_PAGES
790 /* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
791 * a 64K kernel), then we don't preload, hash_page() will take
792 * care of it once we actually try to access the page.
793 * That way we don't have to duplicate all of the logic for segment
794 * page size demotion here
795 */
796 if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
797 return;
798#endif /* CONFIG_PPC_64K_PAGES */
799
800 /* Get VSID */
790 vsid = get_vsid(mm->context.id, ea); 801 vsid = get_vsid(mm->context.id, ea);
791 802
792 /* Hash it in */ 803 /* Hash it in */
@@ -797,12 +808,6 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
797#ifndef CONFIG_PPC_64K_PAGES 808#ifndef CONFIG_PPC_64K_PAGES
798 __hash_page_4K(ea, access, vsid, ptep, trap, local); 809 __hash_page_4K(ea, access, vsid, ptep, trap, local);
799#else 810#else
800 if (mmu_ci_restrictions) {
801 /* If this PTE is non-cacheable, switch to 4k */
802 if (mm->context.user_psize == MMU_PAGE_64K &&
803 (pte_val(*ptep) & _PAGE_NO_CACHE))
804 demote_segment_4k(mm, ea);
805 }
806 if (mm->context.user_psize == MMU_PAGE_64K) 811 if (mm->context.user_psize == MMU_PAGE_64K)
807 __hash_page_64K(ea, access, vsid, ptep, trap, local); 812 __hash_page_64K(ea, access, vsid, ptep, trap, local);
808 else 813 else