diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-05-08 02:27:27 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-09 02:35:00 -0400 |
commit | 16f1c746755836aa823658000493cdab8ce7b098 (patch) | |
tree | 32f534c771b69400839f5795f979c47eac51f923 | |
parent | b15f792fafb7e0524907ddd9e035d73dddeed89c (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>
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 87 |
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 | */ |
599 | void demote_segment_4k(struct mm_struct *mm, unsigned long addr) | ||
600 | { | ||
601 | #ifdef CONFIG_PPC_64K_PAGES | 599 | #ifdef CONFIG_PPC_64K_PAGES |
600 | static 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 */ | |
614 | EXPORT_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 |