1310f541aSLiu Shixin // SPDX-License-Identifier: GPL-2.0 2310f541aSLiu Shixin 3310f541aSLiu Shixin #include <asm/pgalloc.h> 4310f541aSLiu Shixin #include <linux/gfp.h> 5310f541aSLiu Shixin #include <linux/kernel.h> 6310f541aSLiu Shixin #include <linux/pgtable.h> 7310f541aSLiu Shixin 8310f541aSLiu Shixin #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP 9310f541aSLiu Shixin int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot) 10310f541aSLiu Shixin { 11310f541aSLiu Shixin return 0; 12310f541aSLiu Shixin } 13310f541aSLiu Shixin 14310f541aSLiu Shixin void p4d_clear_huge(p4d_t *p4d) 15310f541aSLiu Shixin { 16310f541aSLiu Shixin } 17310f541aSLiu Shixin 18310f541aSLiu Shixin int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) 19310f541aSLiu Shixin { 20310f541aSLiu Shixin pud_t new_pud = pfn_pud(__phys_to_pfn(phys), prot); 21310f541aSLiu Shixin 22310f541aSLiu Shixin set_pud(pud, new_pud); 23310f541aSLiu Shixin return 1; 24310f541aSLiu Shixin } 25310f541aSLiu Shixin 26310f541aSLiu Shixin int pud_clear_huge(pud_t *pud) 27310f541aSLiu Shixin { 28310f541aSLiu Shixin if (!pud_leaf(READ_ONCE(*pud))) 29310f541aSLiu Shixin return 0; 30310f541aSLiu Shixin pud_clear(pud); 31310f541aSLiu Shixin return 1; 32310f541aSLiu Shixin } 33310f541aSLiu Shixin 34310f541aSLiu Shixin int pud_free_pmd_page(pud_t *pud, unsigned long addr) 35310f541aSLiu Shixin { 36310f541aSLiu Shixin pmd_t *pmd = pud_pgtable(*pud); 37310f541aSLiu Shixin int i; 38310f541aSLiu Shixin 39310f541aSLiu Shixin pud_clear(pud); 40310f541aSLiu Shixin 41310f541aSLiu Shixin flush_tlb_kernel_range(addr, addr + PUD_SIZE); 42310f541aSLiu Shixin 43310f541aSLiu Shixin for (i = 0; i < PTRS_PER_PMD; i++) { 44310f541aSLiu Shixin if (!pmd_none(pmd[i])) { 45310f541aSLiu Shixin pte_t *pte = (pte_t *)pmd_page_vaddr(pmd[i]); 46310f541aSLiu Shixin 47310f541aSLiu Shixin pte_free_kernel(NULL, pte); 48310f541aSLiu Shixin } 49310f541aSLiu Shixin } 50310f541aSLiu Shixin 51310f541aSLiu Shixin pmd_free(NULL, pmd); 52310f541aSLiu Shixin 53310f541aSLiu Shixin return 1; 54310f541aSLiu Shixin } 55310f541aSLiu Shixin 56310f541aSLiu Shixin int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) 57310f541aSLiu Shixin { 58310f541aSLiu Shixin pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), prot); 59310f541aSLiu Shixin 60310f541aSLiu Shixin set_pmd(pmd, new_pmd); 61310f541aSLiu Shixin return 1; 62310f541aSLiu Shixin } 63310f541aSLiu Shixin 64310f541aSLiu Shixin int pmd_clear_huge(pmd_t *pmd) 65310f541aSLiu Shixin { 66310f541aSLiu Shixin if (!pmd_leaf(READ_ONCE(*pmd))) 67310f541aSLiu Shixin return 0; 68310f541aSLiu Shixin pmd_clear(pmd); 69310f541aSLiu Shixin return 1; 70310f541aSLiu Shixin } 71310f541aSLiu Shixin 72310f541aSLiu Shixin int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) 73310f541aSLiu Shixin { 74310f541aSLiu Shixin pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd); 75310f541aSLiu Shixin 76310f541aSLiu Shixin pmd_clear(pmd); 77310f541aSLiu Shixin 78310f541aSLiu Shixin flush_tlb_kernel_range(addr, addr + PMD_SIZE); 79310f541aSLiu Shixin pte_free_kernel(NULL, pte); 80310f541aSLiu Shixin return 1; 81310f541aSLiu Shixin } 82310f541aSLiu Shixin 83310f541aSLiu Shixin #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ 84*f0293cd1SMayuresh Chitale #ifdef CONFIG_TRANSPARENT_HUGEPAGE 85*f0293cd1SMayuresh Chitale pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, 86*f0293cd1SMayuresh Chitale unsigned long address, pmd_t *pmdp) 87*f0293cd1SMayuresh Chitale { 88*f0293cd1SMayuresh Chitale pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); 89*f0293cd1SMayuresh Chitale 90*f0293cd1SMayuresh Chitale VM_BUG_ON(address & ~HPAGE_PMD_MASK); 91*f0293cd1SMayuresh Chitale VM_BUG_ON(pmd_trans_huge(*pmdp)); 92*f0293cd1SMayuresh Chitale /* 93*f0293cd1SMayuresh Chitale * When leaf PTE entries (regular pages) are collapsed into a leaf 94*f0293cd1SMayuresh Chitale * PMD entry (huge page), a valid non-leaf PTE is converted into a 95*f0293cd1SMayuresh Chitale * valid leaf PTE at the level 1 page table. Since the sfence.vma 96*f0293cd1SMayuresh Chitale * forms that specify an address only apply to leaf PTEs, we need a 97*f0293cd1SMayuresh Chitale * global flush here. collapse_huge_page() assumes these flushes are 98*f0293cd1SMayuresh Chitale * eager, so just do the fence here. 99*f0293cd1SMayuresh Chitale */ 100*f0293cd1SMayuresh Chitale flush_tlb_mm(vma->vm_mm); 101*f0293cd1SMayuresh Chitale return pmd; 102*f0293cd1SMayuresh Chitale } 103*f0293cd1SMayuresh Chitale #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 104