Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / huron / src / errors_l2_cache.s
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: errors_l2_cache.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#pragma ident "@(#)errors_l2_cache.s 1.12 07/09/18 SMI"
50
51#include <sys/asm_linkage.h>
52#include <hypervisor.h>
53#include <vcpu.h>
54#include <asi.h>
55#include <mmu.h>
56#include <hprivregs.h>
57#include <dram.h>
58#include <abort.h>
59
60#include <offsets.h>
61#include <util.h>
62#include <error_defs.h>
63#include <error_regs.h>
64#include <error_asm.h>
65#include <cmp.h>
66#include <traps.h>
67
68 /*
69 * Clear and correct L2 cache LDAU/LDAC error
70 */
71 ENTRY(correct_l2_ildau)
72 ba correct_l2_lda_common
73 nop
74 SET_SIZE(correct_l2_ildau)
75
76 ENTRY(correct_l2_dldac)
77 ALTENTRY(correct_l2_dldau)
78 ba correct_l2_lda_common
79 nop
80 SET_SIZE(correct_l2_dldac)
81 SET_SIZE(correct_l2_dldau)
82
83 ENTRY(correct_l2_lda_common)
84
85 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
86 brz,pn %g1, .correct_lda_exit
87 nop
88
89 /*
90 * Find the bank/PA in error
91 */
92 set (NO_L2_BANKS - 1), %g3
93.correct_lda_next_bank:
94 add %g1, ERR_DIAG_BUF_L2_CACHE_ESR, %g2
95 mulx %g3, ERR_DIAG_BUF_L2_CACHE_ESR_INCR, %g5
96 add %g2, %g5, %g2
97 ldx [%g2], %g5
98 brz,pn %g5, .correct_lda_next_ear ! no error on this bank
99 nop
100
101 add %g1, ERR_DIAG_BUF_L2_CACHE_EAR, %g2
102 mulx %g3, ERR_DIAG_BUF_L2_CACHE_EAR_INCR, %g5
103 add %g2, %g5, %g2
104 ldx [%g2], %g6
105
106 ! %g3 bank
107 ! %g6 PA
108
109 /*
110 * Check if L2 cache index hashing is enabled
111 */
112 setx L2_IDX_HASH_EN_STATUS, %g5, %g4
113 ldx [%g4], %g4
114 btst L2_IDX_HASH_EN_STATUS_MASK, %g4
115 bz,pt %xcc, .correct_lda_no_idx_hashing
116 nop
117
118 N2_PERFORM_IDX_HASH(%g6, %g2, %g4) ! %g6 = IDX'd flush addr
119.correct_lda_no_idx_hashing:
120 prefetch [%g6], INVALIDATE_CACHE_LINE
121.correct_lda_next_ear:
122 brgz,pt %g3, .correct_lda_next_bank
123 dec %g3
124.correct_lda_exit:
125 HVRET
126
127 SET_SIZE(correct_l2_lda_common)
128
129
130 /*
131 * Dump L2 cache diagnostic data for all L2 errors
132 * %g7 return address
133 *
134 * Note: Erratum 116 requires FBD Syndrome register to be written
135 * twice to clear the value. Recommended to do this for all
136 * DRAM ESRs.
137 */
138 ENTRY(dump_l2_cache)
139
140 /*
141 * save our return address
142 */
143 STORE_ERR_RETURN_ADDR(%g7, %g3, %g4)
144
145 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
146
147 /*
148 * Store L2 ESR/EAR/ND for the bank in error into the DIAG_BUF
149 */
150 set (NO_L2_BANKS - 1), %g3
151.dump_l2c_l2_banks:
152 STRAND_PUSH(%g3, %g4, %g5)
153
154 ! skip banks which are disabled. causes hang.
155 SKIP_DISABLED_L2_BANK(%g3, %g4, %g5, .dump_l2c_no_l2_error)
156
157 setx L2_ERROR_STATUS_REG, %g4, %g5
158 sllx %g3, L2_BANK_SHIFT, %g2
159 or %g5, %g2, %g2
160 ldx [%g2], %g4
161 setx (L2_ESR_VEU | L2_ESR_VEC | L2_ESR_DSC | L2_ESR_DSU), %g5, %g6
162 btst %g6, %g4
163 stx %g4, [%g2] ! clear ESR RW1C
164 stx %g0, [%g2] ! clear ESR RW
165
166 add %g1, ERR_DIAG_BUF_L2_CACHE_ESR, %g2
167 mulx %g3, ERR_DIAG_BUF_L2_CACHE_ESR_INCR, %g5
168 add %g2, %g5, %g2
169 ! %g2 diag_buf->l2_cache.esr
170 bz,pt %xcc, 0f
171 stx %g4, [%g2]
172
173 ! don't save the bank number if CEEN already off,
174 ! this bank did not generate the trap
175 setx L2_ERROR_ENABLE_REG, %g5, %g6
176 sllx %g3, L2_BANK_SHIFT, %g5
177 or %g6, %g5, %g6
178 ldx [%g6], %g5
179 btst L2_CEEN, %g5
180 ! save the bank number
181 bnz,a,pn %xcc, 0f ! CEEN on, store bank in delay slot
182 stx %g3, [%g1 + ERR_DIAG_L2_BANK]
1830:
184
185 ! No L2 data encoded for DSC/DSU
186 ! %g4 ESR
187 setx (L2_ESR_DSC | L2_ESR_DSU), %g5, %g6
188 btst %g6, %g4
189 bnz %xcc, .dump_l2c_no_l2_error
190 nop
191
192 add %g1, ERR_DIAG_BUF_L2_CACHE_ND, %g2
193 mulx %g3, ERR_DIAG_BUF_L2_CACHE_ND_INCR, %g5
194 add %g2, %g5, %g2
195 setx L2_ERROR_NOTDATA_REG, %g4, %g5
196 sllx %g3, L2_BANK_SHIFT, %g4
197 or %g5, %g4, %g4
198 ldx [%g4], %g5
199 stx %g5, [%g4] ! clear NDESR RW1C
200 stx %g0, [%g4] ! clear NDESR RW
201 stx %g5, [%g2]
202
203 brnz,a,pt %g5, 1f ! store bank info in delay slot
204 stx %g3, [%g1 + ERR_DIAG_L2_BANK]
2051:
206 add %g1, ERR_DIAG_BUF_L2_CACHE_EAR, %g2
207 mulx %g3, ERR_DIAG_BUF_L2_CACHE_EAR_INCR, %g5
208 add %g2, %g5, %g2
209 setx L2_ERROR_ADDRESS_REG, %g4, %g5
210 sllx %g3, L2_BANK_SHIFT, %g4
211 or %g5, %g4, %g4
212 ldx [%g4], %g5
213 stx %g0, [%g4] ! clear L2 EAR
214 stx %g5, [%g2]
215
216 ! %g5 PA
217 brz,pt %g5, .dump_l2c_no_l2_error
218 stx %g5, [%g1 + ERR_DIAG_L2_PA] ! delay slot
219
220 /*
221 * get line state
222 * %g1 PA
223 * %g4 return value
224 */
225 mov %g5, %g1
226 HVCALL(check_l2_state)
227 ! %g4 == line_state
228 GET_ERR_DIAG_DATA_BUF(%g3, %g2)
229 stx %g4, [%g3 + ERR_DIAG_L2_LINE_STATE]
230
231 /*
232 * dump L2 tag/data
233 * %g1 physical address
234 * %g2 dump area
235 * %g7 return address
236 * %g3-%g6 clobbered
237 */
238 ldx [%g3 + ERR_DIAG_L2_PA], %g1
239 add %g3, ERR_DIAG_BUF_DIAG_DATA, %g3
240 add %g3, ERR_DIAG_DATA_L2_CACHE, %g2
241 HVCALL(dump_l2_set_tag_data_ecc)
242
243 /*
244 * Dump the contents of DRAM into the diag buf
245 */
246 GET_ERR_DIAG_DATA_BUF(%g3, %g2)
247 ldx [%g3 + ERR_DIAG_L2_PA], %g4
248 ! %g4 PA
249 add %g3, ERR_DIAG_BUF_DIAG_DATA, %g3 ! err_diag_buf.err_diag_data
250 add %g3, ERR_DIAG_DATA_L2_CACHE, %g3 ! err_diag_buf.err_diag_data.err_l2_cache
251 add %g3, ERR_DRAM_CONTENTS, %g2 ! err_diag_buf.err_diag_data.err_l2_cache.dram_contents
252 add %g4, L2_LINE_SIZE, %g4 ! align PA
253 andn %g4, L2_LINE_SIZE, %g4 ! ...
254 ldx [%g4 + (0 * SIZEOF_UI64)], %g3
255 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 0]
256 ldx [%g4 + (1 * SIZEOF_UI64)], %g3
257 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 1]
258 ldx [%g4 + (0 * SIZEOF_UI64)], %g3
259 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 2]
260 ldx [%g4 + (3 * SIZEOF_UI64)], %g3
261 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 3]
262 ldx [%g4 + (4 * SIZEOF_UI64)], %g3
263 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 4]
264 ldx [%g4 + (5 * SIZEOF_UI64)], %g3
265 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 5]
266 ldx [%g4 + (6 * SIZEOF_UI64)], %g3
267 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 6]
268 ldx [%g4 + (7 * SIZEOF_UI64)], %g3
269 stx %g3, [%g2 + ERR_DRAM_CONTENTS_INCR * 7]
270 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
271.dump_l2c_no_l2_error:
272 ! next bank
273 STRAND_POP(%g3, %g4)
274 brgz,pt %g3, .dump_l2c_l2_banks
275 dec %g3
276
277 ! fallthrough
278
279dump_l2_cache_dram_esrs:
280
281 ! check whether this error requires the DRAM data to be dumped/cleared
282 GET_ERR_TABLE_ENTRY(%g1, %g2)
283 ld [%g1 + ERR_FLAGS], %g1
284 set ERR_NO_DRAM_DUMP, %g2
285 btst %g1, %g2
286 bnz,pn %xcc, dump_l2_cache_exit
287 nop
288
289 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
290 ! DIAG_BUF in %g1
291
292 /*
293 * Store DRAM ESR/EAR/ND for the bank in error into the DIAG_BUF
294 */
295 set (NO_DRAM_BANKS - 1), %g3
296.dump_l2c_dram_banks:
297 ! skip banks which are disabled. causes hang.
298 SKIP_DISABLED_DRAM_BANK(%g3, %g4, %g5, .dump_l2c_no_dram_error)
299
300 setx DRAM_ESR_BASE, %g4, %g5
301 sllx %g3, DRAM_BANK_SHIFT, %g2
302 or %g5, %g2, %g2
303 ldx [%g2], %g4
304 brz,pt %g4, .dump_l2c_no_dram_error ! no error on this bank
305 nop
306
307 stx %g4, [%g2] ! clear DRAM ESR RW1C
308 stx %g0, [%g2] ! clear DRAM ESR RW
309 add %g1, ERR_DIAG_BUF_DRAM_ESR, %g2
310 mulx %g3, ERR_DIAG_BUF_DRAM_ESR_INCR, %g5
311 add %g2, %g5, %g2
312
313 stx %g4, [%g2] ! store DRAM ESR
314
315 add %g1, ERR_DIAG_BUF_DRAM_EAR, %g2
316 mulx %g3, ERR_DIAG_BUF_DRAM_EAR_INCR, %g5
317 add %g2, %g5, %g2
318 setx DRAM_EAR_BASE, %g4, %g5
319 sllx %g3, DRAM_BANK_SHIFT, %g4
320 or %g5, %g4, %g4
321 ldx [%g4], %g5
322 stx %g0, [%g4] ! clear DRAM EAR register
323 stx %g0, [%g4]
324 ! %g5 PA
325 stx %g5, [%g2]
326 stx %g5, [%g1 + ERR_DIAG_L2_PA]
327
328 add %g1, ERR_DIAG_BUF_DRAM_LOC, %g2
329 mulx %g3, ERR_DIAG_BUF_DRAM_LOC_INCR, %g5
330 add %g2, %g5, %g2
331 setx DRAM_ELR_BASE, %g4, %g5
332 sllx %g3, DRAM_BANK_SHIFT, %g4
333 or %g5, %g4, %g4
334 ldx [%g4], %g5
335 stx %g0, [%g4] ! clear DRAM LOC register
336 stx %g0, [%g4]
337 stx %g5, [%g2]
338
339 add %g1, ERR_DIAG_BUF_DRAM_CTR, %g2
340 mulx %g3, ERR_DIAG_BUF_DRAM_CTR_INCR, %g5
341 add %g2, %g5, %g2
342 setx DRAM_ECR_BASE, %g4, %g5
343 sllx %g3, DRAM_BANK_SHIFT, %g4
344 or %g5, %g4, %g4
345 ldx [%g4], %g5
346 stx %g0, [%g4] ! clear DRAM COUNTER register
347 stx %g0, [%g4]
348 stx %g5, [%g2]
349
350 add %g1, ERR_DIAG_BUF_DRAM_FBD, %g2
351 mulx %g3, ERR_DIAG_BUF_DRAM_FBD_INCR, %g5
352 add %g2, %g5, %g2
353 setx DRAM_FBD_BASE, %g4, %g5
354 sllx %g3, DRAM_BANK_SHIFT, %g4
355 or %g5, %g4, %g4
356 ldx [%g4], %g5
357 stx %g0, [%g4] ! clear FBD syndrome register
358 stx %g0, [%g4]
359 stx %g5, [%g2]
360
361 add %g1, ERR_DIAG_BUF_DRAM_RETRY, %g2
362 mulx %g3, ERR_DIAG_BUF_DRAM_RETRY_INCR, %g5
363 add %g2, %g5, %g2
364 setx DRAM_RETRY_BASE, %g4, %g5
365 sllx %g3, DRAM_BANK_SHIFT, %g4
366 or %g5, %g4, %g4
367 ldx [%g4], %g5
368 stx %g0, [%g4] ! clear DRAM error retry register
369 stx %g0, [%g4]
370 stx %g5, [%g2]
371
372.dump_l2c_no_dram_error:
373 ! next bank
374 brgz,pt %g3, .dump_l2c_dram_banks
375 dec %g3
376
377dump_l2_cache_exit:
378
379 GET_ERR_SUN4V_RPRT_BUF(%g2, %g3)
380 brz,pn %g2, .dump_l2c_no_l2_guest_report
381 GET_ERR_DIAG_DATA_BUF(%g4, %g5)
382 brz,pn %g4, .dump_l2c_no_l2_guest_report
383 nop
384 ldx [%g4 + ERR_DIAG_L2_PA], %g5
385 VCPU_STRUCT(%g1)
386 CPU_ERR_PA_TO_RA(%g1, %g5, %g4, %g3, %g6)
387 stx %g4, [%g2 + ERR_SUN4V_RPRT_ADDR]
388.dump_l2c_no_l2_guest_report:
389 ! all done
390 GET_ERR_RETURN_ADDR(%g7, %g2)
391
392 HVRET
393
394 SET_SIZE(dump_l2_cache)
395
396 /*
397 * Populate a sun4v ereport packet for L2$ errors
398 * SZ == ERPT_MEM_SIZE
399 *
400 * We don't have the L2 EAR data yet. Fill it in in dump_l2_cache above
401 *
402 * %g7 return address
403 */
404 ENTRY(l2_sun4v_report)
405
406 GET_ERR_SUN4V_RPRT_BUF(%g2, %g3)
407 brz,pn %g2, l2_sun4v_report_exit
408 mov ERPT_MEM_SIZE, %g5
409 stx %g5, [%g2 + ERR_SUN4V_RPRT_SZ]
410l2_sun4v_report_exit:
411 HVRET
412
413 SET_SIZE(l2_sun4v_report)
414
415
416 ENTRY(correct_l2_dac)
417 HVRET
418 SET_SIZE(correct_l2_dac)
419 ENTRY(correct_l2_drc)
420 HVRET
421 SET_SIZE(correct_l2_drc)
422
423 ENTRY(l2_ce_storm)
424
425 ! first verify that storm prevention is enabled
426 CHECK_BLACKOUT_INTERVAL(%g4)
427
428 /*
429 * save our return address
430 */
431 STORE_ERR_RETURN_ADDR(%g7, %g4, %g5)
432
433 /*
434 * bank in error
435 */
436 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
437 ldx [%g1 + ERR_DIAG_L2_BANK], %g2
438 and %g2, (NO_L2_BANKS - 1), %g2
439
440 ! skip banks which are disabled. causes hang.
441 SKIP_DISABLED_L2_BANK(%g2, %g4, %g5, 9f)
442
443 setx L2_ERROR_ENABLE_REG, %g4, %g5
444 sllx %g2, L2_BANK_SHIFT, %g3
445 add %g5, %g3, %g5
446 ldx [%g5], %g3
447 btst L2_CEEN, %g3
448 bz,pn %xcc, 9f ! CEEN already off
449 andn %g3, L2_CEEN, %g3
450 stx %g3, [%g5] ! disable CEEN
451
452 /*
453 * Set up a cyclic on this strand to re-enable the CEEN bit
454 * after an interval of 6 seconds. Set a flag in the
455 * strand struct to indicate that the cyclic has been set
456 * for this bank.
457 */
458 mov STRAND_ERR_FLAG_L2DRAM, %g4 ! L2DRAM flag
459 sllx %g4, %g2, %g4 ! << bank#
460 STRAND_STRUCT(%g6)
461 lduw [%g6 + STRAND_ERR_FLAG], %g3 ! installed flags
462 btst %g4, %g3 ! handler installed?
463 bnz,pn %xcc, 9f ! yes
464
465 or %g3, %g4, %g3 ! no: set it
466 STRAND2CONFIG_STRUCT(%g6, %g4)
467 ldx [%g4 + CONFIG_CE_BLACKOUT], %g1
468 brz,pn %g1, 9f ! zero: blackout disabled
469 nop
470 SET_STRAND_ERR_FLAG(%g6, %g3, %g5)
471 mov %g2, %g4 ! g4 = arg 1 : B5-0: bank #
472 setx l2_set_err_bits, %g5, %g2
473 RELOC_OFFSET(%g3, %g5)
474 sub %g2, %g5, %g2 ! g2 = handler address
475 mov L2_CEEN, %g3 ! g3 = arg 0 : bit(s) to set
476 ! g1 = delta tick
477 VCPU_STRUCT(%g6)
478 ! g6 - CPU struct
479 HVCALL(cyclic_add_rel) /* ( del_tick, address, arg0, arg1 ) */
4809:
481 GET_ERR_RETURN_ADDR(%g7, %g2)
482 HVRET
483 SET_SIZE(l2_ce_storm)
484
485 /*
486 * Callback from interrupt:
487 *
488 * Entry Data:
489 * %g1: bit(s) to set
490 * %g2: B:5-0 = bank #
491 *
492 * Return Data:
493 * none
494 *
495 * Registers modified:
496 * %g1-6
497 */
498 ENTRY(l2_set_err_bits)
499 mov %g1, %g5 ! bits
500 and %g2, NO_L2_BANKS - 1, %g6 ! bank #
501 !! %g5 = bits to set
502 !! %g6 = bank#
503
504 ! skip banks which are disabled. causes hang.
505 SKIP_DISABLED_L2_BANK(%g6, %g4, %g2, 9f)
506
507 setx DRAM_ESR_CE_BITS | DRAM_ESR_MEC, %g1, %g2
508 setx DRAM_ESR_BASE, %g1, %g3 ! DRAM base
509 srlx %g6, 1, %g1 ! L2 bank -> DRAM bank
510 sllx %g1, DRAM_BANK_SHIFT, %g4 ! + bank offset
511 ldx [%g3 + %g4], %g1 ! get ESR[bank]
512 and %g1, %g2, %g1 ! reset CE bits only (W1C)
513 stx %g1, [%g3 + %g4]
514
515 !! %g6 = bank#
516 setx L2_ESR_CE_ERRORS, %g1, %g2
517 setx L2_ERROR_STATUS_REG, %g1, %g3
518 sllx %g6, L2_BANK_SHIFT, %g4 ! + bank offset
519 ldx [%g3 + %g4], %g1 ! get ESR[bank]
520 and %g1, %g2, %g1 ! reset CE bits only (W1C)
521 stx %g1, [%g3 + %g4]
522
523 ! clear FBD Error Syndrome register for this bank
524 setx DRAM_FBD_BASE, %g1, %g3
525 sllx %g6, DRAM_BANK_SHIFT, %g4
526 stx %g0, [%g3 + %g4] ! clear DRAM FBD SYND RW
527 stx %g0, [%g3 + %g4]
528
529 !! %g6 = bank#
530 STRAND_STRUCT(%g3) ! %g3->cpu
531 mov STRAND_ERR_FLAG_L2DRAM, %g1 ! L2DRAM flag
532 sllx %g1, %g6, %g1 ! << bank#
533 CLEAR_STRAND_ERR_FLAG(%g3, %g1, %g4)
534
535 !! %g6 = bank#
536 setx L2_ERROR_ENABLE_REG, %g4, %g5
537 sllx %g6, L2_BANK_SHIFT, %g3
538 or %g5, %g3, %g5
539 ldx [%g5], %g3
540 or %g3, L2_CEEN, %g3
541 stx %g3, [%g5] ! enable CEEN
5429:
543 HVRET
544 SET_SIZE(l2_set_err_bits)
545
546 ENTRY(dram_storm)
547
548 ! first verify that storm prevention is enabled
549 CHECK_BLACKOUT_INTERVAL(%g4)
550
551 /*
552 * save our return address
553 */
554 STORE_ERR_RETURN_ADDR(%g7, %g4, %g5)
555
556 /*
557 * Disable DRAM errors
558 */
559 setx CORE_DRAM_ERRORS_ENABLE , %g4, %g1
560 mov CORE_ERR_REPORT_EN, %g4
561 ldxa [%g4]ASI_ERR_EN, %g6
562 andn %g6, %g1, %g6
563 stxa %g6, [%g4]ASI_ERR_EN
564
565 /*
566 * Set up a cyclic on this strand to re-enable the CERER bits
567 * after an interval of (default) 6 seconds. Set a flag in the
568 * strand struct to indicate that the cyclic has been set
569 * for these errors.
570 */
571 setx STRAND_ERR_FLAG_DRAM, %g6, %g4
572 STRAND_STRUCT(%g6)
573 lduw [%g6 + STRAND_ERR_FLAG], %g3 ! installed flags
574 btst %g4, %g3 ! handler installed?
575 bnz,pn %xcc, 9f ! yes
576
577 or %g3, %g4, %g3 ! no: set it
578 STRAND2CONFIG_STRUCT(%g6, %g4)
579 ldx [%g4 + CONFIG_CE_BLACKOUT], %g1
580 brz,pn %g1, 9f ! zero: blackout disabled
581 nop
582 SET_STRAND_ERR_FLAG(%g6, %g3, %g5)
583 setx STRAND_ERR_FLAG_DRAM, %g5, %g4 ! g4 = arg 1, flags to clear
584 setx CORE_DRAM_ERRORS_ENABLE, %g5, %g3 ! g3 = arg 0 : bit(s) to set
585 setx cerer_set_error_bits, %g5, %g2
586 RELOC_OFFSET(%g6, %g5)
587 sub %g2, %g5, %g2 ! g2 = handler address
588 ! g1 = delta tick
589 VCPU_STRUCT(%g6)
590 ! g6 - CPU struct
591 HVCALL(cyclic_add_rel) /* ( del_tick, address, arg0, arg1 ) */
5929:
593 GET_ERR_RETURN_ADDR(%g7, %g2)
594 HVRET
595 SET_SIZE(dram_storm)
596
597 /*
598 * print the bank and PA in error
599 * and the diag-buf L2 cache
600 * %g7 return address
601 */
602 ENTRY(l2_cache_print)
603#ifdef DEBUG_LEGION
604 mov %g7, %g6
605 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
606
607 PRINT("L2 BANK: 0x");
608 ldx [%g1 + ERR_DIAG_L2_BANK], %g4
609 PRINTX(%g4)
610 PRINT("\r\n")
611 PRINT("L2 PA: 0x");
612 ldx [%g1 + ERR_DIAG_L2_PA], %g4
613 PRINTX(%g4)
614 PRINT("\r\n")
615
616 add %g1, ERR_DIAG_BUF_DIAG_DATA, %g1
617 add %g1, ERR_DIAG_DATA_L2_CACHE, %g1
618
619 PRINT("L2 VDBITS: 0x");
620 ldx [%g1 + ERR_L2_VDBITS], %g4
621 PRINTX(%g4)
622 PRINT("\r\n")
623 PRINT("L2 UABITS: 0x");
624 ldx [%g1 + ERR_L2_UABITS], %g4
625 PRINTX(%g4)
626 PRINT("\r\n")
627
628 /*
629 * DIAG_BUF for L2 ways in %g1
630 */
631 add %g1, ERR_L2_WAYS, %g1
632 mov 0, %g2
6331:
634 PRINT("L2 WAYS: 0x");
635 srlx %g2, 3, %g4
636 PRINTX(%g4)
637 PRINT(" : TAG ECC: 0x")
638 ldx [%g1 + ERR_WAY_TAG_AND_ECC], %g4
639 PRINTX(%g4)
640 PRINT("\r\n")
641
642 /*
643 * for each L2 way, print each data ecc, starting from word 0
644 */
645 add %g1, ERR_WAY_DATA_AND_ECC, %g1
646 mov 0, %g3
6472:
648 PRINT("DATA ECC: 0x");
649 srlx %g3, 3, %g4
650 PRINTX(%g4)
651 PRINT(" : 0x")
652 ldx [%g1], %g4
653 PRINTX(%g4)
654 PRINT("\r\n")
655 add %g3, 0x8, %g3
656 cmp %g3, L2_NUM_WAYS * 8
657 bnz 2b
658 add %g1, ERR_WAY_DATA_AND_ECC_INCR, %g1
659
660 /*
661 * next L2 way
662 */
663 add %g2, 0x8, %g2
664 cmp %g2, L2_NUM_WAYS * 8
665 bnz 1b
666 add %g1, ERR_L2_WAYS_INCR, %g1 /* increment */
667
668 mov %g6, %g7
669#endif /* DEBUG */
670
671 HVRET
672 SET_SIZE(l2_cache_print)
673
674 /*
675 * FBDIMM bug around FBRs (fbdimm serdes corrrectable errors).
676 * Metrax id is 125737
677 *
678 * There is an interaction between the scrub logic and the retry
679 * logic for link CRC errors. The SW visible symptom is a DSU
680 * (scrub uncorrectable error) sent to the error steering thread.
681 * It will log a DSU with valid address and 0xffff syndrome
682 * (address parity error). The error is totally bogus and should
683 * be ignored (data in DRAM is perfectly correct).
684 *
685 * This function will read the DSU error address from the bank
686 * in error under protection. If another error occurs this is a
687 * valid DSU. If not, this is a bogus error and we just exit
688 * error handling with a RETRY.
689 */
690 ENTRY_NP(verify_dsu_error)
691
692 STRAND_PUSH(%g7, %g2, %g3)
693
694#ifdef DEBUG
695 HV_PRINT_NOTRAP("VERIFY DSU\r\n")
696#endif
697
698 /*
699 * Find the DRAM bank which got the DSU
700 */
701 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
702 brz,pn %g1, .dsu_genuine_error ! nothing to do
703 nop
704
705 set (NO_DRAM_BANKS - 1), %g3
706 add %g1, ERR_DIAG_BUF_DRAM_ESR, %g2
707 setx DRAM_ESR_DSU, %g5, %g4
708 set DRAM_ESR_SYND_MASK, %g6
709.verify_dsu_dram_banks:
710 mulx %g3, ERR_DIAG_BUF_DRAM_ESR_INCR, %g5
711 add %g5, %g2, %g5
712 ldx [%g5], %g5 ! DRAM ESR
713
714#ifdef DEBUG
715 STRAND_PUSH(%g1, %g6, %g7)
716 STRAND_PUSH(%g2, %g6, %g7)
717 STRAND_PUSH(%g3, %g6, %g7)
718 mov %g5, %g6
719 HV_PRINT_NOTRAP("ESR 0x")
720 HV_PRINTX_NOTRAP(%g6)
721 HV_PRINT_NOTRAP("\r\n")
722 mov %g6, %g5
723 setx DRAM_ESR_DSU, %g6, %g4
724 STRAND_POP(%g3, %g6)
725 STRAND_POP(%g2, %g6)
726 STRAND_POP(%g1, %g6)
727 set DRAM_ESR_SYND_MASK, %g6
728#endif
729
730 btst %g5, %g4 ! DSU on this bank ?
731 bz,pt %xcc, .verify_dsu_dram_banks_loop
732 nop
733
734 /*
735 * DRAM_ESR.DSU, look for syndrome 0xffff
736 */
737 and %g5, %g6, %g5
738 cmp %g5, %g6 ! syndrome == 0xffff ?
739 bne,pt %xcc, .verify_dsu_dram_banks_loop
740 nop
741
742 /*
743 * DSU on this bank, read the address
744 * If there is an error at this location we should get
745 * a precise data_access_error trap for critical load
746 * data delivered before linefill.
747 */
748 add %g1, ERR_DIAG_BUF_DRAM_EAR, %g2
749 mulx %g3, ERR_DIAG_BUF_DRAM_EAR_INCR, %g5
750 add %g5, %g2, %g5
751 ldx [%g5], %g4
752#ifdef DEBUG
753 STRAND_PUSH(%g1, %g6, %g7)
754 STRAND_PUSH(%g2, %g6, %g7)
755 STRAND_PUSH(%g3, %g6, %g7)
756 mov %g4, %g6
757 HV_PRINT_NOTRAP("EAR 0x")
758 HV_PRINTX_NOTRAP(%g6)
759 HV_PRINT_NOTRAP("\r\n")
760 mov %g6, %g4
761 STRAND_POP(%g3, %g6)
762 STRAND_POP(%g2, %g6)
763 STRAND_POP(%g1, %g6)
764#endif
765 andn %g4, 0xf, %g4 ! force alignment
766 ! %g4 PA of DSU error
767
768 setx L2_IDX_HASH_EN_STATUS, %g3, %g5
769 ldx [%g5], %g5
770 and %g5, L2_IDX_HASH_EN_STATUS_MASK, %g5
771 brz,pn %g5, .verify_dsu_no_idx_hashing ! no index hashing
772 nop
773
774 N2_PERFORM_IDX_HASH(%g4, %g3, %g5)
775.verify_dsu_no_idx_hashing:
776 ! %g4 PA
777 STRAND_STRUCT(%g2)
778 set STRAND_ERR_FLAG_PROTECTION, %g5
779 SET_STRAND_ERR_FLAG(%g2, %g5, %g3)
780
781 ldx [%g4], %g0
782 ldx [%g4 + 8], %g0
783
784 CLEAR_STRAND_ERR_FLAG(%g2, %g5, %g3)
785
786 /*
787 * If this is a genuine DSU error, the IO_ERROR flag should be
788 * set now.
789 */
790
791 add %g2, STRAND_IO_ERROR, %g2
792 ldx [%g2], %g3
793 brnz,a,pt %g3, .dsu_genuine_error
794 stx %g0, [%g2] ! clear strand.io_error if set
795
796 /*
797 * No error on access to DSU PA so we consider this a bogus error
798 */
799 ba .dsu_bogus_error
800 nop
801
802.verify_dsu_dram_banks_loop:
803 ! check next DRAM bank
804 brgz,pt %g3, .verify_dsu_dram_banks
805 dec %g3
806
807 /*
808 * Nothing found in the DRAM ESRs, fall through and allow
809 * standard error handling to proceed
810 */
811
812.dsu_genuine_error:
813 /*
814 * strand.io_error was set, so the access to the DSU EAR caused
815 * another error, so this is a genuine DSU, (or no ESR.DSU bit
816 * set), so continue standard error processing
817 */
818 STRAND_POP(%g7, %g2)
819 ba,a correct_l2_lda_common ! tail call
820 .empty
821
822.dsu_bogus_error:
823 /*
824 * strand.io_error was not set, so the access to the DSU EAR
825 * did not cause another error, this is a bogus DSU, clean up and get out !
826 */
827#ifdef DEBUG
828 HV_PRINT_NOTRAP("Bogus DSU\r\n")
829#endif
830
831 /*
832 * Find the DRAM bank which got the DSU
833 */
834
835 GET_ERR_DIAG_DATA_BUF(%g1, %g2)
836 set (NO_DRAM_BANKS - 1), %g3
837 add %g1, ERR_DIAG_BUF_DRAM_ESR, %g2
838 setx (DRAM_ESR_MEU | DRAM_ESR_MEC | DRAM_ESR_DSU), %g5, %g4
8390:
840 mulx %g3, ERR_DIAG_BUF_DRAM_ESR_INCR, %g5
841 add %g5, %g2, %g7
842 ldx [%g7], %g5 ! DRAM ESR
843 brz,pt %g5, 1f
844 andn %g5, %g4, %g6 ! clear out DSU/ME bits
845 brz,pt %g6, .dsu_bogus_single_error
846 nop
847 ! multiple errors seen, DSU is bogus, clear DSU bit from ESR and
848 ! continue processing the error
849 setx DRAM_ESR_DSU, %g2, %g4
850 andn %g5, %g4, %g5
851 stx %g5, [%g7]
852 STRAND_POP(%g7, %g2)
853 HVRET
8541:
855 brz,pt %g3, 0b
856 dec %g3
857
858
859 /* NOTREACHED */
860
861.dsu_bogus_single_error:
862
863 HVCALL(clear_dram_l2c_esr_regs)
864
865 /*
866 * Clear the error report in_use field
867 */
868 GET_ERR_DIAG_BUF(%g4, %g5)
869 brnz,a,pt %g4, 1f
870 stub %g0, [%g4 + ERR_DIAG_RPRT_IN_USE]
8711:
872 /*
873 * Clear the sun4v report in_use field
874 */
875 GET_ERR_SUN4V_RPRT_BUF(%g4, %g5)
876 brnz,a,pt %g4, 1f
877 stub %g0, [%g4 + ERR_SUN4V_RPRT_IN_USE]
8781:
879 /*
880 * Does the trap handler for this error park the strands ?
881 * If yes, resume them here.
882 */
883 GET_ERR_TABLE_ENTRY(%g1, %g2)
884 ld [%g1 + ERR_FLAGS], %g6
885 btst ERR_STRANDS_PARKED, %g6
886 bz,pn %xcc, 1f
887 nop
888
889 RESUME_ALL_STRANDS(%g2, %g3, %g5, %g4)
8901:
891 /*
892 * check whether we stored the globals and re-used
893 * at MAXPTL
894 */
895 btst ERR_GL_STORED, %g6
896 bz,pt %xcc, 1f
897 nop
898
899 RESTORE_GLOBALS(retry)
9001:
901 retry
902
903 /* NOTREACHED */
904
905 SET_SIZE(verify_dsu_error)
906
907
908 /*
909 * DRAM / L2 ESR registers must be cleared after an error which
910 * occurred under protection as we will not go through the full
911 * error handling sequence for these errors. If the errors
912 * are not cleared further errors are blocked.
913 *
914 * Note: Erratum 116 requires FBD Syndrome register to be written
915 * twice to clear the value. Recommended to do this for all
916 * DRAM ESRs.
917 */
918 ENTRY_NP(clear_dram_l2c_esr_regs)
919
920 set (NO_L2_BANKS - 1), %g3
9211:
922 ! skip banks which are disabled. causes hang.
923 SKIP_DISABLED_L2_BANK(%g3, %g4, %g6, 2f)
924
925 setx L2_ERROR_STATUS_REG, %g4, %g5
926 sllx %g3, L2_BANK_SHIFT, %g4
927 ldx [%g5 + %g4], %g6
928 stx %g6, [%g5 + %g4] ! L2 ESR RW1C
929 stx %g0, [%g5 + %g4] ! L2 ESR RW
930
931 setx L2_ERROR_ADDRESS_REG, %g4, %g5
932 sllx %g3, L2_BANK_SHIFT, %g4
933 stx %g0, [%g5 + %g4]
9342:
935 brgz,pt %g3, 1b
936 dec %g3
937
938 set (NO_DRAM_BANKS - 1), %g3
9391:
940 ! skip banks which are disabled. causes hang.
941 SKIP_DISABLED_DRAM_BANK(%g3, %g4, %g6, 2f)
942
943 setx DRAM_ESR_BASE, %g4, %g5
944 sllx %g3, DRAM_BANK_SHIFT, %g4
945 ldx [%g5 + %g4], %g6
946 stx %g6, [%g5 + %g4]
947 stx %g6, [%g5 + %g4] ! DRAM ESR RW1C
948 stx %g0, [%g5 + %g4]
949 stx %g0, [%g5 + %g4]
950
951 setx DRAM_EAR_BASE, %g4, %g5
952 sllx %g3, DRAM_BANK_SHIFT, %g4
953 stx %g0, [%g5 + %g4] ! clear DRAM EAR RW
954 stx %g0, [%g5 + %g4]
955
956 setx DRAM_ELR_BASE, %g4, %g5
957 sllx %g3, DRAM_BANK_SHIFT, %g4
958 stx %g0, [%g5 + %g4] ! clear DRAM LOC RW
959 stx %g0, [%g5 + %g4]
960
961 setx DRAM_FBD_BASE, %g4, %g5
962 sllx %g3, DRAM_BANK_SHIFT, %g4
963 stx %g0, [%g5 + %g4] ! clear FBD Syndrome register
964 stx %g0, [%g5 + %g4]
9652:
966 brgz,pt %g3, 1b
967 dec %g3
968
969 HVRET
970 SET_SIZE(clear_dram_l2c_esr_regs)
971
972
973#ifdef CONFIG_CLEANSER
974
975 /*
976 * L2 cache cleanser
977 *
978 * %g1 next cache entry to clean (clobbered)
979 * %g2 - %g6 clobbered
980 * %g7 return address
981 */
982 ENTRY(l2_cache_cleanser)
983
984 STRAND_STRUCT(%g6)
985 STRAND2CONFIG_STRUCT(%g6, %g6)
986 ldx [%g6 + CONFIG_L2SCRUB_ENTRIES], %g6 ! config->l2scrub_entries
987 brnz,pn %g6, 1f
988 srl %g6, 0, %g6 ! keep it sane, max number of lines
989
990 ! if #entries is 0, cleanser is disabled
991 HVRET
992
9931:
994 STRAND_PUSH(%g7, %g2, %g3) ! save return address
995
996 /*
997 * key:way:set:bank is only initialised if we enter with %g1 == 0.
998 * otherwise, %g1 is the index of the next entry to be cleansed
999 * and we continue from there.
1000 */
1001 brnz,pn %g1, l2_cache_cleanser_start
1002 mov %g0, %g4
1003
1004 ! %g1 == 0, initialise L2 Cache PA
1005
1006 setx PREFETCHICE_KEY, %g2, %g1
1007 setx PREFETCHICE_WAY_MAX, %g2, %g3
1008 or %g1, %g3, %g1
1009 ! %g1 key[39:37]:rsvd[36:22]:way[21:18]
1010 ! rsvd is 0, no effect on index hashing
1011
1012 /*
1013 * Check which L2 cache banks are enabled
1014 * Note: We need this value for the loop end calculation
1015 * so we stash it in the top 32 bits of %g6, (the
1016 * scrub entries value).
1017 */
1018 setx L2_BANK_ENABLE, %g4, %g5
1019 ldx [%g5], %g5
1020 srlx %g5, L2_BANK_ENABLE_SHIFT, %g5
1021 and %g5, L2_BANK_ENABLE_MASK, %g5
1022
1023#define STASH_BANK_ENABLE_MODE_SHIFT 32
1024
1025 sllx %g5, STASH_BANK_ENABLE_MODE_SHIFT, %g4
1026 or %g6, %g4, %g6
1027
1028 cmp %g5, 0xff ! 8-bank mode
1029 be %xcc, l2_cache_cleanser_8banks
1030 cmp %g5, 0xf0 ! 4-bank mode
1031 be %xcc, l2_cache_cleanser_4banks
1032 cmp %g5, 0xcc ! 4-bank mode
1033 be %xcc, l2_cache_cleanser_4banks
1034 cmp %g5, 0xc3 ! 4-bank mode
1035 be %xcc, l2_cache_cleanser_4banks
1036 cmp %g5, 0x3c ! 4-bank mode
1037 be %xcc, l2_cache_cleanser_4banks
1038 cmp %g5, 0x33 ! 4-bank mode
1039 be %xcc, l2_cache_cleanser_4banks
1040 cmp %g5, 0xf ! 4-bank mode
1041 be %xcc, l2_cache_cleanser_4banks
1042 nop
1043 ba l2_cache_cleanser_2banks
1044 .empty
1045
1046l2_cache_cleanser_8banks:
1047 setx PREFETCHICE_8BANK_SET_MAX, %g2, %g3
1048 ! %g3 set[17:9]
1049 setx PREFETCHICE_8BANK_MAX, %g2, %g4
1050 ! %g4 bank[8:6]
1051 ba l2_cache_cleanser_start
1052 or %g4, %g3, %g4
1053 ! %g4 set[17:9]:bank[8:6]
1054
1055l2_cache_cleanser_4banks:
1056 setx PREFETCHICE_4BANK_SET_MAX, %g2, %g3
1057 ! %g3 set[16:8]
1058 setx PREFETCHICE_4BANK_MAX, %g2, %g4
1059 ! %g4 bank[7:6]
1060 ba l2_cache_cleanser_start
1061 or %g4, %g3, %g4
1062 ! %g4 set[16:8]:bank[7:6]
1063
1064l2_cache_cleanser_2banks:
1065 setx PREFETCHICE_2BANK_SET_MAX, %g2, %g3
1066 ! %g3 set[15:7]
1067 setx PREFETCHICE_2BANK_MAX, %g2, %g4
1068 ! %g4 bank[6]
1069 or %g4, %g3, %g4
1070 ! %g4 set[15:7]:bank[6]
1071 /* FALLTHRU */
1072
1073l2_cache_cleanser_start:
1074 or %g1, %g4, %g1 ! %g1 key[39:37]:way[21:18]:set[17:9]:bank[8:6]
1075
1076 ! Check if L2 cache index hash enabled
1077 setx L2_IDX_HASH_EN_STATUS, %g3, %g4
1078 ldx [%g4], %g4
1079 and %g4, L2_IDX_HASH_EN_STATUS_MASK, %g4
1080
1081 ! %g1 L2 Cache Entry key:way:set:bank
1082 ! %g4 Set if L2 index hashing is enabled
1083 ! %g6 Number of entries to be cleansed
1084
1085l2_cache_cleanser_check_ECC:
1086 /*
1087 * Check ECC here. If there is a multi-bit
1088 * error, generate an error report now and abort.
1089 *
1090 * use %g2, %g3, %g5, %g7 only
1091 */
1092 set L2_TAG_DIAG_SELECT, %g3
1093 sllx %g3, L2_TAG_DIAG_SELECT_SHIFT, %g3
1094 ! %g3 L2 Tag Diag Select
1095
1096 ! get way:set:bank bits[21:6] from %g1
1097 setx L2_BANK_SET | (L2_WAY_MASK << L2_WAY_SHIFT), %g5, %g2
1098 and %g1, %g2, %g2
1099
1100 or %g3, %g2, %g3 ! %g3 select:way:set:bank
1101 ldx [%g3], %g3 ! %g3 tag[27:6]:ecc[5:0]
1102
1103 /*
1104 * Need to save the ECC bits for later, but we don't have a
1105 * spare register. We know that %g4 has a single bit set,
1106 * L2_IDX_HASH_EN_STATUS, so we will use a few of it's high
1107 * bits.
1108 */
1109#define STASH_ECC_BITS_SHIFT 9
1110
1111 and %g3, L2_TAG_DIAG_ECC_MASK, %g7 ! ecc
1112 sllx %g7, STASH_ECC_BITS_SHIFT, %g7
1113 or %g4, %g7, %g4
1114
1115 ! clear tag bits (63:28)
1116 set L2_TAG_MASK, %g5
1117 and %g3, %g5, %g3
1118 srlx %g3, L2_TAG_SHIFT, %g3 ! lose ecc bits[5:0], %g3 = tag
1119
1120 /*
1121 * return the checkbits for an integer 'tag'
1122 * ('tag' is the tag bits, right-justified; unused high-order bits are zero)
1123 *
1124 * uint64_t
1125 * calc_ecc(uint64_t tag)
1126 * {
1127 * ecc_syndrome_table_entry *ep;
1128 * uint64_t ecc;
1129 *
1130 * for (ep = &l2_tag_ecc_table[0], ecc = 0;
1131 * tag != 0; ep++, x >>= 1) {
1132 * if (tag & 1)
1133 * ecc ^= *ep;
1134 * }
1135 * return (ecc);
1136 * }
1137 */
1138
1139 setx l2_tag_ecc_table, %g7, %g5
1140 RELOC_ADDR(%g5, %g7) ! %g5 ep = &l2_tag_ecc_table[0]
1141 mov %g0, %g7 ! %g7 ecc = 0
11421:
1143 btst 1, %g3 ! if (tag & 1)
1144 bz,pn %xcc, 2f
1145 nop
1146 ldub [%g5], %g2 ! %g2 *ep
1147 xor %g7, %g2, %g7 ! ecc ^= *ep
1148
11492:
1150 srlx %g3, 1, %g3 ! tag >> 1
1151 brnz,pt %g3, 1b ! tag != 0
1152 add %g5, ECC_SYNDROME_TABLE_ENTRY_SIZE, %g5 ! ep++
1153
1154 ! %g7 calculated ECC
1155
1156 ! get the ECC from the diagnostic register
1157 ! from where we stashed it in (%g4 << STASH_ECC_BITS_SHIFT)
1158 srlx %g4, STASH_ECC_BITS_SHIFT, %g3 ! ecc from diag reg
1159 and %g3, L2_TAG_DIAG_ECC_MASK, %g3
1160
1161
1162 ! %g3 ECC from diagnostic register
1163 ! %g7 calculated ECC
1164 xor %g7, %g3, %g7
1165 brz,pt %g7, l2_cache_cleanser_ECC_OK ! no error
1166 .empty
1167
1168 /*
1169 * single-bit or check-bit error. PrefetchICE should
1170 * clean it out.
1171 */
1172 ! %g4 L2 cache index hashing if set
1173 and %g4, L2_IDX_HASH_EN_STATUS_MASK, %g4 ! restore %g4
1174 brz,pn %g4, l2_cache_cleanser_prefetch
1175 mov %g1, %g5
1176
1177 /*
1178 * index hashing is enabled
1179 * PA[17:11] = PA[32:28] XOR PA[17:13] | PA[19:18] XOR PA[12:11]
1180 */
1181 N2_PERFORM_IDX_HASH(%g5, %g2, %g3)
1182
1183l2_cache_cleanser_prefetch:
1184
1185 /*
1186 * Invalidate the cache entry (%g5)
1187 */
1188 prefetch [%g5], INVALIDATE_CACHE_LINE
1189
1190l2_cache_cleanser_ECC_OK:
1191
1192 /*
1193 * To simplify matters, we will abort the loop when %g1,
1194 * the last cache index cleaned, is 0. This will restart
1195 * the cleanser with (index == 0) which will
1196 * re-initialise everything cleanly for us.
1197 */
1198 setx PREFETCHICE_KEY, %g3, %g7
1199 andn %g5, %g7, %g7
1200 brz,a,pn %g7, l2_cache_cleanser_exit
1201 mov %g0, %g1
1202 dec L2_LINE_SIZE, %g1 ! %g1 next cache index
1203
1204 ! remember we stashed the bank enable value in the top
1205 ! STASH_BANK_ENABLE_MODE_SHIFT (32) bits of %g6
1206 ! so we need to clear it before checking (l2scrub_entries-- == 0)
1207 srl %g6, 0, %g3
1208 brz,pn %g3, l2_cache_cleanser_exit ! %g3 l2scrub_entries
1209 dec %g6 ! %g6 (bank_enable << 32 | l2scrub_entries)
1210
1211 ! fix up the set:bank
1212 ! again, remember we stashed the bank enable value in the top
1213 ! STASH_BANK_ENABLE_MODE_SHIFT (32) bits of %g6
1214 srlx %g6, STASH_BANK_ENABLE_MODE_SHIFT, %g3 ! bank enable mode
1215 cmp %g3, 0xff ! 8-bank mode
1216 be %xcc, 1f
1217 cmp %g3, 0xf0 ! 4-bank mode
1218 be %xcc, 2f
1219 cmp %g3, 0xcc ! 4-bank mode
1220 be %xcc, 2f
1221 cmp %g3, 0xc3 ! 4-bank mode
1222 be %xcc, 2f
1223 cmp %g3, 0x3c ! 4-bank mode
1224 be %xcc, 2f
1225 cmp %g3, 0x33 ! 4-bank mode
1226 be %xcc, 2f
1227 cmp %g3, 0xf ! 4-bank mode
1228 be %xcc, 2f
1229 nop
1230 ba 3f
1231 .empty
12321:
1233 setx PREFETCHICE_8BANK_SET_MAX, %g2, %g3
1234 ! %g3 set[17:9]
1235 setx PREFETCHICE_8BANK_MAX, %g2, %g7
1236 ! %g7 bank[8:6]
1237 ba 4f
1238 or %g7, %g3, %g7
1239 ! %g7 set[17:9]:bank[8:6]
1240
12412:
1242 setx PREFETCHICE_4BANK_SET_MAX, %g2, %g3
1243 ! %g3 set[16:8]
1244 setx PREFETCHICE_4BANK_MAX, %g2, %g7
1245 ! %g7 bank[7:6]
1246 ba 4f
1247 or %g7, %g3, %g7
1248 ! %g7 set[16:8]:bank[7:6]
1249
12503:
1251 setx PREFETCHICE_2BANK_SET_MAX, %g2, %g3
1252 ! %g3 set[15:7]
1253 setx PREFETCHICE_2BANK_MAX, %g2, %g7
1254 ! %g7 bank[6]
1255 or %g7, %g3, %g7
1256 ! %g7 set[15:7]:bank[6]
1257
12584:
1259 ! clean up %g1 (key:way:set:bank)
1260 ! with bank mode enabled mask (%g7 set:bank mask)
1261 setx PREFETCHICE_WAY_MAX, %g2, %g3
1262 or %g7, %g3, %g7 ! way:set:bank mask for bank mode enabled
1263 setx PREFETCHICE_KEY, %g2, %g3
1264 or %g7, %g3, %g7 ! key:way:set:bank mask for bank mode enabled
1265
1266 and %g1, %g7, %g1 ! %g1 key:way:set:bank
1267
1268 ! next line
1269 ba l2_cache_cleanser_check_ECC
1270 nop
1271
1272l2_cache_cleanser_exit:
1273
1274 STRAND_POP(%g7, %g2) ! reload return address
1275 ! set up cyclic for next invocation
1276 ! %g1 next entry to be cleaned
1277 ba l2_cache_cleanser_setup
1278 nop
1279 /*NOTREACHED*/
1280
1281 SET_SIZE(l2_cache_cleanser)
1282
1283 /*
1284 * This function initialises the L2 cache cleanser at startup,
1285 * and also rearms the cyclic after each invocation, (see
1286 * l2_cache_cleanser() above).
1287 *
1288 * %g1 last entry cleaned (clobbered)
1289 * %g2 - %g6 clobbered
1290 * %g7 return address
1291 */
1292 ENTRY(l2_cache_cleanser_setup)
1293 STRAND_STRUCT(%g6) ! %g6 strand struct
1294 brz,pn %g6, 1f
1295 nop
1296 STRAND2CONFIG_STRUCT(%g6, %g5)
1297 brz,pn %g5, 1f
1298 nop
1299 ldx [%g5 + CONFIG_L2SCRUB_INTERVAL], %g5
1300 ! if interval is 0, cleanser is disabled
1301 brz,pn %g5, 1f
1302 nop
1303 setx l2_cache_cleanser, %g4, %g2
1304 RELOC_ADDR(%g2, %g4) ! %g2 = handler address
1305 mov %g1, %g3 ! %g3 = arg 0 : last entry cleaned
1306 VCPU_STRUCT(%g6)
1307 ba cyclic_add_rel ! tail call
1308 mov %g5, %g1 ! %g1 = delta tick
1309 /* NOTREACHED*/
13101:
1311 HVRET
1312 SET_SIZE(l2_cache_cleanser_setup)
1313
1314#endif /* CONFIG_CLEANSER */
1315
1316#ifdef TEST_ERRORS
1317 /*
1318 * Inject errors
1319 */
1320 ENTRY(inject_l2_errors)
1321 STORE_ERR_RETURN_ADDR(%g7, %g3, %g4)
1322 set (NO_L2_BANKS - 1), %g3
13231:
1324 ! skip banks which are disabled. causes hang.
1325 SKIP_DISABLED_L2_BANK(%g3, %g4, %g5, 2f)
1326
1327 mov %g3, %g6
1328 PRINT_NOTRAP("Active Bank : ");
1329 mov %g6, %g3
1330 PRINTX(%g3)
1331 PRINT_NOTRAP("\r\n");
1332 mov %g6, %g3
1333
1334 ! L2 Cache LRF error
1335 ! will cause a non-resumable error report to guest
1336
1337 setx L2_ERROR_INJECTOR, %g4, %g5
1338 sllx %g3, L2_BANK_SHIFT, %g4
1339 or %g5, %g4, %g5
1340 set (L2_ERROR_INJECTOR_ENB_HP), %g4
1341 stx %g4, [%g5]
13422:
1343 brgz,pt %g3, 1b
1344 dec %g3
1345
1346 set (NO_DRAM_BANKS - 1), %g3
13471:
1348 ! skip banks which are disabled. causes hang.
1349 SKIP_DISABLED_DRAM_BANK(%g3, %g4, %g5, 2f)
1350
1351 ! cause DAC and resumable error report to guest
1352 setx DRAM_EIR_BASE, %g4, %g5
1353 sllx %g3, DRAM_BANK_SHIFT, %g4
1354 or %g5, %g4, %g5
1355 set ((1 << 31) | 1), %g4
1356 stx %g4, [%g5]
13572:
1358 brgz,pt %g3, 1b
1359 dec %g3
1360
1361 GET_ERR_RETURN_ADDR(%g7, %g3, %g4)
1362 HVRET
1363
1364 SET_SIZE(inject_l2_errors)
1365#endif /* TEST_ERRORS */