Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / huron / src / l2subr.s
CommitLineData
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
1180:
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
1241:
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
1492:
150 stx %g2, [%g5] ! restore this banks L2$ mode
151 membar #Sync ! (will flush L2$ buffers)
152 STRAND_POP(%g7, %g2)
153 HVRET
154
155l2_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
1860:
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
1941:
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
2232:
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
3921:
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
4161:
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
5191:
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
5831:
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
6872:
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
7102:
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
7271:
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
7492:
750 jmp %g7 + 4
751 set L2_LINE_DIRTY, %g4 ! return dirty
752
753 ! return invalid
7540:
755 jmp %g7 + 4
756 set L2_LINE_INVALID, %g4 ! return invalid
757 SET_SIZE(check_l2_state)