aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/include/asm/tsb.h
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-09-26 16:45:15 -0400
committerDavid S. Miller <davem@davemloft.net>2013-11-13 15:33:08 -0500
commita7b9403f0e6d5f99139dca18be885819c8d380a1 (patch)
tree3e88ddc9250a1408eefc48a20a8fb445e19fcaa3 /arch/sparc/include/asm/tsb.h
parent2b77933c28f5044629bb19e8045aae65b72b939d (diff)
sparc64: Encode huge PMDs using PTE encoding.
Now that we have 64-bits for PMDs we can stop using special encodings for the huge PMD values, and just put real PTEs in there. We allocate a _PAGE_PMD_HUGE bit to distinguish between plain PMDs and huge ones. It is the same for both 4U and 4V PTE layouts. We also use _PAGE_SPECIAL to indicate the splitting state, since a huge PMD cannot also be special. All of the PMD --> PTE translation code disappears, and most of the huge PMD bit modifications and tests just degenerate into the PTE operations. In particular USER_PGTABLE_CHECK_PMD_HUGE becomes trivial. As a side effect, normal PMDs don't shift the physical address around. This also speeds up the page table walks in the TLB miss paths since they don't have to do the shifts any more. Another non-trivial aspect is that pte_modify() has to be changed to preserve the _PAGE_PMD_HUGE bits as well as the page size field of the pte. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/include/asm/tsb.h')
-rw-r--r--arch/sparc/include/asm/tsb.h92
1 files changed, 12 insertions, 80 deletions
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index cc0432f15817..2230f80d9fe3 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -147,100 +147,34 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
147 brz,pn REG1, FAIL_LABEL; \ 147 brz,pn REG1, FAIL_LABEL; \
148 sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ 148 sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
149 srlx REG2, 64 - PAGE_SHIFT, REG2; \ 149 srlx REG2, 64 - PAGE_SHIFT, REG2; \
150 sllx REG1, PGD_PADDR_SHIFT, REG1; \
151 andn REG2, 0x7, REG2; \ 150 andn REG2, 0x7, REG2; \
152 ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ 151 ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
153 brz,pn REG1, FAIL_LABEL; \ 152 brz,pn REG1, FAIL_LABEL; \
154 sllx VADDR, 64 - PMD_SHIFT, REG2; \ 153 sllx VADDR, 64 - PMD_SHIFT, REG2; \
155 srlx REG2, 64 - PAGE_SHIFT, REG2; \ 154 srlx REG2, 64 - PAGE_SHIFT, REG2; \
156 sllx REG1, PMD_PADDR_SHIFT, REG1; \
157 andn REG2, 0x7, REG2; \ 155 andn REG2, 0x7, REG2; \
158 add REG1, REG2, REG1; 156 add REG1, REG2, REG1;
159 157
160 /* These macros exists only to make the PMD translator below
161 * easier to read. It hides the ELF section switch for the
162 * sun4v code patching.
163 */
164#define OR_PTE_BIT_1INSN(REG, NAME) \
165661: or REG, _PAGE_##NAME##_4U, REG; \
166 .section .sun4v_1insn_patch, "ax"; \
167 .word 661b; \
168 or REG, _PAGE_##NAME##_4V, REG; \
169 .previous;
170
171#define OR_PTE_BIT_2INSN(REG, TMP, NAME) \
172661: sethi %hi(_PAGE_##NAME##_4U), TMP; \
173 or REG, TMP, REG; \
174 .section .sun4v_2insn_patch, "ax"; \
175 .word 661b; \
176 mov -1, TMP; \
177 or REG, _PAGE_##NAME##_4V, REG; \
178 .previous;
179
180 /* Load into REG the PTE value for VALID, CACHE, and SZHUGE.
181 *
182 * We are fabricating an 8MB page using 2 4MB HW pages here.
183 */
184#define BUILD_PTE_VALID_SZHUGE_CACHE(VADDR, PADDR_BITS, REG) \
185 sethi %hi(4 * 1024 * 1024), REG; \
186 andn PADDR_BITS, REG, PADDR_BITS; \
187 and VADDR, REG, REG; \
188 or PADDR_BITS, REG, PADDR_BITS; \
189661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \
190 .section .sun4v_1insn_patch, "ax"; \
191 .word 661b; \
192 sethi %uhi(_PAGE_VALID), REG; \
193 .previous; \
194 sllx REG, 32, REG; \
195661: or REG, _PAGE_CP_4U|_PAGE_CV_4U, REG; \
196 .section .sun4v_1insn_patch, "ax"; \
197 .word 661b; \
198 or REG, _PAGE_CP_4V|_PAGE_CV_4V|_PAGE_SZHUGE_4V, REG; \
199 .previous;
200
201 /* PMD has been loaded into REG1, interpret the value, seeing 158 /* PMD has been loaded into REG1, interpret the value, seeing
202 * if it is a HUGE PMD or a normal one. If it is not valid 159 * if it is a HUGE PMD or a normal one. If it is not valid
203 * then jump to FAIL_LABEL. If it is a HUGE PMD, and it 160 * then jump to FAIL_LABEL. If it is a HUGE PMD, and it
204 * translates to a valid PTE, branch to PTE_LABEL. 161 * translates to a valid PTE, branch to PTE_LABEL.
205 * 162 *
206 * We translate the PMD by hand, one bit at a time, 163 * We have to propagate the 4MB bit of the virtual address
207 * constructing the huge PTE. 164 * because we are fabricating 8MB pages using 4MB hw pages.
208 *
209 * So we construct the PTE in REG2 as follows:
210 *
211 * 1) Extract the PMD PFN from REG1 and place it into REG2.
212 *
213 * 2) Translate PMD protection bits in REG1 into REG2, one bit
214 * at a time using andcc tests on REG1 and OR's into REG2.
215 *
216 * Only two bits to be concerned with here, EXEC and WRITE.
217 * Now REG1 is freed up and we can use it as a temporary.
218 *
219 * 3) Construct the VALID, CACHE, and page size PTE bits in
220 * REG1, OR with REG2 to form final PTE.
221 */ 165 */
222#ifdef CONFIG_TRANSPARENT_HUGEPAGE 166#ifdef CONFIG_TRANSPARENT_HUGEPAGE
223#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \ 167#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
224 brz,pn REG1, FAIL_LABEL; \ 168 brz,pn REG1, FAIL_LABEL; \
225 andcc REG1, PMD_ISHUGE, %g0; \ 169 sethi %uhi(_PAGE_PMD_HUGE), REG2; \
226 be,pt %xcc, 700f; \ 170 sllx REG2, 32, REG2; \
227 and REG1, PMD_HUGE_PRESENT|PMD_HUGE_ACCESSED, REG2; \ 171 andcc REG1, REG2, %g0; \
228 cmp REG2, PMD_HUGE_PRESENT|PMD_HUGE_ACCESSED; \ 172 be,pt %xcc, 700f; \
229 bne,pn %xcc, FAIL_LABEL; \ 173 sethi %hi(4 * 1024 * 1024), REG2; \
230 andn REG1, PMD_HUGE_PROTBITS, REG2; \ 174 andn REG1, REG2, REG1; \
231 sllx REG2, PMD_PADDR_SHIFT, REG2; \ 175 and VADDR, REG2, REG2; \
232 /* REG2 now holds PFN << PAGE_SHIFT */ \ 176 brlz,pt REG1, PTE_LABEL; \
233 andcc REG1, PMD_HUGE_WRITE, %g0; \ 177 or REG1, REG2, REG1; \
234 bne,a,pt %xcc, 1f; \
235 OR_PTE_BIT_1INSN(REG2, W); \
2361: andcc REG1, PMD_HUGE_EXEC, %g0; \
237 be,pt %xcc, 1f; \
238 nop; \
239 OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \
240 /* REG1 can now be clobbered, build final PTE */ \
2411: BUILD_PTE_VALID_SZHUGE_CACHE(VADDR, REG2, REG1); \
242 ba,pt %xcc, PTE_LABEL; \
243 or REG1, REG2, REG1; \
244700: 178700:
245#else 179#else
246#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \ 180#define USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, PTE_LABEL) \
@@ -265,13 +199,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
265 brz,pn REG1, FAIL_LABEL; \ 199 brz,pn REG1, FAIL_LABEL; \
266 sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ 200 sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
267 srlx REG2, 64 - PAGE_SHIFT, REG2; \ 201 srlx REG2, 64 - PAGE_SHIFT, REG2; \
268 sllx REG1, PGD_PADDR_SHIFT, REG1; \
269 andn REG2, 0x7, REG2; \ 202 andn REG2, 0x7, REG2; \
270 ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ 203 ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
271 USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, 800f) \ 204 USER_PGTABLE_CHECK_PMD_HUGE(VADDR, REG1, REG2, FAIL_LABEL, 800f) \
272 sllx VADDR, 64 - PMD_SHIFT, REG2; \ 205 sllx VADDR, 64 - PMD_SHIFT, REG2; \
273 srlx REG2, 64 - PAGE_SHIFT, REG2; \ 206 srlx REG2, 64 - PAGE_SHIFT, REG2; \
274 sllx REG1, PMD_PADDR_SHIFT, REG1; \
275 andn REG2, 0x7, REG2; \ 207 andn REG2, 0x7, REG2; \
276 add REG1, REG2, REG1; \ 208 add REG1, REG2, REG1; \
277 ldxa [REG1] ASI_PHYS_USE_EC, REG1; \ 209 ldxa [REG1] ASI_PHYS_USE_EC, REG1; \