aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.ibm.com>2019-05-14 02:03:00 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2019-07-04 10:43:50 -0400
commitd6eacedd1f0ebf00bdf1c77715d194f7c1036fd4 (patch)
treebf977356cbeb533eb3a4e2d73d4923eba6188be3 /arch
parent259a948c4ba1829ae4a3c31bb6e40ad458a21254 (diff)
powerpc/book3s: Use config independent helpers for page table walk
Even when we have HugeTLB and THP disabled, kernel linear map can still be mapped with hugepages. This is only an issue with radix translation because hash MMU doesn't map kernel linear range in linux page table and other kernel map areas are not mapped using hugepage. Add config independent helpers and put WARN_ON() when we don't expect things to be mapped via hugepages. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h21
-rw-r--r--arch/powerpc/include/asm/pgtable.h24
-rw-r--r--arch/powerpc/include/asm/pte-walk.h28
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_radix.c12
-rw-r--r--arch/powerpc/mm/book3s64/radix_pgtable.c10
-rw-r--r--arch/powerpc/mm/pgtable.c16
-rw-r--r--arch/powerpc/mm/pgtable_64.c12
-rw-r--r--arch/powerpc/mm/ptdump/ptdump.c6
-rw-r--r--arch/powerpc/xmon/xmon.c6
9 files changed, 102 insertions, 33 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index beabb099c040..62e6ea0a7650 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1350,5 +1350,26 @@ static inline bool is_pte_rw_upgrade(unsigned long old_val, unsigned long new_va
1350 return false; 1350 return false;
1351} 1351}
1352 1352
1353/*
1354 * Like pmd_huge() and pmd_large(), but works regardless of config options
1355 */
1356#define pmd_is_leaf pmd_is_leaf
1357static inline bool pmd_is_leaf(pmd_t pmd)
1358{
1359 return !!(pmd_raw(pmd) & cpu_to_be64(_PAGE_PTE));
1360}
1361
1362#define pud_is_leaf pud_is_leaf
1363static inline bool pud_is_leaf(pud_t pud)
1364{
1365 return !!(pud_raw(pud) & cpu_to_be64(_PAGE_PTE));
1366}
1367
1368#define pgd_is_leaf pgd_is_leaf
1369static inline bool pgd_is_leaf(pgd_t pgd)
1370{
1371 return !!(pgd_raw(pgd) & cpu_to_be64(_PAGE_PTE));
1372}
1373
1353#endif /* __ASSEMBLY__ */ 1374#endif /* __ASSEMBLY__ */
1354#endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */ 1375#endif /* _ASM_POWERPC_BOOK3S_64_PGTABLE_H_ */
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 3f53be60fb01..bf7d771f342e 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -140,6 +140,30 @@ static inline void pte_frag_set(mm_context_t *ctx, void *p)
140} 140}
141#endif 141#endif
142 142
143#ifndef pmd_is_leaf
144#define pmd_is_leaf pmd_is_leaf
145static inline bool pmd_is_leaf(pmd_t pmd)
146{
147 return false;
148}
149#endif
150
151#ifndef pud_is_leaf
152#define pud_is_leaf pud_is_leaf
153static inline bool pud_is_leaf(pud_t pud)
154{
155 return false;
156}
157#endif
158
159#ifndef pgd_is_leaf
160#define pgd_is_leaf pgd_is_leaf
161static inline bool pgd_is_leaf(pgd_t pgd)
162{
163 return false;
164}
165#endif
166
143#endif /* __ASSEMBLY__ */ 167#endif /* __ASSEMBLY__ */
144 168
145#endif /* _ASM_POWERPC_PGTABLE_H */ 169#endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/arch/powerpc/include/asm/pte-walk.h b/arch/powerpc/include/asm/pte-walk.h
index 2d633e9d686c..33fa5dd8ee6a 100644
--- a/arch/powerpc/include/asm/pte-walk.h
+++ b/arch/powerpc/include/asm/pte-walk.h
@@ -10,8 +10,20 @@ extern pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
10static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea, 10static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea,
11 bool *is_thp, unsigned *hshift) 11 bool *is_thp, unsigned *hshift)
12{ 12{
13 pte_t *pte;
14
13 VM_WARN(!arch_irqs_disabled(), "%s called with irq enabled\n", __func__); 15 VM_WARN(!arch_irqs_disabled(), "%s called with irq enabled\n", __func__);
14 return __find_linux_pte(pgdir, ea, is_thp, hshift); 16 pte = __find_linux_pte(pgdir, ea, is_thp, hshift);
17
18#if defined(CONFIG_DEBUG_VM) && \
19 !(defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE))
20 /*
21 * We should not find huge page if these configs are not enabled.
22 */
23 if (hshift)
24 WARN_ON(*hshift);
25#endif
26 return pte;
15} 27}
16 28
17static inline pte_t *find_init_mm_pte(unsigned long ea, unsigned *hshift) 29static inline pte_t *find_init_mm_pte(unsigned long ea, unsigned *hshift)
@@ -26,10 +38,22 @@ static inline pte_t *find_init_mm_pte(unsigned long ea, unsigned *hshift)
26static inline pte_t *find_current_mm_pte(pgd_t *pgdir, unsigned long ea, 38static inline pte_t *find_current_mm_pte(pgd_t *pgdir, unsigned long ea,
27 bool *is_thp, unsigned *hshift) 39 bool *is_thp, unsigned *hshift)
28{ 40{
41 pte_t *pte;
42
29 VM_WARN(!arch_irqs_disabled(), "%s called with irq enabled\n", __func__); 43 VM_WARN(!arch_irqs_disabled(), "%s called with irq enabled\n", __func__);
30 VM_WARN(pgdir != current->mm->pgd, 44 VM_WARN(pgdir != current->mm->pgd,
31 "%s lock less page table lookup called on wrong mm\n", __func__); 45 "%s lock less page table lookup called on wrong mm\n", __func__);
32 return __find_linux_pte(pgdir, ea, is_thp, hshift); 46 pte = __find_linux_pte(pgdir, ea, is_thp, hshift);
47
48#if defined(CONFIG_DEBUG_VM) && \
49 !(defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE))
50 /*
51 * We should not find huge page if these configs are not enabled.
52 */
53 if (hshift)
54 WARN_ON(*hshift);
55#endif
56 return pte;
33} 57}
34 58
35#endif /* _ASM_POWERPC_PTE_WALK_H */ 59#endif /* _ASM_POWERPC_PTE_WALK_H */
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
index f55ef071883f..91efee7f0329 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -363,12 +363,6 @@ static void kvmppc_pte_free(pte_t *ptep)
363 kmem_cache_free(kvm_pte_cache, ptep); 363 kmem_cache_free(kvm_pte_cache, ptep);
364} 364}
365 365
366/* Like pmd_huge() and pmd_large(), but works regardless of config options */
367static inline int pmd_is_leaf(pmd_t pmd)
368{
369 return !!(pmd_val(pmd) & _PAGE_PTE);
370}
371
372static pmd_t *kvmppc_pmd_alloc(void) 366static pmd_t *kvmppc_pmd_alloc(void)
373{ 367{
374 return kmem_cache_alloc(kvm_pmd_cache, GFP_KERNEL); 368 return kmem_cache_alloc(kvm_pmd_cache, GFP_KERNEL);
@@ -489,7 +483,7 @@ static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud,
489 for (iu = 0; iu < PTRS_PER_PUD; ++iu, ++p) { 483 for (iu = 0; iu < PTRS_PER_PUD; ++iu, ++p) {
490 if (!pud_present(*p)) 484 if (!pud_present(*p))
491 continue; 485 continue;
492 if (pud_huge(*p)) { 486 if (pud_is_leaf(*p)) {
493 pud_clear(p); 487 pud_clear(p);
494 } else { 488 } else {
495 pmd_t *pmd; 489 pmd_t *pmd;
@@ -588,7 +582,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
588 new_pud = pud_alloc_one(kvm->mm, gpa); 582 new_pud = pud_alloc_one(kvm->mm, gpa);
589 583
590 pmd = NULL; 584 pmd = NULL;
591 if (pud && pud_present(*pud) && !pud_huge(*pud)) 585 if (pud && pud_present(*pud) && !pud_is_leaf(*pud))
592 pmd = pmd_offset(pud, gpa); 586 pmd = pmd_offset(pud, gpa);
593 else if (level <= 1) 587 else if (level <= 1)
594 new_pmd = kvmppc_pmd_alloc(); 588 new_pmd = kvmppc_pmd_alloc();
@@ -611,7 +605,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte,
611 new_pud = NULL; 605 new_pud = NULL;
612 } 606 }
613 pud = pud_offset(pgd, gpa); 607 pud = pud_offset(pgd, gpa);
614 if (pud_huge(*pud)) { 608 if (pud_is_leaf(*pud)) {
615 unsigned long hgpa = gpa & PUD_MASK; 609 unsigned long hgpa = gpa & PUD_MASK;
616 610
617 /* Check if we raced and someone else has set the same thing */ 611 /* Check if we raced and someone else has set the same thing */
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index b573fa024b32..e92c6472a20c 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -203,14 +203,14 @@ void radix__change_memory_range(unsigned long start, unsigned long end,
203 pudp = pud_alloc(&init_mm, pgdp, idx); 203 pudp = pud_alloc(&init_mm, pgdp, idx);
204 if (!pudp) 204 if (!pudp)
205 continue; 205 continue;
206 if (pud_huge(*pudp)) { 206 if (pud_is_leaf(*pudp)) {
207 ptep = (pte_t *)pudp; 207 ptep = (pte_t *)pudp;
208 goto update_the_pte; 208 goto update_the_pte;
209 } 209 }
210 pmdp = pmd_alloc(&init_mm, pudp, idx); 210 pmdp = pmd_alloc(&init_mm, pudp, idx);
211 if (!pmdp) 211 if (!pmdp)
212 continue; 212 continue;
213 if (pmd_huge(*pmdp)) { 213 if (pmd_is_leaf(*pmdp)) {
214 ptep = pmdp_ptep(pmdp); 214 ptep = pmdp_ptep(pmdp);
215 goto update_the_pte; 215 goto update_the_pte;
216 } 216 }
@@ -835,7 +835,7 @@ static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,
835 if (!pmd_present(*pmd)) 835 if (!pmd_present(*pmd))
836 continue; 836 continue;
837 837
838 if (pmd_huge(*pmd)) { 838 if (pmd_is_leaf(*pmd)) {
839 split_kernel_mapping(addr, end, PMD_SIZE, (pte_t *)pmd); 839 split_kernel_mapping(addr, end, PMD_SIZE, (pte_t *)pmd);
840 continue; 840 continue;
841 } 841 }
@@ -860,7 +860,7 @@ static void remove_pud_table(pud_t *pud_start, unsigned long addr,
860 if (!pud_present(*pud)) 860 if (!pud_present(*pud))
861 continue; 861 continue;
862 862
863 if (pud_huge(*pud)) { 863 if (pud_is_leaf(*pud)) {
864 split_kernel_mapping(addr, end, PUD_SIZE, (pte_t *)pud); 864 split_kernel_mapping(addr, end, PUD_SIZE, (pte_t *)pud);
865 continue; 865 continue;
866 } 866 }
@@ -886,7 +886,7 @@ static void __meminit remove_pagetable(unsigned long start, unsigned long end)
886 if (!pgd_present(*pgd)) 886 if (!pgd_present(*pgd))
887 continue; 887 continue;
888 888
889 if (pgd_huge(*pgd)) { 889 if (pgd_is_leaf(*pgd)) {
890 split_kernel_mapping(addr, end, PGDIR_SIZE, (pte_t *)pgd); 890 split_kernel_mapping(addr, end, PGDIR_SIZE, (pte_t *)pgd);
891 continue; 891 continue;
892 } 892 }
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 533fc6fa6726..2029e585e5c3 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -340,10 +340,11 @@ pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
340 if (pgd_none(pgd)) 340 if (pgd_none(pgd))
341 return NULL; 341 return NULL;
342 342
343 if (pgd_huge(pgd)) { 343 if (pgd_is_leaf(pgd)) {
344 ret_pte = (pte_t *)pgdp; 344 ret_pte = (pte_t *)pgdp;
345 goto out; 345 goto out;
346 } 346 }
347
347 if (is_hugepd(__hugepd(pgd_val(pgd)))) { 348 if (is_hugepd(__hugepd(pgd_val(pgd)))) {
348 hpdp = (hugepd_t *)&pgd; 349 hpdp = (hugepd_t *)&pgd;
349 goto out_huge; 350 goto out_huge;
@@ -361,14 +362,16 @@ pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
361 if (pud_none(pud)) 362 if (pud_none(pud))
362 return NULL; 363 return NULL;
363 364
364 if (pud_huge(pud)) { 365 if (pud_is_leaf(pud)) {
365 ret_pte = (pte_t *)pudp; 366 ret_pte = (pte_t *)pudp;
366 goto out; 367 goto out;
367 } 368 }
369
368 if (is_hugepd(__hugepd(pud_val(pud)))) { 370 if (is_hugepd(__hugepd(pud_val(pud)))) {
369 hpdp = (hugepd_t *)&pud; 371 hpdp = (hugepd_t *)&pud;
370 goto out_huge; 372 goto out_huge;
371 } 373 }
374
372 pdshift = PMD_SHIFT; 375 pdshift = PMD_SHIFT;
373 pmdp = pmd_offset(&pud, ea); 376 pmdp = pmd_offset(&pud, ea);
374 pmd = READ_ONCE(*pmdp); 377 pmd = READ_ONCE(*pmdp);
@@ -397,15 +400,12 @@ pte_t *__find_linux_pte(pgd_t *pgdir, unsigned long ea,
397 ret_pte = (pte_t *)pmdp; 400 ret_pte = (pte_t *)pmdp;
398 goto out; 401 goto out;
399 } 402 }
400 /* 403
401 * pmd_large check below will handle the swap pmd pte 404 if (pmd_is_leaf(pmd)) {
402 * we need to do both the check because they are config
403 * dependent.
404 */
405 if (pmd_huge(pmd) || pmd_large(pmd)) {
406 ret_pte = (pte_t *)pmdp; 405 ret_pte = (pte_t *)pmdp;
407 goto out; 406 goto out;
408 } 407 }
408
409 if (is_hugepd(__hugepd(pmd_val(pmd)))) { 409 if (is_hugepd(__hugepd(pmd_val(pmd)))) {
410 hpdp = (hugepd_t *)&pmd; 410 hpdp = (hugepd_t *)&pmd;
411 goto out_huge; 411 goto out_huge;
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 63cd81130643..2892246a6fef 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -309,16 +309,20 @@ EXPORT_SYMBOL(__iounmap_at);
309/* 4 level page table */ 309/* 4 level page table */
310struct page *pgd_page(pgd_t pgd) 310struct page *pgd_page(pgd_t pgd)
311{ 311{
312 if (pgd_huge(pgd)) 312 if (pgd_is_leaf(pgd)) {
313 VM_WARN_ON(!pgd_huge(pgd));
313 return pte_page(pgd_pte(pgd)); 314 return pte_page(pgd_pte(pgd));
315 }
314 return virt_to_page(pgd_page_vaddr(pgd)); 316 return virt_to_page(pgd_page_vaddr(pgd));
315} 317}
316#endif 318#endif
317 319
318struct page *pud_page(pud_t pud) 320struct page *pud_page(pud_t pud)
319{ 321{
320 if (pud_huge(pud)) 322 if (pud_is_leaf(pud)) {
323 VM_WARN_ON(!pud_huge(pud));
321 return pte_page(pud_pte(pud)); 324 return pte_page(pud_pte(pud));
325 }
322 return virt_to_page(pud_page_vaddr(pud)); 326 return virt_to_page(pud_page_vaddr(pud));
323} 327}
324 328
@@ -328,8 +332,10 @@ struct page *pud_page(pud_t pud)
328 */ 332 */
329struct page *pmd_page(pmd_t pmd) 333struct page *pmd_page(pmd_t pmd)
330{ 334{
331 if (pmd_large(pmd) || pmd_huge(pmd) || pmd_devmap(pmd)) 335 if (pmd_is_leaf(pmd)) {
336 VM_WARN_ON(!(pmd_large(pmd) || pmd_huge(pmd) || pmd_devmap(pmd)));
332 return pte_page(pmd_pte(pmd)); 337 return pte_page(pmd_pte(pmd));
338 }
333 return virt_to_page(pmd_page_vaddr(pmd)); 339 return virt_to_page(pmd_page_vaddr(pmd));
334} 340}
335 341
diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c
index 646876d9da64..abe60d25b4e6 100644
--- a/arch/powerpc/mm/ptdump/ptdump.c
+++ b/arch/powerpc/mm/ptdump/ptdump.c
@@ -277,7 +277,7 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
277 277
278 for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { 278 for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
279 addr = start + i * PMD_SIZE; 279 addr = start + i * PMD_SIZE;
280 if (!pmd_none(*pmd) && !pmd_huge(*pmd)) 280 if (!pmd_none(*pmd) && !pmd_is_leaf(*pmd))
281 /* pmd exists */ 281 /* pmd exists */
282 walk_pte(st, pmd, addr); 282 walk_pte(st, pmd, addr);
283 else 283 else
@@ -293,7 +293,7 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
293 293
294 for (i = 0; i < PTRS_PER_PUD; i++, pud++) { 294 for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
295 addr = start + i * PUD_SIZE; 295 addr = start + i * PUD_SIZE;
296 if (!pud_none(*pud) && !pud_huge(*pud)) 296 if (!pud_none(*pud) && !pud_is_leaf(*pud))
297 /* pud exists */ 297 /* pud exists */
298 walk_pmd(st, pud, addr); 298 walk_pmd(st, pud, addr);
299 else 299 else
@@ -314,7 +314,7 @@ static void walk_pagetables(struct pg_state *st)
314 * the hash pagetable. 314 * the hash pagetable.
315 */ 315 */
316 for (i = 0; i < PTRS_PER_PGD; i++, pgd++, addr += PGDIR_SIZE) { 316 for (i = 0; i < PTRS_PER_PGD; i++, pgd++, addr += PGDIR_SIZE) {
317 if (!pgd_none(*pgd) && !pgd_huge(*pgd)) 317 if (!pgd_none(*pgd) && !pgd_is_leaf(*pgd))
318 /* pgd exists */ 318 /* pgd exists */
319 walk_pud(st, pgd, addr); 319 walk_pud(st, pgd, addr);
320 else 320 else
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index f879e9fe9733..2ec20a5bb556 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -3098,7 +3098,7 @@ static void show_pte(unsigned long addr)
3098 3098
3099 printf("pgd @ 0x%px\n", pgdir); 3099 printf("pgd @ 0x%px\n", pgdir);
3100 3100
3101 if (pgd_huge(*pgdp)) { 3101 if (pgd_is_leaf(*pgdp)) {
3102 format_pte(pgdp, pgd_val(*pgdp)); 3102 format_pte(pgdp, pgd_val(*pgdp));
3103 return; 3103 return;
3104 } 3104 }
@@ -3111,7 +3111,7 @@ static void show_pte(unsigned long addr)
3111 return; 3111 return;
3112 } 3112 }
3113 3113
3114 if (pud_huge(*pudp)) { 3114 if (pud_is_leaf(*pudp)) {
3115 format_pte(pudp, pud_val(*pudp)); 3115 format_pte(pudp, pud_val(*pudp));
3116 return; 3116 return;
3117 } 3117 }
@@ -3125,7 +3125,7 @@ static void show_pte(unsigned long addr)
3125 return; 3125 return;
3126 } 3126 }
3127 3127
3128 if (pmd_huge(*pmdp)) { 3128 if (pmd_is_leaf(*pmdp)) {
3129 format_pte(pmdp, pmd_val(*pmdp)); 3129 format_pte(pmdp, pmd_val(*pmdp));
3130 return; 3130 return;
3131 } 3131 }