/* We need to carefully read the error status, ACK the errors, * prevent recursive traps, and pass the information on to C * code for logging. * * We pass the AFAR in as-is, and we encode the status * information as described in asm-sparc64/sfafsr.h */ .type __spitfire_access_error,#function __spitfire_access_error: /* Disable ESTATE error reporting so that we do not take * recursive traps and RED state the processor. */ stxa %g0, [%g0] ASI_ESTATE_ERROR_EN membar #Sync mov UDBE_UE, %g1 ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR /* __spitfire_cee_trap branches here with AFSR in %g4 and * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the ESTATE * Error Enable register. */ __spitfire_cee_trap_continue: ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR rdpr %tt, %g3 and %g3, 0x1ff, %g3 ! Paranoia sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 or %g4, %g3, %g4 rdpr %tl, %g3 cmp %g3, 1 mov 1, %g3 bleu %xcc, 1f sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 or %g4, %g3, %g4 /* Read in the UDB error register state, clearing the sticky * error bits as-needed. We only clear them if the UE bit is * set. Likewise, __spitfire_cee_trap below will only do so * if the CE bit is set. * * NOTE: UltraSparc-I/II have high and low UDB error * registers, corresponding to the two UDB units * present on those chips. UltraSparc-IIi only * has a single UDB, called "SDB" in the manual. * For IIi the upper UDB register always reads * as zero so for our purposes things will just * work with the checks below. */ 1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 and %g3, 0x3ff, %g7 ! Paranoia sllx %g7, SFSTAT_UDBH_SHIFT, %g7 or %g4, %g7, %g4 andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE be,pn %xcc, 1f nop stxa %g3, [%g0] ASI_UDB_ERROR_W membar #Sync 1: mov 0x18, %g3 ldxa [%g3] ASI_UDBL_ERROR_R, %g3 and %g3, 0x3ff, %g7 ! Paranoia sllx %g7, SFSTAT_UDBL_SHIFT, %g7 or %g4, %g7, %g4 andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE be,pn %xcc, 1f nop mov 0x18, %g7 stxa %g3, [%g7] ASI_UDB_ERROR_W membar #Sync 1: /* Ok, now that we've latched the error state, clear the * sticky bits in the AFSR. */ stxa %g4, [%g0] ASI_AFSR membar #Sync rdpr %tl, %g2 cmp %g2, 1 rdpr %pil, %g2 bleu,pt %xcc, 1f wrpr %g0, PIL_NORMAL_MAX, %pil ba,pt %xcc, etraptl1 rd %pc, %g7 ba,pt %xcc, 2f nop 1: ba,pt %xcc, etrap_irq rd %pc, %g7 2: #ifdef CONFIG_TRACE_IRQFLAGS call trace_hardirqs_off nop #endif mov %l4, %o1 mov %l5, %o2 call spitfire_access_error add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap nop .size __spitfire_access_error,.-__spitfire_access_error /* This is the trap handler entry point for ECC correctable * errors. They are corrected, but we listen for the trap so * that the event can be logged. * * Disrupting errors are either: * 1) single-bit ECC errors during UDB reads to system * memory * 2) data parity errors during write-back events * * As far as I can make out from the manual, the CEE trap is * only for correctable errors during memory read accesses by * the front-end of the processor. * * The code below is only for trap level 1 CEE events, as it * is the only situation where we can safely record and log. * For trap level >1 we just clear the CE bit in the AFSR and * return. * * This is just like __spiftire_access_error above, but it * specifically handles correctable errors. If an * uncorrectable error is indicated in the AFSR we will branch * directly above to __spitfire_access_error to handle it * instead. Uncorrectable therefore takes priority over * correctable, and the error logging C code will notice this * case by inspecting the trap type. */ .type __spitfire_cee_trap,#function __spitfire_cee_trap: ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR mov 1, %g3 sllx %g3, SFAFSR_UE_SHIFT, %g3 andcc %g4, %g3, %g0 ! Check for UE bne,pn %xcc, __spitfire_access_error nop /* Ok, in this case we only have a correctable error. * Indicate we only wish to capture that state in register * %g1, and we only disable CE error reporting unlike UE * handling which disables all errors. */ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 andn %g3, ESTATE_ERR_CE, %g3 stxa %g3, [%g0] ASI_ESTATE_ERROR_EN membar #Sync /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ ba,pt %xcc, __spitfire_cee_trap_continue mov UDBE_CE, %g1 .size __spitfire_cee_trap,.-__spitfire_cee_trap .type __spitfire_data_access_exception_tl1,#function __spitfire_data_access_exception_tl1: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 mov DMMU_SFAR, %g5 ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit membar #Sync rdpr %tt, %g3 cmp %g3, 0x80 ! first win spill/fill trap blu,pn %xcc, 1f cmp %g3, 0xff ! last win spill/fill trap bgu,pn %xcc, 1f nop ba,pt %xcc, winfix_dax rdpr %tpc, %g3 1: sethi %hi(109f), %g7 ba,pt %xcc, etraptl1 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 call spitfire_data_access_exception_tl1 add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap nop .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1 .type __spitfire_data_access_exception,#function __spitfire_data_access_exception: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 mov DMMU_SFAR, %g5 ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit membar #Sync sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 call spitfire_data_access_exception add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap nop .size __spitfire_data_access_exception,.-__spitfire_data_access_exception .type __spitfire_insn_access_exception_tl1,#function __spitfire_insn_access_exception_tl1: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit membar #Sync sethi %hi(109f), %g7 ba,pt %xcc, etraptl1 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 call spitfire_insn_access_exception_tl1 add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap nop .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1 .type __spitfire_insn_access_exception,#function __spitfire_insn_access_exception: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit membar #Sync sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 call spitfire_insn_access_exception add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap nop .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception