diff options
Diffstat (limited to 'arch/powerpc/mm/hugetlbpage.c')
-rw-r--r-- | arch/powerpc/mm/hugetlbpage.c | 59 |
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 | 132 | static 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); |
136 | static inline | 136 | else |
137 | pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate) | 137 | return (pud_t *) pgd; |
138 | } | ||
139 | static 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 | } | ||
147 | static 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 | } |
144 | static inline | 154 | static pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr, |
145 | pmd_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 | ||