diff options
Diffstat (limited to 'arch/powerpc/mm/pgtable_64.c')
-rw-r--r-- | arch/powerpc/mm/pgtable_64.c | 104 |
1 files changed, 36 insertions, 68 deletions
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index c8d709ab489d..4fe5f64cc179 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c | |||
@@ -33,9 +33,9 @@ | |||
33 | #include <linux/swap.h> | 33 | #include <linux/swap.h> |
34 | #include <linux/stddef.h> | 34 | #include <linux/stddef.h> |
35 | #include <linux/vmalloc.h> | 35 | #include <linux/vmalloc.h> |
36 | #include <linux/bootmem.h> | ||
37 | #include <linux/memblock.h> | 36 | #include <linux/memblock.h> |
38 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/hugetlb.h> | ||
39 | 39 | ||
40 | #include <asm/pgalloc.h> | 40 | #include <asm/pgalloc.h> |
41 | #include <asm/page.h> | 41 | #include <asm/page.h> |
@@ -51,6 +51,7 @@ | |||
51 | #include <asm/cputable.h> | 51 | #include <asm/cputable.h> |
52 | #include <asm/sections.h> | 52 | #include <asm/sections.h> |
53 | #include <asm/firmware.h> | 53 | #include <asm/firmware.h> |
54 | #include <asm/dma.h> | ||
54 | 55 | ||
55 | #include "mmu_decl.h" | 56 | #include "mmu_decl.h" |
56 | 57 | ||
@@ -75,11 +76,7 @@ static __ref void *early_alloc_pgtable(unsigned long size) | |||
75 | { | 76 | { |
76 | void *pt; | 77 | void *pt; |
77 | 78 | ||
78 | if (init_bootmem_done) | 79 | pt = __va(memblock_alloc_base(size, size, __pa(MAX_DMA_ADDRESS))); |
79 | pt = __alloc_bootmem(size, size, __pa(MAX_DMA_ADDRESS)); | ||
80 | else | ||
81 | pt = __va(memblock_alloc_base(size, size, | ||
82 | __pa(MAX_DMA_ADDRESS))); | ||
83 | memset(pt, 0, size); | 80 | memset(pt, 0, size); |
84 | 81 | ||
85 | return pt; | 82 | return pt; |
@@ -113,10 +110,6 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags) | |||
113 | __pgprot(flags))); | 110 | __pgprot(flags))); |
114 | } else { | 111 | } else { |
115 | #ifdef CONFIG_PPC_MMU_NOHASH | 112 | #ifdef CONFIG_PPC_MMU_NOHASH |
116 | /* Warning ! This will blow up if bootmem is not initialized | ||
117 | * which our ppc64 code is keen to do that, we'll need to | ||
118 | * fix it and/or be more careful | ||
119 | */ | ||
120 | pgdp = pgd_offset_k(ea); | 113 | pgdp = pgd_offset_k(ea); |
121 | #ifdef PUD_TABLE_SIZE | 114 | #ifdef PUD_TABLE_SIZE |
122 | if (pgd_none(*pgdp)) { | 115 | if (pgd_none(*pgdp)) { |
@@ -352,16 +345,31 @@ EXPORT_SYMBOL(iounmap); | |||
352 | EXPORT_SYMBOL(__iounmap); | 345 | EXPORT_SYMBOL(__iounmap); |
353 | EXPORT_SYMBOL(__iounmap_at); | 346 | EXPORT_SYMBOL(__iounmap_at); |
354 | 347 | ||
348 | #ifndef __PAGETABLE_PUD_FOLDED | ||
349 | /* 4 level page table */ | ||
350 | struct page *pgd_page(pgd_t pgd) | ||
351 | { | ||
352 | if (pgd_huge(pgd)) | ||
353 | return pte_page(pgd_pte(pgd)); | ||
354 | return virt_to_page(pgd_page_vaddr(pgd)); | ||
355 | } | ||
356 | #endif | ||
357 | |||
358 | struct page *pud_page(pud_t pud) | ||
359 | { | ||
360 | if (pud_huge(pud)) | ||
361 | return pte_page(pud_pte(pud)); | ||
362 | return virt_to_page(pud_page_vaddr(pud)); | ||
363 | } | ||
364 | |||
355 | /* | 365 | /* |
356 | * For hugepage we have pfn in the pmd, we use PTE_RPN_SHIFT bits for flags | 366 | * For hugepage we have pfn in the pmd, we use PTE_RPN_SHIFT bits for flags |
357 | * For PTE page, we have a PTE_FRAG_SIZE (4K) aligned virtual address. | 367 | * For PTE page, we have a PTE_FRAG_SIZE (4K) aligned virtual address. |
358 | */ | 368 | */ |
359 | struct page *pmd_page(pmd_t pmd) | 369 | struct page *pmd_page(pmd_t pmd) |
360 | { | 370 | { |
361 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 371 | if (pmd_trans_huge(pmd) || pmd_huge(pmd)) |
362 | if (pmd_trans_huge(pmd)) | ||
363 | return pfn_to_page(pmd_pfn(pmd)); | 372 | return pfn_to_page(pmd_pfn(pmd)); |
364 | #endif | ||
365 | return virt_to_page(pmd_page_vaddr(pmd)); | 373 | return virt_to_page(pmd_page_vaddr(pmd)); |
366 | } | 374 | } |
367 | 375 | ||
@@ -731,29 +739,15 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, | |||
731 | void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, | 739 | void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, |
732 | pmd_t *pmdp, unsigned long old_pmd) | 740 | pmd_t *pmdp, unsigned long old_pmd) |
733 | { | 741 | { |
734 | int ssize, i; | 742 | int ssize; |
735 | unsigned long s_addr; | 743 | unsigned int psize; |
736 | int max_hpte_count; | 744 | unsigned long vsid; |
737 | unsigned int psize, valid; | 745 | unsigned long flags = 0; |
738 | unsigned char *hpte_slot_array; | 746 | const struct cpumask *tmp; |
739 | unsigned long hidx, vpn, vsid, hash, shift, slot; | ||
740 | |||
741 | /* | ||
742 | * Flush all the hptes mapping this hugepage | ||
743 | */ | ||
744 | s_addr = addr & HPAGE_PMD_MASK; | ||
745 | hpte_slot_array = get_hpte_slot_array(pmdp); | ||
746 | /* | ||
747 | * IF we try to do a HUGE PTE update after a withdraw is done. | ||
748 | * we will find the below NULL. This happens when we do | ||
749 | * split_huge_page_pmd | ||
750 | */ | ||
751 | if (!hpte_slot_array) | ||
752 | return; | ||
753 | 747 | ||
754 | /* get the base page size,vsid and segment size */ | 748 | /* get the base page size,vsid and segment size */ |
755 | #ifdef CONFIG_DEBUG_VM | 749 | #ifdef CONFIG_DEBUG_VM |
756 | psize = get_slice_psize(mm, s_addr); | 750 | psize = get_slice_psize(mm, addr); |
757 | BUG_ON(psize == MMU_PAGE_16M); | 751 | BUG_ON(psize == MMU_PAGE_16M); |
758 | #endif | 752 | #endif |
759 | if (old_pmd & _PAGE_COMBO) | 753 | if (old_pmd & _PAGE_COMBO) |
@@ -761,46 +755,20 @@ void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, | |||
761 | else | 755 | else |
762 | psize = MMU_PAGE_64K; | 756 | psize = MMU_PAGE_64K; |
763 | 757 | ||
764 | if (!is_kernel_addr(s_addr)) { | 758 | if (!is_kernel_addr(addr)) { |
765 | ssize = user_segment_size(s_addr); | 759 | ssize = user_segment_size(addr); |
766 | vsid = get_vsid(mm->context.id, s_addr, ssize); | 760 | vsid = get_vsid(mm->context.id, addr, ssize); |
767 | WARN_ON(vsid == 0); | 761 | WARN_ON(vsid == 0); |
768 | } else { | 762 | } else { |
769 | vsid = get_kernel_vsid(s_addr, mmu_kernel_ssize); | 763 | vsid = get_kernel_vsid(addr, mmu_kernel_ssize); |
770 | ssize = mmu_kernel_ssize; | 764 | ssize = mmu_kernel_ssize; |
771 | } | 765 | } |
772 | 766 | ||
773 | if (ppc_md.hugepage_invalidate) | 767 | tmp = cpumask_of(smp_processor_id()); |
774 | return ppc_md.hugepage_invalidate(vsid, s_addr, | 768 | if (cpumask_equal(mm_cpumask(mm), tmp)) |
775 | hpte_slot_array, | 769 | flags |= HPTE_LOCAL_UPDATE; |
776 | psize, ssize); | 770 | |
777 | /* | 771 | return flush_hash_hugepage(vsid, addr, pmdp, psize, ssize, flags); |
778 | * No bluk hpte removal support, invalidate each entry | ||
779 | */ | ||
780 | shift = mmu_psize_defs[psize].shift; | ||
781 | max_hpte_count = HPAGE_PMD_SIZE >> shift; | ||
782 | for (i = 0; i < max_hpte_count; i++) { | ||
783 | /* | ||
784 | * 8 bits per each hpte entries | ||
785 | * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit] | ||
786 | */ | ||
787 | valid = hpte_valid(hpte_slot_array, i); | ||
788 | if (!valid) | ||
789 | continue; | ||
790 | hidx = hpte_hash_index(hpte_slot_array, i); | ||
791 | |||
792 | /* get the vpn */ | ||
793 | addr = s_addr + (i * (1ul << shift)); | ||
794 | vpn = hpt_vpn(addr, vsid, ssize); | ||
795 | hash = hpt_hash(vpn, shift, ssize); | ||
796 | if (hidx & _PTEIDX_SECONDARY) | ||
797 | hash = ~hash; | ||
798 | |||
799 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
800 | slot += hidx & _PTEIDX_GROUP_IX; | ||
801 | ppc_md.hpte_invalidate(slot, vpn, psize, | ||
802 | MMU_PAGE_16M, ssize, 0); | ||
803 | } | ||
804 | } | 772 | } |
805 | 773 | ||
806 | static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot) | 774 | static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot) |