162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_BOOK3S_64_PGALLOC_H
362306a36Sopenharmony_ci#define _ASM_POWERPC_BOOK3S_64_PGALLOC_H
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/cpumask.h>
962306a36Sopenharmony_ci#include <linux/kmemleak.h>
1062306a36Sopenharmony_ci#include <linux/percpu.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistruct vmemmap_backing {
1362306a36Sopenharmony_ci	struct vmemmap_backing *list;
1462306a36Sopenharmony_ci	unsigned long phys;
1562306a36Sopenharmony_ci	unsigned long virt_addr;
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ciextern struct vmemmap_backing *vmemmap_list;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciextern pmd_t *pmd_fragment_alloc(struct mm_struct *, unsigned long);
2062306a36Sopenharmony_ciextern void pmd_fragment_free(unsigned long *);
2162306a36Sopenharmony_ciextern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift);
2262306a36Sopenharmony_ciextern void __tlb_remove_table(void *_table);
2362306a36Sopenharmony_civoid pte_frag_destroy(void *pte_frag);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic inline pgd_t *radix__pgd_alloc(struct mm_struct *mm)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
2862306a36Sopenharmony_ci	return (pgd_t *)__get_free_page(pgtable_gfp_flags(mm, PGALLOC_GFP));
2962306a36Sopenharmony_ci#else
3062306a36Sopenharmony_ci	struct page *page;
3162306a36Sopenharmony_ci	page = alloc_pages(pgtable_gfp_flags(mm, PGALLOC_GFP | __GFP_RETRY_MAYFAIL),
3262306a36Sopenharmony_ci				4);
3362306a36Sopenharmony_ci	if (!page)
3462306a36Sopenharmony_ci		return NULL;
3562306a36Sopenharmony_ci	return (pgd_t *) page_address(page);
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic inline void radix__pgd_free(struct mm_struct *mm, pgd_t *pgd)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES
4262306a36Sopenharmony_ci	free_page((unsigned long)pgd);
4362306a36Sopenharmony_ci#else
4462306a36Sopenharmony_ci	free_pages((unsigned long)pgd, 4);
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline pgd_t *pgd_alloc(struct mm_struct *mm)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	pgd_t *pgd;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (radix_enabled())
5362306a36Sopenharmony_ci		return radix__pgd_alloc(mm);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	pgd = kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE),
5662306a36Sopenharmony_ci			       pgtable_gfp_flags(mm, GFP_KERNEL));
5762306a36Sopenharmony_ci	if (unlikely(!pgd))
5862306a36Sopenharmony_ci		return pgd;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/*
6162306a36Sopenharmony_ci	 * Don't scan the PGD for pointers, it contains references to PUDs but
6262306a36Sopenharmony_ci	 * those references are not full pointers and so can't be recognised by
6362306a36Sopenharmony_ci	 * kmemleak.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	kmemleak_no_scan(pgd);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/*
6862306a36Sopenharmony_ci	 * With hugetlb, we don't clear the second half of the page table.
6962306a36Sopenharmony_ci	 * If we share the same slab cache with the pmd or pud level table,
7062306a36Sopenharmony_ci	 * we need to make sure we zero out the full table on alloc.
7162306a36Sopenharmony_ci	 * With 4K we don't store slot in the second half. Hence we don't
7262306a36Sopenharmony_ci	 * need to do this for 4k.
7362306a36Sopenharmony_ci	 */
7462306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_PPC_64K_PAGES) && \
7562306a36Sopenharmony_ci	(H_PGD_INDEX_SIZE == H_PUD_CACHE_INDEX)
7662306a36Sopenharmony_ci	memset(pgd, 0, PGD_TABLE_SIZE);
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci	return pgd;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	if (radix_enabled())
8462306a36Sopenharmony_ci		return radix__pgd_free(mm, pgd);
8562306a36Sopenharmony_ci	kmem_cache_free(PGT_CACHE(PGD_INDEX_SIZE), pgd);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline void p4d_populate(struct mm_struct *mm, p4d_t *pgd, pud_t *pud)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	*pgd =  __p4d(__pgtable_ptr_val(pud) | PGD_VAL_BITS);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	pud_t *pud;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	pud = kmem_cache_alloc(PGT_CACHE(PUD_CACHE_INDEX),
9862306a36Sopenharmony_ci			       pgtable_gfp_flags(mm, GFP_KERNEL));
9962306a36Sopenharmony_ci	/*
10062306a36Sopenharmony_ci	 * Tell kmemleak to ignore the PUD, that means don't scan it for
10162306a36Sopenharmony_ci	 * pointers and don't consider it a leak. PUDs are typically only
10262306a36Sopenharmony_ci	 * referred to by their PGD, but kmemleak is not able to recognise those
10362306a36Sopenharmony_ci	 * as pointers, leading to false leak reports.
10462306a36Sopenharmony_ci	 */
10562306a36Sopenharmony_ci	kmemleak_ignore(pud);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return pud;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline void __pud_free(pud_t *pud)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct page *page = virt_to_page(pud);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * Early pud pages allocated via memblock allocator
11662306a36Sopenharmony_ci	 * can't be directly freed to slab. KFENCE pages have
11762306a36Sopenharmony_ci	 * both reserved and slab flags set so need to be freed
11862306a36Sopenharmony_ci	 * kmem_cache_free.
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	if (PageReserved(page) && !PageSlab(page))
12162306a36Sopenharmony_ci		free_reserved_page(page);
12262306a36Sopenharmony_ci	else
12362306a36Sopenharmony_ci		kmem_cache_free(PGT_CACHE(PUD_CACHE_INDEX), pud);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline void pud_free(struct mm_struct *mm, pud_t *pud)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return __pud_free(pud);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	*pud = __pud(__pgtable_ptr_val(pmd) | PUD_VAL_BITS);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
13762306a36Sopenharmony_ci				  unsigned long address)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	pgtable_free_tlb(tlb, pud, PUD_INDEX);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	return pmd_fragment_alloc(mm, addr);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	pmd_fragment_free((unsigned long *)pmd);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
15362306a36Sopenharmony_ci				  unsigned long address)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return pgtable_free_tlb(tlb, pmd, PMD_INDEX);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
15962306a36Sopenharmony_ci				       pte_t *pte)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	*pmd = __pmd(__pgtable_ptr_val(pte) | PMD_VAL_BITS);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
16562306a36Sopenharmony_ci				pgtable_t pte_page)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	*pmd = __pmd(__pgtable_ptr_val(pte_page) | PMD_VAL_BITS);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
17162306a36Sopenharmony_ci				  unsigned long address)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	pgtable_free_tlb(tlb, table, PTE_INDEX);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciextern atomic_long_t direct_pages_count[MMU_PAGE_COUNT];
17762306a36Sopenharmony_cistatic inline void update_page_count(int psize, long count)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PROC_FS))
18062306a36Sopenharmony_ci		atomic_long_add(count, &direct_pages_count[psize]);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#endif /* _ASM_POWERPC_BOOK3S_64_PGALLOC_H */
184