Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / ontario / src / cpu_errs.s
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: cpu_errs.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 "@(#)cpu_errs.s 1.82 07/05/03 SMI"
50
51#include <sys/asm_linkage.h>
52#include <sys/htypes.h>
53#include <hypervisor.h>
54#include <sparcv9/misc.h>
55#include <sparcv9/asi.h>
56#include <asi.h>
57#include <mmu.h>
58#include <dram.h>
59#include <hprivregs.h>
60#include <sun4v/traps.h>
61#include <sun4v/asi.h>
62#include <sun4v/mmu.h>
63#include <sun4v/queue.h>
64#include <sun4v/errs_defs.h>
65#include <fpga.h>
66
67#include <offsets.h>
68#include <cyclic.h>
69#include <guest.h>
70#include <strand.h>
71#include <config.h>
72#include <cpu_errs.h>
73#include <errs_common.h>
74#include <util.h>
75#include <debug.h>
76#include <cpu_errs_defs.h>
77#include <abort.h>
78#include <iob.h>
79#include <jbi_regs.h>
80#include <util.h>
81
82
83/*
84 * HW issues err. HV attempts to handle the error where appropiate.
85 * HV translates it to a sun4v format. Sends it to the queue.
86 */
87/*
88 * Macro that calls the function to dump the L2$ set diagnostic
89 * data into the error report.
90 * arg1 MUST be specified as %g1, used as arg1 to function
91 * arg2 MUST be specified as %g2, used as arg2 to function
92 * ret7 MUST be specified as %g7, used for return address
93 * scr1 is scratch register
94 */
95/* BEGIN CSTYLED */
96#define ASMCALL_DUMP_L2_DATA_FOR_CE(arg1, arg2, scr1, ret7) \
97 STRAND_STRUCT(scr1) ;\
98 add scr1, STRAND_CE_RPT, arg2 /* set %g2 to ce_rpt pointer */ ;\
99 add arg2, STRAND_EVBSC_L2_AFAR(0), arg1 ;\
100 ldx [arg1], arg1 /* %g1 has physical address */ ;\
101 ba dump_l2_set_tag_data_ecc ;\
102 rd %pc, ret7
103/* END CSTYLED */
104
105/* BEGIN CSTYLED */
106#define SET_CPU_IN_ERROR(scr1, scr2) \
107 VCPU_STRUCT(scr1) /* FIXME: or strand? */ ;\
108 mov CPU_STATE_ERROR, scr2 ;\
109 stx scr2, [scr1 + CPU_STATUS]
110/* END CSTYLED */
111
112/*
113 * Queue the UE error report as a resumable error to the guest
114 */
115/* BEGIN CSTYLED */
116#define ASMCALL_RQ_ERPT(E_OFFT, reg1, reg2, reg3, reg4, reg5, reg6, reg7)\
117 PRINT("queue RESUMABLE\r\n") ;\
118 STRAND_STRUCT(reg1) ;\
119 add reg1, E_OFFT, reg2 /* erpt buf ptr */ ;\
120 ba queue_resumable_erpt /* %g1 = strand, %g2 = erpt */ ;\
121 rd %pc, reg7
122/* END CSTYLED */
123
124/*
125 * The erpt pointer should be passed in %g6 as %g6 is preserved across
126 * print routines. The second argument, reg1, should be %g1, which is
127 * used as the argument to PRINTX.
128 * Arguments:
129 * %g6 - as erpt - pointer to the strand error buffer
130 * %g1 - as reg1
131 * all registers are used.
132 */
133#ifdef NIAGARA_BRINGUP
134/* BEGIN CSTYLED */
135#define CONSOLE_PRINT_DIAG_ERPT(erpt, reg1) \
136 PRINT("ehdl = ") ;\
137 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_EHDL], reg1 /* ehdl */ ;\
138 PRINTX(reg1) ;\
139 PRINT("\r\n") ;\
140 PRINT("stick = ") ;\
141 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_STICK], reg1 /* stick */ ;\
142 PRINTX(reg1) ;\
143 PRINT("\r\n") ;\
144 PRINT("cpuver = ") ;\
145 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_CPUVER], reg1 /* cpuver */;\
146 PRINTX(reg1) ;\
147 PRINT("\r\n") ;\
148 PRINT("sparc_afsr = ") ;\
149 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR], reg1 /* sparc afsr */;\
150 PRINTX(reg1) ;\
151 PRINT("\r\n") ;\
152 PRINT("sparc_afar = ") ;\
153 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], reg1 /* sparc afar */;\
154 PRINTX(reg1) ;\
155 PRINT("\r\n") ;\
156 PRINT("jbus_err_log = ") ;\
157 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_JBI_ERR_LOG], reg1 ;\
158 PRINTX(reg1) ;\
159 PRINT("\r\n") ;\
160 PRINT("L2 ESRs\r\n") ;\
161 ldx [erpt + STRAND_EVBSC_L2_AFSR(0)], reg1 ;\
162 PRINTX(reg1) ;\
163 PRINT(" ") ;\
164 ldx [erpt + STRAND_EVBSC_L2_AFSR(1)], reg1 ;\
165 PRINTX(reg1) ;\
166 PRINT(" ") ;\
167 ldx [erpt + STRAND_EVBSC_L2_AFSR(2)], reg1 ;\
168 PRINTX(reg1) ;\
169 PRINT(" ") ;\
170 ldx [erpt + STRAND_EVBSC_L2_AFSR(3)], reg1 ;\
171 PRINTX(reg1) ;\
172 PRINT("\r\n") ;\
173 PRINT("L2 EARs\r\n") ;\
174 ldx [erpt + STRAND_EVBSC_L2_AFAR(0)], reg1 ;\
175 PRINTX(reg1) ;\
176 PRINT(" ") ;\
177 ldx [erpt + STRAND_EVBSC_L2_AFAR(1)], reg1 ;\
178 PRINTX(reg1) ;\
179 PRINT(" ") ;\
180 ldx [erpt + STRAND_EVBSC_L2_AFAR(2)], reg1 ;\
181 PRINTX(reg1) ;\
182 PRINT(" ") ;\
183 ldx [erpt + STRAND_EVBSC_L2_AFAR(3)], reg1 ;\
184 PRINTX(reg1) ;\
185 PRINT("\r\n") ;\
186 PRINT("DRAM ESRs\r\n") ;\
187 ldx [erpt + STRAND_EVBSC_DRAM_AFSR(0)], reg1 ;\
188 PRINTX(reg1) ;\
189 PRINT(" ") ;\
190 ldx [erpt + STRAND_EVBSC_DRAM_AFSR(1)], reg1 ;\
191 PRINTX(reg1) ;\
192 PRINT(" ") ;\
193 ldx [erpt + STRAND_EVBSC_DRAM_AFSR(2)], reg1 ;\
194 PRINTX(reg1) ;\
195 PRINT(" ") ;\
196 ldx [erpt + STRAND_EVBSC_DRAM_AFSR(3)], reg1 ;\
197 PRINTX(reg1) ;\
198 PRINT("\r\n") ;\
199 PRINT("DRAM EARs\r\n") ;\
200 ldx [erpt + STRAND_EVBSC_L2_AFAR(0)], reg1 ;\
201 PRINTX(reg1) ;\
202 PRINT(" ") ;\
203 ldx [erpt + STRAND_EVBSC_L2_AFAR(1)], reg1 ;\
204 PRINTX(reg1) ;\
205 PRINT(" ") ;\
206 ldx [erpt + STRAND_EVBSC_L2_AFAR(2)], reg1 ;\
207 PRINTX(reg1) ;\
208 PRINT(" ") ;\
209 ldx [erpt + STRAND_EVBSC_L2_AFAR(3)], reg1 ;\
210 PRINTX(reg1) ;\
211 PRINT("\r\n") ;\
212 PRINT("DRAM ELRs\r\n") ;\
213 ldx [erpt + STRAND_EVBSC_DRAM_LOC(0)], reg1 ;\
214 PRINTX(reg1) ;\
215 PRINT(" ") ;\
216 ldx [erpt + STRAND_EVBSC_DRAM_LOC(1)], reg1 ;\
217 PRINTX(reg1) ;\
218 PRINT(" ") ;\
219 ldx [erpt + STRAND_EVBSC_DRAM_LOC(2)], reg1 ;\
220 PRINTX(reg1) ;\
221 PRINT(" ") ;\
222 ldx [erpt + STRAND_EVBSC_DRAM_LOC(3)], reg1 ;\
223 PRINTX(reg1) ;\
224 PRINT("\r\n") ;\
225 PRINT("DRAM ECRs\r\n") ;\
226 ldx [erpt + STRAND_EVBSC_DRAM_CNTR(0)], reg1 ;\
227 PRINTX(reg1) ;\
228 PRINT(" ") ;\
229 ldx [erpt + STRAND_EVBSC_DRAM_CNTR(1)], reg1 ;\
230 PRINTX(reg1) ;\
231 PRINT(" ") ;\
232 ldx [erpt + STRAND_EVBSC_DRAM_CNTR(2)], reg1 ;\
233 PRINTX(reg1) ;\
234 PRINT(" ") ;\
235 ldx [erpt + STRAND_EVBSC_DRAM_CNTR(3)], reg1 ;\
236 PRINTX(reg1) ;\
237 PRINT("\r\n") ;\
238 PRINT("tstate = ") ;\
239 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_TSTATE], reg1 /* tstate */;\
240 PRINTX(reg1) ;\
241 PRINT("\r\n") ;\
242 PRINT("htstate = ") ;\
243 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_HTSTATE], reg1 /* htstate */;\
244 PRINTX(reg1) ;\
245 PRINT("\r\n") ;\
246 PRINT("tpc = ") ;\
247 ldx [erpt + STRAND_VBSC_ERPT + EVBSC_TPC], reg1 /* tpc */ ;\
248 PRINTX(reg1) ;\
249 PRINT("\r\n") ;\
250 PRINT("cpuid = ") ;\
251 lduh [erpt + STRAND_VBSC_ERPT + EVBSC_CPUID], reg1 /* cpuid */;\
252 PRINTX(reg1) ;\
253 PRINT("\r\n") ;\
254 PRINT("TT = ") ;\
255 lduh [erpt + STRAND_VBSC_ERPT + EVBSC_TT], reg1 /* tt */;\
256 PRINTX(reg1) ;\
257 PRINT("\r\n") ;\
258 PRINT("TL = ") ;\
259 ldub [erpt + STRAND_VBSC_ERPT + EVBSC_TL], reg1 /* tl */;\
260 PRINTX(reg1) ;\
261 PRINT("\r\n") ;\
262 PRINT("------END-------\r\n")
263/* END CSTYLED */
264#else /* NIAGARA_BRINGUP */
265#define CONSOLE_PRINT_DIAG_ERPT(erpt, reg1)
266#endif /* NIAGARA_BRINGUP */
267
268 /*
269 * Correctable error traps can be taken only if PSTATE.IE = 1.
270 * The hypervisor is run with PSTATE.IE = 0, so no CE traps
271 * will be taken when running in hypervisor. Therefore, CE
272 * trap handler is entered only from supervisor which means:
273 * - no need to check for %htstate.hpriv
274 * - no need to check for %tstate.gl == MAXGL
275 * Assume the CE trap taken when executing in supervisor mode.
276 * If TL > MAXPTL
277 * then
278 * watchdog_reset
279 * else
280 * handle error
281 *
282 * For CEs no error report is sent to the sun4v guest. Hence
283 * the sun4v guest error report members of the erpt struct
284 * are not filled in. Only the diagnostic error report is
285 * constructed and sent.
286 *
287 * At entry, PSTATE.IE = 0.
288 *
289 * Register usage: where ever possible
290 * g1-3 = scratch
291 * g4-6 : preserved across PRINT* macros
292 * g5 : error report pointer
293 * g6 : strand struct pointer
294 */
295 ENTRY_NP(ce_poll_entry) /* entry point for the error daemon */
296 stx %g7, [%g6 + STRAND_ERR_RET] ! save return address
297
298 ENTRY_NP(ce_err)
299
300 /* get strand, CE buffer in %g6-5, they are safe across calls */
301 STRAND_ERPT_STRUCT(STRAND_CE_RPT, %g6, %g5) ! g6->strand, g5->strand.ce_rpt
302
303 ! get the lock
304 SPINLOCK_ENTER_ERRORLOCK(%g1, %g2, %g3)
305 ! XXX set the buffer busy flag
306
307 PRINT("CE_ERR\r\n")
308 CONSOLE_PRINT_ESRS(%g1, %g2, %g3, %g4)
309
310 /*
311 * Niagara PRM Programming Note: To minimize the possibility of
312 * missing notification of another error, software should clear any
313 * multiple error indication as soon as possible.
314 *
315 * Note: - hardware insures that we will not clear a non-CE error
316 * See PRM 12.4.2 Table 12-6.
317 */
318.ce_0:
319 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! SPARC afsr
320.ce_rd_sa:
321 ldxa [%g0]ASI_SPARC_ERR_ADDR, %g3 ! SPARC afar
322 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g1 ! re-read afsr
323 cmp %g1, %g4 ! same?
324 bnz,a %xcc, .ce_rd_sa ! no: read both again
325 mov %g1, %g4 ! save last status
326
327 stxa %g4, [%g0]ASI_SPARC_ERR_STATUS ! clear everything seen
328
329 stx %g4, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR] ! save afsr
330 stx %g3, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR] ! save afar
331 stx %g0, [%g5 + STRAND_VBSC_ERPT + EVBSC_JBI_ERR_LOG]
332
333 /*
334 * Check to see if there is any error to process
335 */
336 CE_CHECK(%g6, %g4, %g1, %g2, %g3) ! strand, spesr,
337 bz,a %xcc, .ce_unlock_exit ! none: exit
338 nop
339
340 /*
341 * Generate a basic error report
342 *
343 * Sparc status & address are already loaded
344 */
345 LOAD_BASIC_ERPT(%g6, %g5, %g1, %g2)
346
347 ! now we have a base diagnostic error report captured that
348 ! can be sent to the SC or diagnosis service provider
349
350 !! %g5 -> ce_rpt
351 !! %g6 -> strand
352
353 ! XXX check for TL saturation - why do this for CEs?
354 ! Too drastic to watchdog reset a guest on a corrected error!
355 ! rdpr %tl, %g3 ! get trap level
356 ! cmp %g3, MAXPTL ! is it at max?
357 ! bg,pn %xcc, 1f ! if TL > MAXPTL, watchdog reset
358 ! nop
359#ifdef DEBUG
360 .pushlocals
361 setx 0xdeadbeefdeadbeef,%g3, %g4
362 set STRAND_VBSC_ERPT + EVBSC_DIAG_BUF + DIAG_BUF_SIZE-8, %g3
3631: stx %g4, [%g5 + %g3]
364 cmp %g3, STRAND_VBSC_ERPT + EVBSC_DIAG_BUF
365 bgu,pt %xcc, 1b
366 dec 8, %g3
367 .poplocals
368#endif /* DEBUG */
369
370 /*
371 * At this point we now look for the specific errors:
372 */
373 lduw [%g6 + STRAND_ERR_FLAG], %g3
374 btst ERR_FLAG_SPARC, %g3 ! blackout?
375 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR], %g3 ! sparc status
376 bnz %xcc, .ce_check_l2 ! yes: check l2 dram
377
378 set SPARC_CE_BITS, %g4
379 btst %g4, %g3 ! any valid CE bit set?
380 bz %xcc, .ce_check_l2 ! no SPARC, check L2DRAM
381 nop
382
383 /*
384 * Sparc Errors:
385 */
386 mov %g5, %g2 ! g2 = cpu.ce_erpt
387 set SPARC_ESR_IRC, %g4
388 btst %g4, %g3 ! is IRC set?
389 bnz %xcc, .ce_irc_err
390 nop
391
392 set SPARC_ESR_FRC, %g4
393 btst %g4, %g3 ! is FRC set?
394 bnz %xcc, .ce_frc_err
395 nop
396
397 set SPARC_ESR_DTC, %g4
398 btst %g4, %g3 ! is DTC set?
399 bnz %xcc, .ce_dtc_err
400 nop
401
402 set SPARC_ESR_DDC, %g4
403 btst %g4, %g3 ! is DDC set?
404 bnz %xcc, .ce_ddc_err
405 nop
406
407 set SPARC_ESR_IDC, %g4
408 btst %g4, %g3 ! is IDC set?
409 bnz %xcc, .ce_idc_err
410 nop
411
412 set SPARC_ESR_ITC, %g4
413 btst %g4, %g3 ! is ITC set?
414 bnz %xcc, .ce_itc_err
415 nop
416
417 ! SPARC ESR may have a CE bit and/or MEC bit set
418 set SPARC_ESR_MEC, %g4
419 btst %g4, %g3 ! MEC bit set?
420 bnz %xcc, .ce_just_mec
421 nop
422
423 ! should not get here as all CE conditions have been tested
424 PRINT("NOTE: Sparc CE: failed to find error bit set!!")
425 ba,a .ce_no_error
426
427
428 ! IRC error handler
429.ce_irc_err:
430 PRINT("IRC DIAG\r\n")
431 ! set up %g1 as first arg to irc_check()
432 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1 ! arg1 = EAR
433 HVCALL(irc_check) ! %g2 is return value
434 cmp %g2, RF_TRANSIENT
435 be 1f ! transient IRC
436 nop
437 ! persistent IRC error,
438 ! let storm protection throttle irc and iru reports
439 PRINT("persistent IRC error\r\n")
440 ba .ce_sparc_storm ! finish up
441 clr %g1 ! no print or send
442
4431:
444 ! send the sparc_err_ebl reg to the diag eng
445 ldxa [%g0]ASI_SPARC_ERR_EN, %g1
446 stx %g1, [%g5 + EVBSC_DIAG_BUF + DIAG_BUF_REG_INFO]
447 ba,a .ce_send_sparc_erpt ! send report & finish up
448
449
450 ! Default CE error handler.
451 ! This just sends the CE diagnostic error report to the
452 ! vBSC to generate an FMA error report.
453/*
454 * L1 Instruction Cache:
455 */
456.ce_itc_err: /* Tag */
457 PRINT("ITC DIAG\r\n")
458 DUMP_ICACHE_INFO(STRAND_CE_RPT, %g1, %g5, %g3, %g4, %g2, %g6, %g7)
459 ba,a .ce_send_sparc_erpt
460
461.ce_idc_err:
462 PRINT("IDC DIAG\r\n")
463 DUMP_ICACHE_INFO(STRAND_CE_RPT, %g1, %g5, %g3, %g4, %g2, %g6, %g7)
464 ba,a .ce_send_sparc_erpt
465
466/*
467 * L1 Data Cache:
468 */
469.ce_dtc_err: /* Tag */
470 PRINT("DTC DIAG\r\n")
471 DUMP_DCACHE_INFO(STRAND_CE_RPT, %g6, %g5, %g1, %g2, %g3, %g4, %g7)
472 ba,a .ce_send_sparc_erpt
473
474
475.ce_ddc_err: /* Data */
476 PRINT("DDC DIAG\r\n")
477 DUMP_DCACHE_INFO(STRAND_CE_RPT, %g6, %g5, %g1, %g2, %g3, %g4, %g7)
478 ba,a .ce_send_sparc_erpt
479/*
480 * Float Register Correctable:
481 */
482.ce_frc_err:
483 PRINT("FRC DIAG\r\n")
484 ! set up %g1 as first arg to frc_check()
485 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1
486 !! %g1 = EAR
487 HVCALL(frc_check)
488 !! %g2 = return value
489 cmp %g2, RF_TRANSIENT
490 be 1f ! transient FRC
491 nop
492 ! persistent FRC error,
493 ! let storm protection throttle frc and fru reports
494 PRINT("persistent FRC error\r\n")
495 ba .ce_sparc_storm ! finish up
496 clr %g1 ! no print or send
4971:
498 ! send the sparc_err_ebl reg to the diag eng
499 ldxa [%g0]ASI_SPARC_ERR_EN, %g1
500 stx %g1, [%g5 + EVBSC_DIAG_BUF + DIAG_BUF_REG_INFO]
501 ba,a .ce_send_sparc_erpt ! send report & finish up
502
503.ce_just_mec:
504 PRINT("JUST MEC\r\n")
505 ba,a .ce_send_sparc_erpt ! send report & finish up
506
507.ce_send_sparc_erpt:
508 /*
509 * Note: this path is taken also for "MEC only" and "nothing found".
510 * It will throttle "false" interrupts.
511 */
512 STRAND_STRUCT(%g6)
513 add %g6, STRAND_CE_RPT, %g5 ! g5 -> strand.ce_rpt
514
515 set ERR_SEND_DIAG, %g1
516 SET_STRAND_RPTFLAGS(%g6, %g1)
517
518 /*
519 * Storm Prevention:
520 *
521 * This code prevents more than one error every time period from
522 * the group: SPARC Register File & L1$
523 */
524.ce_sparc_storm:
525 lduw [%g6 + STRAND_ERR_FLAG], %g2
526 btst ERR_FLAG_SPARC, %g2 ! handler installed?
527 bnz,pn %xcc, .ce_sparc_storm_done ! yes
528
529 bset ERR_FLAG_SPARC, %g2 ! no: set it
530 STRAND2CONFIG_STRUCT(%g6, %g1) ! ->configp
531 ldx [%g1 + CONFIG_CE_BLACKOUT], %g1
532 brz,a,pn %g1, .ce_sparc_storm_done ! zero: blackout disabled
533 nop
534 stw %g2, [%g6 + STRAND_ERR_FLAG] ! flag as installed
535 ! g1 = delta tick
536 HVCALL(err_set_sparc_bits) ! g2 = handler address
537 set CEEN, %g3 ! g3 = arg 0 : bit(s) to set
538 clr %g4 ! g4 = arg 1 : not used
539 HVCALL(cyclic_add_rel) /* ( del_tick, address, arg0, arg1 ) */
540.ce_sparc_storm_done:
541 ba,a ce_err_ret
542
543 /*
544 * L2DRAM Error Handling:
545 */
546 /* g6->strand, g5->ce_rpt */
547.ce_check_l2:
548 /*
549 * L2DRAM errors are global and may not be valid for this cpu.
550 * Process if PID == ERRORSTEER, or this cpu was sent the error.
551 */
552 DUMP_L2_DRAM_ERROR_LOGS(%g6, %g5, %g1, %g2, %g3, %g4, %g7)
553 /*
554 * Only one error in one bank will be processed
555 * each pass through here.
556 *
557 * Note: storm prevention will block processing of banks
558 * in a blackout
559 */
560 ! go through each L2 bank and check for valid CE bits
561.ce_check_l2_b0:
562 CE_CHECK_L2_ESR(0, %g6, %g4, %g1, %g2)
563 bz %xcc, .ce_check_l2_b1 ! check next bank
564 nop
565 SET_STRAND_L2BANK(0, %g6, %g7) ! save bank#
566 ! dump all of the l2 info. must pass the registers as is
567 DUMP_L2_SET_TAG_DATA(0, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
568 ! dram data here since all L2 esr need it
569 ldx [%g6 + STRAND_CE_RPT + STRAND_EVBSC_L2_AFSR(0)], %g4 ! l2esr
570 setx L2_ESR_CE_NO_EAR_BITS, %g1, %g2
571 btst %g4, %g2
572 bz,pn %xcc, 1f
573 nop
574 CLEAR_DRAM_CONTENTS(0, STRAND_CE_RPT, %g6, %g5)
575 ba 2f
576 nop
5771:
578 DUMP_DRAM_CONTENTS(0, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
5792:
580 /* %g6->cpu %g4=l2esr */
581 CLEAR_L2_ESR(0, %g4, %g1, %g2)
582 /* 6->strand 4=l2esr */
583 PROCESS_CE_IN_L2_ESR(0, %g6, %g5, %g4, %g1, %g2, %g3)
584 /* 6->strand 5->erpt 4=flags: action */
585 ba,a .ce_l2_all
586
587.ce_check_l2_b1:
588 CE_CHECK_L2_ESR(1, %g6, %g4, %g1, %g2)
589 bz %xcc, .ce_check_l2_b2 ! check next bank
590 nop
591 SET_STRAND_L2BANK(1, %g6, %g7) ! save bank#
592 ! dump all of the l2 info. must pass the registers as is
593 DUMP_L2_SET_TAG_DATA(1, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
594 ! dram data here since all L2 esr need it
595 ldx [%g6 + STRAND_CE_RPT + STRAND_EVBSC_L2_AFSR(1)], %g4 ! l2esr
596 setx L2_ESR_CE_NO_EAR_BITS, %g1, %g2
597 btst %g4, %g2
598 bz,pn %xcc, 1f
599 nop
600 CLEAR_DRAM_CONTENTS(0, STRAND_CE_RPT, %g6, %g5)
601 ba 2f
602 nop
6031:
604 DUMP_DRAM_CONTENTS(1, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
6052:
606 /* %g6->cpu %g4=l2esr */
607 CLEAR_L2_ESR(1, %g4, %g1, %g2)
608 PROCESS_CE_IN_L2_ESR(1, %g6, %g5, %g4, %g1, %g2, %g3)
609 ba,a .ce_l2_all
610
611.ce_check_l2_b2:
612 CE_CHECK_L2_ESR(2, %g6, %g4, %g1, %g2)
613 bz %xcc, .ce_check_l2_b3 ! check next bank
614 nop
615 SET_STRAND_L2BANK(2, %g6, %g7) ! save bank#
616 ! dump all of the l2 info. must pass the registers as is
617 DUMP_L2_SET_TAG_DATA(2, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
618 ! dram data here since all L2 esr need it
619 ldx [%g6 + STRAND_CE_RPT + STRAND_EVBSC_L2_AFSR(2)], %g4 ! l2esr
620 setx L2_ESR_CE_NO_EAR_BITS, %g1, %g2
621 btst %g4, %g2
622 bz,pn %xcc, 1f
623 nop
624 CLEAR_DRAM_CONTENTS(0, STRAND_CE_RPT, %g6, %g5)
625 ba 2f
626 nop
6271:
628 DUMP_DRAM_CONTENTS(2, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
6292:
630 /* %g6->cpu %g4=l2esr */
631 CLEAR_L2_ESR(2, %g4, %g1, %g2)
632 PROCESS_CE_IN_L2_ESR(2, %g6, %g5, %g4, %g1, %g2, %g3)
633 ba,a .ce_l2_all
634
635.ce_check_l2_b3:
636 CE_CHECK_L2_ESR(3, %g6, %g4, %g1, %g2)
637 bz %xcc, .ce_no_error
638 nop
639 SET_STRAND_L2BANK(3, %g6, %g7) ! save bank#
640 ! dump all of the l2 info. must pass the registers as is
641 DUMP_L2_SET_TAG_DATA(3, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
642 ! dram data here since all L2 esr need it
643 ldx [%g6 + STRAND_CE_RPT + STRAND_EVBSC_L2_AFSR(3)], %g4 ! l2esr
644 setx L2_ESR_CE_NO_EAR_BITS, %g1, %g2
645 btst %g4, %g2
646 bz,pn %xcc, 1f
647 nop
648 CLEAR_DRAM_CONTENTS(0, STRAND_CE_RPT, %g6, %g5)
649 ba 2f
650 nop
6511:
652 DUMP_DRAM_CONTENTS(3, STRAND_CE_RPT, %g6, %g5, %g1, %g2)
6532:
654 /* %g6->cpu %g4=l2esr */
655 CLEAR_L2_ESR(3, %g4, %g1, %g2)
656 PROCESS_CE_IN_L2_ESR(3, %g6, %g5, %g4, %g1, %g2, %g3)
657 ba,a .ce_l2_all
658
659.ce_l2_all:
660 brlz %g4, .ce_no_error ! no error found - exit now
661 nop
662 SET_STRAND_RPTFLAGS(%g6, %g4)
663
664 /*
665 * Storm Prevention:
666 *
667 * This code prevents more than one error every six seconds from
668 * the groups: L2$, DRAM Banks. Since the enables are system wide
669 * we use the error enable bits to indicate the blackout period.
670 * The callback flag is used to indicate if the handler is enabled
671 * on this cpu.
672 */
673 /*
674 * There is a very small window where multiple interrupts can be
675 * delivered to more than one cpu.
676 * Only one will get through this set successfully.
677 */
678.ce_l2dram_storm:
679 GET_STRAND_L2BANK(%g6, %g4)
680 BCLR_L2_BANK_EEN(%g4, CEEN, %g1, %g2) ! g4 = bank#
681 bz %xcc, .ce_l2dram_storm_done ! already disabled
682 nop
683 mov ERR_FLAG_L2DRAM, %g1 ! L2DRAM flag
684 sll %g1, %g4, %g1 ! << bank#
685 lduw [%g6 + STRAND_ERR_FLAG], %g2 ! installed flags
686 btst %g1, %g2 ! handler installed?
687 bnz,pn %xcc, .ce_l2dram_storm_done ! yes
688
689 bset %g1, %g2 ! no: set it
690 STRAND2CONFIG_STRUCT(%g6, %g1) ! ->configp
691 ldx [%g1 + CONFIG_CE_BLACKOUT], %g1
692 brz,a,pn %g1, .ce_l2dram_storm_done ! zero: blackout disabled
693 nop
694 stw %g2, [%g6 + STRAND_ERR_FLAG] ! handler installed
695 ! g1 = delta tick
696 HVCALL(err_set_l2_bits) ! g2 = handler address
697 mov CEEN, %g3 ! g3 = arg 0 : bit(s) to set
698 ! g4 = arg 1 : B5-0: bank #
699 HVCALL(cyclic_add_rel) /* ( del_tick, address, arg0, arg1 ) */
700.ce_l2dram_storm_done:
701 ba,a ce_err_ret
702
703 ENTRY_NP(ce_err_ret)
704
705 STRAND_STRUCT(%g6)
706 GET_STRAND_RPTFLAGS(%g6, %g4) ! g4: flags: action
707
708 btst ERR_SEND_DIAG, %g4 ! send diag report?
709 bz %xcc, .ce_unlock_exit ! no
710 nop
711 ! send CE diag report
712 add %g6, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
713 add %g6, STRAND_CE_RPT + STRAND_UNSENT_PKT, %g2 ! erpt.unsent flag
714 mov EVBSC_SIZE, %g3 ! size
715 HVCALL(send_diag_erpt) ! g4-6 clobbered
716 STRAND_STRUCT(%g6)
717 SET_STRAND_RPTFLAGS(%g6, %g0) ! clear report flags
718 ba,a .ce_unlock_exit ! handler epilogue
719
720 ! XXX CEs should never watchdog_reset a guest???
721 ! XXX It should also not inadvertently let a guest run at TL > MAXPTL
722 ! send the error report to the diagnostic service provider
723 ! before watchdog_guest
724
725 ! ba,a watchdog_guest
726 /*NOTREACHED*/
727
728 /*
729 * Sparc and L2DRAM checked with no error to report:
730 */
731.ce_no_error:
732 ! Some other thread beat us to it, or we don't own it, or
733 ! the blackout(s) have left us nothing to report.
734 PRINT("NOTE: No Reportable Error\r\n")
735
736 /*
737 * CE epilogue
738 * The CE error handlers return here after handling the error.
739 */
740.ce_unlock_exit:
741 /* MUST leave Sparc CEEN enabled to get L2DRAM interrupts! */
742 /* Reenable CEEN */
743 ldxa [%g0]ASI_SPARC_ERR_EN, %g1 ! get current
744 bset CEEN, %g1 ! enable CEEN
745 stxa %g1, [%g0] ASI_SPARC_ERR_EN ! ..
746
747 /*
748 * With CE storm prevention, the CEEN will be reenabled by the
749 * hstick_match handler when errors stop.
750 */
751 SPINLOCK_EXIT_ERRORLOCK(%g1) ! release lock
752
753 ba,a .ce_exit ! exit now
754
755.ce_exit:
756 ldx [%g6 + STRAND_ERR_RET], %g7 ! get return address
757 brnz,a %g7, .ce_return ! valid: clear it & return
758 stx %g0, [%g6+ STRAND_ERR_RET] ! ..
759 SET_SIZE(ce_poll_entry)
760 ! NULL: return from interrupt
761 retry ! return from CE interrupt
762
763.ce_return:
764 HVRET
765 SET_SIZE(ce_err_ret)
766 SET_SIZE(ce_err)
767
768
769 /*
770 * Disrupting uncorrectable error handler.
771 * All of these errors are resumable errors to the guest. I.e. they
772 * are not nonresumable errors.
773 *
774 * At entry, PSTATE.IE = 0, so no furthur disrupting error traps.
775 *
776 * The CE error report buffer is used for reporting.
777 */
778 ENTRY_NP(dis_ue_err)
779
780 /*
781 * Check for DBU in DRAM ESR
782 */
783 CHECK_DRAM_ERROR(DRAM_ESR_DBU, %g1, %g2, %g3, %g4)
784 bnz,pn %xcc, .fatal_reset_dbu ! yes: bail now
785 nop
786
787 /* get strand, CE buffer in %g6-5, they are safe across calls */
788 STRAND_ERPT_STRUCT(STRAND_CE_RPT, %g6, %g5) ! g6->strand, g5->strand.ce_rpt
789
790 /*
791 * We do not idle all strands if the scrubber got a UE
792 */
793 CHECK_L2_ERROR(L2_ESR_LDSU, %g1, %g2, %g3)
794 bnz,pn %xcc, .dis_ue_no_idle
795 mov ERR_FLAG_STRANDS_NOT_IDLED, %g1
796 CHECK_DRAM_ERROR(DRAM_ESR_DSU, %g1, %g2, %g3, %g4)
797 bnz,pn %xcc, .dis_ue_no_idle
798 mov ERR_FLAG_STRANDS_NOT_IDLED, %g1
799
800 SPINLOCK_IDLE_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
801 ! At this point, this is the only strand executing
802 mov %g0, %g1
803
804.dis_ue_no_idle:
805
806 lduw [%g6 + STRAND_ERR_FLAG], %g2 ! installed flags
807 bclr ERR_FLAG_STRANDS_NOT_IDLED, %g2 ! reset STRANDS_IDLED
808 or %g2, %g1, %g2
809 stw %g2, [%g6 + STRAND_ERR_FLAG] ! ..
810
811 PRINT("DATA ERR\r\n")
812 CONSOLE_PRINT_ESRS(%g1, %g2, %g3, %g4)
813
814 /*
815 * Niagara PRM Programming Note: To minimize the possibility of
816 * missing notification of an error, software should any multiple
817 * error indication as soon as possible.
818 */
819 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! SPARC afsr
820.dis_ue_rd_sa:
821 ldxa [%g0]ASI_SPARC_ERR_ADDR, %g3 ! SPARC afar
822 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g1 ! re-read afsr
823 cmp %g1, %g4 ! same?
824 bnz,a %xcc, .dis_ue_rd_sa ! no: read both again
825 mov %g1, %g4 ! save last status
826 stxa %g4, [%g0]ASI_SPARC_ERR_STATUS ! clear SPARC afsr
827
828 ! save ce_rpt.sparc_afsr
829 stx %g4, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR]
830 ! save ce_rpt.sparc_afar
831 stx %g3, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR]
832 stx %g0, [%g5 + STRAND_VBSC_ERPT + EVBSC_JBI_ERR_LOG]
833
834 /*
835 * Generate a basic error report
836 *
837 * Sparc status & address are already loaded
838 */
839 LOAD_BASIC_ERPT(%g6, %g5, %g1, %g2)
840
841 mov %g6, %g1 ! strand
842 mov %g5, %g2 ! strand.ue_erpt
843
844#ifdef DEBUG
845 .pushlocals
846 setx 0xdeadbeefdeadbeef,%g3, %g4
847 set STRAND_VBSC_ERPT + EVBSC_DIAG_BUF + DIAG_BUF_SIZE-8, %g3
8481: stx %g4, [%g5 + %g3]
849 cmp %g3, STRAND_VBSC_ERPT + EVBSC_DIAG_BUF
850 bgu,pt %xcc, 1b
851 dec 8, %g3
852 .poplocals
853#endif
854 ! check for MAU error
855 /* Dump the L2 and DRAM registers also */
856 ! %g1 has strand pointer, %g2 has &ce_rpt - pointer to error report
857 DUMP_L2_DRAM_ERROR_LOGS(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
858
859 ! go through each L2 bank and check for valid UE bits
860.dis_ue_check_l2_b0:
861 DIS_UE_CHECK_L2_ESR(0, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
862 bz %xcc, .dis_ue_check_l2_b1 ! check next bank
863 nop
864 /* save the state of the line */
865 SAVE_L2_LINE_STATE(0, STRAND_CE_RPT, %g1, %g2)
866 !! %g1= strand
867 !! %g2 = erpt
868 DUMP_L2_SET_TAG_DATA(0, STRAND_CE_RPT, %g1, %g2, %g1, %g2)
869 !! %g1 = cpu
870 !! %g2 = cpu.erpt
871 ldx [%g2 + STRAND_EVBSC_L2_AFSR(0)], %g4 ! l2esr
872 CLEAR_L2_ESR(0, %g4, %g5, %g6) ! clear L2 ESR
873 PROCESS_DIS_UE_IN_L2_ESR(0, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
874 .dis_ue_err_ret, .ue_resume_exit)
875
876.dis_ue_check_l2_b1:
877 DIS_UE_CHECK_L2_ESR(1, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
878 bz %xcc, .dis_ue_check_l2_b2 ! check next bank
879 nop
880 /* save the state of the line */
881 SAVE_L2_LINE_STATE(1, STRAND_CE_RPT, %g1, %g2)
882 !! %g1= strand
883 !! %g2 = erpt
884 DUMP_L2_SET_TAG_DATA(1, STRAND_CE_RPT, %g1, %g2, %g1, %g2)
885 ldx [%g2 + STRAND_EVBSC_L2_AFSR(1)], %g4 ! l2esr
886 CLEAR_L2_ESR(1, %g4, %g5, %g6) ! clear L2 ESR
887 PROCESS_DIS_UE_IN_L2_ESR(1, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
888 .dis_ue_err_ret, .ue_resume_exit)
889
890.dis_ue_check_l2_b2:
891 DIS_UE_CHECK_L2_ESR(2, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
892 bz %xcc, .dis_ue_check_l2_b3 ! check next bank
893 nop
894 /* save the state of the line */
895 SAVE_L2_LINE_STATE(2, STRAND_CE_RPT, %g1, %g2)
896 !! %g1= strand
897 !! %g2 = erpt
898 DUMP_L2_SET_TAG_DATA(2, STRAND_CE_RPT, %g1, %g2, %g1, %g2)
899 ldx [%g2 + STRAND_EVBSC_L2_AFSR(2)], %g4 ! l2esr
900 CLEAR_L2_ESR(2, %g4, %g5, %g6) ! clear L2 ESR
901 PROCESS_DIS_UE_IN_L2_ESR(2, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
902 .dis_ue_err_ret, .ue_resume_exit)
903
904.dis_ue_check_l2_b3:
905 DIS_UE_CHECK_L2_ESR(3, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
906 bz %xcc, .dis_ue_no_error ! XXX spurious?
907 nop
908 /* save the state of the line */
909 SAVE_L2_LINE_STATE(3, STRAND_CE_RPT, %g1, %g2)
910 !! %g1= strand
911 !! %g2 = erpt
912 DUMP_L2_SET_TAG_DATA(3, STRAND_CE_RPT, %g1, %g2, %g1, %g2)
913 ldx [%g2 + STRAND_EVBSC_L2_AFSR(3)], %g4 ! l2esr
914 CLEAR_L2_ESR(3, %g4, %g5, %g6) ! clear L2 ESR
915 PROCESS_DIS_UE_IN_L2_ESR(3, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
916 .dis_ue_err_ret, .ue_resume_exit)
917 !
918 ! All banks checked, now return
919 !
920 ba,a .dis_ue_err_ret ! UE handler epilogue
921 /*NOTREACHED*/
922
923.dis_ue_no_error:
924 PRINT("NO DIS UE ERROR\r\n")
925 ! some other thread beat us to it.
926 ! no bits in L2, simply return (XXX send a service error report?)
927 ! send CE diag report
928 STRAND_STRUCT(%g6)
929 add %g6, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
930 add %g6, STRAND_CE_RPT + STRAND_UNSENT_PKT, %g2 ! erpt.unsent flag
931 mov EVBSC_SIZE, %g3 ! size
932 HVCALL(send_diag_erpt)
933
934 ba,a .dis_ue_err_ret ! CE handler epilogue
935 /*NOTREACHED*/
936 SET_SIZE(dis_ue_err)
937
938 /*
939 * General handling of UEs
940 * if HTSTATE[TL].GL == MAXPGL
941 * reset chip and partitions
942 * else if HTSTATE.PRIV == 1
943 * reset chip and partitions
944 * else if TL > MAXPTL then watchdog_reset
945 * else call common handler
946 */
947
948 /*
949 * Uncorrectable error traps can be taken any time NCEEN
950 * in the SPARC error status register is set.
951 * UEs can occur when executing in the hypervisor, supervisor,
952 * or user code.
953 *
954 * XXX UEs when executing in hypervisor resets the system XXX
955 * TL overflow causes guest to be reset
956 */
957 ENTRY_NP(ue_poll_entry) /* entry point for the error daemon */
958 ! %g6->strand
959 stx %g7, [%g6 + STRAND_ERR_RET] ! save return address
960
961 ba,a ue_err_notrap
962 .empty
963
964 ENTRY_NP(ue_err)
965
966 /*
967 * Check for global register saturation and save the current
968 * global register set if necessary.
969 */
970 SAVE_UE_GLOBALS()
971
972ue_err_notrap:
973 /*
974 * Check for DBU in DRAM ESR
975 */
976 CHECK_DRAM_ERROR(DRAM_ESR_DBU, %g1, %g2, %g3, %g4)
977 bnz,pn %xcc, .fatal_reset_dbu ! yes: bail now
978 nop
979
980 /* get strand, UE buffer in %g6-5, they are safe across calls */
981 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g6, %g5) ! g6->strand, g5->strand.ue_rpt
982
983 /*
984 * check to see if UE occurred in hypervisor
985 * We check early in order to avoid a deadlock situation.
986 * in the previous trap, we were handling either a dis UE or a CE
987 */
988 rdhpr %htstate, %g1
989 btst HTSTATE_HPRIV, %g1
990 bnz %xcc, .ue_get_status_addr ! UE in hypervisor
991 nop
992
993 SPINLOCK_IDLE_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
994 ! At this point, this is the only strand executing
995
996#ifdef DEBUG
997 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g1 ! SPARC afsr
998 set SPARC_ESR_NCU, %g4 ! Ifetch/Load from IO space bit
999 btst %g4, %g1 ! NCU set?
1000 bnz %xcc, .skip_print_esrs ! skip printing ESRs
1001 nop
1002
1003 PRINT("UE_ERR\r\n")
1004 CONSOLE_PRINT_ESRS(%g1, %g2, %g3, %g4)
1005.skip_print_esrs:
1006#endif /* DEBUG */
1007
1008
1009.ue_get_status_addr:
1010 /*
1011 * Niagara PRM Programming Note: To minimize the possibility of
1012 * missing notification of an error, software should clear the
1013 * error indication as soon as possible.
1014 */
1015 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! SPARC afsr
1016.ue_rd_sa:
1017 ldxa [%g0]ASI_SPARC_ERR_ADDR, %g3 ! SPARC afar
1018 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g1 ! re-read afsr
1019 cmp %g1, %g4 ! same?
1020 bnz,a %xcc, .ue_rd_sa ! no: read both again
1021 mov %g1, %g4 ! save last status
1022
1023 stxa %g4, [%g0]ASI_SPARC_ERR_STATUS ! clear everything seen
1024
1025 ! save ue_rpt.sparc_afsr
1026 stx %g4, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR]
1027 ! save ue_rpt.sparc_afar
1028 stx %g3, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR]
1029 stx %g0, [%g5 + STRAND_VBSC_ERPT + EVBSC_JBI_ERR_LOG]
1030
1031 /*
1032 * Check to see if there is any error to process
1033 */
1034 UE_CHECK(SPARC_UE_MEU_BITS, L2_ESR_UE_BITS, %g4, %g1, %g2, %g3)
1035 bz,a %xcc, .ue_resume_exit ! none: exit
1036 nop
1037
1038 /*
1039 * Generate a basic error report
1040 *
1041 * Sparc status & address are already loaded
1042 */
1043 LOAD_BASIC_ERPT(%g6, %g5, %g1, %g2)
1044
1045 mov %g6, %g1 ! strand
1046 mov %g5, %g2 ! strand.ue_erpt
1047
1048#ifdef DEBUG
1049 .pushlocals
1050 setx 0xdeadbeefdeadbeef,%g3, %g4
1051 set STRAND_VBSC_ERPT + EVBSC_DIAG_BUF + DIAG_BUF_SIZE-8, %g3
10521: stx %g4, [%g5 + %g3]
1053 cmp %g3, STRAND_VBSC_ERPT + EVBSC_DIAG_BUF
1054 bgu,pt %xcc, 1b
1055 dec 8, %g3
1056 .poplocals
1057#endif
1058 ! set error descriptor to UE resumable
1059 set EDESC_UE_RESUMABLE, %g3
1060 ! edesc in guest erpt
1061 st %g3, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_EDESC]
1062
1063 ! check SPARC ESR for thread-specific errors
1064 ! %g3 = saved sparc_afsr
1065 ldx [%g2 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR], %g3
1066 set SPARC_UE_MEU_BITS, %g4
1067 btst %g4, %g3 ! any UE or MEU bit set?
1068 bz %xcc, .ue_dump_l2 ! no UEs, check L2
1069 nop
1070
1071 ! a UE/MEU bit is set in the SPARC ESR. If it is LDAU, then
1072 ! it is L2$/DRAM related.
1073 set SPARC_ESR_LDAU, %g4 ! LDAU bit
1074 btst %g4, %g3 ! LDAU set?
1075 bnz %xcc, .ue_ldau_err
1076 nop
1077
1078 set SPARC_ESR_NCU, %g4 ! NCU bit
1079 btst %g4, %g3 ! NCU set?
1080 bnz %xcc, .ue_ncu_err
1081 nop
1082
1083 set SPARC_ESR_IRU, %g4 ! IRU bit
1084 btst %g4, %g3 ! IRU set?
1085 bnz %xcc, .ue_iru_err
1086 nop
1087
1088 set SPARC_ESR_FRU, %g4 ! FRU bit
1089 btst %g4, %g3 ! FRU set?
1090 bnz %xcc, .ue_fru_err
1091 nop
1092
1093 /*
1094 * check to see if UE occurred in hypervisor
1095 * We check early in order to avoid a deadlock situation.
1096 * in the previous trap, we were handling either a dis UE or a CE
1097 */
1098 rdhpr %htstate, %g1
1099 btst HTSTATE_HPRIV, %g1
1100 bnz %xcc, .hpriv_ue ! UE in hypervisor
1101 nop
1102
1103 set SPARC_ESR_MAU, %g4 ! MAU bit
1104 btst %g4, %g3 ! MAU set?
1105 bnz %xcc, .ue_mau_err
1106 nop
1107
1108 set SPARC_ESR_IMDU, %g4 ! IMDU bit
1109 btst %g4, %g3 ! IMDU set?
1110 bnz %xcc, .ue_imdu_err
1111 nop
1112
1113 set SPARC_ESR_IMTU, %g4 ! IMTU bit
1114 btst %g4, %g3 ! IMTU set?
1115 bnz %xcc, .ue_imtu_err
1116 nop
1117
1118 set SPARC_ESR_DMTU, %g4 ! DMTU bit
1119 btst %g4, %g3 ! DMTU set?
1120 bnz %xcc, .ue_dmtu_err
1121 nop
1122
1123 set SPARC_ESR_DMDU, %g4 ! DMDU bit
1124 btst %g4, %g3 ! DMDU set?
1125 bnz %xcc, .ue_dmdu_err
1126 nop
1127
1128 set SPARC_ESR_DMSU, %g4 ! DMSU bit
1129 btst %g4, %g3 ! DMSU set?
1130 bnz %xcc, .ue_dmsu_err
1131 nop
1132
1133 set SPARC_ESR_MEU, %g4 ! MEU bit
1134 btst %g4, %g3 ! MEU set?
1135 bnz %xcc, .ue_just_meu_err
1136 nop
1137 /*NOTREACHED*/
1138 ! Should not get here as all UE bits have been tested
1139 PRINT("NOTREACHED\r\n")
1140 ba,a .ue_send_resume_exit
1141
1142 /*
1143 * FRU: Float Register File uncorrectable ECC error
1144 */
1145 ! If the error is unrecoverable, mark the cpu in error. Else
1146 ! fill out the ue error report in cpu structure. send service
1147 ! entity diagnosis report, then call precise_ue_err_ret. In
1148 ! precise_ue_err_ret, it will queue the error report to guest.
1149.ue_fru_err:
1150 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g2, %g2) ! ->cpu.ue_rpt
1151 ldx [%g2 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1
1152 !! %g1 = sparc afar
1153 HVCALL(clear_fregerr) ! %g1 = input, g2 = output
1154 !! %g2 contains a 0 if we got FRU after FRC for a persistent error
1155 brnz %g2, .ue_not_from_frc ! it is a new FRU
1156 nop
1157 ! Took an FRU trap from the FRC handler reread. Return to FRC handler
1158 PRINT("FRU FROM FRC DIAG\r\n");
1159
1160 STRAND_STRUCT(%g6)
1161 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
1162
1163 RESTORE_UE_GLOBALS()
1164
1165 done ! complete reread of reg
1166
1167.ue_not_from_frc:
1168 /*
1169 * check to see if UE occurred in hypervisor
1170 */
1171 rdhpr %htstate, %g3
1172 btst HTSTATE_HPRIV, %g3
1173 bnz %xcc, .hpriv_ue ! UE in hypervisor
1174 nop
1175
1176 HVCALL(fru_check) ! g2 = status
1177 ! %g2 contains whether the error is transient, persistent or a failed RF
1178 cmp %g2, RF_TRANSIENT ! transient?
1179 bne .ue_fru_cpu ! no: unrecoverable
1180 nop
1181
1182 ! FRU is recoverable, send a nonresumable error to the guest
1183 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_FRF,
1184 EDESC_PRECISE_NONRESUMABLE, %g1, %g2, %g3)
1185 CLEAR_SPARC_ESR(STRAND_UE_RPT, SPARC_ESR_FRU, %g1, %g2, %g3, %g4)
1186 PRINT("FRU DIAG\r\n")
1187 ba,a .ue_eer_send_ue_rpt
1188
1189 /* FRU is unrecoverable, mark CPU in error */
1190.ue_fru_cpu:
1191 PRINT("CPU in ERROR -FRU\r\n")
1192 ! Set the CPU_ERROR status flag
1193 SET_CPU_IN_ERROR(%g1, %g2)
1194 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_CPU,
1195 EDESC_UE_RESUMABLE, %g1, %g2, %g3)
1196 ba,a .ue_send_resume_exit
1197
1198 /*
1199 * IMDU: ITLB Data Parity Error (precise)
1200 * Detected on instruction translation as well as with loads
1201 * to ASI_ITLB_DATA_ACCESS_REG.
1202 */
1203.ue_imdu_err:
1204 PRINT("IMDU DIAG\r\n")
1205 STRAND_STRUCT(%g1)
1206 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1207 ! dump the ITLB entries into cpu.ue_rpt.diag_buf
1208 DUMP_ITLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1209 mov I_INVALIDATE, %g1
1210 stxa %g0, [%g1] ASI_TLB_INVALIDATE
1211#if 0 /* { FIXME: no longer required */
1212 mov MAP_ITLB, %g1
1213 HVCALL(remap_perm_addr)
1214#endif /* } */
1215 ! log the TLB entries on the console
1216 CONSOLE_PRINT_TLB_DATA("ITLB Tag Data\r\n", %g1, %g2, %g3, %g4, \
1217 %g5, %g6, %g7)
1218 ! For bringup, dump out the TLB entries after demap page
1219#ifdef NIAGARA_BRINGUP
1220 PRINT("IMDU demap\r\n")
1221 STRAND_STRUCT(%g1)
1222 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1223 add %g2, 0x400, %g2 ! use the second 1KB area
1224 ! dump the ITLB entries into strand diag buffer area
1225 DUMP_ITLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1226 ! log the TLB entries on the console for bringup
1227 CONSOLE_PRINT_TLB_DATA_2("ITLB Tag Data\r\n", %g1, %g2, %g3, \
1228 %g4, %g5, %g6, %g7)
1229#endif
1230 ba,a .ue_send_resume_exit ! resumable error
1231 /*NOTREACHED*/
1232
1233 /*
1234 * IMTU: ITLB Tag Parity Error
1235 * Parity error when accessed via a load from ASI_ITLB_TAG_READ
1236 * Action: Reset the platform.
1237 */
1238.ue_imtu_err:
1239 PRINT("IMTU DIAG\r\n")
1240 ! Can't dump tlb since there is no safe mechanism
1241 ba,a .ue_send_rpt_and_abort ! reset
1242 /*NOTREACHED*/
1243
1244 /*
1245 * DMTU: DTLB Tag Parity Error
1246 * Parity error when accessed via a load from ASI_DTLB_TAG_READ
1247 * Action: reset the platform.
1248 */
1249.ue_dmtu_err:
1250 PRINT("DMTU DIAG\r\n")
1251 ! Can't dump tlb since there is no safe mechanism
1252 ba,a .ue_send_rpt_and_abort ! reset
1253 /*NOTREACHED*/
1254
1255 /*
1256 * DMDU: DTLB Data Parity Error on Load and Atomics
1257 * Parity error on atomic or load translation as well
1258 * as with loads to ASI_DTLB_DATA_ACCESS_REG.
1259 */
1260.ue_dmdu_err:
1261 PRINT("DMDU DIAG\r\n")
1262 STRAND_STRUCT(%g1)
1263 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1264 ! dump the DTLB entries into the strand diag buffer
1265 DUMP_DTLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1266 ! log the TLB data on the console
1267 CONSOLE_PRINT_TLB_DATA("DTLB Tag Data\r\n", %g1, %g2, %g3, %g4, \
1268 %g5, %g6, %g7)
1269 mov D_INVALIDATE, %g1
1270 stxa %g0, [%g1] ASI_TLB_INVALIDATE
1271#if 0 /* { FIXME: no longer required */
1272 mov MAP_DTLB, %g1
1273 HVCALL(remap_perm_addr)
1274#endif /* } */
1275 ! For bringup, dump out the TLB entries after demap page
1276#ifdef NIAGARA_BRINGUP
1277 PRINT("after demap\r\n")
1278 STRAND_STRUCT(%g1)
1279 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1280 add %g2, 1024, %g2 ! use next 1KB area
1281 ! dump the dtlb entries into the strand diag buffer
1282 DUMP_DTLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1283 ! log the tlb entries on the console for bringup
1284 CONSOLE_PRINT_TLB_DATA_2("DTLB Tag Data\r\n", %g1, %g2, %g3, \
1285 %g4, %g5, %g6, %g7)
1286#endif
1287 ba,a .ue_send_resume_exit ! resumable UE
1288 /*NOTREACHED*/
1289
1290 /*
1291 * IRU: IRF Uncorrectable ECC Error
1292 */
1293.ue_iru_err:
1294 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g2, %g2)
1295 ldx [%g2 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1
1296 !! %g1 = sparc afar
1297 HVCALL(clear_iregerr) ! %g1 = input, %g2 = output
1298 !! %g2 = 0 if we got IRU after IRC for a persistent error bit
1299 brnz %g2, .ue_not_from_irc ! it is a new IRU
1300 nop
1301 ! Took an IRU trap from the IRC handler reread. Return to IRC handler
1302 PRINT("IRU FROM IRC DIAG\r\n")
1303
1304 STRAND_STRUCT(%g6)
1305 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
1306
1307 RESTORE_UE_GLOBALS()
1308
1309 done ! complete reread of reg
1310
1311.ue_not_from_irc:
1312 /*
1313 * check to see if UE occurred in hypervisor
1314 */
1315 rdhpr %htstate, %g3
1316 btst HTSTATE_HPRIV, %g3
1317 bnz %xcc, .hpriv_ue ! UE in hypervisor
1318 nop
1319
1320 HVCALL(iru_check) ! g2 = status
1321 cmp %g2, RF_TRANSIENT ! transient?
1322 bne .ue_iru_cpu ! no: unrecoverable
1323 nop
1324
1325 ! IRU is recoverable, send a nonresumable error to the guest
1326 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_IRF,
1327 EDESC_PRECISE_NONRESUMABLE, %g1, %g2, %g3)
1328 CLEAR_SPARC_ESR(STRAND_UE_RPT, SPARC_ESR_IRU, %g1, %g2, %g3, %g4)
1329 PRINT("IRU DIAG\r\n")
1330.ue_eer_send_ue_rpt:
1331 ! send the sparc_err_ebl reg to the diag eng
1332 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g1, %g2)
1333 ldxa [%g0]ASI_SPARC_ERR_EN, %g3
1334 stx %g3, [%g2 + STRAND_VBSC_ERPT + EVBSC_DIAG_BUF + DIAG_BUF_REG_INFO]
1335 ba,a .sendnr_ue_resume_exit
1336 /*NOTREACHED*/
1337
1338 ! IRU is unrecoverable, mark CPU in error
1339.ue_iru_cpu:
1340 PRINT("CPU in ERROR - IRU\r\n")
1341 ! Set the CPU_ERROR status flag
1342 SET_CPU_IN_ERROR(%g1, %g2)
1343 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_CPU,
1344 EDESC_UE_RESUMABLE, %g1, %g2, %g3)
1345 ba,a .ue_resume_exit
1346
1347 /*
1348 * DMSU: DTLB Data Parity Error on Store
1349 * Parity error on store translation.
1350 */
1351.ue_dmsu_err:
1352 PRINT("DMSU DIAG\r\n")
1353 mov D_INVALIDATE, %g1
1354 stxa %g0, [%g1] ASI_TLB_INVALIDATE
1355 STRAND_STRUCT(%g1)
1356 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1357 ! dump the DTLB entries into the strand diag buffer
1358 DUMP_DTLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1359 ! log the TLB data on the console
1360 CONSOLE_PRINT_TLB_DATA("DTLB Tag Data\r\n", %g1, %g2, %g3, %g4, \
1361 %g5, %g6, %g7)
1362#if 0 /* { FIXME: no longer required */
1363 mov MAP_DTLB, %g1
1364 HVCALL(remap_perm_addr)
1365#endif /* } */
1366 ! For bringup we dump the TLB after the demap operation
1367#ifdef NIAGARA_BRINGUP
1368 PRINT("DMSU demap\r\n")
1369 STRAND_STRUCT(%g1)
1370 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1371 add %g2, 1024, %g2 ! use the next 1KB area
1372 ! dump the dtlb entries
1373 DUMP_DTLB(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1374 ! log the dtlb to the console
1375 CONSOLE_PRINT_TLB_DATA_2("DTLB Tag Data\r\n", %g1, %g2, %g3, \
1376 %g4, %g5, %g6, %g7)
1377#endif
1378 ba,a .ue_send_resume_exit ! resumable error
1379 /*NOTREACHED*/
1380
1381 /*
1382 * MEU: Multiple Uncorrectable Error bit
1383 * Sometimes only the MEU bit will be set. It is treated as
1384 * a resumable error.
1385 */
1386.ue_just_meu_err:
1387 PRINT("JUST MEU\r\n")
1388 ba,a .ue_send_resume_exit ! resumable UE
1389 /*NOTREACHED*/
1390
1391.ue_send_rpt_and_abort:
1392 ! send UE diag report
1393 STRAND_STRUCT(%g6)
1394 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1395 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1396 add %g6, %g2, %g2 ! erpt.unsent flag
1397 mov EVBSC_SIZE, %g3 ! size
1398 HVCALL(send_diag_erpt)
1399 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
1400 ! abort HV
1401 ba,pt %xcc, hvabort
1402 rd %pc, %g1
1403 /*NOTREACHED*/
1404
1405 /*
1406 * NCU: IO Load/Instruction Fetch Error
1407 */
1408.ue_ncu_err:
1409
1410 ! check for io_prot
1411 STRAND_STRUCT(%g1)
1412 set STRAND_IO_PROT, %g2
1413 ldx [%g1 + %g2], %g2 ! strand.io_prot
1414 brz %g2, 1f ! if zero, no error protection
1415 nop
1416 ! under i/o error protection
1417 ! set the i/o error flag in the cpu structure and complete the
1418 ! instruction
1419 set STRAND_IO_ERROR, %g2
1420 mov 1, %g3
1421 stx %g3, [%g1 + %g2] ! strand.io_error = 1
1422
1423 ! clear JBI_ERR_LOG, JBI_ERR_OVF
1424 setx JBI_ERR_LOG, %g3, %g4
1425 ldx [%g4], %g5
1426 stx %g5, [%g4] ! clear JBI_ERROR_LOG
1427 setx JBI_ERR_OVF, %g3, %g4
1428 ldx [%g4], %g5
1429 stx %g5, [%g4] ! clear JBI_ERROR_OVF
1430
1431 SPINLOCK_RESUME_ALL_STRAND(%g1, %g3, %g4, %g5, %g6)
1432
1433 RESTORE_UE_GLOBALS()
1434
1435 done ! complete the instruction
1436 ! process error
14371:
1438 PRINT("NCU DIAG\r\n")
1439
1440 rdhpr %htstate, %g1
1441 btst HTSTATE_HPRIV, %g1
1442 bnz %xcc, .hpriv_ue
1443 nop
1444
1445 ! collect all diagnostic data
1446 STRAND_STRUCT(%g1)
1447 add %g1, STRAND_UE_RPT, %g2 ! %g2 = strand.ue_rpt
1448 DUMP_JBI_SSI(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1449
1450 ! clear JBI_ERR_LOG, JBI_ERR_OVF, SSI_LOG
1451 setx JBI_ERR_LOG, %g3, %g4
1452 ldx [%g4], %g5
1453 brz %g5, .ue_check_ssi
1454 stx %g5, [%g4] ! clear JBI_ERROR_LOG
1455 setx JBI_ERR_OVF, %g3, %g4
1456 ldx [%g4], %g5
1457 stx %g5, [%g4] ! clear JBI_ERROR_OVF
1458 ba,a .ue_ncu_diag
1459 ! check SSI
1460.ue_check_ssi:
1461 setx SSI_LOG, %g3, %g4
1462 ldx [%g4], %g5
1463 brz %g5, .ue_no_ncu_info
1464 stx %g5, [%g4]
1465 ba,a .ue_ncu_diag
1466
1467.ue_no_ncu_info:
1468 PRINT("NO ERROR LOGGED IN JBI SSI LOG\r\n")
1469 ba,a .ue_ncu_diag
1470
1471.ue_ncu_diag:
1472 CONSOLE_PRINT_JBI_SSI("JBI SSI Log\r\n", %g1, %g2, %g3, %g4, \
1473 %g5, %g6, %g7)
1474 ! send UE diag report
1475 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g6, %g1)
1476 inc STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1477 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1478 add %g6, %g2, %g2 ! erpt.unsent flag
1479 mov EVBSC_SIZE, %g3 ! size
1480 HVCALL(send_diag_erpt)
1481 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_PIO, \
1482 EDESC_PRECISE_NONRESUMABLE, %g4, %g5, %g6)
1483 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g1, %g2)
1484 ldx [%g2 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g3 ! VA
1485 stx %g3, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR]
1486 ba,a precise_ue_err_ret ! UE error epilogue
1487 /*NOTREACHED*/
1488
1489.ue_mau_err:
1490 PRINT("MAU DIAG\r\n")
1491 ba,a .sendnr_ue_resume_exit ! non-resumable UE epilogue
1492
1493 /*
1494 * Precise UEs that are nonresumable errors get here.
1495 * Here the diagnostic erpt is sent before executing
1496 * the handler epilogue.
1497 */
1498.sendnr_ue_resume_exit: ! non-resumable UE epilogue
1499 ! send UE diag report
1500 STRAND_STRUCT(%g6)
1501 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1502 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1503 add %g6, %g2, %g2 ! erpt.unsent flag
1504 mov EVBSC_SIZE, %g3 ! size
1505 HVCALL(send_diag_erpt)
1506 ba,a precise_ue_err_ret ! UE error epilogue
1507
1508
1509 ! %g1 has the strand pointer, %g2 has the UE error report buffer
1510.ue_ldau_err:
1511.ue_dump_l2:
1512 DUMP_L2_DRAM_ERROR_LOGS(%g1, %g2, %g3, %g4, %g5, %g6, %g7)
1513
1514 /*
1515 * check to see if UE occurred in hypervisor
1516 * We check early in order to avoid a deadlock situation.
1517 * in the previous trap, we were handling either a dis UE or a CE
1518 */
1519 rdhpr %htstate, %g1
1520 btst HTSTATE_HPRIV, %g1
1521 bnz %xcc, .hpriv_ue ! UE in hypervisor
1522 nop
1523
1524 ! check for privileged TL overflow
1525 rdpr %tl, %g1 ! get trap level
1526 cmp %g1, MAXPTL ! is it at max?
1527 bgu,pn %xcc, .tl_overflow ! TL > MAXPTL
1528 nop
1529
1530 ! check for SPARC_ESR.LDAU
1531 ! go through each L2 bank and check for valid UE bits
1532.ue_check_l2_b0:
1533 UE_CHECK_L2_ESR(0, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
1534 bz %xcc, .ue_check_l2_b1 ! check next bank
1535 nop
1536 SAVE_L2_LINE_STATE(0, STRAND_UE_RPT, %g1, %g2)
1537 DUMP_L2_SET_TAG_DATA(0, STRAND_UE_RPT, %g1, %g2, %g1, %g2)
1538 !! %g1->strand
1539 !! %g2->erpt
1540 ldx [%g2 + STRAND_EVBSC_L2_AFSR(0)], %g4 ! l2esr
1541 CLEAR_L2_ESR(0, %g4, %g5, %g6) ! clear L2 ESR
1542 PROCESS_UE_IN_L2_ESR(0, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
1543 .sendnr_ue_resume_exit, .ue_senddiag_resume_exit, \
1544 .ue_resume_exit)
1545
1546.ue_check_l2_b1:
1547 UE_CHECK_L2_ESR(1, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
1548 bz %xcc, .ue_check_l2_b2 ! check next bank
1549 nop
1550 SAVE_L2_LINE_STATE(1, STRAND_UE_RPT, %g1, %g2)
1551 DUMP_L2_SET_TAG_DATA(1, STRAND_UE_RPT, %g1, %g2, %g1, %g2)
1552 ldx [%g2 + STRAND_EVBSC_L2_AFSR(1)], %g4 ! l2esr
1553 CLEAR_L2_ESR(1, %g4, %g5, %g6) ! clear L2 ESR
1554 PROCESS_UE_IN_L2_ESR(1, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
1555 .sendnr_ue_resume_exit, .ue_senddiag_resume_exit, \
1556 .ue_resume_exit)
1557
1558.ue_check_l2_b2:
1559 UE_CHECK_L2_ESR(2, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
1560 bz %xcc, .ue_check_l2_b3 ! check next bank
1561 nop
1562 SAVE_L2_LINE_STATE(2, STRAND_UE_RPT, %g1, %g2)
1563 DUMP_L2_SET_TAG_DATA(2, STRAND_UE_RPT, %g1, %g2, %g1, %g2)
1564 ldx [%g2 + STRAND_EVBSC_L2_AFSR(2)], %g4 ! l2esr
1565 CLEAR_L2_ESR(2, %g4, %g5, %g6) ! clear L2 ESR
1566 PROCESS_UE_IN_L2_ESR(2, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
1567 .sendnr_ue_resume_exit, .ue_senddiag_resume_exit, \
1568 .ue_resume_exit)
1569
1570.ue_check_l2_b3:
1571 UE_CHECK_L2_ESR(3, %g1, %g2, %g3, %g4) ! %g1 = L2ESR
1572 bz %xcc, .ue_no_error ! XXX spurious?
1573 nop
1574 SAVE_L2_LINE_STATE(3, STRAND_UE_RPT, %g1, %g2)
1575 DUMP_L2_SET_TAG_DATA(3, STRAND_UE_RPT, %g1, %g2, %g1, %g2)
1576 ldx [%g2 + STRAND_EVBSC_L2_AFSR(3)], %g4 ! l2esr
1577 CLEAR_L2_ESR(3, %g4, %g5, %g6) ! clear L2 ESR
1578 PROCESS_UE_IN_L2_ESR(3, %g1, %g2, %g3, %g4, %g5, %g6, %g7, \
1579 .sendnr_ue_resume_exit, .ue_senddiag_resume_exit, \
1580 .ue_resume_exit)
1581 !
1582 ! All banks checked, now return
1583 !
1584 PRINT("NOTREACHED!\r\n")
1585 ba,a .ue_resume_exit
1586
1587.ue_no_error:
1588 PRINT("NO_UE_ERROR\r\n")
1589 ! some other thread beat us to it.
1590 ! no bits in L2, simply return (XXX send a service error report?)
1591
1592.ue_send_resume_exit:
1593 /*
1594 * Precise UEs that are resumable errors get here.
1595 * Here the diagnostic erpt is sent before executing
1596 * the instruction retry.
1597 */
1598 ! send UE diag report
1599 STRAND_STRUCT(%g6)
1600 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1601 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1602 add %g6, %g2, %g2 ! erpt.unsent flag
1603 mov EVBSC_SIZE, %g3 ! size
1604 HVCALL(send_diag_erpt)
1605
1606 ba,a .ue_resume_exit ! resumable UE epilogue
1607
1608
1609.tl_overflow:
1610 PRINT("TL OVERFLOW\r\n")
1611 ! send UE diag report
1612 STRAND_STRUCT(%g6)
1613 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1614 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1615 add %g6, %g2, %g2 ! erpt.unsent flag
1616 mov EVBSC_SIZE, %g3 ! size
1617 HVCALL(send_diag_erpt)
1618
1619 RESTORE_UE_GLOBALS()
1620
1621 ba,a watchdog_guest
1622
1623.hpriv_ue:
1624 ! send UE diag report
1625 STRAND_STRUCT(%g6)
1626 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1627 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1628 add %g6, %g2, %g2 ! erpt.unsent flag
1629 mov EVBSC_SIZE, %g3 ! size
1630
1631 HVCALL(send_diag_erpt)
1632
1633 HV_PRINT_SPINLOCK_ENTER(%g1, %g2, %g3)
1634 HV_PRINT_NOTRAP("UE in hypervisor - reset the system\r\n")
1635 rdpr %tl, %g2
1636
1637 HV_PRINT_NOTRAP("TPC: 0x")
1638 rdpr %tpc, %g1
1639 HV_PRINTX_NOTRAP(%g1)
1640 HV_PRINT_NOTRAP("\r\n")
1641
1642 HV_PRINT_NOTRAP("TT: 0x")
1643 rdpr %tt, %g1
1644 HV_PRINTX_NOTRAP(%g1)
1645 HV_PRINT_NOTRAP("\r\n")
1646
1647 HV_PRINT_NOTRAP("TSTATE: 0x")
1648 rdpr %tstate, %g1
1649 HV_PRINTX_NOTRAP(%g1)
1650 HV_PRINT_NOTRAP("\r\n")
1651
1652 HV_PRINT_SPINLOCK_EXIT(%g1)
1653
1654 STRAND_STRUCT(%g6)
1655 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
1656 LEGION_EXIT(3)
1657 ! abort HV
1658 ba,pt %xcc, hvabort
1659 rd %pc, %g1
1660
1661.err_resume_bad_guest_err_q:
1662 SET_CPU_IN_ERROR(%g1, %g2)
1663 SET_ERPT_EDESC_EATTR(STRAND_UE_RPT, EATTR_CPU,
1664 EDESC_UE_RESUMABLE, %g1, %g2, %g3)
1665 ba,a .ue_send_resume_exit ! resumable UE
1666
1667.fatal_reset_dbu: /* this is where we take the system down! */
1668 ! don't care how we got here, stop everything now
1669 PRINT("Reset the System: sir 0 %o0=1 fatal error\r\n")
16701:
1671 PRINT("TT 0x")
1672 rdpr %tt, %g1
1673 PRINTX(%g1)
1674 PRINT(" TL 0x")
1675 rdpr %tl, %g2
1676 PRINTX(%g2)
1677 PRINT(" TPC 0x")
1678 rdpr %tpc, %g1
1679 PRINTX(%g1)
1680 PRINT(" TNPC 0x")
1681 rdpr %tnpc, %g1
1682 PRINTX(%g1)
1683 PRINT(" TSTATE 0x")
1684 rdpr %tstate, %g1
1685 PRINTX(%g1)
1686 PRINT("\r\n")
1687 sub %g2, 1, %g2
1688 brnz %g2, 1b
1689 wrpr %g2, %tl
1690
1691 mov SIR_TYPE_FATAL_DBU, %o0
1692 sir 0
1693
1694 /*
1695 * Disrupting UE error handler epilogue
1696 * The disrupting UE error handlers return here after handling
1697 * the error
1698 * NCEEN was not disabled, so disrupting UE handler did not
1699 * mask any UEs. But we could have hit some CEs or other
1700 * disrupting UEs whose trap will be taken when we return.
1701 * Here we queue up the resumable error report to the guest.
1702 *
1703 * Disrupting UEs use the CE error buffer
1704 */
1705.dis_ue_err_ret:
1706 PRINT("DIS UE_ERR_RET\r\n")
1707
1708 /* send diag report to vbsc */
1709 STRAND_STRUCT(%g6)
1710 add %g6, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1
1711 add %g6, STRAND_CE_RPT + STRAND_UNSENT_PKT, %g2 ! erpt.unsent flag
1712 mov EVBSC_SIZE, %g3
1713 HVCALL(send_diag_erpt)
1714
1715.dis_ue_err_rerouting:
1716
1717 /*
1718 * Check if this error needs to be re-routed
1719 * Find which L2 ESR is set and check whether the
1720 * error requires re-routing. If the ESR is non-zero
1721 * but not re-routing, continue as normal.
1722 */
1723 setx L2_ESR_REROUTED_BITS, %g5, %g4
1724 STRAND_STRUCT(%g6)
1725 add %g6, STRAND_CE_RPT, %g6
1726
1727 ldx [%g6 + STRAND_EVBSC_L2_AFSR(0)], %g5
1728 btst %g5, %g4
1729 bnz,pt %xcc, .dis_ue_err_ret_rerouting
1730 mov 0, %g1 ! bank number
1731 brnz,pt %g5, .dis_ue_err_ret_no_rerouting
1732 nop
1733 ldx [%g6 + STRAND_EVBSC_L2_AFSR(1)], %g5
1734 btst %g5, %g4
1735 bnz,pt %xcc, .dis_ue_err_ret_rerouting
1736 mov 1, %g1 ! bank number
1737 brnz,pt %g5, .dis_ue_err_ret_no_rerouting
1738 nop
1739 ldx [%g6 + STRAND_EVBSC_L2_AFSR(2)], %g5
1740 btst %g5, %g4
1741 bnz,pt %xcc, .dis_ue_err_ret_rerouting
1742 mov 2, %g1 ! bank number
1743 brnz,pt %g5, .dis_ue_err_ret_no_rerouting
1744 nop
1745 ldx [%g6 + STRAND_EVBSC_L2_AFSR(3)], %g5
1746 btst %g5, %g4
1747 bnz,pn %xcc, .dis_ue_err_ret_rerouting
1748 mov 3, %g1 ! bank number
1749 nop
1750 ba .dis_ue_err_ret_no_rerouting
1751 nop
1752
1753 /*
1754 * re-route an error report
1755 * 1. Get the PA of the error from the diag report
1756 * 2. determine whch guest this PA belongs to
1757 */
1758.dis_ue_err_ret_rerouting:
1759 ! %g1 bank number
1760 ! %g5 L2 ESR
1761 ! %g6 strand->ce_rprt
1762
1763 /*
1764 * Need to get the PA from either the DRAM or L2 EAR
1765 */
1766 setx (L2_ESR_DAU | L2_ESR_DSU), %g3, %g2
1767 btst %g5, %g2
1768 be,pt %xcc, .dis_ue_err_ret_rerouting_l2
1769 nop
1770
1771 ! DRAM error
1772 ! %g1 bank number
1773 mulx %g1, EVBSC_DRAM_AFAR_INCR, %g1
1774 add %g1, EVBSC_DRAM_AFAR, %g1
1775 ldx [%g6 + %g1], %g4 ! PA
1776 ba .dis_ue_err_ret_rerouting_find_guest
1777 nop
1778
1779.dis_ue_err_ret_rerouting_l2:
1780 ! %g1 bank number
1781 mulx %g1, EVBSC_L2_AFAR_INCR, %g1
1782 add %g1, EVBSC_L2_AFAR, %g1
1783 ldx [%g6 + %g1], %g4 ! PA
1784
1785.dis_ue_err_ret_rerouting_find_guest:
1786 /*
1787 * Find the guest which owns this PA.
1788 * For each guest loop through the ra2pa_segment array and check the
1789 * PA against the base/limit
1790 * %g4 PA
1791 */
1792 ROOT_STRUCT(%g2)
1793 ldx [%g2 + CONFIG_GUESTS], %g2 ! &guests[0]
1794 set NGUESTS - 1, %g3 ! %g3 guest loop counter
17951:
1796 ! PA2RA_CONV(guestp, paddr, raddr, scr1, scr2)
1797 PA2RA_CONV(%g2, %g4, %g6, %g1, %g5)
1798 ! we got a valid RA (%g6), so this is the guest for this PA
1799 brz,pt %g5, 4f
1800 nop
18012:
1802 set GUEST_SIZE, %g5
1803 add %g2, %g5, %g2 ! guest++
1804 brnz,pt %g3, 1b
1805 dec %g3 ! nguests--
1806
1807 ! no guest found for this PA
1808 ba .dis_ue_err_ret_no_rerouting
1809 nop
18104:
1811 ! %g2 &guest
1812 ! %g4 PA
1813
1814 ! is it for the guest we are running on ?
1815 GUEST_STRUCT(%g1)
1816 cmp %g1, %g2
1817 be .dis_ue_err_ret_no_rerouting
1818 nop
1819
1820 ! go and finish re-routing this error
1821 ba cpu_reroute_error
1822 nop
1823
1824 /*
1825 * send resumable error report on this CPU
1826 */
1827.dis_ue_err_ret_no_rerouting:
1828
1829 ASMCALL_RQ_ERPT(STRAND_CE_RPT, %g1, %g2, %g3, %g4, %g5, %g6, %g7)
1830
1831 ba,a .dis_ue_resume_exit
1832
1833
1834#if 1 /* XXXX DEAD CODE */
1835 /*
1836 * Precise UE but ressumable error handler epilogue
1837 * The precise UE error handlers return here after handling the error
1838 * A resumable error will be queued to the affected guest.
1839 */
1840 ENTRY_NP(precise_ue_res_ret)
1841 PRINT("RES UE_ERR_RET\r\n")
1842 ! Call the function to queue the resumable report
1843 ASMCALL_RQ_ERPT(STRAND_UE_RPT, %g1, %g2, %g3, %g4, %g5, %g6, %g7)
1844 ba,a .ue_resume_exit
1845#endif
1846
1847.ue_senddiag_resume_exit:
1848 ! send UE diag report
1849 STRAND_STRUCT(%g6)
1850 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
1851 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
1852 add %g6, %g2, %g2 ! erpt.unsent flag
1853 mov EVBSC_SIZE, %g3 ! size
1854 HVCALL(send_diag_erpt)
1855
1856.dis_ue_resume_exit:
1857.ue_resume_exit:
1858 ! See if CPU is in ERROR and handle the case
1859 VCPU_STRUCT(%g1)
1860 IS_CPU_IN_ERROR(%g1, %g2)
1861 bne %xcc, .ue_continue
1862 nop
1863
1864 ! Mark the corresponding strand in error
1865 HVCALL(strand_in_error)
1866
1867.ue_continue:
1868 STRAND_STRUCT(%g6)
1869
1870 /*
1871 * Check whether the UE error handler idled the
1872 * strands
1873 */
1874 lduw [%g6 + STRAND_ERR_FLAG], %g2
1875 btst ERR_FLAG_STRANDS_NOT_IDLED, %g2
1876 bnz %xcc, .ue_continue_not_idled ! strands were not idled
1877 bclr ERR_FLAG_STRANDS_NOT_IDLED, %g2 ! reset STRANDS_IDLED
1878
1879 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
1880 ba .ue_continue_idled ! flag is not set,
1881 nop ! so skip clearing it
1882
1883.ue_continue_not_idled:
1884
1885 stw %g2, [%g6 + STRAND_ERR_FLAG] ! ..
1886
1887.ue_continue_idled:
1888
1889 ldx [%g6 + STRAND_ERR_RET], %g7 ! get return address
1890 brnz,a %g7, .ue_return ! valid: clear it & return
1891 stx %g0, [%g6+ STRAND_ERR_RET] ! ..
1892 ! NULL: return from interrupt
1893 RESTORE_UE_GLOBALS()
1894 retry ! return from UE interrupt
1895
1896.ue_return:
1897 HVRET
1898 SET_SIZE(ue_poll_entry)
1899 SET_SIZE(ue_err)
1900
1901
1902 /*
1903 * Precise UE error handler epilogue
1904 * The precise UE error handlers return here after handling the error
1905 * A nonresumable error will be queued to the affected guest.
1906 */
1907 ENTRY_NP(precise_ue_err_ret)
1908 PRINT("precise_ue_err_ret\r\n")
1909
1910 ! queue nonresumable error report
1911 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g1, %g2)
1912
1913 /*
1914 * Translate error address
1915 *
1916 * When EATTR_PIO, the error PA is in the RA field of the erpt.
1917 * For others, check the four L2 AFARs to find a non-zero
1918 * address.
1919 */
1920 lduw [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4
1921 btst EATTR_PIO, %g4
1922 bz,pt %xcc, .precise_ue_err_ret_mem
1923 nop
1924
1925.precise_ue_err_ret_io:
1926 /* No affected memory region */
1927 stw %g0, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
1928
1929 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4
1930 VCPU_STRUCT(%g1)
1931 CPU_ERR_IO_PA_TO_RA(%g1, %g4, %g4, %g3, %g5, %g6, .precise_ue_err_ret_io)
1932 ba,pt %xcc, 2f
1933 nop
1934
1935.precise_ue_err_ret_mem:
1936 mov ERPT_MEM_SIZE, %g4
1937 stw %g4, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
1938 ldx [%g2 + STRAND_EVBSC_L2_AFAR(0)], %g4
1939 brnz %g4, 1f
1940 nop
1941 ldx [%g2 + STRAND_EVBSC_L2_AFAR(1)], %g4
1942 brnz %g4, 1f
1943 nop
1944 ldx [%g2 + STRAND_EVBSC_L2_AFAR(2)], %g4
1945 brnz %g4, 1f
1946 nop
1947 ldx [%g2 + STRAND_EVBSC_L2_AFAR(3)], %g4
1948 brnz %g4, 1f
1949 nop
1950 ba,pt %xcc, 2f
1951 mov CPU_ERR_INVALID_RA, %g4
1952
19531:
1954 VCPU_STRUCT(%g1) /* FIXME: or strand? */
1955 CPU_ERR_PA_TO_RA(%g1, %g4, %g4, %g5, %g6)
1956
19572:
1958 stx %g4, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR]
1959
1960 !! %g1 = cpup
1961 !! %g2 = erpt
1962 HVCALL(queue_nonresumable_erpt)
1963
1964 STRAND_STRUCT(%g1)
1965 SPINLOCK_RESUME_ALL_STRAND(%g1, %g3, %g4, %g5, %g6)
1966
1967 ba,pt %xcc, nonresumable_error_trap
1968 nop
1969 /*NOTREACHED*/
1970 SET_SIZE(precise_ue_err_ret)
1971
1972#if STRAND_SUN4V_ERPT != 0
1973#error "STRAND_SUN4V_ERPT must be 0"
1974#endif
1975
1976/*
1977 * Queue a resumable error report on this CPU
1978 * %g1 contains pointer to the STRAND structure
1979 * %g2 contains pointer to the error report
1980 * (STRAND_SUN4V_ERPT *must* be 0x0 for this to be called generically)
1981 *
1982 * XXX If there is no free entry in the resumable error queue
1983 * print a message and return. XXX
1984 */
1985 ENTRY_NP(queue_resumable_erpt)
1986 VCPU_STRUCT(%g1)
1987 ldx [%g1 + CPU_ERRQR_BASE_RA], %g3 ! get q base RA
1988 brnz %g3, 1f ! if base RA is zero, skip
1989 nop
1990 mov %g7, %g6
1991 PRINT("RQ NOT ALLOC\r\n")
1992 mov %g6, %g7
1993 ! The resumable error queue is not allocated/initialized
1994 ! simply return. No guest is there to receive it.
1995 jmp %g7 + 4
1996 nop
19971:
1998 /*
1999 * Translate error address
2000 *
2001 * When EATTR_PIO, the error PA is in the RA field of the erpt.
2002 * For others, check the four L2 AFARs to find a non-zero
2003 * address.
2004 */
2005 lduw [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4
2006 btst EATTR_PIO, %g4
2007 bz,pt %xcc, .dis_ue_err_ret_mem
2008 nop
2009
2010.dis_ue_err_ret_io:
2011 /* No affected memory region */
2012 stw %g0, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
2013
2014 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4
2015 CPU_ERR_IO_PA_TO_RA(%g1, %g4, %g4, %g3, %g5, %g6, .dis_ue_err_ret_io)
2016 ba,pt %xcc, 2f
2017 nop
2018
2019.dis_ue_err_ret_mem:
2020 mov ERPT_MEM_SIZE, %g4
2021 stw %g4, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
2022 ldx [%g2 + STRAND_EVBSC_L2_AFAR(0)], %g4
2023 brnz %g4, 1f
2024 nop
2025 ldx [%g2 + STRAND_EVBSC_L2_AFAR(1)], %g4
2026 brnz %g4, 1f
2027 nop
2028 ldx [%g2 + STRAND_EVBSC_L2_AFAR(2)], %g4
2029 brnz %g4, 1f
2030 nop
2031 ldx [%g2 + STRAND_EVBSC_L2_AFAR(3)], %g4
2032 brnz %g4, 1f
2033 nop
2034 ba,pt %xcc, 2f
2035 mov CPU_ERR_INVALID_RA, %g4
2036
20371:
2038 VCPU_STRUCT(%g1) /* FIXME: or strand? */
2039 CPU_ERR_PA_TO_RA(%g1, %g4, %g4, %g5, %g6)
2040
20412:
2042 stx %g4, [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR]
2043 /*
2044 * If this is a MEM error report, ensure that it has a valid
2045 * RA for this guest
2046 */
2047 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4 ! attr
2048 btst EATTR_MEM, %g4
2049 bz,pt %xcc, 1f
2050 nop
2051 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4 ! ra
2052 cmp %g4, CPU_ERR_INVALID_RA
2053 bne,pt %xcc, 1f
2054 nop
2055
2056 ! not for this guest, return
2057
2058 jmp %g7 + 4
2059 nop
20601:
2061 mov ERROR_RESUMABLE_QUEUE_TAIL, %g3
2062 ldxa [%g3]ASI_QUEUE, %g5 ! %g5 = rq_tail
2063 add %g5, 0x40, %g6 ! %g6 = rq_next = rq_tail++
2064 ldx [%g1 + CPU_ERRQR_MASK], %g4
2065 and %g6, %g4, %g6 ! %g6 = rq_next mod
2066 mov ERROR_RESUMABLE_QUEUE_HEAD, %g3
2067 ldxa [%g3] ASI_QUEUE, %g4 ! %g4 = rq_head
2068 cmp %g6, %g4 ! head = ++tail?
2069 be %xcc, .rq_full
2070 mov ERROR_RESUMABLE_QUEUE_TAIL, %g3
2071 stxa %g6, [%g3] ASI_QUEUE ! new tail = rq_next
2072 ! write up the queue record
2073 ldx [%g1 + CPU_ERRQR_BASE], %g4
2074 add %g5, %g4, %g3 ! %g3 = base + tail
2075 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL], %g4 ! ehdl
2076 stx %g4, [%g3 + 0x0]
2077 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK], %g4 ! stick
2078 stx %g4, [%g3 + 0x8]
2079 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_EDESC], %g4 ! edesc
2080 st %g4, [%g3 + 0x10]
2081 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4 ! attr
2082 st %g4, [%g3 + 0x14]
2083 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4 ! ra
2084 stx %g4, [%g3 + 0x18]
2085 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ], %g4 ! sz
2086 st %g4, [%g3 + 0x20]
2087 lduh [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_CPUID], %g4 ! cpuid
2088 stuh %g4, [%g3 + 0x24]
2089 lduh [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_SECS], %g4
2090 stuh %g4, [%g3 + 0x26] ! pad/secs
2091 stx %g0, [%g3 + 0x28] ! word5
2092 stx %g0, [%g3 + 0x30] ! word6
2093 stx %g0, [%g3 + 0x38] ! word7
2094
2095 jmp %g7 + 4
2096 nop
2097
2098.rq_full:
2099 ! The resumable error queue is full.
2100 ! simply return
2101 mov %g7, %g6
2102 PRINT("RQ FULL\r\n")
2103 mov %g6, %g7
2104
2105 jmp %g7 + 4
2106 nop
2107 SET_SIZE(queue_resumable_erpt)
2108
2109/*
2110 * Queue a nonresumable error report on this CPU
2111 * %g2 contains pointer to the error report
2112 * %g1, %g3 - %g6 clobbered
2113 * %g7 return address
2114 *
2115 * Check to see what is the guest state:
2116 * switch(guestp->state) {
2117 * case GUEST_STATE_SUSPENDED:
2118 * case GUEST_STATE_NORMAL:
2119 * ! calculate new head
2120 * oldtail = [ERROR_NONRESUMABLE_QUEUE_TAIL]ASI_QUEUE
2121 * qnr_mask =vpup->errqnr_mask;
2122 * newtail = (oldtail + qsize) & mask;
2123 * head = [ERROR_NONRESUMABLE_QUEUE_HEAD]ASI_QUEUE
2124 * if (vcpup->cpu_errqnr_base_ra == 0 || (head == newhead)) {
2125 * sir_guest()
2126 * } else {
2127 * deliver_pkt(pkt);
2128 * }
2129 * break;
2130 * case GUEST_STATE_EXITING:
2131 * case GUEST_STATE_STOPPED:
2132 * case GUEST_STATE_UNCONFIGURED:
2133 * drop_pkt();
2134 *
2135 * break;
2136 * }
2137 *
2138 * This routine just moves the erpt to the queue, it does not
2139 * modify the data.
2140 */
2141 ENTRY_NP(queue_nonresumable_erpt)
2142
2143 VCPU_STRUCT(%g1)
2144 ! Get the guest structure this vcpu belongs
2145 VCPU2GUEST_STRUCT(%g1, %g5)
2146
2147 ! Determine the guest state
2148 lduw [%g5 + GUEST_STATE], %g4
2149 set GUEST_STATE_SUSPENDED, %g3
2150 cmp %g4, %g3
2151 be,pn %xcc, .check_vcpu_queues
2152 set GUEST_STATE_NORMAL, %g3
2153 cmp %g4, %g3
2154 be,pn %xcc, .check_vcpu_queues
2155 set GUEST_STATE_EXITING, %g3
2156 cmp %g4, %g3
2157 be,pn %xcc, .drop_nrq_pkt
2158 set GUEST_STATE_STOPPED, %g3
2159 cmp %g4, %g3
2160 be,pn %xcc, .drop_nrq_pkt
2161 set GUEST_STATE_UNCONFIGURED, %g3
2162 cmp %g4, %g3
2163 be,pn %xcc, .drop_nrq_pkt
2164 nop
2165
2166.check_vcpu_queues:
2167 ! %g1 vcpup
2168 ldx [%g1 + CPU_ERRQNR_BASE_RA], %g3 ! get q base RA
2169 brz,pn %g3, .queue_nonresumable_bad_queue
2170 nop
2171 mov ERROR_NONRESUMABLE_QUEUE_TAIL, %g3
2172 ldxa [%g3]ASI_QUEUE, %g5 ! %g5 = rq_tail
2173 add %g5, 0x40, %g6 ! %g6 = rq_next = rq_tail++
2174 ldx [%g1 + CPU_ERRQNR_MASK], %g4
2175 and %g6, %g4, %g6 ! %g6 = rq_next mod
2176 mov ERROR_NONRESUMABLE_QUEUE_HEAD, %g3
2177 ldxa [%g3] ASI_QUEUE, %g4 ! %g4 = rq_head
2178 cmp %g6, %g4 ! head = ++tail?
2179 be,pn %xcc, .queue_nonresumable_full_queue
2180 mov ERROR_NONRESUMABLE_QUEUE_TAIL, %g3
2181
2182 /*
2183 * Deliver NR error pkt to guest
2184 */
2185 stxa %g6, [%g3]ASI_QUEUE ! new tail = rq_next
2186 ! write the queue record
2187 ldx [%g1 + CPU_ERRQNR_BASE], %g4
2188 add %g5, %g4, %g3 ! %g3 = base + tail
2189 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL], %g4 ! ehdl
2190 stx %g4, [%g3 + 0x0]
2191 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK], %g4 ! stick
2192 stx %g4, [%g3 + 0x8]
2193 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_EDESC], %g4 ! edesc
2194 st %g4, [%g3 + 0x10]
2195 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4 ! attr
2196 st %g4, [%g3 + 0x14]
2197 ldx [%g2 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4 ! ra
2198 stx %g4, [%g3 + 0x18]
2199 ld [%g2 + STRAND_SUN4V_ERPT + ESUN4V_SZ], %g4 ! sz
2200 st %g4, [%g3 + 0x20]
2201 lduh [%g2 + STRAND_SUN4V_ERPT + ESUN4V_G_CPUID], %g4 ! cpuid
2202 stuh %g4, [%g3 + 0x24]
2203 stuh %g0, [%g3 + 0x26] ! pad
2204 stx %g0, [%g3 + 0x28] ! word5
2205 stx %g0, [%g3 + 0x30] ! word6
2206 stx %g0, [%g3 + 0x38] ! word7
2207
2208 mov %g7, %g6
2209 PRINT("queue_nonresumable_erpt: entry enqueued\r\n")
2210 mov %g6, %g7
2211
2212 HVRET
2213
2214.drop_nrq_pkt:
2215 /*
2216 * The guest is not in the proper state to receive pkts
2217 * Drop packet by just returning
2218 */
2219#ifdef DEBUG
2220 mov %g7, %g6
2221 PRINT("no guest to deliver NR error pkt. Dropping it\r\n")
2222 mov %g6, %g7
2223#endif
2224 HVRET
2225
2226.queue_nonresumable_full_queue:
2227 /*
2228 * The nonresumable error queue is full.
2229 * Reset the guest
2230 */
2231#ifdef DEBUG
2232 mov %g7, %g6
2233 PRINT("queue_nonresumable_erpt: nrq full - exiting guest\r\n")
2234 mov %g6, %g7
2235#endif
2236 ba,a .queue_nonresumable_reset
2237
2238.queue_nonresumable_bad_queue:
2239 /*
2240 * The nonresumable error queue is not allocated/initialized
2241 * Reset the guest
2242 */
2243#ifdef DEBUG
2244 mov %g7, %g6
2245 PRINT("NRQ NOT ALLOC - exiting guest\r\n")
2246 mov %g6, %g7
2247#endif
2248 /* fall through */
2249
2250.queue_nonresumable_reset:
2251#ifdef NIAGARA_BRINGUP
2252 rdpr %tl, %g2
2253 deccc %g2
2254 bz %xcc, 1f
2255 nop
2256 wrpr %g2, %tl
2257 PRINT("TPC \r\n")
2258 rdpr %tpc, %g1
2259 PRINTX(%g1)
2260 PRINT("\r\n")
2261 PRINT("TT \r\n")
2262 rdpr %tt, %g1
2263 PRINTX(%g1)
2264 PRINT("\r\n")
2265 PRINT("TSTATE \r\n")
2266 rdpr %tstate, %g1
2267 PRINTX(%g1)
2268 PRINT("\r\n")
22691:
2270#endif
2271 ba,a .err_resume_bad_guest_err_q
2272 SET_SIZE(queue_nonresumable_erpt)
2273
2274
2275/*
2276 * JBUS error
2277 */
2278 ENTRY(ue_jbus_err)
2279
2280 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g6, %g5) ! g6->strand, g5->strand.ue_rpt
2281
2282 SPINLOCK_IDLE_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
2283 ! At this point, this is the only strand executing
2284
2285 /*
2286 * Generate a basic error report
2287 */
2288 LOAD_BASIC_ERPT(%g6, %g5, %g1, %g2)
2289
2290 /*
2291 * Clear unused diag buf fields
2292 */
2293 stx %g0, [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFSR]
2294 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_L2_AFSR(0)]
2295 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_L2_AFSR(1)]
2296 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_L2_AFSR(2)]
2297 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_L2_AFSR(3)]
2298 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_DRAM_AFSR(0)]
2299 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_DRAM_AFSR(1)]
2300 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_DRAM_AFSR(2)]
2301 stx %g0, [%g5 + STRAND_VBSC_ERPT + STRAND_EVBSC_DRAM_AFSR(3)]
2302
2303 /*
2304 * Store JBUS error data in error report
2305 */
2306 DUMP_JBI_SSI(%g6, %g5, %g3, %g4, %g1, %g2, %g7)
2307
2308 /*
2309 * Clear the JBI errors logged in the erpt
2310 */
2311 STRAND_ERPT_STRUCT(STRAND_UE_RPT, %g6, %g5) ! g6->strand, g5->strand.ue_rpt
2312 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_JBI_ERR_LOG], %g1
2313 setx JBI_ERR_LOG, %g3, %g2
2314 stx %g1, [%g2]
2315 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_DIAG_BUF + JS_JBI_ERR_OVF], %g4
2316 setx JBI_ERR_OVF, %g3, %g2
2317 stx %g4, [%g2]
2318 or %g1, %g4, %g1 ! combine primary and overflow for fatal check
2319 CPU_PUSH(%g1, %g2, %g3, %g4) /* save JBI_ERR_LOG|JVI_ERR_OVF */
2320
2321 /*
2322 * send UE diag report
2323 */
2324 add %g6, STRAND_UE_RPT + STRAND_VBSC_ERPT, %g1 ! erpt.vbsc
2325 set STRAND_UE_RPT + STRAND_UNSENT_PKT, %g2
2326 add %g6, %g2, %g2 ! erpt.unsent flag
2327 mov EVBSC_SIZE, %g3 ! size
2328 HVCALL(send_diag_erpt)
2329
2330 STRAND_STRUCT(%g6)
2331 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
2332
2333 /*
2334 * Clear interrupt
2335 */
2336 setx IOBBASE, %g3, %g2
2337 stx %g0, [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSIERR)]
2338
2339 /*
2340 * Get saved JBI error log register and check for fatal errors
2341 */
2342 CPU_POP(%g1, %g2, %g3, %g4)
2343 btst JBI_ABORT_ERRS, %g1
2344 bnz,pn %xcc, .ue_jbus_err_fatal
2345 nop
2346
2347 /*
2348 * Not a fatal JBI error, we sent the info to vbsc so just
2349 * return to whatever this strand was doing.
2350 */
2351 retry
2352
2353.ue_jbus_err_fatal:
2354 LEGION_EXIT(3)
2355 ! abort HV
2356 ba,pt %xcc, hvabort
2357 rd %pc, %g1
2358 SET_SIZE(ue_jbus_err)
2359
2360
2361 /*
2362 * irc_check(uint64_t sparc_ear) [Non-LEAF]
2363 *
2364 * Checks whether the IRC error is transient or persistent.
2365 * Before we re-read the register in error, we set the irc_ear
2366 * in the CPU struct to the SPARC EAR value, which has the reg#
2367 * and the syndrome. A zero syndrome is not possible for error,
2368 * therefore irc_ear == 0 means IRC trap didn't set it.
2369 * (Note %g0 like other registers can generate errors.)
2370 * If the IRU trap is taken because of a persistent uncorrectable error,
2371 * the IRU trap handler will check the irc_ear field with the SPARC_EAR
2372 * logged. If they are the same, then IRU trap handler clears the
2373 * irc_ear field and returns.
2374 *
2375 * set_ircear(sparc_ear)
2376 * irf_reread(sparc_ear)
2377 * if (CPU.irc_ear == 0)
2378 * return RF_PERSISTENT;
2379 * else {
2380 * CPU.irc_ear = 0;
2381 * return RF_TRANSIENT;
2382 * }
2383 * Arguments:
2384 * %g1 - input - SPARC EAR - clobbered
2385 * %g2 - output (RF_TRANSIENT, RF_PERSISTENT)
2386 * %g3 - scratch
2387 * %g4 - scratch
2388 * %g5 - erpt
2389 * %g6 - strand
2390 * %g7 - return address
2391 */
2392 ENTRY_NP(irc_check)
2393
2394 ! init STRAND.irc_ear
2395 stx %g1, [%g6 + STRAND_REGERR] ! CPU.irc_ear = sparc EAR (!=0)
2396
2397 ! reread register
2398 mov %g7, %g6 ! save return address
2399 HVCALL(irf_reread) ! %g1 has SPARC EAR
2400 mov %g6, %g7 ! restore return address
2401
2402 STRAND_STRUCT(%g6) ! restore g6->strand
2403
2404 ! check STRAND.irc_ear
2405 ldx [%g6 + STRAND_REGERR], %g2 ! read STRAND.irc_ear
2406 brz %g2, .irc_ret ! persistent error
2407 mov RF_PERSISTENT, %g2
2408
2409 ! transient error. H/W has fixed it now after the reread
2410 ! get back to interrupted program
2411 stx %g0, [%g6 + STRAND_REGERR] ! clear irc_ear
2412 mov RF_TRANSIENT, %g2 ! return transient
2413.irc_ret:
2414 HVRET
2415 SET_SIZE(irc_check)
2416
2417
2418 /*
2419 * int iru_check(uint64_t sparc_ear) [Non-Leaf]
2420 *
2421 * Check whether the IRU error is transient, persistent
2422 * or if the integer register file is flaky.
2423 *
2424 * clear_irf_ue(sparc_ear);
2425 * irf_reread(sparc_ear);
2426 * if (SPARC_ESR.IRU == 0) {
2427 * return RF_TRANSIENT;
2428 * }
2429 * if (SPARC_EAR == sparc_ear)
2430 * return RF_PERSISTENT;
2431 * } else {
2432 * return RF_FAILURE;
2433 * }
2434 * Arguments:
2435 * %g1 - input - SPARC EAR - clobbered
2436 * %g2 - output (RF_TRANSIENT, RF_PERSISTENT, RF_FAILURE)
2437 * %g3 - scratch
2438 * %g4 - scratch
2439 * %g5 - erpt pointer
2440 * %g6 - strand pointer
2441 */
2442 ENTRY_NP(iru_check)
2443 mov %g7, %g6 ! save return address
2444
2445 HVCALL(clear_irf_ue) ! %g1 has SPARC EAR
2446
2447 ! reread register
2448 HVCALL(irf_reread) ! %g1 has SPARC EAR
2449
2450 mov %g6, %g7 ! restore return address
2451 STRAND_STRUCT(%g6) ! restore strand
2452
2453 ! check SPARC ESR for IRU error
2454 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! get SPARC ESR
2455 set SPARC_ESR_IRU, %g3 ! IRU bit
2456 btst %g3, %g4 ! check for IRU
2457 bz %xcc, .iru_ret ! no:
2458 mov RF_TRANSIENT, %g2 ! return transient
2459
2460 ! persistent IRU error?
2461 ! check EAR for match
2462 ldxa [%g0]ASI_SPARC_ERR_ADDR, %g2 ! get SPARC EAR
2463 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1 ! saved EAR
2464 xor %g2, %g1, %g2 ! Are they the same?
2465 andcc %g2, SPARC_EAR_IREG_MASK, %g2 ! (ignore non-register bits)
2466 bnz %xcc, .iru_ret ! no:
2467 mov RF_FAILURE, %g2 ! return reg file failure
2468 stxa %g4, [%g0]ASI_SPARC_ERR_STATUS ! yes: clear SPARC ESR
2469 mov RF_PERSISTENT, %g2 ! return persistent error
2470.iru_ret:
2471 HVRET ! return to caller
2472 SET_SIZE(iru_check)
2473
2474
2475 /*
2476 * void irf_reread(uint64_t sparc_ear) [LEAF function]
2477 *
2478 * Caller: IRC or IRU handler
2479 *
2480 * Re-read integer register in error
2481 * Arguments:
2482 * %g1 - input - SPARC_EAR
2483 * %g2 - %g4 - scratch
2484 * %g5, %g6 - preserved
2485 * %g7 - return address
2486 */
2487 ENTRY_NP(irf_reread)
2488 and %g1, SPARC_EAR_IREG_MASK, %g2
2489 srlx %g2, SPARC_EAR_IREG_SHIFT, %g2 ! %g2 has int reg num
2490
2491 ! %g2 has the int reg# in error.
2492 ! Current window is pointing to the window of the reg in error
2493
2494 ! get the register number within the set
2495 and %g2, 0x1f, %g2 ! mask off GL/CWP
2496 cmp %g2, 8 ! is reg# < 8?
2497 bl .glob ! yes, then global reg
2498 nop
2499
2500 ! Now re-read the register in error
2501 ba 1f ! do reread
2502 rd %pc, %g3 ! get reread instr base addr
2503 ! an array of instruction blocks indexed by register number to
2504 ! reread the non-global register reported in error.
2505 or %g0, %o0, %o0 ! reread %o0
2506 ba,a .reread_done
2507 or %g0, %o1, %o1 ! reread %o1
2508 ba,a .reread_done
2509 or %g0, %o2, %o2 ! reread %o2
2510 ba,a .reread_done
2511 or %g0, %o3, %o3 ! reread %o3
2512 ba,a .reread_done
2513 or %g0, %o4, %o4 ! reread %o4
2514 ba,a .reread_done
2515 or %g0, %o5, %o5 ! reread %o5
2516 ba,a .reread_done
2517 or %g0, %o6, %o6 ! reread %o6
2518 ba,a .reread_done
2519 or %g0, %o7, %o7 ! reread %o7
2520 ba,a .reread_done
2521 or %g0, %l0, %l0 ! reread %l0
2522 ba,a .reread_done
2523 or %g0, %l1, %l1 ! reread %l1
2524 ba,a .reread_done
2525 or %g0, %l2, %l2 ! reread %l2
2526 ba,a .reread_done
2527 or %g0, %l3, %l3 ! reread %l3
2528 ba,a .reread_done
2529 or %g0, %l4, %l4 ! reread %l4
2530 ba,a .reread_done
2531 or %g0, %l5, %l5 ! reread %l5
2532 ba,a .reread_done
2533 or %g0, %l6, %l6 ! reread %l6
2534 ba,a .reread_done
2535 or %g0, %l7, %l7 ! reread %l7
2536 ba,a .reread_done
2537 or %g0, %i0, %i0 ! reread %i0
2538 ba,a .reread_done
2539 or %g0, %i1, %i1 ! reread %i1
2540 ba,a .reread_done
2541 or %g0, %i2, %i2 ! reread %i2
2542 ba,a .reread_done
2543 or %g0, %i3, %i3 ! reread %i3
2544 ba,a .reread_done
2545 or %g0, %i4, %i4 ! reread %i4
2546 ba,a .reread_done
2547 or %g0, %i5, %i5 ! reread %i5
2548 ba,a .reread_done
2549 or %g0, %i6, %i6 ! reread %i6
2550 ba,a .reread_done
2551 or %g0, %i7, %i7 ! reread %i7
2552 ba,a .reread_done
25531:
2554 sub %g2, 8, %g2 ! skip globals
2555 sllx %g2, 3, %g2 ! offset = reg# * 8
2556 add %g3, %g2, %g3 ! %g3 = instruction block addr
2557
2558 ldxa [%g0]ASI_SPARC_ERR_EN, %g2 ! save current in %g2
2559 andn %g2, CEEN, %g4 ! disable CEEN
2560 stxa %g4, [%g0] ASI_SPARC_ERR_EN ! ..
2561
2562 jmp %g3 + SZ_INSTR ! jmp to reread register
2563 nop
2564
2565 ! restore gl from value in %o0, and restore %o0
2566.gl_reread_done:
2567 wrpr %o0, %gl ! restore %gl
2568 mov %g4, %o0 ! restore %o0
2569
2570 ! Here, we check the iregerr field after the reread. If it
2571 ! is zero, then we know it is a persistent uncorrectable error.
2572 ! If it is nonzero, then we know it is a transient error.
2573.reread_done:
2574 stxa %g2, [%g0] ASI_SPARC_ERR_EN ! restore CEEN
2575 HVRET ! return to caller
2576
2577 ! %g2 has the register number
2578.glob:
2579 ! now re-read the global register in error
2580 ba 1f
2581 rd %pc, %g3 ! reread instruction base addr
2582 ! an array of instructions blocks indexed by global register number
2583 ! to reread the global register reported in error.
2584 ! %gl points to the error global set
2585 or %g0, %g0, %g0 ! reread %g0 (yay!)
2586 ba,a .gl_reread_done
2587 or %g0, %g1, %g1 ! reread %g1
2588 ba,a .gl_reread_done
2589 or %g0, %g2, %g2 ! reread %g2
2590 ba,a .gl_reread_done
2591 or %g0, %g3, %g3 ! reread %g3
2592 ba,a .gl_reread_done
2593 or %g0, %g4, %g4 ! reread %g4
2594 ba,a .gl_reread_done
2595 or %g0, %g5, %g5 ! reread %g5
2596 ba,a .gl_reread_done
2597 or %g0, %g6, %g6 ! reread %g6
2598 ba,a .gl_reread_done
2599 or %g0, %g7, %g7 ! reread %g7
2600 ba,a .gl_reread_done
26011:
2602 sllx %g2, 3, %g2 ! offset (2 instrs)
2603 add %g3, %g2, %g3 ! %g3 = instruction entry
2604
2605 ldxa [%g0]ASI_SPARC_ERR_EN, %g2 ! save current in %g2
2606 andn %g2, CEEN, %g4 ! disable CEEN
2607 stxa %g4, [%g0] ASI_SPARC_ERR_EN ! ..
2608
2609 mov %o0, %g4 ! save %o0 in %g4
2610 rdpr %gl, %o0 ! save %gl in %o0
2611
2612 ! set gl to error global
2613 and %g1, SPARC_EAR_GL_MASK, %g1 ! get global set from EAR
2614 srlx %g1, SPARC_EAR_GL_SHIFT, %g1 ! %g1 has %gl value
2615
2616 jmp %g3 + SZ_INSTR ! jump to reread global
2617 wrpr %g1, %gl ! set gl to error gl
2618 SET_SIZE(irf_reread)
2619
2620
2621 /* clear_iregerr(sparc_ear) [LEAF Function]
2622 *
2623 * Clear CPU.iregerr if the IRU register in error == CPU.iregerr
2624 * Return 0 if CPU.iregerr matches, and 1 if no match
2625 * Arguments:
2626 * %g1 - SPARC EAR
2627 * %g2 - output - 0 if CPU.iregerr matches, 1 if no match
2628 * %g3, %g4 - scratch
2629 * %g5 - erpt pointer
2630 * %g6 - strand pointer
2631 * %g7 - return address
2632 */
2633 ENTRY_NP(clear_iregerr)
2634 ldx [%g6 + STRAND_REGERR], %g3 ! %g3 = STRAND.iregerr
2635
2636 ! compare the register number from EAR
2637 xor %g3, %g1, %g3 ! Are they the same?
2638 andcc %g3, SPARC_EAR_IREG_MASK, %g3 ! (ignore non-register bits)
2639 bz %xcc, .ireg_match ! yes, then clear
2640 nop
2641 mov 1, %g2 ! return 1 for no match
2642 HVRET
2643
2644 ! %g4 has CPU.iregerr address
2645 ! IRU was taken from IRC trap handler reread attempt
2646.ireg_match:
2647 stx %g0, [%g6 + STRAND_REGERR] ! clear STRAND.iregerr
2648 mov %g0, %g2 ! return 0 for ireg match
2649 HVRET
2650 SET_SIZE(clear_iregerr)
2651
2652
2653 /*
2654 * void clear_irf_ue(uint64_t sparc_ear)
2655 *
2656 * Clear the UE in the integer register file
2657 * Arguments:
2658 * %g1 - input - SPARC EAR
2659 * %g2-%g4 -scratch
2660 * %g5, %g6 - preserved
2661 * %g7 - return address
2662 */
2663 ENTRY_NP(clear_irf_ue)
2664 and %g1, SPARC_EAR_IREG_MASK, %g2
2665 srlx %g2, SPARC_EAR_IREG_SHIFT, %g2 ! %g2 has int reg num
2666 ! get the register number within the set
2667 and %g2, 0x1f, %g2 ! mask off GL/CWP
2668 cmp %g2, 8 ! is reg# < 8?
2669 bl .glob_ue ! yes, then global reg
2670 nop
2671
2672 ! Now clear the register in error
2673 ba 1f ! clear register
2674 rd %pc, %g3 ! get clear instr base addr
2675 ! an array of instruction blocks indexed by register number to
2676 ! clear the non-global register reported in error.
2677 mov %g0, %o0 ! clear %o0
2678 ba,a .clear_done
2679 mov %g0, %o1 ! clear %o1
2680 ba,a .clear_done
2681 mov %g0, %o2 ! clear %o2
2682 ba,a .clear_done
2683 mov %g0, %o3 ! clear %o3
2684 ba,a .clear_done
2685 mov %g0, %o4 ! clear %o4
2686 ba,a .clear_done
2687 mov %g0, %o5 ! clear %o5
2688 ba,a .clear_done
2689 mov %g0, %o6 ! clear %o6
2690 ba,a .clear_done
2691 mov %g0, %o7 ! clear %o7
2692 ba,a .clear_done
2693 mov %g0, %l0 ! clear %l0
2694 ba,a .clear_done
2695 mov %g0, %l1 ! clear %l1
2696 ba,a .clear_done
2697 mov %g0, %l2 ! clear %l2
2698 ba,a .clear_done
2699 mov %g0, %l3 ! clear %l3
2700 ba,a .clear_done
2701 mov %g0, %l4 ! clear %l4
2702 ba,a .clear_done
2703 mov %g0, %l5 ! clear %l5
2704 ba,a .clear_done
2705 mov %g0, %l6 ! clear %l6
2706 ba,a .clear_done
2707 mov %g0, %l7 ! clear %l7
2708 ba,a .clear_done
2709 mov %g0, %i0 ! clear %i0
2710 ba,a .clear_done
2711 mov %g0, %i1 ! clear %i1
2712 ba,a .clear_done
2713 mov %g0, %i2 ! clear %i2
2714 ba,a .clear_done
2715 mov %g0, %i3 ! clear %i3
2716 ba,a .clear_done
2717 mov %g0, %i4 ! clear %i4
2718 ba,a .clear_done
2719 mov %g0, %i5 ! clear %i5
2720 ba,a .clear_done
2721 mov %g0, %i6 ! clear %i6
2722 ba,a .clear_done
2723 mov %g0, %i7 ! clear %i7
2724 ba,a .clear_done
27251:
2726 sub %g2, 8, %g2 ! skip globals
2727 sllx %g2, 3, %g2 ! offset = reg# * 8
2728 add %g3, %g2, %g3 ! %g3 = instruction block addr
2729 jmp %g3 + SZ_INSTR ! jmp to clear register
2730 nop
2731
2732 ! restore gl from value in %o0, and restore %o0
2733.gl_clear_done:
2734 wrpr %o0, %gl ! restore %gl
2735 mov %g4, %o0 ! restore %o0
2736
2737 ! Here, we check the iregerr field after the reread. If it
2738 ! is zero, then we know it is a persistent uncorrectable error.
2739 ! If it is nonzero, then we know it is a transient error.
2740.clear_done:
2741 HVRET ! return to caller
2742
2743 ! %g2 has the gl + register number
2744.glob_ue:
2745 ! now re-read the global register in error
2746 ba 1f
2747 rd %pc, %g3 ! get clear instr base addr
2748 ! an array of instructions blocks indexed by global register number
2749 ! to clear the global register reported in error.
2750 ! %gl points to the error global set
2751 mov %g0, %g0 ! clear %g0 (yay!)
2752 ba,a .gl_clear_done
2753 mov %g0, %g1 ! clear %g1
2754 ba,a .gl_clear_done
2755 mov %g0, %g2 ! clear %g2
2756 ba,a .gl_clear_done
2757 mov %g0, %g3 ! clear %g3
2758 ba,a .gl_clear_done
2759 mov %g0, %g4 ! clear %g4
2760 ba,a .gl_clear_done
2761 mov %g0, %g5 ! clear %g5
2762 ba,a .gl_clear_done
2763 mov %g0, %g6 ! clear %g6
2764 ba,a .gl_clear_done
2765 mov %g0, %g7 ! clear %g7
2766 ba,a .gl_clear_done
27671:
2768 sllx %g2, 3, %g2 ! offset (2 instrs)
2769 add %g3, %g2, %g3 ! %g3 = instruction entry
2770 mov %o0, %g4 ! save %o0 in %g4
2771 rdpr %gl, %o0 ! save %gl in %o0
2772
2773 ! set gl to error global
2774 and %g1, SPARC_EAR_GL_MASK, %g2 ! get global set from EAR
2775 srlx %g2, SPARC_EAR_GL_SHIFT, %g2 ! %g2 has %gl value
2776
2777 jmp %g3 + SZ_INSTR ! jump to clear global
2778 wrpr %g2, %gl ! set gl to error gl
2779 SET_SIZE(clear_irf_ue)
2780
2781
2782 /*
2783 * frc_check(uint64_t sparc_ear) [Non-Leaf]
2784 *
2785 * Check whether the FRC error is transient or persistent.
2786 * Before we re-read the register in error, we set the frc_ear
2787 * in the CPU struct to the SPARC EAR value, which has the reg#
2788 * and the syndrome. A zero syndrome is not possible for error,
2789 * therefore frc_ear == 0 means FRC trap didn't set it.
2790 * (Note %g0 like other registers can generate errors.)
2791 * If the FRU trap is taken because of a persistent uncorrectable error,
2792 * the FRU trap handler will check the frc_ear field with the SPARC_EAR
2793 * logged. If they are the same, then FRU trap handler clears the
2794 * frc_ear field and returns.
2795 *
2796 * set_frcear(sparc_ear)
2797 * frf_reread(sparc_ear)
2798 * if (cpu.frc_ear == 0)
2799 * return RF_PERSISTENT;
2800 * else {
2801 * cpu.frc_ear = 0;
2802 * return RF_TRANSIENT;
2803 * }
2804 * Arguments:
2805 * %g1 - input - SPARC EAR - clobbered
2806 * %g2 - output (RF_TRANSIENT, RF_PERSISTENT)
2807 * %g3 - scratch
2808 * %g4 - scratch
2809 * %g5 - erpt pointer
2810 * %g6 - strand pointer
2811 */
2812 ENTRY_NP(frc_check)
2813
2814 ! init strand.frc_ear
2815 stx %g1, [%g6 + STRAND_REGERR] ! strand.frc_ear = sparc EAR (!=0)
2816
2817 /*
2818 * It is possible that FPRS.FEF was disabled when we took the
2819 * disrupting trap caused by the FP CE. We must ensure that FPRS.FEF
2820 * is enabled before calling frf_reread().
2821 *
2822 * Note that the Sparc V9 spec mandates that PSTATE.PEF be enabled
2823 * when we take a trap if there is an FPU present. As this error
2824 * condition can only occur with an FPU we do not need to verify
2825 * PSTATE.PEF here.
2826 */
2827 rd %fprs, %g5
2828 btst FPRS_FEF, %g5 ! FPRS.FEF set ?
2829 bz,a,pn %xcc, 1f ! no: set it
2830 wr %g5, FPRS_FEF, %fprs ! yes: annulled
28311:
2832 ! reread register
2833 mov %g7, %g6 ! save return address
2834 HVCALL(frf_reread) ! %g1 has SPARC EAR,
2835 ! %g5/%g6 preserved
2836 wr %g5, %g0, %fprs ! restore FPRS
2837 mov %g6, %g7 ! restore return address
2838
2839 STRAND_ERPT_STRUCT(STRAND_CE_RPT, %g6, %g5) ! g6->strand, g5->strand.ce_rpt
2840
2841 ! check strand.frc_ear
2842 ldx [%g6 + STRAND_REGERR], %g2 ! read strand.frc_ear
2843 brz %g2, .frc_ret ! persistent error
2844 mov RF_PERSISTENT, %g2
2845
2846 ! transient error. H/W has fixed it now after the reread
2847 ! get back to interrupted program
2848 stx %g0, [%g6 + STRAND_REGERR] ! clear frc_ear
2849 mov RF_TRANSIENT, %g2 ! return transient
2850.frc_ret:
2851 HVRET
2852 SET_SIZE(frc_check)
2853
2854
2855 /*
2856 * fru_check(uint64_t sparc_ear) [Non-Leaf]
2857 *
2858 * Check whether the FRU error is transient or persistent
2859 * or if the floating point register file is failing.
2860 * clear_frf_ue(sparc_ear);
2861 * frf_reread(sparc_ear);
2862 * if (SPARC_ESR.FRU == 0) {
2863 * return RF_TRANSIENT;
2864 * }
2865 * if (SPARC_EAR == sparc_ear)
2866 * return RF_PERSISTENT;
2867 * } else {
2868 * return RF_FAILURE;
2869 * }
2870 * Arguments:
2871 * %g1 - input - SPARC EAR - clobbered
2872 * %g2 - output (RF_TRANSIENT, RF_PERSISTENT, RF_FAILURE)
2873 * %g3 - scratch
2874 * %g4 - scratch
2875 * %g5 - erpt pointer
2876 * %g6 - strand pointer
2877 */
2878 ENTRY_NP(fru_check)
2879 mov %g7, %g6 ! save return address
2880
2881 HVCALL(clear_frf_ue) ! %g1 has SPARC EAR
2882
2883 ! reread register
2884 HVCALL(frf_reread) ! %g1 has SPARC EAR
2885
2886 mov %g6, %g7 ! restore return address
2887 STRAND_STRUCT(%g6) ! restore strand
2888
2889 ! check SPARC ESR for FRU error
2890 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! get SPARC ESR
2891 set SPARC_ESR_FRU, %g3 ! FRU bit
2892 btst %g3, %g4 ! check for FRU
2893 bz %xcc, .fru_ret ! no:
2894 mov RF_TRANSIENT, %g2 ! return transient
2895
2896 ! persistent FRU error?
2897 ! check EAR for match
2898 ldxa [%g0]ASI_SPARC_ERR_ADDR, %g2 ! get SPARC EAR
2899 ldx [%g5 + STRAND_VBSC_ERPT + EVBSC_SPARC_AFAR], %g1 ! saved EAR
2900 xor %g2, %g1, %g2 ! Are they the same?
2901 andcc %g2, SPARC_EAR_FPREG_MASK, %g2 ! (ignore non-register bits)
2902 bnz %xcc, .fru_ret ! no:
2903 mov RF_FAILURE, %g2 ! return reg file failure
2904 stxa %g4, [%g0]ASI_SPARC_ERR_STATUS ! yes: clear SPARC ESR
2905 mov RF_PERSISTENT, %g2 ! return persistent
2906.fru_ret:
2907 HVRET ! return to caller
2908 SET_SIZE(fru_check)
2909
2910
2911 /*
2912 * IRF Uncorrectible ECC Error
2913 *
2914 * if (clear_iregerr(sparc_ear) == MATCH from IRC) {
2915 * DONE;
2916 * } else {
2917 * if (iru_check(sparc_ear) == RF_PERSISTENT) {
2918 * CPU.status = mark CPU in ERROR;
2919 * if ((CPUnext = avail(partID)) != NULL) {
2920 * x_call(CPUnext, I_AM_IN_ERROR);
2921 * stop_self();
2922 * } else {
2923 * q_service_error_report(spi);
2924 * stop_self(); - watchdog reset later?
2925 * }
2926 * } else {
2927 * q_sun4v_error_report(nrq);
2928 * q_service_error_report(spi);
2929 * jmp nonresumable_error trap handler
2930 * }
2931 * }
2932 */
2933
2934
2935 /*
2936 * frf_reread(uint64_t sparc_ear) [LEAF function]
2937 *
2938 * Reread the FRF register in error.
2939 * Arguments:
2940 * %g1 - input - SPARC EAR
2941 * %g2 - %g4 - scratch
2942 * %g5, %g6 - preserved
2943 * %g7 - return address
2944 */
2945 ENTRY_NP(frf_reread)
2946 and %g1, SPARC_EAR_FPREG_MASK, %g2
2947 srlx %g2, SPARC_EAR_FPREG_SHIFT, %g2 ! %g2 has 6-bit fpreg number
2948
2949 ! Now reread the register in error
2950 ba 1f
2951 rd %pc, %g3 ! %g3 = base address
2952
2953 ! an array of instruction blocks indexed by register number to
2954 ! reread the floating-point register reported in error
2955 ! The first 32 entries use single-precision register
2956 ! The next 32 entries reread the double-precision register
2957 fmovs %f0, %f0 ! reread %f0
2958 ba,a .fp_reread_done
2959 fmovs %f1, %f1 ! reread %f1
2960 ba,a .fp_reread_done
2961 fmovs %f2, %f2 ! reread %f2
2962 ba,a .fp_reread_done
2963 fmovs %f3, %f3 ! reread %f3
2964 ba,a .fp_reread_done
2965 fmovs %f4, %f4 ! reread %f4
2966 ba,a .fp_reread_done
2967 fmovs %f5, %f5 ! reread %f5
2968 ba,a .fp_reread_done
2969 fmovs %f6, %f6 ! reread %f6
2970 ba,a .fp_reread_done
2971 fmovs %f7, %f7 ! reread %f7
2972 ba,a .fp_reread_done
2973 fmovs %f8, %f8 ! reread %f8
2974 ba,a .fp_reread_done
2975 fmovs %f9, %f9 ! reread %f9
2976 ba,a .fp_reread_done
2977 fmovs %f10, %f10 ! reread %f10
2978 ba,a .fp_reread_done
2979 fmovs %f11, %f11 ! reread %f11
2980 ba,a .fp_reread_done
2981 fmovs %f12, %f12 ! reread %f12
2982 ba,a .fp_reread_done
2983 fmovs %f13, %f13 ! reread %f13
2984 ba,a .fp_reread_done
2985 fmovs %f14, %f14 ! reread %f14
2986 ba,a .fp_reread_done
2987 fmovs %f15, %f15 ! reread %f15
2988 ba,a .fp_reread_done
2989 fmovs %f16, %f16 ! reread %f16
2990 ba,a .fp_reread_done
2991 fmovs %f17, %f17 ! reread %f17
2992 ba,a .fp_reread_done
2993 fmovs %f18, %f18 ! reread %f18
2994 ba,a .fp_reread_done
2995 fmovs %f19, %f19 ! reread %f19
2996 ba,a .fp_reread_done
2997 fmovs %f20, %f20 ! reread %f20
2998 ba,a .fp_reread_done
2999 fmovs %f21, %f21 ! reread %f21
3000 ba,a .fp_reread_done
3001 fmovs %f22, %f22 ! reread %f22
3002 ba,a .fp_reread_done
3003 fmovs %f23, %f23 ! reread %f23
3004 ba,a .fp_reread_done
3005 fmovs %f24, %f24 ! reread %f24
3006 ba,a .fp_reread_done
3007 fmovs %f25, %f25 ! reread %f25
3008 ba,a .fp_reread_done
3009 fmovs %f26, %f26 ! reread %f26
3010 ba,a .fp_reread_done
3011 fmovs %f27, %f27 ! reread %f27
3012 ba,a .fp_reread_done
3013 fmovs %f28, %f28 ! reread %f28
3014 ba,a .fp_reread_done
3015 fmovs %f29, %f29 ! reread %f29
3016 ba,a .fp_reread_done
3017 fmovs %f30, %f30 ! reread %f30
3018 ba,a .fp_reread_done
3019 fmovs %f30, %f31 ! reread %f31
3020 ba,a .fp_reread_done
3021 ! double precision register pairs, reread both of them on errors
3022 fmovd %f32, %f32 ! reread %f32
3023 ba,a .fp_reread_done
3024 fmovd %f32, %f32 ! reread %f32
3025 ba,a .fp_reread_done
3026 fmovd %f34, %f34 ! reread %f34
3027 ba,a .fp_reread_done
3028 fmovd %f34, %f34 ! reread %f34
3029 ba,a .fp_reread_done
3030 fmovd %f36, %f36 ! reread %f36
3031 ba,a .fp_reread_done
3032 fmovd %f36, %f36 ! reread %f36
3033 ba,a .fp_reread_done
3034 fmovd %f38, %f38 ! reread %f38
3035 ba,a .fp_reread_done
3036 fmovd %f38, %f38 ! reread %f38
3037 ba,a .fp_reread_done
3038 fmovd %f40, %f40 ! reread %f40
3039 ba,a .fp_reread_done
3040 fmovd %f40, %f40 ! reread %f40
3041 ba,a .fp_reread_done
3042 fmovd %f42, %f42 ! reread %f42
3043 ba,a .fp_reread_done
3044 fmovd %f42, %f42 ! reread %f42
3045 ba,a .fp_reread_done
3046 fmovd %f44, %f44 ! reread %f44
3047 ba,a .fp_reread_done
3048 fmovd %f44, %f44 ! reread %f44
3049 ba,a .fp_reread_done
3050 fmovd %f46, %f46 ! reread %f46
3051 ba,a .fp_reread_done
3052 fmovd %f46, %f46 ! reread %f46
3053 ba,a .fp_reread_done
3054 fmovd %f48, %f48 ! reread %f48
3055 ba,a .fp_reread_done
3056 fmovd %f48, %f48 ! reread %f48
3057 ba,a .fp_reread_done
3058 fmovd %f50, %f50 ! reread %f50
3059 ba,a .fp_reread_done
3060 fmovd %f50, %f50 ! reread %f50
3061 ba,a .fp_reread_done
3062 fmovd %f52, %f52 ! reread %f52
3063 ba,a .fp_reread_done
3064 fmovd %f52, %f52 ! reread %f52
3065 ba,a .fp_reread_done
3066 fmovd %f54, %f54 ! reread %f54
3067 ba,a .fp_reread_done
3068 fmovd %f54, %f54 ! reread %f54
3069 ba,a .fp_reread_done
3070 fmovd %f56, %f56 ! reread %f56
3071 ba,a .fp_reread_done
3072 fmovd %f56, %f56 ! reread %f56
3073 ba,a .fp_reread_done
3074 fmovd %f58, %f58 ! reread %f58
3075 ba,a .fp_reread_done
3076 fmovd %f58, %f58 ! reread %f58
3077 ba,a .fp_reread_done
3078 fmovd %f60, %f60 ! reread %f60
3079 ba,a .fp_reread_done
3080 fmovd %f60, %f60 ! reread %f60
3081 ba,a .fp_reread_done
3082 fmovd %f62, %f62 ! reread %f62
3083 ba,a .fp_reread_done
3084 fmovd %f62, %f62 ! reread %f62
3085 ba,a .fp_reread_done
30861:
3087 ! %g2 has freg number, %g3 has base address-4
3088 sllx %g2, 3, %g2 ! offset = freg# * 8
3089 add %g3, %g2, %g3 ! %g3 = instruction block addr
3090
3091 ldxa [%g0]ASI_SPARC_ERR_EN, %g2 ! save current in %g2
3092 andn %g2, CEEN, %g4 ! disable CEEN
3093 stxa %g4, [%g0] ASI_SPARC_ERR_EN ! ..
3094
3095 jmp %g3 + SZ_INSTR ! jmp to reread register
3096 nop
3097
3098.fp_reread_done:
3099 stxa %g2, [%g0] ASI_SPARC_ERR_EN ! restore CEEN
3100 HVRET ! return to caller
3101 SET_SIZE(frf_reread)
3102
3103
3104 /*
3105 * clear_fregerr(sparc_ear) [LEAF Function]
3106 *
3107 * Clear cpu.fregerr if the FRU register in error == cpu.fregerr
3108 * Return 0 if cpu.fregerr matches, and 1 if no match
3109 * Arguments:
3110 * %g1 - SPARC EAR
3111 * %g2 - output - 0 if cpu.fregerr matches, 1 if no match
3112 * %g3, %g4 - scratch
3113 * %g5 - erpt pointer
3114 * %g6 - strand pointer
3115 * %g7 - return address
3116 */
3117 ENTRY_NP(clear_fregerr)
3118 ldx [%g6 + STRAND_REGERR], %g3 ! %g3 = strand.fregerr
3119
3120 ! get register number from EAR
3121 xor %g3, %g1, %g3 ! Are they the same?
3122 andcc %g3, SPARC_EAR_FPREG_MASK, %g3 ! (ignore non-register bits)
3123 bz %xcc, .freg_match ! yes, then clear
3124 nop
3125 mov 1, %g2 ! return 1 for no match
3126 HVRET
3127
3128 ! %g4 has cpu.fregerr address
3129 ! FRU was taken from FRC trap handler reread attempt
3130.freg_match:
3131 stx %g0, [%g6 + STRAND_REGERR] ! clear strand.fregerr
3132 mov %g0, %g2 ! return 0 for freg match
3133 HVRET
3134 SET_SIZE(clear_fregerr)
3135
3136
3137 /*
3138 * clear_frf_ue(uint64_t sparc_ear) [LEAF function]
3139 *
3140 * Clear the UE in the floating-point register file
3141 * Arguments:
3142 * %g1 - SPARC EAR
3143 * %g2 - %g4 - scratch
3144 * %g5, %g6 - preserverd
3145 * %g7 - return address
3146 */
3147 ENTRY_NP(clear_frf_ue)
3148 and %g1, SPARC_EAR_FPREG_MASK, %g2
3149 srlx %g2, SPARC_EAR_FPREG_SHIFT, %g2 ! %g2 has 6-bit fpreg number
3150
3151 ! Now clear the register in error
3152 ba 1f
3153 rd %pc, %g3 ! %g3 = base address
3154
3155 ! an array of instruction blocks indexed by register number to
3156 ! clear the floating-point register reported in error
3157 ! The first 32 entries use single-precision register
3158 ! The next 32 entries clear the double-precision register
3159 fzeros %f0 ! clear %f0
3160 ba,a .fp_clear_done
3161 fzeros %f1 ! clear %f1
3162 ba,a .fp_clear_done
3163 fzeros %f2 ! clear %f2
3164 ba,a .fp_clear_done
3165 fzeros %f3 ! clear %f3
3166 ba,a .fp_clear_done
3167 fzeros %f4 ! clear %f4
3168 ba,a .fp_clear_done
3169 fzeros %f5 ! clear %f5
3170 ba,a .fp_clear_done
3171 fzeros %f6 ! clear %f6
3172 ba,a .fp_clear_done
3173 fzeros %f7 ! clear %f7
3174 ba,a .fp_clear_done
3175 fzeros %f8 ! clear %f8
3176 ba,a .fp_clear_done
3177 fzeros %f9 ! clear %f9
3178 ba,a .fp_clear_done
3179 fzeros %f10 ! clear %f10
3180 ba,a .fp_clear_done
3181 fzeros %f11 ! clear %f11
3182 ba,a .fp_clear_done
3183 fzeros %f12 ! clear %f12
3184 ba,a .fp_clear_done
3185 fzeros %f13 ! clear %f13
3186 ba,a .fp_clear_done
3187 fzeros %f14 ! clear %f14
3188 ba,a .fp_clear_done
3189 fzeros %f15 ! clear %f15
3190 ba,a .fp_clear_done
3191 fzeros %f16 ! clear %f16
3192 ba,a .fp_clear_done
3193 fzeros %f17 ! clear %f17
3194 ba,a .fp_clear_done
3195 fzeros %f18 ! clear %f18
3196 ba,a .fp_clear_done
3197 fzeros %f19 ! clear %f19
3198 ba,a .fp_clear_done
3199 fzeros %f20 ! clear %f20
3200 ba,a .fp_clear_done
3201 fzeros %f21 ! clear %f21
3202 ba,a .fp_clear_done
3203 fzeros %f22 ! clear %f22
3204 ba,a .fp_clear_done
3205 fzeros %f23 ! clear %f23
3206 ba,a .fp_clear_done
3207 fzeros %f24 ! clear %f24
3208 ba,a .fp_clear_done
3209 fzeros %f25 ! clear %f25
3210 ba,a .fp_clear_done
3211 fzeros %f26 ! clear %f26
3212 ba,a .fp_clear_done
3213 fzeros %f27 ! clear %f27
3214 ba,a .fp_clear_done
3215 fzeros %f28 ! clear %f28
3216 ba,a .fp_clear_done
3217 fzeros %f29 ! clear %f29
3218 ba,a .fp_clear_done
3219 fzeros %f30 ! clear %f30
3220 ba,a .fp_clear_done
3221 fzeros %f31 ! clear %f31
3222 ba,a .fp_clear_done
3223 ! double precision register pairs, clear both of them on errors
3224 fzero %f32 ! clear %f32
3225 ba,a .fp_clear_done
3226 fzero %f32 ! clear %f32
3227 ba,a .fp_clear_done
3228 fzero %f34 ! clear %f34
3229 ba,a .fp_clear_done
3230 fzero %f34 ! clear %f34
3231 ba,a .fp_clear_done
3232 fzero %f36 ! clear %f36
3233 ba,a .fp_clear_done
3234 fzero %f36 ! clear %f36
3235 ba,a .fp_clear_done
3236 fzero %f38 ! clear %f38
3237 ba,a .fp_clear_done
3238 fzero %f38 ! clear %f38
3239 ba,a .fp_clear_done
3240 fzero %f40 ! clear %f40
3241 ba,a .fp_clear_done
3242 fzero %f40 ! clear %f40
3243 ba,a .fp_clear_done
3244 fzero %f42 ! clear %f42
3245 ba,a .fp_clear_done
3246 fzero %f42 ! clear %f42
3247 ba,a .fp_clear_done
3248 fzero %f44 ! clear %f44
3249 ba,a .fp_clear_done
3250 fzero %f44 ! clear %f44
3251 ba,a .fp_clear_done
3252 fzero %f46 ! clear %f46
3253 ba,a .fp_clear_done
3254 fzero %f46 ! clear %f46
3255 ba,a .fp_clear_done
3256 fzero %f48 ! clear %f48
3257 ba,a .fp_clear_done
3258 fzero %f48 ! clear %f48
3259 ba,a .fp_clear_done
3260 fzero %f50 ! clear %f50
3261 ba,a .fp_clear_done
3262 fzero %f50 ! clear %f50
3263 ba,a .fp_clear_done
3264 fzero %f52 ! clear %f52
3265 ba,a .fp_clear_done
3266 fzero %f52 ! clear %f52
3267 ba,a .fp_clear_done
3268 fzero %f54 ! clear %f54
3269 ba,a .fp_clear_done
3270 fzero %f54 ! clear %f54
3271 ba,a .fp_clear_done
3272 fzero %f56 ! clear %f56
3273 ba,a .fp_clear_done
3274 fzero %f56 ! clear %f56
3275 ba,a .fp_clear_done
3276 fzero %f58 ! clear %f58
3277 ba,a .fp_clear_done
3278 fzero %f58 ! clear %f58
3279 ba,a .fp_clear_done
3280 fzero %f60 ! clear %f60
3281 ba,a .fp_clear_done
3282 fzero %f60 ! clear %f60
3283 ba,a .fp_clear_done
3284 fzero %f62 ! clear %f62
3285 ba,a .fp_clear_done
3286 fzero %f62 ! clear %f62
3287 ba,a .fp_clear_done
32881:
3289 ! %g2 has freg number, %g3 has base address-4
3290 sllx %g2, 3, %g2 ! offset = freg# * 8
3291 add %g3, %g2, %g3 ! %g3 = instruction block addr
3292 jmp %g3 + SZ_INSTR ! jmp to clear register
3293 nop
3294
3295.fp_clear_done:
3296 HVRET ! return to caller
3297 SET_SIZE(clear_frf_ue)
3298
3299
3300 /*
3301 * FRC Uncorrectible ECC Error
3302 *
3303 * FRU Error Handler: Check for persistent error
3304 * if (fru_check(sparc_ear) == RF_TRANSIENT) {
3305 * q_sun4v_error_report(nrq);
3306 * q_service_error_report(spi);
3307 * jmp nonresumable_error trap handler;
3308 * } else {
3309 * CPU.status = mark CPU in ERROR;
3310 * if ((CPUnext = avail(partID)) != NULL) {
3311 * x_call(CPUnext, I_AM_IN_ERROR);
3312 * stop_self();
3313 * } else {
3314 * q_service_error_report(spi);
3315 * stop_self(); causes watchdog reset later?
3316 * }
3317 * }
3318 */
3319
3320
3321 /*
3322 * Handler to set bit(s) in the SPARC Error Enable Register
3323 *
3324 * Called to get handler callback address (avoid relocation problems)
3325 *
3326 * Entry Data:
3327 * none
3328 *
3329 * Return Data:
3330 * %g2: handler address
3331 *
3332 * Registers modified:
3333 * %g2
3334 */
3335 ENTRY_NP(err_set_sparc_bits)
3336 RETURN_HANDLER_ADDRESS(%g2) ! in %g2
3337
3338 /*
3339 * Callback from interrupt:
3340 *
3341 * This will re-enable the Sparc interrupts.
3342 * Process in this order:
3343 * - clear any Sparc CE's
3344 * - clear blackout
3345 * - enable Sparc EEN
3346 *
3347 * Entry Data:
3348 * %g1: bit(s) to set
3349 * %g2: <scratch>
3350 *
3351 * Return Data:
3352 * none
3353 *
3354 * Registers modified:
3355 * %g1-6
3356 */
3357.err_set_sparc_bits: /* This is the actual function entry */
3358 mov %g1, %g5 ! bits
3359 !! %g5 = bits to set
3360
3361 set SPARC_CE_BITS, %g1
3362 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g3 ! SPARC afsr
3363 btst %g1, %g3 ! is a CE pending?
3364 bz .err_set_sparc_1 ! no:
3365 set SPARC_ESR_PRIV, %g2
3366 or %g1, %g2, %g1 ! yes: include PRIV
3367 and %g3, %g1, %g3 ! just the CE bits
3368 stxa %g3, [%g0]ASI_SPARC_ERR_STATUS ! clear SPARC CE afsr bits
3369.err_set_sparc_1:
3370 STRAND_STRUCT(%g3)
3371 lduw [%g3 + STRAND_ERR_FLAG], %g1 ! installed flags
3372 bclr ERR_FLAG_SPARC, %g1 ! reset SPARC ESR
3373 stw %g1, [%g3 + STRAND_ERR_FLAG] ! ..
3374
3375 ldxa [%g0]ASI_SPARC_ERR_EN, %g3 ! get current
3376 or %g3, %g5, %g3 ! set bit(s)
3377 stxa %g3, [%g0]ASI_SPARC_ERR_EN ! store back
3378
3379
3380 HVRET
3381 SET_SIZE(err_set_sparc_bits)
3382
3383
3384 /*
3385 * Handler to set bit(s) in the L2 Error Enable Register
3386 *
3387 * This will re-enable the L2/DRAM interrupts.
3388 * Process in this order:
3389 * - clear any DRAM CE's
3390 * - clear any L2 CE's
3391 * - clear blackout
3392 * - enable L2DRAM EEN
3393 *
3394 * Called to get handler callback address (avoid relocation problems)
3395 *
3396 * Entry Data:
3397 * none
3398 *
3399 * Return Data:
3400 * %g2: handler address
3401 *
3402 * Registers modified:
3403 * %g2
3404 */
3405 ENTRY_NP(err_set_l2_bits)
3406 RETURN_HANDLER_ADDRESS(%g2) ! in %g2
3407
3408 /*
3409 * Callback from interrupt:
3410 *
3411 * Entry Data:
3412 * %g1: bit(s) to set
3413 * %g2: B:5-0 = bank #
3414 *
3415 * Return Data:
3416 * none
3417 *
3418 * Registers modified:
3419 * %g1-6
3420 */
3421.err_set_l2_bits: /* This is the actual function entry */
3422 mov %g1, %g5 ! bits
3423 and %g2, NO_L2_BANKS - 1, %g6 ! bank #
3424 !! %g5 = bits to set
3425 !! %g6 = bank#
3426 setx DRAM_ESR_CE_BITS | DRAM_ESR_MEC, %g1, %g2
3427 setx DRAM_ESR_BASE, %g1, %g3 ! DRAM base
3428 sllx %g6, DRAM_BANK_SHIFT, %g4 ! + bank offset
3429 ldx [%g3 + %g4], %g1 ! get ESR[bank]
3430 and %g1, %g2, %g1 ! reset CE bits only
3431 stx %g1, [%g3 + %g4]
3432
3433 setx L2_ESR_CE_BITS | L2_ESR_VEC, %g1, %g2
3434 setx L2_ESR_BASE, %g1, %g3 ! L2 base
3435 sll %g6, L2_BANK_SHIFT, %g4 ! + bank offset
3436 ldx [%g3 + %g4], %g1 ! get ESR[bank]
3437 and %g1, %g2, %g1 ! reset CE bits only
3438 stx %g1, [%g3 + %g4]
3439
3440 STRAND_STRUCT(%g3)
3441 mov ERR_FLAG_L2DRAM, %g1 ! L2DRAM flag
3442 sll %g1, %g6, %g1 ! << bank#
3443 lduw [%g3 + STRAND_ERR_FLAG], %g2 ! installed flags
3444 bclr %g1, %g2 ! reset L2DRAM[bank]
3445 stw %g2, [%g3 + STRAND_ERR_FLAG] ! ..
3446 !! %g1 = bits
3447 !! %g6 = bank#
3448 BSET_L2_BANK_EEN(%g6, %g5, %g2, %g3) ! L2 Bank EEN[%g6] |= %g5
3449
3450 HVRET
3451 SET_SIZE(err_set_l2_bits)
3452
3453
3454 /*
3455 * Poll to detect errors that did not cause an interrupt for one
3456 * reason or another.
3457 * Most common cause: L2/DRAM error from prefetch.
3458 *
3459 * Called to get handler callback address (avoid relocation problems)
3460 *
3461 * Entry Data:
3462 * none
3463 *
3464 * Return Data:
3465 * %g2: handler address
3466 *
3467 * Registers modified:
3468 * %g2
3469 */
3470 ENTRY_NP(err_poll_daemon)
3471 RETURN_HANDLER_ADDRESS(%g2) ! in %g2
3472
3473 /*
3474 * Callback from interrupt:
3475 *
3476 * Entry Data:
3477 * %g1: 0
3478 * %g2: 0
3479 * %g3: Interrupt Tick Time
3480 *
3481 * Return Data:
3482 * none
3483 *
3484 * Registers modified:
3485 * %g1-6
3486 */
3487.err_poll_daemon:
3488 /*
3489 * Get strand, CE buffer in %g6-5, they are safe across calls
3490 */
3491
3492 STRAND_STRUCT(%g6)
3493
3494 stx %g3, [%g6 + STRAND_ERR_POLL_ITT] ! save interrupt tick time
3495 stx %g7, [%g6 + STRAND_ERR_POLL_RET] ! save return address
3496
3497 /*
3498 * Look for Sparc errors: test only,
3499 * the error handler will do the work
3500 */
3501.err_poll_sparc:
3502 ldxa [%g0]ASI_SPARC_ERR_STATUS, %g4 ! SPARC afsr
3503 !
3504 ! Check for any UE:
3505 !
3506 UE_CHECK(SPARC_UE_MEU_BITS, L2_ESR_UE_BITS, %g4, %g1, %g2, %g3)
3507 bz %xcc, .err_poll_no_ue ! no
3508 nop
3509 HVCALL(ue_poll_entry) ! yes: go process
3510
3511 ba,a .err_poll_sparc ! and re-check Sparc status
3512.err_poll_no_ue:
3513
3514 !
3515 ! Check for any CE:
3516 !
3517 CE_CHECK(%g6, %g4, %g1, %g2, %g3) ! cpup, spesr,
3518 bz %xcc, .err_poll_no_ce ! no
3519 nop
3520 HVCALL(ce_poll_entry) ! yes
3521
3522 ba,a .err_poll_sparc ! go re-check Sparc status
3523.err_poll_no_ce:
3524
3525 /*
3526 * reinstall poll handler
3527 */
3528 STRAND2CONFIG_STRUCT(%g6, %g1) ! ->config
3529 ldx [%g1 + CONFIG_CE_POLL_TIME], %g1 ! g1 = time interval
3530 brz %g1, 9f ! disabled: branch
3531 nop
3532 ldx [%g6 + STRAND_ERR_POLL_ITT], %g2 ! this interrupt tick time
3533 add %g1, %g2, %g1 ! abs time for next poll
3534
3535 HVCALL(err_poll_daemon) ! g2 = handler address
3536 clr %g3 ! g3 = arg 0 : n/a
3537 clr %g4 ! g4 = arg 1 : n/a
3538 HVCALL(cyclic_add_abs) /* ( abs_tick, address, arg0, arg1 ) */
35399:
3540
3541 STRAND_STRUCT(%g6)
3542 ldx [%g6 + STRAND_ERR_POLL_RET], %g7 ! restore return address
3543 HVRET
3544 SET_SIZE(err_poll_daemon)
3545
3546 /*
3547 * Function to start error polling daemon:
3548 *
3549 * Entry Data:
3550 * none
3551 *
3552 * Return Data:
3553 * %g1: status
3554 * 0 - success (started)
3555 * 1 - failed (already running)
3556 * 2 - failed to start
3557 *
3558 * Registers modified:
3559 * %g1-6
3560 */
3561 ENTRY_NP(err_poll_daemon_start)
3562 STRAND_STRUCT(%g6)
3563
3564 stx %g7, [%g6 + STRAND_ERR_POLL_RET] ! save return address
3565
3566 lduw [%g6 + STRAND_ERR_FLAG], %g2
3567 btst ERR_FLAG_POLLD, %g2 ! handler flags
3568 bnz,a %xcc, 9f ! poll deamon installed?
3569 mov 1, %g1 ! yes: return "running"
3570 bset ERR_FLAG_POLLD, %g2 ! set it
3571 stw %g2, [%g6 + STRAND_ERR_FLAG] ! store
3572
3573 /*
3574 * Install the callback handler: just start at now + ce_poll_time
3575 */
3576 STRAND2CONFIG_STRUCT(%g6, %g1) ! ->config
3577 ldx [%g1 + CONFIG_CE_POLL_TIME], %g1 ! g1 = cycle time in ticks
3578 HVCALL(err_poll_daemon) ! g2 = handler address
3579 clr %g3 ! g3 = arg 0 : error bits
3580 clr %g4 ! g3 = arg 1 :
3581 HVCALL(cyclic_add_rel) /* ( del_tick, address, arg0, arg1 ) */
3582
3583 STRAND_STRUCT(%g6)
3584 ldx [%g6 + STRAND_ERR_POLL_RET], %g7 ! restore return address
3585 clr %g1 ! status = success
35869:
3587 HVRET ! %g1 = status
3588 SET_SIZE(err_poll_daemon_start)
3589
3590
3591#if EVBSC_L2_AFSR_INCR == 8
3592#define EVBSC_L2_AFSR_SHIFT 3
3593#else
3594#error "EVBSC_L2_AFSR_INCR is not 8"
3595#endif
3596#if EVBSC_L2_AFAR_INCR == 8
3597#define EVBSC_L2_AFAR_SHIFT 3
3598#else
3599#error "EVBSC_L2_AFAR_INCR is not 8"
3600#endif
3601 /*
3602 * This function determines if an error is transient, sticky or
3603 * permanent. We only check disposition on Memory CE's. Hence,
3604 * we only work the L2 error registers.
3605 * The algorithm to classify the error is as follows:
3606 * 1) Displacement flush the E$ line corresponding to %addr.
3607 * The first ldxa guarantees that the %addr is no longer in
3608 * M, O, or E (goes to I or S (if instruction fetch also
3609 * happens).
3610 * 2) "Write" the data using a ldx %addrm %scr CAS %addr,%scr,%scr.
3611 * The casxa guarantees a transition from I to M or S to M.
3612 * There are two possibilities that the sequence does not act
3613 * as intended:
3614 * - the line is displaced between the ld and the cas:
3615 * we still have the correct value in %scr and the cas will
3616 * reload the line - this is OK since the ld was to get the
3617 * value, no to get the line in the cache.
3618 * - the line is written between the ld and the cas:
3619 * the intent to modify the line has effectively succeeded
3620 * 3) Displacement flush the E$ line corresponding to %addr.
3621 * The second ldxa pushes the M line out of the ecache,
3622 * into the writeback buffers, on the way to memory.
3623 * 4) The "membar #Sync" pushes the cache line out of
3624 * the writeback buffers onto the bus, on the way to
3625 * dram finally.
3626 * %g1 - bank number
3627 *
3628 * XXX - Need to handle race with HW scrubber
3629 */
3630 ENTRY_NP(err_determine_disposition)
3631 CPU_PUSH(%g7, %g4, %g5, %g6) ! save return address
3632
3633 ! Read and save the current enable
3634 mov %g1, %g6 ! bank #
3635 GET_L2_BANK_EEN(%g6, %g5, %g4)
3636 CPU_PUSH(%g5, %g3, %g4, %g2) ! save for later
3637
3638 ! disable CEEN
3639 BCLR_L2_BANK_EEN(%g6, CEEN, %g4, %g3)
3640
3641 ! get err address into %g1
3642 STRAND_STRUCT(%g1)
3643 add %g1, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g1
3644 sllx %g6, EVBSC_L2_AFAR_SHIFT, %g4
3645 add %g4, EVBSC_L2_AFAR, %g2
3646 ldx [%g1 + %g2], %g1
3647 ! Mask AFAR to get only valid bits
3648 and %g1, ~L2_EAR_DRAM_MASK, %g1
3649
3650 ! l2_flush_line garbles %g6. Save %g6 which
3651 ! contains the BNUM
3652 CPU_PUSH(%g6, %g3, %g4, %g2) ! save for later
3653
3654 /*
3655 * displace and cause a write back
3656 * Niagara works differently than previous generations.
3657 * On previous generations, a cas will mark the line dirty,
3658 * regardless of the success of the compare.
3659 * In Niagara, the line only gets mark dirty if the swap occurs.
3660 * Hence, we need to first load the value and store it back via the cas
3661 */
3662 HVCALL(l2_flush_line)
3663 ldx [%g1], %g6
3664 casx [%g1], %g6, %g6
3665 HVCALL(l2_flush_line)
3666
3667 ! push cache line out of the write back buffers
3668 membar #Sync
3669
3670 CPU_POP(%g6, %g2, %g3, %g4)
3671
3672 /*
3673 * Read the errs registers again and compare them with our saved
3674 * version. If they are the same, then error is persistent
3675 */
3676
3677 ! read err regs
3678 setx L2_ESR_DRAM_CE_BITS, %g3, %g2
3679 setx L2_ESR_BASE, %g3, %g5 ! L2 base
3680 sll %g6, L2_BANK_SHIFT, %g4 ! + bank offset
3681 ldx [%g5 + %g4], %g5 ! get ESR[bank]
3682 and %g5, %g2, %g5 ! compare only CEs
3683
3684 ! get our copy
3685 STRAND_STRUCT(%g3)
3686 add %g3, STRAND_CE_RPT + STRAND_VBSC_ERPT, %g3
3687 sllx %g6, EVBSC_L2_AFSR_SHIFT, %g4
3688 add %g4, EVBSC_L2_AFSR, %g4
3689 ldx [%g3 + %g4], %g4 ! orig AFSR
3690 and %g4, %g2, %g4 ! only CEs
3691
3692 ! clear the disposition to have none
3693 mov CE_XDIAG_NONE, %g2
3694 stx %g2, [%g3 + EVBSC_DIAG_BUF + DRAM_DISPOSITION]
3695
3696 ! compare with stored
3697 cmp %g4, %g5
3698 bne,pt %xcc, 2f
3699 nop
3700
3701 ! now check afar and see if same.
3702 ! %g1 still contains the stored afar
3703
3704 setx L2_EAR_BASE, %g4, %g5 ! L2 base
3705 sll %g6, L2_BANK_SHIFT, %g4 ! + bank offset
3706 ldx [%g5 + %g4], %g4
3707 ! mask only valid bits
3708 and %g4, ~L2_EAR_DRAM_MASK, %g4
3709
3710 cmp %g1, %g4
3711 bne,pt %xcc, 2f
3712 mov CE_XDIAG_CE1, %g4
3713
3714 ! set ce1 if match
3715 stx %g4, [%g3 + EVBSC_DIAG_BUF + DRAM_DISPOSITION]
3716
3717 ! clear the error reg
3718 sllx %g6, EVBSC_L2_AFSR_SHIFT, %g4
3719 add %g4, EVBSC_L2_AFSR, %g4
3720 ldx [%g3 + %g4], %g4 ! orig AFSR
3721
3722 setx L2_ESR_BASE, %g2, %g5 ! L2 base
3723 sll %g6, L2_BANK_SHIFT, %g2 ! + bank offset
3724 stx %g4, [%g5 + %g2] ! clear ESR[bank]
3725
3726 /*
3727 * Read data again. data should now come from memory. We check
3728 * for errors. If the saved version and new errs registers are the
3729 * same then it is a stuck bit
3730 * %g1 still contains our stored afar
3731 */
37322:
3733 ldx [%g1], %g2
3734
3735 ! read regs
3736 setx L2_ESR_DRAM_CE_BITS, %g5, %g2
3737 setx L2_ESR_BASE, %g4, %g5 ! L2 base
3738 sll %g6, L2_BANK_SHIFT, %g4 ! + bank offset
3739 ldx [%g5 + %g4], %g5 ! get ESR[bank]
3740 and %g5, %g2, %g5 ! compare only CEs
3741
3742 ! stored value
3743 sllx %g6, EVBSC_L2_AFSR_SHIFT, %g4
3744 add %g4, EVBSC_L2_AFSR, %g4
3745 ldx [%g3 + %g4], %g4 ! orig AFSR
3746 and %g4, %g2, %g4 ! only CEs
3747
3748 ! compare with stored
3749 cmp %g4, %g5
3750 bne,pt %xcc, 1f
3751 nop
3752
3753 ! now check afar and see if same.
3754 ! %g1 still contains the stored afar
3755
3756 setx L2_EAR_BASE, %g4, %g5 ! L2 base
3757 sll %g6, L2_BANK_SHIFT, %g4 ! + bank offset
3758 ldx [%g5 + %g4], %g4
3759 ! mask only valid bits
3760 and %g4, ~L2_EAR_DRAM_MASK, %g4
3761
3762 cmp %g1, %g4
3763 bne,pt %xcc, 1f
3764 mov CE_XDIAG_CE2, %g5
3765
3766 ! set ce2 if match
3767 ldx [%g3 + EVBSC_DIAG_BUF + DRAM_DISPOSITION], %g2
3768 or %g5, %g2, %g2
3769 stx %g2, [%g3 + EVBSC_DIAG_BUF + DRAM_DISPOSITION]
3770
37711:
3772 ! restore orig ce
3773 CPU_POP(%g5, %g2, %g3, %g4)
3774 SET_L2_EEN_BASE(%g2)
3775 sllx %g6, L2_BANK_SHIFT, %g3 ! bank offset
3776 add %g2, %g3, %g2 ! bank address
3777 stx %g5, [%g2] ! restore value
3778
3779 CPU_POP(%g7, %g1, %g2, %g3)
3780 HVRET
3781
3782 SET_SIZE(err_determine_disposition)
3783
3784
3785 /*
3786 * Handle strand in error
3787 * All other strands are idle
3788 * This strand:
3789 * - search for another "good" strand
3790 * - flag as halted (bit mask)
3791 * - Remove cyclic (Error Daemon)
3792 * - handoff interrupt steering
3793 * - Migrate all intrs
3794 * - notify good strand to finish rest of work
3795 * - put myself into idle
3796 * Selected Good strand:
3797 * - send resumable error to guest
3798 * %g6 should not be clobbered
3799 */
3800
3801 ENTRY_NP(strand_in_error)
3802
3803 ! Remove this cpu from the active bitmask and add it to halted
3804 STRAND_STRUCT(%g5)
3805 ldub [%g5 + STRAND_ID], %g5
3806 mov 1, %g4
3807 sllx %g4, %g5, %g4
3808
3809 !! %g5 - strand id
3810 ROOT_STRUCT(%g2) ! config ptr
3811
3812 ! clear this strand from the active list
3813 ldx [%g2 + CONFIG_STACTIVE], %g3
3814 bclr %g4, %g3
3815 stx %g3, [%g2 + CONFIG_STACTIVE]
3816
3817 ! set this cpu in the halted list
3818 ldx [%g2 + CONFIG_STHALT], %g3
3819 bset %g4, %g3
3820 stx %g3, [%g2 + CONFIG_STHALT]
3821
3822 ! find another idle strand for re-targetting
3823 ldx [%g2 + CONFIG_STIDLE], %g3
3824 mov 0, %g6
3825.find_strand:
3826 cmp %g5, %g6
3827 be,pn %xcc, .next_strand
3828 mov 1, %g4
3829 sllx %g4, %g6, %g4
3830 andcc %g3, %g4, %g0
3831 bnz,a %xcc, .found_a_strand
3832 nop
3833
3834.next_strand:
3835 inc %g6
3836 cmp %g6, NSTRANDS
3837 bne,pn %xcc, .find_strand
3838 nop
3839
3840 /*
3841 * No usable active strands are left in the
3842 * system, force host exit
3843 */
3844#ifdef CONFIG_VBSC_SVC
3845 ba,a vbsc_guest_exit
3846#else
3847 LEGION_EXIT(%o0)
3848#endif
3849
3850.found_a_strand:
3851 /*
3852 * handoff L2 Steering CPU
3853 * If we are the steering cpu, migrate it to our chosen one
3854 */
3855
3856 !! %g5 - this strand ID
3857 !! %g6 - target strand ID
3858 setx L2_CONTROL_REG, %g3, %g4
3859 ldx [%g4], %g2 ! current setting
3860 srlx %g2, L2_ERRORSTEER_SHIFT, %g3
3861 and %g3, (NSTRANDS - 1), %g3
3862 cmp %g3, %g5 ! is this steering strand ?
3863 bnz,pt %xcc, 1f
3864 nop
3865
3866 ! It is the L2 Steering strand. Migrate responsibility to tgt strand
3867 sllx %g3, L2_ERRORSTEER_SHIFT, %g3
3868 andn %g3, %g2, %g2 ! remove this strand
3869 sllx %g6, L2_ERRORSTEER_SHIFT, %g3
3870 or %g2, %g3, %g2
3871 stx %g2, [%g4]
38721:
3873 mov %g5, %g1
3874 mov %g6, %g2
3875
3876 !! %g1 - this strand ID
3877 !! %g2 - target strand ID
3878#ifdef CONFIG_FPGA
3879 /*
3880 * Migrate SSI intrs
3881 */
3882 STRAND_PUSH(%g1, %g3, %g4)
3883 STRAND_PUSH(%g2, %g3, %g4)
3884 HVCALL(ssi_intr_redistribution)
3885 STRAND_POP(%g2, %g3)
3886 STRAND_POP(%g1, %g3)
3887#endif
3888
3889#if 0 /* XXX */
3890 /*
3891 * XXX err_poll_daemon (collapse into heartbeat?)
3892 */
3893#endif
3894
3895 /*
3896 * Disable heartbeat interrupts if they're on this cpu.
3897 * cpu_in_error_finish will invoke heartbeat_enable on the
3898 * remote cpu if the heartbeat was disabled.
3899 */
3900 STRAND_PUSH(%g1, %g3, %g4)
3901 STRAND_PUSH(%g2, %g3, %g4)
3902 HVCALL(heartbeat_disable)
3903 STRAND_POP(%g2, %g3)
3904 STRAND_POP(%g1, %g3)
3905
3906#ifdef CONFIG_FIRE
3907 /*
3908 * if this guest owns a fire bus, redirect
3909 * fire interrupts
3910 */
3911 GUEST_STRUCT(%g3)
3912 ROOT_STRUCT(%g4)
3913 ldx [%g4 + CONFIG_PCIE_BUSSES], %g4
3914 ! check leaf A
3915 ldx [%g4 + PCIE_DEVICE_GUESTP], %g5
3916 cmp %g3, %g5
3917 be %xcc, 2f
3918 nop
3919 ! check leaf B
3920 ldx [%g4 + PCIE_DEVICE_GUESTP + PCIE_DEVICE_SIZE], %g5
3921 cmp %g3, %g5
3922 bne %xcc, 3f
3923 nop
39242:
3925 /*
3926 * Migrate fire intrs
3927 */
3928 STRAND_PUSH(%g1, %g3, %g4)
3929 STRAND_PUSH(%g2, %g3, %g4)
3930 HVCALL(fire_intr_redistribution)
3931 STRAND_POP(%g2, %g3)
3932 STRAND_POP(%g1, %g3)
3933 /*
3934 * Migrate fire err intrs
3935 */
3936 STRAND_PUSH(%g1, %g3, %g4)
3937 STRAND_PUSH(%g2, %g3, %g4)
3938 HVCALL(fire_err_intr_redistribution)
3939 STRAND_POP(%g2, %g3)
3940 STRAND_POP(%g1, %g3)
39413:
3942#endif
3943 /*
3944 * Migrate vdev intrs
3945 */
3946 STRAND_PUSH(%g1, %g3, %g4)
3947 STRAND_PUSH(%g2, %g3, %g4)
3948 HVCALL(vdev_intr_redistribution)
3949 STRAND_POP(%g2, %g3)
3950 STRAND_POP(%g1, %g3)
3951
3952 /*
3953 * Now pick another VCPU in this guest to target the erpt
3954 * Ensure that the VCPU is not bound to the strand in error
3955 */
3956 VCPU_STRUCT(%g1)
3957 GUEST_STRUCT(%g2)
3958 add %g2, GUEST_VCPUS, %g2
3959 mov 0, %g3
3960
3961 !! %g1 - this vcpu struct
3962 !! %g2 - array of vcpus in guest
3963 !! %g3 - vcpu array idx
3964.find_cpu_loop:
3965 ldx [%g2], %g4 ! vcpu struct
3966 brz,pn %g4, .find_cpu_continue
3967 nop
3968
3969 ! ignore this vcpu
3970 cmp %g4, %g1
3971 be,pn %xcc, .find_cpu_continue
3972 nop
3973
3974 ! check whether this CPU is running guest code ?
3975 ldx [%g4 + CPU_STATUS], %g6
3976 cmp %g6, CPU_STATE_RUNNING
3977 bne,pt %xcc, .find_cpu_continue
3978 nop
3979
3980 ! check the error queues.. if not set, not a good candidate
3981 ldx [%g4 + CPU_ERRQR_BASE], %g6
3982 brz,pt %g6, .find_cpu_continue
3983 nop
3984
3985 /*
3986 * find the strand this vcpu is ON, make sure it is idle
3987 * NOTE: currently this check is not necessary, more
3988 * likely when we have sub-strand scheduling
3989 */
3990 !! %g1 - this vcpu struct
3991 !! %g2 - curr vcpu in guest vcpu array
3992 !! %g3 - vcpu array idx
3993 !! %g4 - target vcpus struct
3994 STRAND_STRUCT(%g5) ! this strand
3995 ldx [%g4 + CPU_STRAND], %g6 ! vcpu->strand
3996 cmp %g5, %g6
3997 be,pn %xcc, .find_cpu_continue
3998 nop
3999
4000 ! check if the target strand is IDLE
4001 ldub [%g6 + STRAND_ID], %g6 ! vcpu->strand->id
4002 mov 1, %g5
4003 sllx %g5, %g6, %g6
4004 VCPU2ROOT_STRUCT(%g1, %g5)
4005 ldx [%g5 + CONFIG_STIDLE], %g5
4006 btst %g5, %g6
4007 bnz,pt %xcc, .found_a_cpu
4008 nop
4009
4010.find_cpu_continue:
4011 add %g2, GUEST_VCPUS_INCR, %g2
4012 inc %g3
4013 cmp %g3, NVCPUS
4014 bne,pn %xcc, .find_cpu_loop
4015 nop
4016
4017 ! If we got here, we didn't find a good tgt cpu
4018 ! do not send an erpt, exit the guest
4019
4020 HVCALL(guest_exit)
4021
4022 ba,a .skip_sending_erpt
4023
4024.found_a_cpu:
4025 !! %g4 - target vcpu struct
4026 /*
4027 * This cpu has most of the information to send to the Guest.
4028 * We copy from this cpu err rpt to the tgt's err rpt
4029 */
4030 STRAND_STRUCT(%g1) ! this strand
4031 STRAND2ERPT_STRUCT(STRAND_UE_RPT, %g1, %g1)
4032
4033 ! get tgt strand ce erpt
4034 ldx [%g4 + CPU_STRAND], %g2 ! tgt_vcpu->strand
4035 STRAND2ERPT_STRUCT(STRAND_CE_RPT, %g2, %g3)
4036
4037 ! copy info to tgt cpu ce err buf
4038 ldx [%g1 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL], %g4 ! ehdl
4039 stx %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL]
4040 ldx [%g1 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK], %g4 ! stick
4041 stx %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK]
4042 ld [%g1 + STRAND_SUN4V_ERPT + ESUN4V_EDESC], %g4 ! edesc
4043 st %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_EDESC]
4044 ld [%g1 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g4 ! attr
4045 st %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_ATTR]
4046 ldx [%g1 + STRAND_SUN4V_ERPT + ESUN4V_ADDR], %g4 ! ra
4047 stx %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_ADDR]
4048 ld [%g1 + STRAND_SUN4V_ERPT + ESUN4V_SZ], %g4 ! sz
4049 st %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
4050 lduh [%g1 + STRAND_SUN4V_ERPT + ESUN4V_G_CPUID], %g4 ! cpuid
4051 stuh %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_G_CPUID]
4052 lduh [%g1 + STRAND_SUN4V_ERPT + ESUN4V_G_SECS], %g4
4053 stuh %g4, [%g3 + STRAND_SUN4V_ERPT + ESUN4V_G_SECS]
4054
4055 /*
4056 * Send a xcall to the target strand so it can finish the work
4057 */
4058 ldub [%g2 + STRAND_ID], %g6 ! tgt strand id
4059 sllx %g6, INT_VEC_DIS_VCID_SHIFT, %g5
4060 or %g5, VECINTR_CPUINERR, %g5
4061 stxa %g5, [%g0]ASI_INTR_UDB_W
4062
4063.skip_sending_erpt:
4064 STRAND_STRUCT(%g6)
4065 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
4066
4067 ! remove self from idle list
4068 STRAND_STRUCT(%g1)
4069 ldub [%g1 + STRAND_ID], %g6 /* phys id */
4070 mov 1, %g1
4071 sllx %g1, %g6, %g1
4072 ROOT_STRUCT(%g6)
4073 ldx [%g6 + CONFIG_STIDLE], %g5
4074 bclr %g1, %g5
4075 stx %g5, [%g6 + CONFIG_STIDLE]
4076
4077 ! idle myself
4078 STRAND_STRUCT(%g1)
4079 ldub [%g1 + STRAND_ID], %g6 /* phys id */
4080 INT_VEC_DSPCH_ONE(INT_VEC_DIS_TYPE_IDLE, %g6, %g3, %g4)
4081
4082 /*
4083 * Paranoia!! If we get here someone else resumed this strand
4084 * by mistake
4085 * hvabort to catch the mistake
4086 */
4087 ba hvabort
4088 rd %pc, %g1
4089
4090 SET_SIZE(strand_in_error)
4091
4092 ENTRY(ssi_mondo)
4093
4094 /*
4095 * Check for JBUS error
4096 */
4097 setx JBI_ERR_LOG, %g1, %g2
4098 ldx [%g2], %g2
4099 brnz,pn %g2, ue_jbus_err
4100 nop
4101
4102 /*
4103 * Clear the INT_CTL.MASK bit for the SSI
4104 */
4105 setx IOBBASE, %g3, %g2
4106 stx %g0, [%g2 + INT_CTL + INT_CTL_DEV_OFF(IOBDEV_SSIERR)]
4107
4108 retry
4109
4110 SET_SIZE(ssi_mondo)
4111
4112 /*
4113 * re-route an error report (cont'd)
4114 * 3. select one of the active CPUs for that guest
4115 * 4. Copy the data from the error erport into that
4116 * CPUs cpu struct
4117 * 5. Send a VECINTR_ERROR_XCALL to that CPU
4118 * 6: RETRY
4119 *
4120 * %g2 target guest
4121 * %g4 PA
4122 */
4123
4124 /* FIXME: re-whack this for vcpu/strand split */
4125
4126 ENTRY_NP(cpu_reroute_error)
4127
4128 /*
4129 * find first live cpu in guest->vcpus
4130 * Then deliver the error to that vcpu, and interrupt
4131 * the strand it is running on to make that happen.
4132 */
4133 add %g2, GUEST_VCPUS, %g2
4134 mov 0, %g3
41351:
4136 cmp %g3, NVCPUS
4137 be,pn %xcc, cpu_reroute_error_exit
4138 nop
4139
4140 mulx %g3, GUEST_VCPUS_INCR, %g5
4141 ldx [%g2 + %g5], %g1
4142 brz,a,pn %g1, 1b
4143 inc %g3
4144 ! check whether this CPU is running guest code ?
4145 ldx [%g1 + CPU_STATUS], %g5
4146 cmp %g5, CPU_STATE_RUNNING
4147 bne,pt %xcc, 1b
4148 inc %g3
4149
4150 ! %g3 target vcpu id
4151 ! %g1 &vcpus[target]
4152
4153 ldx [%g1 + CPU_STRAND], %g1
4154
4155 /*
4156 * It is possible that the CPUs rerouted data is already in use.
4157 * We use the rerouted_addr field as a spinlock. The target CPU
4158 * will set this to 0 after reading the error data allowing us
4159 * to re-use the rerouting fields.
4160 * See cpu_err_rerouted() below.
4161 *
4162 * %g1 &strands[target]
4163 * %g3 target cpuid
4164 * %g4 PA
4165 */
4166 set STRAND_REROUTED_ADDR, %g2
4167 add %g1, %g2, %g6
41681: casx [%g6], %g0, %g4
4169 brnz,pn %g4, 1b
4170 nop
4171
4172
4173 ! get the data out of the current STRAND's ce_rpt buf and store
4174 ! in the target STRAND struct
4175 STRAND_ERPT_STRUCT(STRAND_CE_RPT, %g6, %g5) ! g6->strand, g5->strand.ce_rpt
4176 ldx [%g5 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL], %g6
4177 set STRAND_REROUTED_EHDL, %g4
4178 stx %g6, [%g1 + %g4]
4179 lduw [%g5 + STRAND_SUN4V_ERPT + ESUN4V_ATTR], %g6
4180 set STRAND_REROUTED_ATTR, %g4
4181 stx %g6, [%g1 + %g4]
4182 ldx [%g5 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK], %g6
4183 ! STICK is probably not necssary. I doubt if FMA checks
4184 ! both EHDL/STICK when looking for duplicate reports,
4185 ! but it doesn't kill us to do it.
4186 set STRAND_REROUTED_STICK, %g4
4187 stx %g6, [%g1 + %g4]
4188
4189 ! send an x-call to the target CPU
4190 ldub [%g1 + STRAND_ID], %g3
4191 sllx %g3, IVDR_THREAD, %g3
4192 mov VECINTR_ERROR_XCALL, %g5
4193 or %g3, %g5, %g3
4194 stxa %g3, [%g0]ASI_INTR_UDB_W
4195cpu_reroute_error_exit:
4196 ! error is re-routed, get out of here
4197 STRAND_STRUCT(%g6)
4198 SPINLOCK_RESUME_ALL_STRAND(%g6, %g1, %g2, %g3, %g4)
4199
4200 ldx [%g6 + STRAND_ERR_RET], %g7 ! get return address
4201 brnz,a %g7, .ue_return ! valid: clear it & return
4202 stx %g0, [%g6 + STRAND_ERR_RET] ! ..
4203
4204 retry
4205
4206 SET_SIZE(cpu_reroute_error)
4207
4208 /*
4209 * An error has been re-routed to this STRAND.
4210 * The EHDL/ADDR/STICK/ATTR have been stored in the STRAND struct
4211 * by the STRAND that originally detected the error.
4212 *
4213 * Note: STICK may not be strictly necessary
4214 */
4215 ENTRY_NP(cpu_err_rerouted)
4216
4217 STRAND_ERPT_STRUCT(STRAND_CE_RPT, %g6, %g5) ! g6->strand, g5->strand.ce_rpt
4218#ifdef DEBUG_ERROR_REROUTING
4219 PRINT("Error Re-routed to CPU strand ");
4220 ldub [%g6 + STRAND_ID], %g4
4221 PRINTX(%g4)
4222 PRINT("\r\n");
4223#endif
4224
4225 set STRAND_REROUTED_EHDL, %g4
4226 ldx [%g6 + %g4], %g4
4227 stx %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_G_EHDL]
4228
4229 set STRAND_REROUTED_STICK, %g4
4230 ldx [%g6 + %g4], %g4
4231 stx %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_G_STICK]
4232
4233 set STRAND_REROUTED_ATTR, %g4
4234 ldx [%g6 + %g4], %g4
4235 stw %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_ATTR]
4236
4237 ! keep ADDR after EHDL/STICK/ATTR to avoid race
4238 set STRAND_REROUTED_ADDR, %g4
4239 ldx [%g6 + %g4], %g1
4240 ! Clear the strand->rerouted-addr field now to let other
4241 ! errors in.
4242 stx %g0, [%g6 + %g4]
4243 ! Translate the PA to a guest RA
4244 VCPU_STRUCT(%g6)
4245 CPU_ERR_PA_TO_RA(%g6, %g1, %g4, %g2, %g3)
4246 stx %g1, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_ADDR]
4247
4248 ldub [%g6 + CPU_VID], %g4 /* guest cpuid */
4249 stuh %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_G_CPUID]
4250
4251 set EDESC_UE_RESUMABLE, %g4
4252 stw %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_EDESC]
4253
4254 mov ERPT_MEM_SIZE, %g4
4255 st %g4, [%g5 + STRAND_SUN4V_ERPT + ESUN4V_SZ]
4256
4257 /*
4258 * gueue a resumable error report and return
4259 */
4260 ASMCALL_RQ_ERPT(STRAND_CE_RPT, %g1, %g2, %g3, %g4, %g5, %g6, %g7)
4261
4262 retry
4263
4264 SET_SIZE(cpu_err_rerouted)
4265
4266
4267 ENTRY_NP(hvabort)
4268 mov %g1, %g6
4269 HV_PRINT_NOTRAP("ABORT: Failure 0x");
4270 HV_PRINTX_NOTRAP(%g6)
4271#ifdef CONFIG_VBSC_SVC
4272 HV_PRINT_NOTRAP(", contacting vbsc\r\n");
4273 ba,pt %xcc, vbsc_hv_abort
4274 mov %g6, %g1
4275
4276#else
4277 HV_PRINT_NOTRAP(", spinning\r\n");
4278 LEGION_EXIT(1)
42792: ba,a 2b
4280 nop
4281#endif
4282 SET_SIZE(hvabort)
4283
4284
4285 ! intended never to return
4286 ENTRY(c_hvabort)
4287 mov %o7, %g1
4288 ba hvabort
4289 nop
4290 SET_SIZE(c_hvabort)