Commit | Line | Data |
---|---|---|
fe6cb7b0 VG |
1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* | |
3 | * Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com) | |
4 | */ | |
5 | ||
6 | /* | |
7 | * Helpers for implemenintg paging levels | |
8 | */ | |
9 | ||
10 | #ifndef _ASM_ARC_PGTABLE_LEVELS_H | |
11 | #define _ASM_ARC_PGTABLE_LEVELS_H | |
12 | ||
2dde02ab VG |
13 | #if CONFIG_PGTABLE_LEVELS == 2 |
14 | ||
fe6cb7b0 VG |
15 | /* |
16 | * 2 level paging setup for software walked MMUv3 (ARC700) and MMUv4 (HS) | |
17 | * | |
18 | * [31] 32 bit virtual address [0] | |
19 | * ------------------------------------------------------- | |
20 | * | | <---------- PGDIR_SHIFT ----------> | | |
21 | * | | | <-- PAGE_SHIFT --> | | |
22 | * ------------------------------------------------------- | |
23 | * | | | | |
24 | * | | --> off in page frame | |
25 | * | ---> index into Page Table | |
26 | * ----> index into Page Directory | |
27 | * | |
28 | * Given software walk, the vaddr split is arbitrary set to 11:8:13 | |
29 | * However enabling of super page in a 2 level regime pegs PGDIR_SHIFT to | |
30 | * super page size. | |
31 | */ | |
32 | ||
33 | #if defined(CONFIG_ARC_HUGEPAGE_16M) | |
34 | #define PGDIR_SHIFT 24 | |
35 | #elif defined(CONFIG_ARC_HUGEPAGE_2M) | |
36 | #define PGDIR_SHIFT 21 | |
37 | #else | |
38 | /* | |
39 | * No Super page case | |
d9820ff7 VG |
40 | * Default value provides 11:8:13 (8K), 10:10:12 (4K) |
41 | * Limits imposed by pgtable_t only PAGE_SIZE long | |
42 | * (so 4K page can only have 1K entries: or 10 bits) | |
fe6cb7b0 | 43 | */ |
d9820ff7 VG |
44 | #ifdef CONFIG_ARC_PAGE_SIZE_4K |
45 | #define PGDIR_SHIFT 22 | |
46 | #else | |
fe6cb7b0 | 47 | #define PGDIR_SHIFT 21 |
d9820ff7 | 48 | #endif |
fe6cb7b0 VG |
49 | |
50 | #endif | |
51 | ||
2dde02ab VG |
52 | #else /* CONFIG_PGTABLE_LEVELS != 2 */ |
53 | ||
54 | /* | |
55 | * A default 3 level paging testing setup in software walked MMU | |
56 | * MMUv4 (8K page): <4> : <7> : <8> : <13> | |
8747ff70 VG |
57 | * A default 4 level paging testing setup in software walked MMU |
58 | * MMUv4 (8K page): <4> : <3> : <4> : <8> : <13> | |
2dde02ab VG |
59 | */ |
60 | #define PGDIR_SHIFT 28 | |
8747ff70 VG |
61 | #if CONFIG_PGTABLE_LEVELS > 3 |
62 | #define PUD_SHIFT 25 | |
63 | #endif | |
2dde02ab VG |
64 | #if CONFIG_PGTABLE_LEVELS > 2 |
65 | #define PMD_SHIFT 21 | |
66 | #endif | |
fe6cb7b0 | 67 | |
2dde02ab VG |
68 | #endif /* CONFIG_PGTABLE_LEVELS */ |
69 | ||
70 | #define PGDIR_SIZE BIT(PGDIR_SHIFT) | |
71 | #define PGDIR_MASK (~(PGDIR_SIZE - 1)) | |
fe6cb7b0 VG |
72 | #define PTRS_PER_PGD BIT(32 - PGDIR_SHIFT) |
73 | ||
8747ff70 VG |
74 | #if CONFIG_PGTABLE_LEVELS > 3 |
75 | #define PUD_SIZE BIT(PUD_SHIFT) | |
76 | #define PUD_MASK (~(PUD_SIZE - 1)) | |
77 | #define PTRS_PER_PUD BIT(PGDIR_SHIFT - PUD_SHIFT) | |
78 | #endif | |
79 | ||
2dde02ab VG |
80 | #if CONFIG_PGTABLE_LEVELS > 2 |
81 | #define PMD_SIZE BIT(PMD_SHIFT) | |
82 | #define PMD_MASK (~(PMD_SIZE - 1)) | |
8747ff70 | 83 | #define PTRS_PER_PMD BIT(PUD_SHIFT - PMD_SHIFT) |
2dde02ab VG |
84 | #endif |
85 | ||
86 | #define PTRS_PER_PTE BIT(PMD_SHIFT - PAGE_SHIFT) | |
fe6cb7b0 VG |
87 | |
88 | #ifndef __ASSEMBLY__ | |
89 | ||
8747ff70 VG |
90 | #if CONFIG_PGTABLE_LEVELS > 3 |
91 | #include <asm-generic/pgtable-nop4d.h> | |
92 | #elif CONFIG_PGTABLE_LEVELS > 2 | |
2dde02ab VG |
93 | #include <asm-generic/pgtable-nopud.h> |
94 | #else | |
fe6cb7b0 | 95 | #include <asm-generic/pgtable-nopmd.h> |
2dde02ab | 96 | #endif |
fe6cb7b0 VG |
97 | |
98 | /* | |
99 | * 1st level paging: pgd | |
100 | */ | |
fe6cb7b0 VG |
101 | #define pgd_ERROR(e) \ |
102 | pr_crit("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) | |
103 | ||
8747ff70 VG |
104 | #if CONFIG_PGTABLE_LEVELS > 3 |
105 | ||
106 | /* In 4 level paging, p4d_* macros work on pgd */ | |
107 | #define p4d_none(x) (!p4d_val(x)) | |
108 | #define p4d_bad(x) ((p4d_val(x) & ~PAGE_MASK)) | |
109 | #define p4d_present(x) (p4d_val(x)) | |
110 | #define p4d_clear(xp) do { p4d_val(*(xp)) = 0; } while (0) | |
111 | #define p4d_pgtable(p4d) ((pud_t *)(p4d_val(p4d) & PAGE_MASK)) | |
112 | #define p4d_page(p4d) virt_to_page(p4d_pgtable(p4d)) | |
113 | #define set_p4d(p4dp, p4d) (*(p4dp) = p4d) | |
114 | ||
115 | /* | |
116 | * 2nd level paging: pud | |
117 | */ | |
118 | #define pud_ERROR(e) \ | |
119 | pr_crit("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e)) | |
120 | ||
121 | #endif | |
122 | ||
2dde02ab VG |
123 | #if CONFIG_PGTABLE_LEVELS > 2 |
124 | ||
8747ff70 VG |
125 | /* |
126 | * In 3 level paging, pud_* macros work on pgd | |
127 | * In 4 level paging, pud_* macros work on pud | |
128 | */ | |
2dde02ab VG |
129 | #define pud_none(x) (!pud_val(x)) |
130 | #define pud_bad(x) ((pud_val(x) & ~PAGE_MASK)) | |
131 | #define pud_present(x) (pud_val(x)) | |
132 | #define pud_clear(xp) do { pud_val(*(xp)) = 0; } while (0) | |
133 | #define pud_pgtable(pud) ((pmd_t *)(pud_val(pud) & PAGE_MASK)) | |
134 | #define pud_page(pud) virt_to_page(pud_pgtable(pud)) | |
135 | #define set_pud(pudp, pud) (*(pudp) = pud) | |
136 | ||
fe6cb7b0 | 137 | /* |
8747ff70 | 138 | * 3rd level paging: pmd |
2dde02ab VG |
139 | */ |
140 | #define pmd_ERROR(e) \ | |
141 | pr_crit("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) | |
142 | ||
143 | #define pmd_pfn(pmd) ((pmd_val(pmd) & PMD_MASK) >> PAGE_SHIFT) | |
144 | #define pfn_pmd(pfn,prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) | |
145 | #define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) | |
146 | ||
147 | #endif | |
148 | ||
149 | /* | |
150 | * Due to the strange way generic pgtable level folding works, the pmd_* macros | |
151 | * - are valid even for 2 levels (which supposedly only has pgd - pte) | |
152 | * - behave differently for 2 vs. 3 | |
153 | * In 2 level paging (pgd -> pte), pmd_* macros work on pgd | |
154 | * In 3+ level paging (pgd -> pmd -> pte), pmd_* macros work on pmd | |
fe6cb7b0 VG |
155 | */ |
156 | #define pmd_none(x) (!pmd_val(x)) | |
157 | #define pmd_bad(x) ((pmd_val(x) & ~PAGE_MASK)) | |
158 | #define pmd_present(x) (pmd_val(x)) | |
159 | #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) | |
160 | #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) | |
7106c51e | 161 | #define pmd_pfn(pmd) ((pmd_val(pmd) & PAGE_MASK) >> PAGE_SHIFT) |
da4382a7 | 162 | #define pmd_page(pmd) virt_to_page((void *)pmd_page_vaddr(pmd)) |
fe6cb7b0 | 163 | #define set_pmd(pmdp, pmd) (*(pmdp) = pmd) |
4fd9df10 | 164 | #define pmd_pgtable(pmd) ((pgtable_t) pmd_page(pmd)) |
fe6cb7b0 | 165 | |
2dde02ab | 166 | /* |
8747ff70 | 167 | * 4th level paging: pte |
2dde02ab | 168 | */ |
fe6cb7b0 VG |
169 | #define pte_ERROR(e) \ |
170 | pr_crit("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) | |
171 | ||
ac4cfacc | 172 | #define PFN_PTE_SHIFT PAGE_SHIFT |
fe6cb7b0 VG |
173 | #define pte_none(x) (!pte_val(x)) |
174 | #define pte_present(x) (pte_val(x) & _PAGE_PRESENT) | |
175 | #define pte_clear(mm,addr,ptep) set_pte_at(mm, addr, ptep, __pte(0)) | |
176 | #define pte_page(pte) pfn_to_page(pte_pfn(pte)) | |
177 | #define set_pte(ptep, pte) ((*(ptep)) = (pte)) | |
178 | #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) | |
179 | #define pfn_pte(pfn, prot) __pte(__pfn_to_phys(pfn) | pgprot_val(prot)) | |
180 | #define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) | |
181 | ||
182 | #ifdef CONFIG_ISA_ARCV2 | |
183 | #define pmd_leaf(x) (pmd_val(x) & _PAGE_HW_SZ) | |
184 | #endif | |
185 | ||
186 | #endif /* !__ASSEMBLY__ */ | |
187 | ||
188 | #endif |