162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <asm/pgalloc.h> 462306a36Sopenharmony_ci#include <linux/gfp.h> 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/pgtable.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP 962306a36Sopenharmony_ciint p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci return 0; 1262306a36Sopenharmony_ci} 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_civoid p4d_clear_huge(p4d_t *p4d) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci} 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciint pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci pud_t new_pud = pfn_pud(__phys_to_pfn(phys), prot); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci set_pud(pud, new_pud); 2362306a36Sopenharmony_ci return 1; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint pud_clear_huge(pud_t *pud) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci if (!pud_leaf(READ_ONCE(*pud))) 2962306a36Sopenharmony_ci return 0; 3062306a36Sopenharmony_ci pud_clear(pud); 3162306a36Sopenharmony_ci return 1; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciint pud_free_pmd_page(pud_t *pud, unsigned long addr) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci pmd_t *pmd = pud_pgtable(*pud); 3762306a36Sopenharmony_ci int i; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci pud_clear(pud); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci flush_tlb_kernel_range(addr, addr + PUD_SIZE); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PMD; i++) { 4462306a36Sopenharmony_ci if (!pmd_none(pmd[i])) { 4562306a36Sopenharmony_ci pte_t *pte = (pte_t *)pmd_page_vaddr(pmd[i]); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci pte_free_kernel(NULL, pte); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci pmd_free(NULL, pmd); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return 1; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), prot); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci set_pmd(pmd, new_pmd); 6162306a36Sopenharmony_ci return 1; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciint pmd_clear_huge(pmd_t *pmd) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci if (!pmd_leaf(READ_ONCE(*pmd))) 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci pmd_clear(pmd); 6962306a36Sopenharmony_ci return 1; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciint pmd_free_pte_page(pmd_t *pmd, unsigned long addr) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci pmd_clear(pmd); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci flush_tlb_kernel_range(addr, addr + PMD_SIZE); 7962306a36Sopenharmony_ci pte_free_kernel(NULL, pte); 8062306a36Sopenharmony_ci return 1; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ 8462306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 8562306a36Sopenharmony_cipmd_t pmdp_collapse_flush(struct vm_area_struct *vma, 8662306a36Sopenharmony_ci unsigned long address, pmd_t *pmdp) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci VM_BUG_ON(address & ~HPAGE_PMD_MASK); 9162306a36Sopenharmony_ci VM_BUG_ON(pmd_trans_huge(*pmdp)); 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * When leaf PTE entries (regular pages) are collapsed into a leaf 9462306a36Sopenharmony_ci * PMD entry (huge page), a valid non-leaf PTE is converted into a 9562306a36Sopenharmony_ci * valid leaf PTE at the level 1 page table. Since the sfence.vma 9662306a36Sopenharmony_ci * forms that specify an address only apply to leaf PTEs, we need a 9762306a36Sopenharmony_ci * global flush here. collapse_huge_page() assumes these flushes are 9862306a36Sopenharmony_ci * eager, so just do the fence here. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci flush_tlb_mm(vma->vm_mm); 10162306a36Sopenharmony_ci return pmd; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 104