18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef __ASM_GENERIC_PGALLOC_H 38c2ecf20Sopenharmony_ci#define __ASM_GENERIC_PGALLOC_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define GFP_PGTABLE_KERNEL (GFP_KERNEL | __GFP_ZERO) 88c2ecf20Sopenharmony_ci#define GFP_PGTABLE_USER (GFP_PGTABLE_KERNEL | __GFP_ACCOUNT) 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/** 118c2ecf20Sopenharmony_ci * __pte_alloc_one_kernel - allocate a page for PTE-level kernel page table 128c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This function is intended for architectures that need 158c2ecf20Sopenharmony_ci * anything beyond simple page allocation. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Return: pointer to the allocated memory or %NULL on error 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistatic inline pte_t *__pte_alloc_one_kernel(struct mm_struct *mm) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci return (pte_t *)__get_free_page(GFP_PGTABLE_KERNEL); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL 258c2ecf20Sopenharmony_ci/** 268c2ecf20Sopenharmony_ci * pte_alloc_one_kernel - allocate a page for PTE-level kernel page table 278c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Return: pointer to the allocated memory or %NULL on error 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci return __pte_alloc_one_kernel(mm); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/** 388c2ecf20Sopenharmony_ci * pte_free_kernel - free PTE-level kernel page table page 398c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 408c2ecf20Sopenharmony_ci * @pte: pointer to the memory containing the page table 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci free_page((unsigned long)pte); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * __pte_alloc_one - allocate a page for PTE-level user page table 498c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 508c2ecf20Sopenharmony_ci * @gfp: GFP flags to use for the allocation 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * Allocates a page and runs the pgtable_pte_page_ctor(). 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * This function is intended for architectures that need 558c2ecf20Sopenharmony_ci * anything beyond simple page allocation or must have custom GFP flags. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Return: `struct page` initialized as page table or %NULL on error 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistatic inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct page *pte; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci pte = alloc_page(gfp); 648c2ecf20Sopenharmony_ci if (!pte) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci if (!pgtable_pte_page_ctor(pte)) { 678c2ecf20Sopenharmony_ci __free_page(pte); 688c2ecf20Sopenharmony_ci return NULL; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return pte; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PTE_ALLOC_ONE 758c2ecf20Sopenharmony_ci/** 768c2ecf20Sopenharmony_ci * pte_alloc_one - allocate a page for PTE-level user page table 778c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * Allocates a page and runs the pgtable_pte_page_ctor(). 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Return: `struct page` initialized as page table or %NULL on error 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic inline pgtable_t pte_alloc_one(struct mm_struct *mm) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return __pte_alloc_one(mm, GFP_PGTABLE_USER); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci#endif 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Should really implement gc for free page table pages. This could be 918c2ecf20Sopenharmony_ci * done with a reference count in struct page. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * pte_free - free PTE-level user page table page 968c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 978c2ecf20Sopenharmony_ci * @pte_page: the `struct page` representing the page table 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic inline void pte_free(struct mm_struct *mm, struct page *pte_page) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci pgtable_pte_page_dtor(pte_page); 1028c2ecf20Sopenharmony_ci __free_page(pte_page); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMD_ALLOC_ONE 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * pmd_alloc_one - allocate a page for PMD-level page table 1118c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Allocates a page and runs the pgtable_pmd_page_ctor(). 1148c2ecf20Sopenharmony_ci * Allocations use %GFP_PGTABLE_USER in user context and 1158c2ecf20Sopenharmony_ci * %GFP_PGTABLE_KERNEL in kernel context. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Return: pointer to the allocated memory or %NULL on error 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct page *page; 1228c2ecf20Sopenharmony_ci gfp_t gfp = GFP_PGTABLE_USER; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (mm == &init_mm) 1258c2ecf20Sopenharmony_ci gfp = GFP_PGTABLE_KERNEL; 1268c2ecf20Sopenharmony_ci page = alloc_pages(gfp, 0); 1278c2ecf20Sopenharmony_ci if (!page) 1288c2ecf20Sopenharmony_ci return NULL; 1298c2ecf20Sopenharmony_ci if (!pgtable_pmd_page_ctor(page)) { 1308c2ecf20Sopenharmony_ci __free_pages(page, 0); 1318c2ecf20Sopenharmony_ci return NULL; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci return (pmd_t *)page_address(page); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci#endif 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PMD_FREE 1388c2ecf20Sopenharmony_cistatic inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); 1418c2ecf20Sopenharmony_ci pgtable_pmd_page_dtor(virt_to_page(pmd)); 1428c2ecf20Sopenharmony_ci free_page((unsigned long)pmd); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci#endif 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#endif /* CONFIG_PGTABLE_LEVELS > 2 */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PUD_ALLOC_ONE 1518c2ecf20Sopenharmony_ci/** 1528c2ecf20Sopenharmony_ci * pud_alloc_one - allocate a page for PUD-level page table 1538c2ecf20Sopenharmony_ci * @mm: the mm_struct of the current context 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Allocates a page using %GFP_PGTABLE_USER for user context and 1568c2ecf20Sopenharmony_ci * %GFP_PGTABLE_KERNEL for kernel context. 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * Return: pointer to the allocated memory or %NULL on error 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci gfp_t gfp = GFP_PGTABLE_USER; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (mm == &init_mm) 1658c2ecf20Sopenharmony_ci gfp = GFP_PGTABLE_KERNEL; 1668c2ecf20Sopenharmony_ci return (pud_t *)get_zeroed_page(gfp); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci#endif 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline void pud_free(struct mm_struct *mm, pud_t *pud) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); 1738c2ecf20Sopenharmony_ci free_page((unsigned long)pud); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#endif /* CONFIG_PGTABLE_LEVELS > 3 */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_PGD_FREE 1798c2ecf20Sopenharmony_cistatic inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci free_page((unsigned long)pgd); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci#endif 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#endif /* CONFIG_MMU */ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#endif /* __ASM_GENERIC_PGALLOC_H */ 188