diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 35 |
2 files changed, 35 insertions, 2 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 706e8a63ced9..a33583f3b0e7 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -601,7 +601,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
601 | /* Handle hugepage regions */ | 601 | /* Handle hugepage regions */ |
602 | if (unlikely(in_hugepage_area(mm->context, ea))) { | 602 | if (unlikely(in_hugepage_area(mm->context, ea))) { |
603 | DBG_LOW(" -> huge page !\n"); | 603 | DBG_LOW(" -> huge page !\n"); |
604 | return hash_huge_page(mm, access, ea, vsid, local); | 604 | return hash_huge_page(mm, access, ea, vsid, local, trap); |
605 | } | 605 | } |
606 | 606 | ||
607 | /* Get PTE and page size from page tables */ | 607 | /* Get PTE and page size from page tables */ |
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 8bce515dc320..97512b89e7b0 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
@@ -639,8 +639,36 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
639 | return -ENOMEM; | 639 | return -ENOMEM; |
640 | } | 640 | } |
641 | 641 | ||
642 | /* | ||
643 | * Called by asm hashtable.S for doing lazy icache flush | ||
644 | */ | ||
645 | static unsigned int hash_huge_page_do_lazy_icache(unsigned long rflags, | ||
646 | pte_t pte, int trap) | ||
647 | { | ||
648 | struct page *page; | ||
649 | int i; | ||
650 | |||
651 | if (!pfn_valid(pte_pfn(pte))) | ||
652 | return rflags; | ||
653 | |||
654 | page = pte_page(pte); | ||
655 | |||
656 | /* page is dirty */ | ||
657 | if (!test_bit(PG_arch_1, &page->flags) && !PageReserved(page)) { | ||
658 | if (trap == 0x400) { | ||
659 | for (i = 0; i < (HPAGE_SIZE / PAGE_SIZE); i++) | ||
660 | __flush_dcache_icache(page_address(page+i)); | ||
661 | set_bit(PG_arch_1, &page->flags); | ||
662 | } else { | ||
663 | rflags |= HPTE_R_N; | ||
664 | } | ||
665 | } | ||
666 | return rflags; | ||
667 | } | ||
668 | |||
642 | int hash_huge_page(struct mm_struct *mm, unsigned long access, | 669 | int hash_huge_page(struct mm_struct *mm, unsigned long access, |
643 | unsigned long ea, unsigned long vsid, int local) | 670 | unsigned long ea, unsigned long vsid, int local, |
671 | unsigned long trap) | ||
644 | { | 672 | { |
645 | pte_t *ptep; | 673 | pte_t *ptep; |
646 | unsigned long old_pte, new_pte; | 674 | unsigned long old_pte, new_pte; |
@@ -691,6 +719,11 @@ int hash_huge_page(struct mm_struct *mm, unsigned long access, | |||
691 | rflags = 0x2 | (!(new_pte & _PAGE_RW)); | 719 | rflags = 0x2 | (!(new_pte & _PAGE_RW)); |
692 | /* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */ | 720 | /* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */ |
693 | rflags |= ((new_pte & _PAGE_EXEC) ? 0 : HPTE_R_N); | 721 | rflags |= ((new_pte & _PAGE_EXEC) ? 0 : HPTE_R_N); |
722 | if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) | ||
723 | /* No CPU has hugepages but lacks no execute, so we | ||
724 | * don't need to worry about that case */ | ||
725 | rflags = hash_huge_page_do_lazy_icache(rflags, __pte(old_pte), | ||
726 | trap); | ||
694 | 727 | ||
695 | /* Check if pte already has an hpte (case 2) */ | 728 | /* Check if pte already has an hpte (case 2) */ |
696 | if (unlikely(old_pte & _PAGE_HASHPTE)) { | 729 | if (unlikely(old_pte & _PAGE_HASHPTE)) { |