xref: /openbmc/linux/arch/riscv/mm/pgtable.c (revision f0293cd1f4fcc4fbdcd65a5a7b3b318a6d471f78)
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