diff options
Diffstat (limited to 'arch/sparc64/kernel/ktlb.S')
-rw-r--r-- | arch/sparc64/kernel/ktlb.S | 363 |
1 files changed, 224 insertions, 139 deletions
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index d9244d3c9f73..31da1e564c95 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
@@ -4,191 +4,276 @@ | |||
4 | * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de) | 4 | * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de) |
5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) | 5 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) |
6 | * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 6 | * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
10 | #include <asm/head.h> | 10 | #include <asm/head.h> |
11 | #include <asm/asi.h> | 11 | #include <asm/asi.h> |
12 | #include <asm/page.h> | 12 | #include <asm/page.h> |
13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
14 | #include <asm/tsb.h> | ||
14 | 15 | ||
15 | .text | 16 | .text |
16 | .align 32 | 17 | .align 32 |
17 | 18 | ||
18 | /* | 19 | kvmap_itlb: |
19 | * On a second level vpte miss, check whether the original fault is to the OBP | 20 | /* g6: TAG TARGET */ |
20 | * range (note that this is only possible for instruction miss, data misses to | 21 | mov TLB_TAG_ACCESS, %g4 |
21 | * obp range do not use vpte). If so, go back directly to the faulting address. | 22 | ldxa [%g4] ASI_IMMU, %g4 |
22 | * This is because we want to read the tpc, otherwise we have no way of knowing | 23 | |
23 | * the 8k aligned faulting address if we are using >8k kernel pagesize. This | 24 | /* sun4v_itlb_miss branches here with the missing virtual |
24 | * also ensures no vpte range addresses are dropped into tlb while obp is | 25 | * address already loaded into %g4 |
25 | * executing (see inherit_locked_prom_mappings() rant). | ||
26 | */ | ||
27 | sparc64_vpte_nucleus: | ||
28 | /* Note that kvmap below has verified that the address is | ||
29 | * in the range MODULES_VADDR --> VMALLOC_END already. So | ||
30 | * here we need only check if it is an OBP address or not. | ||
31 | */ | 26 | */ |
27 | kvmap_itlb_4v: | ||
28 | |||
29 | kvmap_itlb_nonlinear: | ||
30 | /* Catch kernel NULL pointer calls. */ | ||
31 | sethi %hi(PAGE_SIZE), %g5 | ||
32 | cmp %g4, %g5 | ||
33 | bleu,pn %xcc, kvmap_dtlb_longpath | ||
34 | nop | ||
35 | |||
36 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_itlb_load) | ||
37 | |||
38 | kvmap_itlb_tsb_miss: | ||
32 | sethi %hi(LOW_OBP_ADDRESS), %g5 | 39 | sethi %hi(LOW_OBP_ADDRESS), %g5 |
33 | cmp %g4, %g5 | 40 | cmp %g4, %g5 |
34 | blu,pn %xcc, kern_vpte | 41 | blu,pn %xcc, kvmap_itlb_vmalloc_addr |
35 | mov 0x1, %g5 | 42 | mov 0x1, %g5 |
36 | sllx %g5, 32, %g5 | 43 | sllx %g5, 32, %g5 |
37 | cmp %g4, %g5 | 44 | cmp %g4, %g5 |
38 | blu,pn %xcc, vpte_insn_obp | 45 | blu,pn %xcc, kvmap_itlb_obp |
39 | nop | 46 | nop |
40 | 47 | ||
41 | /* These two instructions are patched by paginig_init(). */ | 48 | kvmap_itlb_vmalloc_addr: |
42 | kern_vpte: | 49 | KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath) |
43 | sethi %hi(swapper_pgd_zero), %g5 | ||
44 | lduw [%g5 + %lo(swapper_pgd_zero)], %g5 | ||
45 | 50 | ||
46 | /* With kernel PGD in %g5, branch back into dtlb_backend. */ | 51 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
47 | ba,pt %xcc, sparc64_kpte_continue | ||
48 | andn %g1, 0x3, %g1 /* Finish PMD offset adjustment. */ | ||
49 | 52 | ||
50 | vpte_noent: | 53 | /* Load and check PTE. */ |
51 | /* Restore previous TAG_ACCESS, %g5 is zero, and we will | 54 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 |
52 | * skip over the trap instruction so that the top level | 55 | mov 1, %g7 |
53 | * TLB miss handler will thing this %g5 value is just an | 56 | sllx %g7, TSB_TAG_INVALID_BIT, %g7 |
54 | * invalid PTE, thus branching to full fault processing. | 57 | brgez,a,pn %g5, kvmap_itlb_longpath |
55 | */ | 58 | KTSB_STORE(%g1, %g7) |
56 | mov TLB_SFSR, %g1 | 59 | |
57 | stxa %g4, [%g1 + %g1] ASI_DMMU | 60 | KTSB_WRITE(%g1, %g5, %g6) |
58 | done | 61 | |
59 | 62 | /* fallthrough to TLB load */ | |
60 | vpte_insn_obp: | ||
61 | /* Behave as if we are at TL0. */ | ||
62 | wrpr %g0, 1, %tl | ||
63 | rdpr %tpc, %g4 /* Find original faulting iaddr */ | ||
64 | srlx %g4, 13, %g4 /* Throw out context bits */ | ||
65 | sllx %g4, 13, %g4 /* g4 has vpn + ctx0 now */ | ||
66 | |||
67 | /* Restore previous TAG_ACCESS. */ | ||
68 | mov TLB_SFSR, %g1 | ||
69 | stxa %g4, [%g1 + %g1] ASI_IMMU | ||
70 | |||
71 | sethi %hi(prom_trans), %g5 | ||
72 | or %g5, %lo(prom_trans), %g5 | ||
73 | |||
74 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
75 | brz,a,pn %g6, longpath ! no more entries, fail | ||
76 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
77 | ldx [%g5 + 0x08], %g1 ! len | ||
78 | add %g6, %g1, %g1 ! end | ||
79 | cmp %g6, %g4 | ||
80 | bgu,pt %xcc, 2f | ||
81 | cmp %g4, %g1 | ||
82 | bgeu,pt %xcc, 2f | ||
83 | ldx [%g5 + 0x10], %g1 ! PTE | ||
84 | |||
85 | /* TLB load, restore %g1, and return from trap. */ | ||
86 | sub %g4, %g6, %g6 | ||
87 | add %g1, %g6, %g5 | ||
88 | mov TLB_SFSR, %g1 | ||
89 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | ||
90 | retry | ||
91 | 63 | ||
92 | 2: ba,pt %xcc, 1b | 64 | kvmap_itlb_load: |
93 | add %g5, (3 * 8), %g5 ! next entry | 65 | |
94 | 66 | 661: stxa %g5, [%g0] ASI_ITLB_DATA_IN | |
95 | kvmap_do_obp: | ||
96 | sethi %hi(prom_trans), %g5 | ||
97 | or %g5, %lo(prom_trans), %g5 | ||
98 | srlx %g4, 13, %g4 | ||
99 | sllx %g4, 13, %g4 | ||
100 | |||
101 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
102 | brz,a,pn %g6, longpath ! no more entries, fail | ||
103 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
104 | ldx [%g5 + 0x08], %g1 ! len | ||
105 | add %g6, %g1, %g1 ! end | ||
106 | cmp %g6, %g4 | ||
107 | bgu,pt %xcc, 2f | ||
108 | cmp %g4, %g1 | ||
109 | bgeu,pt %xcc, 2f | ||
110 | ldx [%g5 + 0x10], %g1 ! PTE | ||
111 | |||
112 | /* TLB load, restore %g1, and return from trap. */ | ||
113 | sub %g4, %g6, %g6 | ||
114 | add %g1, %g6, %g5 | ||
115 | mov TLB_SFSR, %g1 | ||
116 | stxa %g5, [%g0] ASI_DTLB_DATA_IN | ||
117 | retry | 67 | retry |
68 | .section .sun4v_2insn_patch, "ax" | ||
69 | .word 661b | ||
70 | nop | ||
71 | nop | ||
72 | .previous | ||
73 | |||
74 | /* For sun4v the ASI_ITLB_DATA_IN store and the retry | ||
75 | * instruction get nop'd out and we get here to branch | ||
76 | * to the sun4v tlb load code. The registers are setup | ||
77 | * as follows: | ||
78 | * | ||
79 | * %g4: vaddr | ||
80 | * %g5: PTE | ||
81 | * %g6: TAG | ||
82 | * | ||
83 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
84 | * up here. | ||
85 | */ | ||
86 | ba,pt %xcc, sun4v_itlb_load | ||
87 | mov %g5, %g3 | ||
118 | 88 | ||
119 | 2: ba,pt %xcc, 1b | 89 | kvmap_itlb_longpath: |
120 | add %g5, (3 * 8), %g5 ! next entry | 90 | |
91 | 661: rdpr %pstate, %g5 | ||
92 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate | ||
93 | .section .sun4v_2insn_patch, "ax" | ||
94 | .word 661b | ||
95 | SET_GL(1) | ||
96 | nop | ||
97 | .previous | ||
98 | |||
99 | rdpr %tpc, %g5 | ||
100 | ba,pt %xcc, sparc64_realfault_common | ||
101 | mov FAULT_CODE_ITLB, %g4 | ||
102 | |||
103 | kvmap_itlb_obp: | ||
104 | OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath) | ||
105 | |||
106 | KTSB_LOCK_TAG(%g1, %g2, %g7) | ||
107 | |||
108 | KTSB_WRITE(%g1, %g5, %g6) | ||
109 | |||
110 | ba,pt %xcc, kvmap_itlb_load | ||
111 | nop | ||
112 | |||
113 | kvmap_dtlb_obp: | ||
114 | OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath) | ||
115 | |||
116 | KTSB_LOCK_TAG(%g1, %g2, %g7) | ||
117 | |||
118 | KTSB_WRITE(%g1, %g5, %g6) | ||
119 | |||
120 | ba,pt %xcc, kvmap_dtlb_load | ||
121 | nop | ||
121 | 122 | ||
122 | /* | ||
123 | * On a first level data miss, check whether this is to the OBP range (note | ||
124 | * that such accesses can be made by prom, as well as by kernel using | ||
125 | * prom_getproperty on "address"), and if so, do not use vpte access ... | ||
126 | * rather, use information saved during inherit_prom_mappings() using 8k | ||
127 | * pagesize. | ||
128 | */ | ||
129 | .align 32 | 123 | .align 32 |
130 | kvmap: | 124 | kvmap_dtlb_tsb4m_load: |
131 | brgez,pn %g4, kvmap_nonlinear | 125 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
126 | KTSB_WRITE(%g1, %g5, %g6) | ||
127 | ba,pt %xcc, kvmap_dtlb_load | ||
132 | nop | 128 | nop |
133 | 129 | ||
134 | #ifdef CONFIG_DEBUG_PAGEALLOC | 130 | kvmap_dtlb: |
131 | /* %g6: TAG TARGET */ | ||
132 | mov TLB_TAG_ACCESS, %g4 | ||
133 | ldxa [%g4] ASI_DMMU, %g4 | ||
134 | |||
135 | /* sun4v_dtlb_miss branches here with the missing virtual | ||
136 | * address already loaded into %g4 | ||
137 | */ | ||
138 | kvmap_dtlb_4v: | ||
139 | brgez,pn %g4, kvmap_dtlb_nonlinear | ||
140 | nop | ||
141 | |||
142 | /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */ | ||
143 | KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) | ||
144 | |||
145 | /* TSB entry address left in %g1, lookup linear PTE. | ||
146 | * Must preserve %g1 and %g6 (TAG). | ||
147 | */ | ||
148 | kvmap_dtlb_tsb4m_miss: | ||
149 | sethi %hi(kpte_linear_bitmap), %g2 | ||
150 | or %g2, %lo(kpte_linear_bitmap), %g2 | ||
151 | |||
152 | /* Clear the PAGE_OFFSET top virtual bits, then shift | ||
153 | * down to get a 256MB physical address index. | ||
154 | */ | ||
155 | sllx %g4, 21, %g5 | ||
156 | mov 1, %g7 | ||
157 | srlx %g5, 21 + 28, %g5 | ||
158 | |||
159 | /* Don't try this at home kids... this depends upon srlx | ||
160 | * only taking the low 6 bits of the shift count in %g5. | ||
161 | */ | ||
162 | sllx %g7, %g5, %g7 | ||
163 | |||
164 | /* Divide by 64 to get the offset into the bitmask. */ | ||
165 | srlx %g5, 6, %g5 | ||
166 | sllx %g5, 3, %g5 | ||
167 | |||
168 | /* kern_linear_pte_xor[((mask & bit) ? 1 : 0)] */ | ||
169 | ldx [%g2 + %g5], %g2 | ||
170 | andcc %g2, %g7, %g0 | ||
171 | sethi %hi(kern_linear_pte_xor), %g5 | ||
172 | or %g5, %lo(kern_linear_pte_xor), %g5 | ||
173 | bne,a,pt %xcc, 1f | ||
174 | add %g5, 8, %g5 | ||
175 | |||
176 | 1: ldx [%g5], %g2 | ||
177 | |||
135 | .globl kvmap_linear_patch | 178 | .globl kvmap_linear_patch |
136 | kvmap_linear_patch: | 179 | kvmap_linear_patch: |
137 | #endif | 180 | ba,pt %xcc, kvmap_dtlb_tsb4m_load |
138 | ba,pt %xcc, kvmap_load | ||
139 | xor %g2, %g4, %g5 | 181 | xor %g2, %g4, %g5 |
140 | 182 | ||
141 | #ifdef CONFIG_DEBUG_PAGEALLOC | 183 | kvmap_dtlb_vmalloc_addr: |
142 | sethi %hi(swapper_pg_dir), %g5 | 184 | KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath) |
143 | or %g5, %lo(swapper_pg_dir), %g5 | 185 | |
144 | sllx %g4, 64 - (PGDIR_SHIFT + PGDIR_BITS), %g6 | 186 | KTSB_LOCK_TAG(%g1, %g2, %g7) |
145 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 187 | |
146 | andn %g6, 0x3, %g6 | 188 | /* Load and check PTE. */ |
147 | lduw [%g5 + %g6], %g5 | 189 | ldxa [%g5] ASI_PHYS_USE_EC, %g5 |
148 | brz,pn %g5, longpath | 190 | mov 1, %g7 |
149 | sllx %g4, 64 - (PMD_SHIFT + PMD_BITS), %g6 | 191 | sllx %g7, TSB_TAG_INVALID_BIT, %g7 |
150 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 192 | brgez,a,pn %g5, kvmap_dtlb_longpath |
151 | sllx %g5, 11, %g5 | 193 | KTSB_STORE(%g1, %g7) |
152 | andn %g6, 0x3, %g6 | 194 | |
153 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 195 | KTSB_WRITE(%g1, %g5, %g6) |
154 | brz,pn %g5, longpath | 196 | |
155 | sllx %g4, 64 - PMD_SHIFT, %g6 | 197 | /* fallthrough to TLB load */ |
156 | srlx %g6, 64 - PAGE_SHIFT, %g6 | 198 | |
157 | sllx %g5, 11, %g5 | 199 | kvmap_dtlb_load: |
158 | andn %g6, 0x7, %g6 | 200 | |
159 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 201 | 661: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB |
160 | brz,pn %g5, longpath | 202 | retry |
203 | .section .sun4v_2insn_patch, "ax" | ||
204 | .word 661b | ||
205 | nop | ||
206 | nop | ||
207 | .previous | ||
208 | |||
209 | /* For sun4v the ASI_DTLB_DATA_IN store and the retry | ||
210 | * instruction get nop'd out and we get here to branch | ||
211 | * to the sun4v tlb load code. The registers are setup | ||
212 | * as follows: | ||
213 | * | ||
214 | * %g4: vaddr | ||
215 | * %g5: PTE | ||
216 | * %g6: TAG | ||
217 | * | ||
218 | * The sun4v TLB load wants the PTE in %g3 so we fix that | ||
219 | * up here. | ||
220 | */ | ||
221 | ba,pt %xcc, sun4v_dtlb_load | ||
222 | mov %g5, %g3 | ||
223 | |||
224 | kvmap_dtlb_nonlinear: | ||
225 | /* Catch kernel NULL pointer derefs. */ | ||
226 | sethi %hi(PAGE_SIZE), %g5 | ||
227 | cmp %g4, %g5 | ||
228 | bleu,pn %xcc, kvmap_dtlb_longpath | ||
161 | nop | 229 | nop |
162 | ba,a,pt %xcc, kvmap_load | ||
163 | #endif | ||
164 | 230 | ||
165 | kvmap_nonlinear: | 231 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) |
232 | |||
233 | kvmap_dtlb_tsbmiss: | ||
166 | sethi %hi(MODULES_VADDR), %g5 | 234 | sethi %hi(MODULES_VADDR), %g5 |
167 | cmp %g4, %g5 | 235 | cmp %g4, %g5 |
168 | blu,pn %xcc, longpath | 236 | blu,pn %xcc, kvmap_dtlb_longpath |
169 | mov (VMALLOC_END >> 24), %g5 | 237 | mov (VMALLOC_END >> 24), %g5 |
170 | sllx %g5, 24, %g5 | 238 | sllx %g5, 24, %g5 |
171 | cmp %g4, %g5 | 239 | cmp %g4, %g5 |
172 | bgeu,pn %xcc, longpath | 240 | bgeu,pn %xcc, kvmap_dtlb_longpath |
173 | nop | 241 | nop |
174 | 242 | ||
175 | kvmap_check_obp: | 243 | kvmap_check_obp: |
176 | sethi %hi(LOW_OBP_ADDRESS), %g5 | 244 | sethi %hi(LOW_OBP_ADDRESS), %g5 |
177 | cmp %g4, %g5 | 245 | cmp %g4, %g5 |
178 | blu,pn %xcc, kvmap_vmalloc_addr | 246 | blu,pn %xcc, kvmap_dtlb_vmalloc_addr |
179 | mov 0x1, %g5 | 247 | mov 0x1, %g5 |
180 | sllx %g5, 32, %g5 | 248 | sllx %g5, 32, %g5 |
181 | cmp %g4, %g5 | 249 | cmp %g4, %g5 |
182 | blu,pn %xcc, kvmap_do_obp | 250 | blu,pn %xcc, kvmap_dtlb_obp |
183 | nop | 251 | nop |
184 | 252 | ba,pt %xcc, kvmap_dtlb_vmalloc_addr | |
185 | kvmap_vmalloc_addr: | ||
186 | /* If we get here, a vmalloc addr was accessed, load kernel VPTE. */ | ||
187 | ldxa [%g3 + %g6] ASI_N, %g5 | ||
188 | brgez,pn %g5, longpath | ||
189 | nop | 253 | nop |
190 | 254 | ||
191 | kvmap_load: | 255 | kvmap_dtlb_longpath: |
192 | /* PTE is valid, load into TLB and return from trap. */ | 256 | |
193 | stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB | 257 | 661: rdpr %pstate, %g5 |
194 | retry | 258 | wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate |
259 | .section .sun4v_2insn_patch, "ax" | ||
260 | .word 661b | ||
261 | SET_GL(1) | ||
262 | ldxa [%g0] ASI_SCRATCHPAD, %g5 | ||
263 | .previous | ||
264 | |||
265 | rdpr %tl, %g3 | ||
266 | cmp %g3, 1 | ||
267 | |||
268 | 661: mov TLB_TAG_ACCESS, %g4 | ||
269 | ldxa [%g4] ASI_DMMU, %g5 | ||
270 | .section .sun4v_2insn_patch, "ax" | ||
271 | .word 661b | ||
272 | ldx [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5 | ||
273 | nop | ||
274 | .previous | ||
275 | |||
276 | be,pt %xcc, sparc64_realfault_common | ||
277 | mov FAULT_CODE_DTLB, %g4 | ||
278 | ba,pt %xcc, winfix_trampoline | ||
279 | nop | ||