Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: l2subr.s | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
46 | * Use is subject to license terms. | |
47 | */ | |
48 | ||
49 | .ident "@(#)l2subr.s 1.4 07/06/28 SMI" | |
50 | ||
51 | .file "l2subr.s" | |
52 | ||
53 | #include <sys/asm_linkage.h> | |
54 | #include <sys/htypes.h> | |
55 | #include <offsets.h> | |
56 | #include <asi.h> | |
57 | #include <util.h> | |
58 | #include <cache.h> | |
59 | #include <debug.h> | |
60 | ||
61 | ||
62 | /* | |
63 | * L2_FLUSH_BASEADDR - get a 4MB-aligned DRAM address for l2$ flushing | |
64 | * The assumption is that %htba contains a valid dram address valid | |
65 | * for the current machine configuration. Round it down to a 4MB | |
66 | * boundary to use as a base address for l2$ flushing. | |
67 | */ | |
68 | #define L2_FLUSH_BASEADDR(addr, scr) \ | |
69 | rdhpr %htba, addr ;\ | |
70 | set (4 MB) - 1, scr ;\ | |
71 | andn addr, scr, addr | |
72 | ||
73 | ||
74 | /* | |
75 | * This routine does a displacement flush of an entry specified by it's | |
76 | * physical address, from the Niagara-II L2$ (in hypervisor mode). | |
77 | * | |
78 | * | |
79 | * %g1 - paddr to flush from the cache | |
80 | * %g2 - %g6 clobbered | |
81 | * %g7 - return address | |
82 | */ | |
83 | ENTRY_NP(l2_flush_line) | |
84 | ||
85 | STRAND_PUSH(%g7, %g2, %g3) | |
86 | ||
87 | /* | |
88 | * Check if L2 cache index hashing is enabled | |
89 | */ | |
90 | setx L2_IDX_HASH_EN_STATUS, %g3, %g4 | |
91 | ldx [%g4], %g4 | |
92 | btst L2_IDX_HASH_EN_STATUS_MASK, %g4 | |
93 | bnz,pt %xcc, l2_flush_line_idx_enabled | |
94 | .empty | |
95 | ||
96 | /* | |
97 | * Determine the initial L2 flush addr for the specified paddr. | |
98 | * NOTE: this routine is used when IDX index hashing is disabled. | |
99 | */ | |
100 | set L2_BANK_SET, %g3 ! PA mask for bank and set | |
101 | and %g3, %g1, %g3 ! PA[17:6] | |
102 | ||
103 | L2_FLUSH_BASEADDR(%g4, %g2) | |
104 | add %g3, %g4, %g3 ! %g3 = the flush addr to use | |
105 | ||
106 | /* | |
107 | * Put L2 into direct mapped mode, this bank only. | |
108 | */ | |
109 | setx L2_CONTROL_REG, %g4, %g5 | |
110 | and %g3, (L2_BANK_MASK << L2_BANK_SHIFT), %g2 | |
111 | or %g5, %g2, %g5 ! include offset in reg addr | |
112 | ||
113 | ldx [%g5], %g2 ! %g2=prev L2_CTL_REG contents | |
114 | or %g2, L2_DMMODE, %g6 | |
115 | stx %g6, [%g5] | |
116 | ||
117 | clr %g2 | |
118 | 0: | |
119 | /* | |
120 | * Flush all 16 ways (all possible locations of the data). | |
121 | */ | |
122 | mov (L2_NUM_WAYS - 1), %g6 | |
123 | set (1 << L2_WAY_SHIFT), %g4 | |
124 | 1: | |
125 | ldx [%g3], %g0 ! access flush addr to flush | |
126 | membar #Sync ! data out to DRAM | |
127 | add %g3, %g4, %g3 | |
128 | brgz,pt %g6, 1b ! next WAY | |
129 | dec %g6 | |
130 | ||
131 | inc %g2 | |
132 | cmp %g2, 3 | |
133 | be,pn %xcc, 2f | |
134 | nop | |
135 | ||
136 | set L2_BANK_SET, %g3 ! PA mask for bank and set | |
137 | and %g3, %g1, %g3 ! PA[17:6] | |
138 | ||
139 | L2_FLUSH_BASEADDR(%g4, %g7) | |
140 | set 4 MB, %g7 | |
141 | cmp %g2, 2 | |
142 | move %xcc, %g0, %g7 | |
143 | add %g4, %g7, %g4 | |
144 | add %g3, %g4, %g3 ! %g3 = the flush addr to use | |
145 | ||
146 | ba 0b | |
147 | nop | |
148 | ||
149 | 2: | |
150 | stx %g2, [%g5] ! restore this banks L2$ mode | |
151 | membar #Sync ! (will flush L2$ buffers) | |
152 | STRAND_POP(%g7, %g2) | |
153 | HVRET | |
154 | ||
155 | l2_flush_line_idx_enabled: | |
156 | ! %g1 PA | |
157 | ! %g7 return address | |
158 | STRAND_PUSH(%g1, %g2, %g3) | |
159 | ||
160 | /* | |
161 | * Mask addr so only the index bits remain, then add flush BA. | |
162 | */ | |
163 | set L2_BANK_SET, %g3 ! PA mask for bank and set | |
164 | and %g3, %g1, %g3 ! %g3 PA[17:6] | |
165 | ||
166 | L2_FLUSH_BASEADDR(%g6, %g2) ! %g6 flush Base Address | |
167 | add %g3, %g6, %g3 ! %g3 first flush addr to use | |
168 | ||
169 | set (L2_WAY_MASK << L2_WAY_SHIFT), %g7 ! %g7 = mask of all way bits | |
170 | andn %g3, %g7, %g3 ! clear way bits from flush addr | |
171 | ||
172 | /* | |
173 | * Put L2 into direct mapped mode, this bank only. | |
174 | */ | |
175 | setx L2_CONTROL_REG, %g4, %g5 | |
176 | and %g3, (L2_BANK_MASK << L2_BANK_SHIFT), %g2 ! %g2 bank | |
177 | or %g5, %g2, %g5 | |
178 | ldx [%g5], %g7 ! %g7 L2_CTL_REG contents | |
179 | or %g7, L2_DMMODE, %g6 | |
180 | stx %g6, [%g5] | |
181 | ! store control register address/mode for later restore | |
182 | STRAND_PUSH(%g7, %g4, %g6) | |
183 | STRAND_PUSH(%g5, %g4, %g6) | |
184 | ||
185 | clr %g1 | |
186 | 0: | |
187 | mov 1, %g6 ! %g6 = L2 way inc. value | |
188 | sllx %g6, L2_WAY_SHIFT, %g6 | |
189 | ||
190 | /* | |
191 | * Flush all ways (all possible locations of the data). | |
192 | */ | |
193 | mov (L2_NUM_WAYS - 1), %g5 ! %g5 = number of L2 ways | |
194 | 1: | |
195 | mov %g3, %g7 | |
196 | N2_PERFORM_IDX_HASH(%g7, %g2, %g4) ! %g7 = IDX'd flush addr | |
197 | ||
198 | ldx [%g7], %g0 ! access flush addr to flush | |
199 | membar #Sync ! data out to DRAM | |
200 | ||
201 | add %g3, %g6, %g3 ! go to next way (add way inc) | |
202 | ||
203 | brgz %g5, 1b ! are we done all ways? | |
204 | sub %g5, 1, %g5 ! decrement count | |
205 | ||
206 | inc %g1 | |
207 | cmp %g1, 3 | |
208 | be,pn %xcc, 2f | |
209 | nop | |
210 | ||
211 | L2_FLUSH_BASEADDR(%g6, %g7) ! %g6 flush Base Address | |
212 | set 4 MB, %g7 | |
213 | cmp %g1, 2 | |
214 | move %xcc, %g0, %g7 | |
215 | add %g6, %g7, %g6 | |
216 | add %g3, %g6, %g3 ! %g3 first flush addr to use | |
217 | ||
218 | set (L2_WAY_MASK << L2_WAY_SHIFT), %g7 ! %g7 = mask of all way bits | |
219 | andn %g3, %g7, %g3 ! clear way bits from flush addr | |
220 | ba 0b | |
221 | nop | |
222 | ||
223 | 2: | |
224 | ! restore direct mapped mode | |
225 | STRAND_POP(%g5, %g4) | |
226 | STRAND_POP(%g7, %g4) | |
227 | stx %g7, [%g5] ! restore this banks L2$ mode | |
228 | membar #Sync ! (will flush L2$ buffers) | |
229 | ||
230 | STRAND_POP(%g1, %g6) | |
231 | STRAND_POP(%g7, %g6) | |
232 | HVRET | |
233 | ||
234 | SET_SIZE(l2_flush_line) | |
235 | ||
236 | /* | |
237 | * get_l2_vdbits_for_pa()() | |
238 | * Read VD (Valid Dirty) bits of l2$ set for a given PA | |
239 | * Arguments: | |
240 | * %g1 -> input - physical address (preserved) | |
241 | * %g2 -> output - VD bit array for 16 ways: | |
242 | * | |
243 | * bit 38->32: ECC for all dirty and valid bits | |
244 | * bit 31->16: valid bit for way 15->0 | |
245 | * bit 15->0: dirty bit for way 15->0 | |
246 | * | |
247 | * %g3 -> scratch | |
248 | * %g4 - preserved | |
249 | * %g5, %g6 - preserved | |
250 | * %g7 -> input - return address | |
251 | */ | |
252 | ENTRY_NP(get_l2_vdbits_for_pa) | |
253 | set 0xa6004000, %g2 | |
254 | sllx %g2, 8, %g2 ! %g2 = L2_SELECT_A6 | L2_VDSEL | |
255 | set L2_BANK_SET, %g3 ! %g3 = L2 SET|BANK MASK <17:6> | |
256 | and %g1, %g3, %g3 ! %g3 = set and bank bits of paddr | |
257 | or %g2, %g3, %g2 ! %g2 = addr to read L2_DIAG_VD | |
258 | jmp %g7 + 4 ! return | |
259 | ldx [%g2], %g2 ! %g2 -> output | |
260 | SET_SIZE(get_l2_vdbits_for_pa) | |
261 | ||
262 | ||
263 | /* | |
264 | * get_l2_vdbits_for_set() | |
265 | * Read VD (Valid Dirty) bits of l2$ set specified by index and bank | |
266 | * Arguments: | |
267 | * %g1 -> input - set index (preserved) | |
268 | * %g2 -> input - L2 bank number (preserved) | |
269 | * %g3 -> output - VD bit array for 12 ways | |
270 | * --------------------------------------- | |
271 | * |VPARITY| DPARITY |V11 .. V0|D11 .. D0| | |
272 | * --------------------------------------- | |
273 | * Bits-> 25 24 23 12 11 0 | |
274 | * | |
275 | * %g4 -> scratch | |
276 | * %g5, %g6 - preserved | |
277 | * %g7 -> input - return address | |
278 | */ | |
279 | ENTRY_NP(get_l2_vdbits_for_set) | |
280 | set 0xa6004000, %g3 | |
281 | sllx %g3, 8, %g3 ! %g3 = L2_SELECT_A6 | L2_VDSEL | |
282 | sllx %g1, L2_SET_SHIFT, %g4 ! %g4 = set << L2_SET_SHIFT | |
283 | or %g3, %g4, %g3 ! %g3 |= %g4 | |
284 | sllx %g2, L2_BANK_SHIFT, %g4 ! %g4 = bank << L2_BANK_SHIFT | |
285 | or %g3, %g4, %g3 ! %g3 |= %g4 | |
286 | jmp %g7 + 4 ! return | |
287 | ldx [%g3], %g3 ! %g3 -> output | |
288 | SET_SIZE(get_l2_vdbits_for_set) | |
289 | ||
290 | /* | |
291 | * get_l2_uabits_for_pa()() | |
292 | * Read UA (Used Allocated) bits of l2$ set for a given PA | |
293 | * Arguments: | |
294 | * %g1 -> input - physical address (preserved) | |
295 | * %g2 -> output - UA bit array for 16 ways | |
296 | * | |
297 | * bit 38->32: ECC for all used and alloc bits | |
298 | * bit 31->16: used bit for way 15->0 | |
299 | * bit 15->0: allocated bit for way 15->0 | |
300 | * | |
301 | * %g3 -> scratch | |
302 | * %g4 - preserved | |
303 | * %g5, %g6 - preserved | |
304 | * %g7 -> input - return address | |
305 | */ | |
306 | ENTRY_NP(get_l2_uabits_for_pa) | |
307 | set 0xa6000000, %g2 | |
308 | sllx %g2, 8, %g2 ! %g2 = L2_SELECT_A6 | |
309 | set L2_BANK_SET, %g3 ! %g3 = L2 SET|BANK MASK <17:6> | |
310 | and %g1, %g3, %g3 ! %g3 = set and bank bits of paddr | |
311 | or %g2, %g3, %g2 ! %g2 = addr to read L2_DIAG_UA | |
312 | jmp %g7 + 4 ! return | |
313 | ldx [%g2], %g2 ! %g2 -> output | |
314 | SET_SIZE(get_l2_uabits_for_pa) | |
315 | ||
316 | /* | |
317 | * get_l2_tag_for_line(int way, int set, int bank) | |
318 | * Read L2$ tag for a given way, set, and bank. | |
319 | * Arguments: | |
320 | * %g1 -> input - cache way | |
321 | * %g2 -> input - set index | |
322 | * %g3 -> input - bank number | |
323 | * %g4 -> output - L2$ tag | |
324 | * -------------------------- | |
325 | * | TAG => PA<39:18> | ECC | | |
326 | * -------------------------- | |
327 | * 27...............6 5...0 | |
328 | * %g5, %g6 - preserved | |
329 | * %g7 -> return address | |
330 | */ | |
331 | ENTRY_NP(get_l2_tag_for_line) | |
332 | set 0xa4000000, %g4 ! %g4 = L2_SELECT_A4 >> 8 | |
333 | or %g4, %g2, %g4 ! %g4 += set index | |
334 | sllx %g4, L2_SET_SHIFT, %g4 ! %g4 << L2_SET_SHIFT (8) | |
335 | sllx %g1, L2_WAY_SHIFT, %g1 ! %g1 = %g1 << L2_WAY_SHIFT | |
336 | or %g4, %g1, %g4 ! %g4 |= %g1 | |
337 | srlx %g1, L2_WAY_SHIFT, %g1 ! %g1 = %g1 >> L2_WAY_SHIFT | |
338 | sllx %g3, L2_BANK_SHIFT, %g3 ! %g3 = %g3 << L2_BANK_SHIFT | |
339 | or %g4, %g3, %g4 ! %g4 |= %g3 | |
340 | srlx %g3, L2_BANK_SHIFT, %g3 ! %g3 = %g3 >> L2_BANK_SHIFT | |
341 | jmp %g7 + 4 ! return | |
342 | ldx [%g4], %g4 ! %g4 -> output | |
343 | SET_SIZE(get_l2_tag_for_line) | |
344 | ||
345 | /* | |
346 | * get_l2_tag_by_way(uint64_t pa, int way) | |
347 | * Read L2$ tag for a given way and physical address | |
348 | * Arguments: | |
349 | * %g1 -> input - physical address | |
350 | * %g2 -> input - way | |
351 | * %g3 -> output - L2$ tag | |
352 | * -------------------------- | |
353 | * | TAG => PA<39:18> | ECC | | |
354 | * -------------------------- | |
355 | * 27...............6 5...0 | |
356 | * %g4 -> scratch | |
357 | * %g5, %g6 - preserved | |
358 | * %g7 -> return address | |
359 | */ | |
360 | ENTRY_NP(get_l2_tag_by_way) | |
361 | set L2_BANK_SET, %g4 | |
362 | ! %g4 = L2 SET|BANK MASK <17:6> | |
363 | and %g4, %g1, %g4 ! %g4 &= %g1 (pa) | |
364 | sllx %g2, L2_WAY_SHIFT, %g3 ! %g3 = %g2 << L2_WAY_SHIFT | |
365 | or %g4, %g3, %g4 ! %g4 |= %g3 | |
366 | set 0xA4, %g3 | |
367 | sllx %g3, 32, %g3 ! %g3 = L2_SELECT_A4 | |
368 | or %g3, %g4, %g3 ! %g3 |= %g4 | |
369 | jmp %g7 + 4 ! return | |
370 | ldx [%g3], %g3 ! %g3 -> output | |
371 | SET_SIZE(get_l2_tag_by_way) | |
372 | ||
373 | /* | |
374 | * set_l2_bank_dmmode(int bank) | |
375 | * Set the L2 bank in direct-mapped displacement mode | |
376 | * Arguments: | |
377 | * %g1 - input -> L2 bank number (preserved) | |
378 | * %g2 - scratch | |
379 | * %g3 - scratch | |
380 | * %g4, %g5, %g6 - preserved | |
381 | * %g7 - input -> return address | |
382 | */ | |
383 | ENTRY_NP(set_l2_bank_dmmode) | |
384 | SKIP_DISABLED_L2_BANK(%g1, %g2, %g3, 1f) | |
385 | setx L2_CONTROL_REG, %g3, %g2 | |
386 | sllx %g1, L2_BANK_SHIFT, %g3 | |
387 | or %g2, %g3, %g2 ! or in L2 bank | |
388 | ldx [%g2], %g3 ! read L2_CONTROL[bank] | |
389 | or %g3, L2_DMMODE, %g3 ! %g3 |= L2_DMMODE | |
390 | jmp %g7 + 4 ! return | |
391 | stx %g3, [%g2] ! L2_CONTROL[bank] = %g3 | |
392 | 1: | |
393 | HVRET | |
394 | SET_SIZE(set_l2_bank_dmmode) | |
395 | ||
396 | ||
397 | /* | |
398 | * reset_l2_bank_dmmode(int bank) | |
399 | * Reset the L2 bank to normal mode | |
400 | * Arguments: | |
401 | * %g1 - input -> L2 bank number (preserved) | |
402 | * %g2 - scratch | |
403 | * %g3 - scratch | |
404 | * %g4, %g5, %g6 - preserved | |
405 | * %g7 - input -> return address | |
406 | */ | |
407 | ENTRY_NP(reset_l2_bank_dmmode) | |
408 | SKIP_DISABLED_L2_BANK(%g1, %g2, %g3, 1f) | |
409 | setx L2_CONTROL_REG, %g3, %g2 | |
410 | sllx %g1, L2_BANK_SHIFT, %g3 | |
411 | or %g2, %g3, %g2 ! or in L2 bank | |
412 | ldx [%g2], %g3 ! read L2_CONTROL[bank] | |
413 | bclr L2_DMMODE, %g3 ! %g3 &= ~L2_DMMODE | |
414 | jmp %g7 + 4 ! return | |
415 | stx %g3, [%g2] ! L2_CONTROL[bank] = %g3 | |
416 | 1: | |
417 | HVRET | |
418 | SET_SIZE(reset_l2_bank_dmmode) | |
419 | ||
420 | ||
421 | /* | |
422 | * set_all_banks_dmmode - set all l2 banks to direct-mapped mode | |
423 | * | |
424 | * NON-LEAF | |
425 | * %g7 - return address | |
426 | * clobbers %g6 along with the lowered-numbered registers | |
427 | * clobbered by set_l2_bank_dmmode | |
428 | */ | |
429 | ENTRY_NP(set_all_banks_dmmode) | |
430 | mov %g7, %g6 ! save return | |
431 | ||
432 | mov 0, %g1 ! bank 0 | |
433 | HVCALL(set_l2_bank_dmmode) | |
434 | ||
435 | mov 1, %g1 ! bank 1 | |
436 | HVCALL(set_l2_bank_dmmode) | |
437 | ||
438 | mov 2, %g1 ! bank 2 | |
439 | HVCALL(set_l2_bank_dmmode) | |
440 | ||
441 | mov 3, %g1 ! bank 3 | |
442 | HVCALL(set_l2_bank_dmmode) | |
443 | ||
444 | mov 4, %g1 ! bank 4 | |
445 | HVCALL(set_l2_bank_dmmode) | |
446 | ||
447 | mov 5, %g1 ! bank 5 | |
448 | HVCALL(set_l2_bank_dmmode) | |
449 | ||
450 | mov 6, %g1 ! bank 6 | |
451 | HVCALL(set_l2_bank_dmmode) | |
452 | ||
453 | mov 7, %g1 ! bank 7 | |
454 | HVCALL(set_l2_bank_dmmode) | |
455 | ||
456 | mov %g6, %g7 ! restore return | |
457 | HVRET | |
458 | SET_SIZE(set_all_banks_dmmode) | |
459 | ||
460 | /* | |
461 | * reset_all_banks_dmmode - set all l2 banks to normal mode | |
462 | * | |
463 | * NON-LEAF | |
464 | * %g7 - return address | |
465 | * clobbers %g6 along with the lowered-numbered registers | |
466 | * clobbered by reset_set_l2_bank_dmmode | |
467 | */ | |
468 | ENTRY_NP(reset_all_banks_dmmode) | |
469 | mov %g7, %g6 ! save return | |
470 | ||
471 | mov 0, %g1 | |
472 | HVCALL(reset_l2_bank_dmmode) | |
473 | ||
474 | mov 1, %g1 ! bank 1 | |
475 | HVCALL(reset_l2_bank_dmmode) | |
476 | ||
477 | mov 2, %g1 ! bank 2 | |
478 | HVCALL(reset_l2_bank_dmmode) | |
479 | ||
480 | mov 3, %g1 ! bank 3 | |
481 | HVCALL(reset_l2_bank_dmmode) | |
482 | ||
483 | mov 4, %g1 ! bank 4 | |
484 | HVCALL(reset_l2_bank_dmmode) | |
485 | ||
486 | mov 5, %g1 ! bank 5 | |
487 | HVCALL(reset_l2_bank_dmmode) | |
488 | ||
489 | mov 6, %g1 ! bank 6 | |
490 | HVCALL(reset_l2_bank_dmmode) | |
491 | ||
492 | mov 7, %g1 ! bank 7 | |
493 | HVCALL(reset_l2_bank_dmmode) | |
494 | ||
495 | mov %g6, %g7 ! restore return | |
496 | HVRET | |
497 | SET_SIZE(reset_all_banks_dmmode) | |
498 | ||
499 | /* | |
500 | * l2_flush_cache(void) | |
501 | * Flush the entire l2 cache | |
502 | * clobbers %g1-%g6 | |
503 | * %g7 - return address | |
504 | */ | |
505 | ENTRY_NP(l2_flush_cache) | |
506 | mov %g7, %g5 ! set_all_banks_dmmode clobbers %g6 | |
507 | ||
508 | HVCALL(set_all_banks_dmmode) | |
509 | ||
510 | /* | |
511 | * read in from 0 to 3MB * 2. Experiments have shown that reading | |
512 | * in 3 times the size of L2$ from 3 different 4MB-aligned addresses | |
513 | * flushes the cache reliably. | |
514 | */ | |
515 | L2_FLUSH_BASEADDR(%g2, %g4) | |
516 | set 0x900000, %g1 ! end | |
517 | add %g2, %g1, %g1 | |
518 | ||
519 | 1: | |
520 | ldx [%g2], %g0 | |
521 | inc L2_LINE_SIZE, %g2 ! next cache line | |
522 | cmp %g2, %g1 | |
523 | blu,pt %xcc, 1b ! not done, go to 1 | |
524 | nop | |
525 | ||
526 | HVCALL(reset_all_banks_dmmode) | |
527 | ||
528 | mov %g5, %g7 | |
529 | HVRET | |
530 | SET_SIZE(l2_flush_cache) | |
531 | ||
532 | /* | |
533 | * dump_l2_set_tag_data_ecc(uint64_t pa, void *dump_area) [Non-leaf] | |
534 | * Dump the L2$ tag and data and ECC for the set corresponding to the | |
535 | * given physical address, pa. | |
536 | * | |
537 | * The dump format is: | |
538 | * 0x0 [VPARITY | DPARITY | VALID bits | DIRTY bits] | |
539 | * 0x8 [APARITY | USED bits | ALLOC bits] | |
540 | * 0x10 [way 0 tag + ECC] | |
541 | * 0x18 [way 0 32-bit word 0 + ECC] | |
542 | * 0x20 [way 0 32-bit word 1 + ECC] | |
543 | * 0x28 [way 0 32-bit word 2 + ECC] | |
544 | * ... | |
545 | * 0x90 [way 0 32-bit word 15 + ECC] | |
546 | * 0x98 [way 1 tag + ECC] | |
547 | * 0xa0 way 1 data | |
548 | * ... | |
549 | * | |
550 | * This function does not change L2$ enabled/disabled status. | |
551 | * | |
552 | * Arguments: | |
553 | * %g1 - input - physical address | |
554 | * %g2 - input - pointer to dump area | |
555 | * %g3-%g6 - scratch | |
556 | * %g7 - input - return address | |
557 | */ | |
558 | ENTRY_NP(dump_l2_set_tag_data_ecc) | |
559 | mov %g2, %g5 | |
560 | mov %g7, %g6 | |
561 | ba get_l2_vdbits_for_pa | |
562 | rd %pc, %g7 | |
563 | ||
564 | stx %g2, [%g5] ! store VD bits and parity | |
565 | add %g5, 8, %g5 | |
566 | ||
567 | ba get_l2_uabits_for_pa | |
568 | rd %pc, %g7 | |
569 | ||
570 | stx %g2, [%g5] ! save UA bits and parity | |
571 | add %g5, 8, %g5 | |
572 | ||
573 | mov %g0, %g2 ! set way = 0 | |
574 | ba get_l2_tag_by_way | |
575 | rd %pc, %g7 | |
576 | ||
577 | stx %g3, [%g5] ! save tag_ECC[0] | |
578 | add %g5, 8, %g5 | |
579 | ||
580 | mov %g6, %g7 ! restore original return | |
581 | ||
582 | mov %g0, %g2 ! way number | |
583 | 1: | |
584 | set L2_BANK_SET, %g4 ! %g4 = L2 SET|BANK MASK <17:6> | |
585 | and %g4, %g1, %g4 ! %g4 &= %g1 (pa) | |
586 | or %g4, %g2, %g4 ! %g4 |= (way_num << L2_WAY_SHIFT) | |
587 | ! way 0, word 0 | |
588 | set 0xA1, %g3 | |
589 | sllx %g3, 32, %g3 ! %g3 = L2_SELECT_A1 | EVEN | |
590 | or %g4, %g3, %g4 ! %g4 |= L2_SELECT_A1 | |
591 | ldx [%g4], %g6 ! read even 32-bit | |
592 | stx %g6, [%g5] ! store even 32-bit data | |
593 | add %g5, 8, %g5 ! increment pointer | |
594 | set (1 << 22), %g3 ! ODDEVEN = 1 | |
595 | or %g4, %g3, %g4 ! select ODD | |
596 | ldx [%g4], %g6 ! read odd 32-bit | |
597 | stx %g6, [%g5] ! store odd 32-bit data | |
598 | add %g5, 8, %g5 ! increment pointer | |
599 | ! way 0, word 1 | |
600 | add %g4, 8, %g4 ! next word | |
601 | andn %g4, %g3, %g4 ! EVEN | |
602 | ldx [%g4], %g6 ! read even 32-bit | |
603 | stx %g6, [%g5] ! store even 32-bit data | |
604 | add %g5, 8, %g5 ! increment pointer | |
605 | set (1 << 22), %g3 ! ODDEVEN = 1 | |
606 | or %g4, %g3, %g4 ! select ODD | |
607 | ldx [%g4], %g6 ! read odd 32-bit | |
608 | stx %g6, [%g5] ! store odd 32-bit data | |
609 | add %g5, 8, %g5 ! increment pointer | |
610 | ! way 0, word 2 | |
611 | add %g4, 8, %g4 ! next word | |
612 | andn %g4, %g3, %g4 ! EVEN | |
613 | ldx [%g4], %g6 ! read even 32-bit | |
614 | stx %g6, [%g5] ! store even 32-bit data | |
615 | add %g5, 8, %g5 ! increment pointer | |
616 | or %g4, %g3, %g4 ! select ODD | |
617 | ldx [%g4], %g6 ! read odd 32-bit | |
618 | stx %g6, [%g5] ! store odd 32-bit data | |
619 | add %g5, 8, %g5 ! increment pointer | |
620 | ! way 0, word 3 | |
621 | add %g4, 8, %g4 ! next word | |
622 | andn %g4, %g3, %g4 ! EVEN | |
623 | ldx [%g4], %g6 ! read even 32-bit | |
624 | stx %g6, [%g5] ! store even 32-bit data | |
625 | add %g5, 8, %g5 ! increment pointer | |
626 | or %g4, %g3, %g4 ! select ODD | |
627 | ldx [%g4], %g6 ! read odd 32-bit | |
628 | stx %g6, [%g5] ! store odd 32-bit data | |
629 | add %g5, 8, %g5 ! increment pointer | |
630 | ! way 0, word 4 | |
631 | add %g4, 8, %g4 ! next word | |
632 | andn %g4, %g3, %g4 ! EVEN | |
633 | ldx [%g4], %g6 ! read even 32-bit | |
634 | stx %g6, [%g5] ! store even 32-bit data | |
635 | add %g5, 8, %g5 ! increment pointer | |
636 | or %g4, %g3, %g4 ! select ODD | |
637 | ldx [%g4], %g6 ! read odd 32-bit | |
638 | stx %g6, [%g5] ! store odd 32-bit data | |
639 | add %g5, 8, %g5 ! increment pointer | |
640 | ! way 0, word 5 | |
641 | add %g4, 8, %g4 ! next word | |
642 | andn %g4, %g3, %g4 ! EVEN | |
643 | ldx [%g4], %g6 ! read even 32-bit | |
644 | stx %g6, [%g5] ! store even 32-bit data | |
645 | add %g5, 8, %g5 ! increment pointer | |
646 | or %g4, %g3, %g4 ! select ODD | |
647 | ldx [%g4], %g6 ! read odd 32-bit | |
648 | stx %g6, [%g5] ! store odd 32-bit data | |
649 | add %g5, 8, %g5 ! increment pointer | |
650 | ! way 0, word 6 | |
651 | add %g4, 8, %g4 ! next word | |
652 | andn %g4, %g3, %g4 ! EVEN | |
653 | ldx [%g4], %g6 ! read even 32-bit | |
654 | stx %g6, [%g5] ! store even 32-bit data | |
655 | add %g5, 8, %g5 ! increment pointer | |
656 | or %g4, %g3, %g4 ! select ODD | |
657 | ldx [%g4], %g6 ! read odd 32-bit | |
658 | stx %g6, [%g5] ! store odd 32-bit data | |
659 | add %g5, 8, %g5 ! increment pointer | |
660 | ! way 0, word 7 | |
661 | add %g4, 8, %g4 ! next word | |
662 | andn %g4, %g3, %g4 ! EVEN | |
663 | ldx [%g4], %g6 ! read even 32-bit | |
664 | stx %g6, [%g5] ! store even 32-bit data | |
665 | add %g5, 8, %g5 ! increment pointer | |
666 | or %g4, %g3, %g4 ! select ODD | |
667 | ldx [%g4], %g6 ! read odd 32-bit | |
668 | stx %g6, [%g5] ! store odd 32-bit data | |
669 | add %g5, 8, %g5 ! increment pointer | |
670 | ! next way | |
671 | srlx %g2, L2_WAY_SHIFT, %g2 ! current way | |
672 | add %g2, 1, %g2 ! next way | |
673 | cmp %g2, L2_NUM_WAYS | |
674 | bz 2f ! read tag and loop back if not done | |
675 | nop | |
676 | ||
677 | ! read tag | |
678 | mov %g7, %g6 ! save original return | |
679 | ba get_l2_tag_by_way | |
680 | rd %pc, %g7 | |
681 | mov %g6, %g7 ! restore original return | |
682 | stx %g3, [%g5] ! save tag_ECC[next] | |
683 | add %g5, 8, %g5 ! increment | |
684 | ba 1b | |
685 | sllx %g2, L2_WAY_SHIFT, %g2 ! shift to way field | |
686 | ||
687 | 2: | |
688 | HVRET | |
689 | SET_SIZE(dump_l2_set_tag_data_ecc) | |
690 | ||
691 | /* | |
692 | * check_l2_state(uint64_t pa) | |
693 | * Checks L2$ line state for the given physical address | |
694 | * and returns 0 for clean, 1 for dirty, 2 for invalid, 3 = not found | |
695 | * Arguments: | |
696 | * %g1 - input - physical address | |
697 | * %g4 - output - clean, dirty or invalid state | |
698 | * %g7 - input - return address | |
699 | */ | |
700 | ENTRY_NP(check_l2_state) | |
701 | mov %g7, %g6 | |
702 | ||
703 | ! get PA<39:18> from pa | |
704 | setx L2_PA_TAG_MASK, %g2, %g5 | |
705 | and %g1, %g5, %g5 ! %g5 has PA<39:18> | |
706 | srlx %g5, L2_PA_TAG_SHIFT, %g5 | |
707 | ||
708 | ! read L2 tag | |
709 | set 0, %g2 | |
710 | 2: | |
711 | ba get_l2_tag_by_way ! returns tag in %g3 | |
712 | rd %pc, %g7 | |
713 | setx L2_TAG_MASK, %g7, %g4 | |
714 | and %g3, %g4, %g3 | |
715 | srlx %g3, L2_TAG_SHIFT, %g3 ! %g3 has L2 TAG<27:6> | |
716 | cmp %g3, %g5 ! %g5 has the PA tag | |
717 | bz 1f | |
718 | add %g2, 1, %g2 | |
719 | cmp %g2, L2_NUM_WAYS ! 16th way? | |
720 | bnz 2b ! no, do next way | |
721 | mov %g6, %g7 | |
722 | ! done, return not found | |
723 | jmp %g7 + 4 | |
724 | set L2_LINE_NOT_FOUND, %g4 ! return not found | |
725 | ||
726 | ! tag match found | |
727 | 1: | |
728 | mov %g2, %g5 ! %g5 = %g2 | |
729 | sub %g5, 1, %g5 ! %g5 has the way number | |
730 | ba get_l2_vdbits_for_pa ! returns vdbits in %g2 | |
731 | rd %pc, %g7 | |
732 | add %g5, L2_NUM_WAYS, %g5 | |
733 | set 1, %g3 | |
734 | sllx %g3, %g5, %g3 ! set valid[way] | |
735 | btst %g3, %g2 ! is valid? | |
736 | bz 0f | |
737 | mov %g6, %g7 | |
738 | ||
739 | ! check dirty or clean | |
740 | srlx %g3, L2_NUM_WAYS, %g3 ! set dirty[way] | |
741 | btst %g3, %g2 ! is dirty? | |
742 | bnz 2f ! yes, return dirty | |
743 | mov %g6, %g7 | |
744 | ! return clean | |
745 | jmp %g7 + 4 | |
746 | set L2_LINE_CLEAN, %g4 ! return clean | |
747 | ||
748 | ! return dirty | |
749 | 2: | |
750 | jmp %g7 + 4 | |
751 | set L2_LINE_DIRTY, %g4 ! return dirty | |
752 | ||
753 | ! return invalid | |
754 | 0: | |
755 | jmp %g7 + 4 | |
756 | set L2_LINE_INVALID, %g4 ! return invalid | |
757 | SET_SIZE(check_l2_state) |