18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_PGALLOC_H 38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_PGALLOC_H 48c2ecf20Sopenharmony_ci/* 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 98c2ecf20Sopenharmony_ci#include <linux/kmemleak.h> 108c2ecf20Sopenharmony_ci#include <linux/percpu.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct vmemmap_backing { 138c2ecf20Sopenharmony_ci struct vmemmap_backing *list; 148c2ecf20Sopenharmony_ci unsigned long phys; 158c2ecf20Sopenharmony_ci unsigned long virt_addr; 168c2ecf20Sopenharmony_ci}; 178c2ecf20Sopenharmony_ciextern struct vmemmap_backing *vmemmap_list; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciextern pmd_t *pmd_fragment_alloc(struct mm_struct *, unsigned long); 208c2ecf20Sopenharmony_ciextern void pmd_fragment_free(unsigned long *); 218c2ecf20Sopenharmony_ciextern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift); 228c2ecf20Sopenharmony_ciextern void __tlb_remove_table(void *_table); 238c2ecf20Sopenharmony_civoid pte_frag_destroy(void *pte_frag); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic inline pgd_t *radix__pgd_alloc(struct mm_struct *mm) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 288c2ecf20Sopenharmony_ci return (pgd_t *)__get_free_page(pgtable_gfp_flags(mm, PGALLOC_GFP)); 298c2ecf20Sopenharmony_ci#else 308c2ecf20Sopenharmony_ci struct page *page; 318c2ecf20Sopenharmony_ci page = alloc_pages(pgtable_gfp_flags(mm, PGALLOC_GFP | __GFP_RETRY_MAYFAIL), 328c2ecf20Sopenharmony_ci 4); 338c2ecf20Sopenharmony_ci if (!page) 348c2ecf20Sopenharmony_ci return NULL; 358c2ecf20Sopenharmony_ci return (pgd_t *) page_address(page); 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline void radix__pgd_free(struct mm_struct *mm, pgd_t *pgd) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 428c2ecf20Sopenharmony_ci free_page((unsigned long)pgd); 438c2ecf20Sopenharmony_ci#else 448c2ecf20Sopenharmony_ci free_pages((unsigned long)pgd, 4); 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline pgd_t *pgd_alloc(struct mm_struct *mm) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci pgd_t *pgd; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (radix_enabled()) 538c2ecf20Sopenharmony_ci return radix__pgd_alloc(mm); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci pgd = kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), 568c2ecf20Sopenharmony_ci pgtable_gfp_flags(mm, GFP_KERNEL)); 578c2ecf20Sopenharmony_ci if (unlikely(!pgd)) 588c2ecf20Sopenharmony_ci return pgd; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * Don't scan the PGD for pointers, it contains references to PUDs but 628c2ecf20Sopenharmony_ci * those references are not full pointers and so can't be recognised by 638c2ecf20Sopenharmony_ci * kmemleak. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci kmemleak_no_scan(pgd); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * With hugetlb, we don't clear the second half of the page table. 698c2ecf20Sopenharmony_ci * If we share the same slab cache with the pmd or pud level table, 708c2ecf20Sopenharmony_ci * we need to make sure we zero out the full table on alloc. 718c2ecf20Sopenharmony_ci * With 4K we don't store slot in the second half. Hence we don't 728c2ecf20Sopenharmony_ci * need to do this for 4k. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_PPC_64K_PAGES) && \ 758c2ecf20Sopenharmony_ci (H_PGD_INDEX_SIZE == H_PUD_CACHE_INDEX) 768c2ecf20Sopenharmony_ci memset(pgd, 0, PGD_TABLE_SIZE); 778c2ecf20Sopenharmony_ci#endif 788c2ecf20Sopenharmony_ci return pgd; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci if (radix_enabled()) 848c2ecf20Sopenharmony_ci return radix__pgd_free(mm, pgd); 858c2ecf20Sopenharmony_ci kmem_cache_free(PGT_CACHE(PGD_INDEX_SIZE), pgd); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic inline void p4d_populate(struct mm_struct *mm, p4d_t *pgd, pud_t *pud) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci *pgd = __p4d(__pgtable_ptr_val(pud) | PGD_VAL_BITS); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci pud_t *pud; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pud = kmem_cache_alloc(PGT_CACHE(PUD_CACHE_INDEX), 988c2ecf20Sopenharmony_ci pgtable_gfp_flags(mm, GFP_KERNEL)); 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Tell kmemleak to ignore the PUD, that means don't scan it for 1018c2ecf20Sopenharmony_ci * pointers and don't consider it a leak. PUDs are typically only 1028c2ecf20Sopenharmony_ci * referred to by their PGD, but kmemleak is not able to recognise those 1038c2ecf20Sopenharmony_ci * as pointers, leading to false leak reports. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci kmemleak_ignore(pud); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return pud; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic inline void __pud_free(pud_t *pud) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct page *page = virt_to_page(pud); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * Early pud pages allocated via memblock allocator 1168c2ecf20Sopenharmony_ci * can't be directly freed to slab 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci if (PageReserved(page)) 1198c2ecf20Sopenharmony_ci free_reserved_page(page); 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci kmem_cache_free(PGT_CACHE(PUD_CACHE_INDEX), pud); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline void pud_free(struct mm_struct *mm, pud_t *pud) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci return __pud_free(pud); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci *pud = __pud(__pgtable_ptr_val(pmd) | PUD_VAL_BITS); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, 1358c2ecf20Sopenharmony_ci unsigned long address) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci pgtable_free_tlb(tlb, pud, PUD_INDEX); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci return pmd_fragment_alloc(mm, addr); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci pmd_fragment_free((unsigned long *)pmd); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, 1518c2ecf20Sopenharmony_ci unsigned long address) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci return pgtable_free_tlb(tlb, pmd, PMD_INDEX); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, 1578c2ecf20Sopenharmony_ci pte_t *pte) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci *pmd = __pmd(__pgtable_ptr_val(pte) | PMD_VAL_BITS); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, 1638c2ecf20Sopenharmony_ci pgtable_t pte_page) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci *pmd = __pmd(__pgtable_ptr_val(pte_page) | PMD_VAL_BITS); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table, 1698c2ecf20Sopenharmony_ci unsigned long address) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci pgtable_free_tlb(tlb, table, PTE_INDEX); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciextern atomic_long_t direct_pages_count[MMU_PAGE_COUNT]; 1758c2ecf20Sopenharmony_cistatic inline void update_page_count(int psize, long count) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PROC_FS)) 1788c2ecf20Sopenharmony_ci atomic_long_add(count, &direct_pages_count[psize]); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_64_PGALLOC_H */ 182