aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/mm/hash_utils_64.c2
-rw-r--r--arch/powerpc/mm/hugetlbpage.c35
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 */
645static 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
642int hash_huge_page(struct mm_struct *mm, unsigned long access, 669int 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)) {