1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 Loongson Technology Corporation Limited
4  */
5 #include <linux/export.h>
6 #include <linux/init.h>
7 #include <linux/mm.h>
8 #include <asm/fixmap.h>
9 #include <asm/pgtable.h>
10 #include <asm/pgalloc.h>
11 #include <asm/tlbflush.h>
12 
pgd_init(unsigned long page)13 void pgd_init(unsigned long page)
14 {
15 	unsigned long *p, *end;
16 	unsigned long entry;
17 
18 #if !defined(__PAGETABLE_PUD_FOLDED)
19 	entry = (unsigned long)invalid_pud_table;
20 #elif !defined(__PAGETABLE_PMD_FOLDED)
21 	entry = (unsigned long)invalid_pmd_table;
22 #else
23 	entry = (unsigned long)invalid_pte_table;
24 #endif
25 
26 	p = (unsigned long *) page;
27 	end = p + PTRS_PER_PGD;
28 
29 	do {
30 		p[0] = entry;
31 		p[1] = entry;
32 		p[2] = entry;
33 		p[3] = entry;
34 		p[4] = entry;
35 		p += 8;
36 		p[-3] = entry;
37 		p[-2] = entry;
38 		p[-1] = entry;
39 	} while (p != end);
40 }
41 EXPORT_SYMBOL_GPL(pgd_init);
42 
43 #ifndef __PAGETABLE_PMD_FOLDED
pmd_init(unsigned long addr, unsigned long pagetable)44 void pmd_init(unsigned long addr, unsigned long pagetable)
45 {
46 	unsigned long *p, *end;
47 
48 	p = (unsigned long *) addr;
49 	end = p + PTRS_PER_PMD;
50 
51 	do {
52 		p[0] = pagetable;
53 		p[1] = pagetable;
54 		p[2] = pagetable;
55 		p[3] = pagetable;
56 		p[4] = pagetable;
57 		p += 8;
58 		p[-3] = pagetable;
59 		p[-2] = pagetable;
60 		p[-1] = pagetable;
61 	} while (p != end);
62 }
63 EXPORT_SYMBOL_GPL(pmd_init);
64 #endif
65 
66 #ifndef __PAGETABLE_PUD_FOLDED
pud_init(unsigned long addr, unsigned long pagetable)67 void pud_init(unsigned long addr, unsigned long pagetable)
68 {
69 	unsigned long *p, *end;
70 
71 	p = (unsigned long *)addr;
72 	end = p + PTRS_PER_PUD;
73 
74 	do {
75 		p[0] = pagetable;
76 		p[1] = pagetable;
77 		p[2] = pagetable;
78 		p[3] = pagetable;
79 		p[4] = pagetable;
80 		p += 8;
81 		p[-3] = pagetable;
82 		p[-2] = pagetable;
83 		p[-1] = pagetable;
84 	} while (p != end);
85 }
86 #endif
87 
mk_pmd(struct page *page, pgprot_t prot)88 pmd_t mk_pmd(struct page *page, pgprot_t prot)
89 {
90 	pmd_t pmd;
91 
92 	pmd_val(pmd) = (page_to_pfn(page) << _PFN_SHIFT) | pgprot_val(prot);
93 
94 	return pmd;
95 }
96 
set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd)97 void set_pmd_at(struct mm_struct *mm, unsigned long addr,
98 		pmd_t *pmdp, pmd_t pmd)
99 {
100 	*pmdp = pmd;
101 	flush_tlb_all();
102 }
103 
pagetable_init(void)104 void __init pagetable_init(void)
105 {
106 	unsigned long vaddr;
107 
108 	/* Initialize the entire pgd.  */
109 	pgd_init((unsigned long)swapper_pg_dir);
110 	pgd_init((unsigned long)invalid_pg_dir);
111 #ifndef __PAGETABLE_PUD_FOLDED
112 	pud_init((unsigned long)invalid_pud_table, (unsigned long)invalid_pmd_table);
113 #endif
114 #ifndef __PAGETABLE_PMD_FOLDED
115 	pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
116 #endif
117 	/*
118 	 * Fixed mappings:
119 	 */
120 	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
121 }
122