aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Gibson <dwg@au1.ibm.com>2008-09-04 21:49:54 -0400
committerPaul Mackerras <paulus@samba.org>2008-09-15 14:08:47 -0400
commit0b26425ce101a7c1b1ad4ec353d4e860223d9fc4 (patch)
treeea179429b60efda0e4ce60ca41ad974f921c5fbb
parent150c6c8fecf6daaf68c2987ba2b6b259baefdff2 (diff)
powerpc: Clean up hugepage pagetable allocation for powerpc with 16G pages
There is a small bug in the handling of 16G hugepages recently added to the kernel. This doesn't cause a crash or other user-visible problems, but it does mean that more levels of pagetable are allocated than makes sense for 16G pages. The hugepage pagetables for the 16G pages are allocated much lower in the pagetable tree than they should be, with the intervening levels allocated with full pmd and pud pages which will only ever have one entry filled in. This corrects this problem, at the same time cleaning up the handling of which level 64k versus 16M hugepage pagetables are allocated at. The new way of formatting the tests should be more robust against changes in pagetable structure, or any newly added hugepage sizes. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/mm/hugetlbpage.c59
1 files changed, 33 insertions, 26 deletions
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f1c2d55b4377..a117024ab8cd 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -128,29 +128,37 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
128 return 0; 128 return 0;
129} 129}
130 130
131/* Base page size affects how we walk hugetlb page tables */ 131
132#ifdef CONFIG_PPC_64K_PAGES 132static pud_t *hpud_offset(pgd_t *pgd, unsigned long addr, struct hstate *hstate)
133#define hpmd_offset(pud, addr, h) pmd_offset(pud, addr) 133{
134#define hpmd_alloc(mm, pud, addr, h) pmd_alloc(mm, pud, addr) 134 if (huge_page_shift(hstate) < PUD_SHIFT)
135#else 135 return pud_offset(pgd, addr);
136static inline 136 else
137pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate) 137 return (pud_t *) pgd;
138}
139static pud_t *hpud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long addr,
140 struct hstate *hstate)
138{ 141{
139 if (huge_page_shift(hstate) == PAGE_SHIFT_64K) 142 if (huge_page_shift(hstate) < PUD_SHIFT)
143 return pud_alloc(mm, pgd, addr);
144 else
145 return (pud_t *) pgd;
146}
147static pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate)
148{
149 if (huge_page_shift(hstate) < PMD_SHIFT)
140 return pmd_offset(pud, addr); 150 return pmd_offset(pud, addr);
141 else 151 else
142 return (pmd_t *) pud; 152 return (pmd_t *) pud;
143} 153}
144static inline 154static pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr,
145pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr, 155 struct hstate *hstate)
146 struct hstate *hstate)
147{ 156{
148 if (huge_page_shift(hstate) == PAGE_SHIFT_64K) 157 if (huge_page_shift(hstate) < PMD_SHIFT)
149 return pmd_alloc(mm, pud, addr); 158 return pmd_alloc(mm, pud, addr);
150 else 159 else
151 return (pmd_t *) pud; 160 return (pmd_t *) pud;
152} 161}
153#endif
154 162
155/* Build list of addresses of gigantic pages. This function is used in early 163/* Build list of addresses of gigantic pages. This function is used in early
156 * boot before the buddy or bootmem allocator is setup. 164 * boot before the buddy or bootmem allocator is setup.
@@ -204,7 +212,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
204 212
205 pg = pgd_offset(mm, addr); 213 pg = pgd_offset(mm, addr);
206 if (!pgd_none(*pg)) { 214 if (!pgd_none(*pg)) {
207 pu = pud_offset(pg, addr); 215 pu = hpud_offset(pg, addr, hstate);
208 if (!pud_none(*pu)) { 216 if (!pud_none(*pu)) {
209 pm = hpmd_offset(pu, addr, hstate); 217 pm = hpmd_offset(pu, addr, hstate);
210 if (!pmd_none(*pm)) 218 if (!pmd_none(*pm))
@@ -233,7 +241,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
233 addr &= hstate->mask; 241 addr &= hstate->mask;
234 242
235 pg = pgd_offset(mm, addr); 243 pg = pgd_offset(mm, addr);
236 pu = pud_alloc(mm, pg, addr); 244 pu = hpud_alloc(mm, pg, addr, hstate);
237 245
238 if (pu) { 246 if (pu) {
239 pm = hpmd_alloc(mm, pu, addr, hstate); 247 pm = hpmd_alloc(mm, pu, addr, hstate);
@@ -316,13 +324,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
316 pud = pud_offset(pgd, addr); 324 pud = pud_offset(pgd, addr);
317 do { 325 do {
318 next = pud_addr_end(addr, end); 326 next = pud_addr_end(addr, end);
319#ifdef CONFIG_PPC_64K_PAGES 327 if (shift < PMD_SHIFT) {
320 if (pud_none_or_clear_bad(pud))
321 continue;
322 hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling,
323 psize);
324#else
325 if (shift == PAGE_SHIFT_64K) {
326 if (pud_none_or_clear_bad(pud)) 328 if (pud_none_or_clear_bad(pud))
327 continue; 329 continue;
328 hugetlb_free_pmd_range(tlb, pud, addr, next, floor, 330 hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
@@ -332,7 +334,6 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
332 continue; 334 continue;
333 free_hugepte_range(tlb, (hugepd_t *)pud, psize); 335 free_hugepte_range(tlb, (hugepd_t *)pud, psize);
334 } 336 }
335#endif
336 } while (pud++, addr = next, addr != end); 337 } while (pud++, addr = next, addr != end);
337 338
338 start &= PGDIR_MASK; 339 start &= PGDIR_MASK;
@@ -422,9 +423,15 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
422 psize = get_slice_psize(tlb->mm, addr); 423 psize = get_slice_psize(tlb->mm, addr);
423 BUG_ON(!mmu_huge_psizes[psize]); 424 BUG_ON(!mmu_huge_psizes[psize]);
424 next = pgd_addr_end(addr, end); 425 next = pgd_addr_end(addr, end);
425 if (pgd_none_or_clear_bad(pgd)) 426 if (mmu_psize_to_shift(psize) < PUD_SHIFT) {
426 continue; 427 if (pgd_none_or_clear_bad(pgd))
427 hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling); 428 continue;
429 hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
430 } else {
431 if (pgd_none(*pgd))
432 continue;
433 free_hugepte_range(tlb, (hugepd_t *)pgd, psize);
434 }
428 } while (pgd++, addr = next, addr != end); 435 } while (pgd++, addr = next, addr != end);
429} 436}
430 437