+ bge- PassUpTrap ; Outside of range
+ blt- cr1,PassUpTrap ; Outside of range
+;
+; We need to fix up the BATs here because the probe
+; routine messed them all up... As long as we are at it,
+; fix up to return directly to caller of probe.
+;
+
+ lis r11,hi16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
+ ori r11,r11,lo16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
+
+ lwz r30,0(r11) ; Pick up DBAT 0 high
+ lwz r28,4(r11) ; Pick up DBAT 0 low
+ lwz r27,8(r11) ; Pick up DBAT 1 high
+ lwz r18,16(r11) ; Pick up DBAT 2 high
+ lwz r11,24(r11) ; Pick up DBAT 3 high
+
+ sync
+ mtdbatu 0,r30 ; Restore DBAT 0 high
+ mtdbatl 0,r28 ; Restore DBAT 0 low
+ mtdbatu 1,r27 ; Restore DBAT 1 high
+ mtdbatu 2,r18 ; Restore DBAT 2 high
+ mtdbatu 3,r11 ; Restore DBAT 3 high
+ sync
+
+ lwz r28,savelr+4(r13) ; Get return point
+ lwz r27,saver0+4(r13) ; Get the saved MSR
+ li r30,0 ; Get a failure RC
+ stw r28,savesrr0+4(r13) ; Set the return point
+ stw r27,savesrr1+4(r13) ; Set the continued MSR
+ stw r30,saver3+4(r13) ; Set return code
+ b EatRupt ; Yum, yum, eat it all up...
+
+;
+; 64-bit machine checks
+;
+
+mck64:
+
+;
+; NOTE: WE NEED TO RETHINK RECOVERABILITY A BIT - radar 3167190
+;
+
+ ld r23,savesrr0(r13) ; Grab the SRR0 in case we need bad instruction
+ ld r20,savesrr1(r13) ; Grab the SRR1 so we can decode the thing
+ lwz r21,savedsisr(r13) ; We might need this in a bit
+ ld r22,savedar(r13) ; We might need this in a bit
+
+ lis r8,AsyMCKSrc ; Get the Async MCK Source register address
+ mfsprg r19,2 ; Get the feature flags
+ ori r8,r8,0x8000 ; Set to read data
+ rlwinm. r0,r19,0,pfSCOMFixUpb,pfSCOMFixUpb ; Do we need to fix the SCOM data?
+
+ sync
+
+ mtspr scomc,r8 ; Request the MCK source
+ mfspr r24,scomd ; Get the source
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+ lis r8,AsyMCKRSrc ; Get the Async MCK Source AND mask address
+ li r9,0 ; Get and AND mask of 0
+
+ sync
+
+ mtspr scomd,r9 ; Set the AND mask to 0
+ mtspr scomc,r8 ; Write the AND mask and clear conditions
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+ lis r8,cFIR ; Get the Core FIR register address
+ ori r8,r8,0x8000 ; Set to read data
+
+ sync
+
+ mtspr scomc,r8 ; Request the Core FIR
+ mfspr r25,scomd ; Get the source
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+ lis r8,cFIRrst ; Get the Core FIR AND mask address
+
+ sync
+
+ mtspr scomd,r9 ; Set the AND mask to 0
+ mtspr scomc,r8 ; Write the AND mask and clear conditions
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+; Note: bug in early chips where scom reads are shifted right by 1. We fix that here.
+; Also note that we will lose bit 63
+
+ beq++ mckNoFix ; No fix up is needed
+ sldi r24,r24,1 ; Shift left 1
+ sldi r25,r25,1 ; Shift left 1
+
+mckNoFix: std r24,savemisc0(r13) ; Save the MCK source in case we pass the error
+ std r25,savemisc1(r13) ; Save the Core FIR in case we pass the error
+
+ rlwinm. r0,r20,0,mckIFUE-32,mckIFUE-32 ; Is this some kind of uncorrectable?
+ bne mckUE ; Yeah...
+
+ rlwinm. r0,r20,0,mckLDST-32,mckLDST-32 ; Some kind of load/store error?
+ bne mckHandleLDST ; Yes...
+
+ rldicl. r0,r20,46,62 ; Get the error cause code
+ beq mckNotSure ; We need some more checks for this one...
+
+ cmplwi r0,2 ; Check for TLB parity error
+ blt mckSLBparity ; This is an SLB parity error...
+ bgt mckhIFUE ; This is an IFetch tablewalk reload UE...
+
+; IFetch TLB parity error
+
+ isync
+ tlbiel r23 ; Locally invalidate TLB entry for iaddr
+ sync ; Wait for it
+ b EatRupt ; All recovered...
+
+; SLB parity error. This could be software caused. We get one if there is
+; more than 1 valid SLBE with a matching ESID. That one we do not want to
+; try to recover from. Search for it and if we get it, panic.
+
+mckSLBparity:
+ crclr cr0_eq ; Make sure we are not equal so we take correct exit
+
+ la r3,emvr0(r2) ; Use this to keep track of valid ESIDs we find
+ li r5,0 ; Start with index 0
+
+mckSLBck: la r4,emvr0(r2) ; Use this to keep track of valid ESIDs we find
+ slbmfee r6,r5 ; Get the next SLBE
+ andis. r0,r6,0x0800 ; See if valid bit is on
+ beq mckSLBnx ; Skip invalid and go to next
+
+mckSLBck2: cmpld r4,r3 ; Have we reached the end of the table?
+ beq mckSLBne ; Yes, go enter this one...
+ ld r7,0(r4) ; Pick up the saved ESID
+ cmpld r6,r7 ; Is this a match?
+ beq mckSLBrec ; Whoops, I did bad, recover and pass up...
+ addi r4,r4,8 ; Next table entry
+ b mckSLBck2 ; Check the next...
+
+mckSLBnx: addi r5,r5,1 ; Point to next SLBE
+ cmplwi r5,64 ; Have we checked all of them?
+ bne++ mckSLBck ; Not yet, check again...
+ b mckSLBrec ; We looked at them all, go recover...
+
+mckSLBne: std r6,0(r3) ; Save this ESID
+ addi r3,r3,8 ; Point to the new slot
+ b mckSLBnx ; Go do the next SLBE...
+
+; Recover an SLB error
+
+mckSLBrec: li r0,0 ; Set an SLB slot index of 0
+ slbia ; Trash all SLB entries (except for entry 0 that is)
+ slbmfee r7,r0 ; Get the entry that is in SLB index 0
+ rldicr r7,r7,0,35 ; Clear the valid bit and the rest
+ slbie r7 ; Invalidate it
+
+ li r3,0 ; Set the first SLBE
+
+mckSLBclr: slbmte r0,r3 ; Clear the whole entry to 0s
+ addi r3,r3,1 ; Bump index
+ cmplwi cr1,r3,64 ; Have we done them all?
+ bne++ cr1,mckSLBclr ; Yup....
+
+ sth r3,ppInvSeg(r2) ; Store non-zero to trigger SLB reload
+ bne++ EatRupt ; This was not a programming error, all recovered...
+ b PassUpTrap ; Pass the software error up...
+
+;
+; Handle a load/store unit error. We need to decode the DSISR
+;
+
+mckHandleLDST:
+ rlwinm. r0,r21,0,mckL1DCPE,mckL1DCPE ; An L1 data cache parity error?
+ bne++ mckL1D ; Yeah, we dealt with this back in the vector...
+
+ rlwinm. r0,r21,0,mckL1DTPE,mckL1DTPE ; An L1 tag error?
+ bne++ mckL1T ; Yeah, we dealt with this back in the vector...
+
+ rlwinm. r0,r21,0,mckUEdfr,mckUEdfr ; Is the a "deferred" UE?
+ bne mckDUE ; Yeah, go see if expected...
+
+ rlwinm. r0,r21,0,mckUETwDfr,mckUETwDfr ; Is the a "deferred" tablewalk UE?
+ bne mckDTW ; Yeah, no recovery...
+
+ rlwinm. r0,r21,0,mckSLBPE,mckSLBPE ; SLB parity error?
+ bne mckSLBparity ; Yeah, go attempt recovery....
+
+; This is a recoverable D-ERAT or TLB error
+
+ la r9,hwMckERCPE(r2) ; Get DERAT parity error count
+
+mckInvDAR: isync
+ tlbiel r22 ; Locally invalidate the TLB entry
+ sync
+
+ lwz r21,0(r9) ; Get count
+ addi r21,r21,1 ; Count this one
+ stw r21,0(r9) ; Stick it back
+
+ b EatRupt ; All recovered...
+
+;
+; When we come here, we are not quite sure what the error is. We need to
+; dig a bit further.
+;
+; R24 is interrupt source
+; R25 is Core FIR
+;
+; Note that both have been cleared already.
+;
+
+mckNotSure:
+ rldicl. r0,r24,AsyMCKfir+1,63 ; Something in the FIR?
+ bne-- mckFIR ; Yup, go check some more...
+
+ rldicl. r0,r24,AsyMCKhri+1,63 ; Hang recovery?
+ bne-- mckHangRcvr ; Yup...
+
+ rldicl. r0,r24,AsyMCKext+1,63 ; External signal?
+ bne-- mckExtMck ; Yup...
+
+;
+; We really do not know what this one is or what to do with it...
+;
+
+mckUnk: lwz r21,hwMckUnk(r2) ; Get unknown error count
+ addi r21,r21,1 ; Count it
+ stw r21,hwMckUnk(r2) ; Stuff it
+ b PassUpTrap ; Go south, young man...
+
+;
+; Hang recovery. This is just a notification so we only count.
+;
+
+mckHangRcrvr:
+ lwz r21,hwMckHang(r2) ; Get hang recovery count
+ addi r21,r21,1 ; Count this one
+ stw r21,hwMckHang(r2) ; Stick it back
+ b EatRupt ; All recovered...
+
+;
+; Externally signaled MCK. No recovery for the moment, but we this may be
+; where we handle ml_probe_read problems eventually.
+;
+mckExtMck:
+ lwz r21,hwMckHang(r2) ; Get hang recovery count
+ addi r21,r21,1 ; Count this one
+ stw r21,hwMckHang(r2) ; Stick it back
+ b EatRupt ; All recovered...
+
+;
+; Machine check cause is in a FIR. Suss it out here.
+; Core FIR is in R25 and has been cleared in HW.
+;
+
+mckFIR: rldicl. r0,r25,cFIRICachePE+1,63 ; I-Cache parity error?
+ la r19,hwMckICachePE(r2) ; Point to counter
+ bne mckInvICache ; Go invalidate I-Cache...
+
+ rldicl. r0,r25,cFIRITagPE0+1,63 ; I-Cache tag parity error?
+ la r19,hwMckITagPE(r2) ; Point to counter
+ bne mckInvICache ; Go invalidate I-Cache...
+
+ rldicl. r0,r25,cFIRITagPE1+1,63 ; I-Cache tag parity error?
+ la r19,hwMckITagPE(r2) ; Point to counter
+ bne mckInvICache ; Go invalidate I-Cache...
+
+ rldicl. r0,r25,cFIRIEratPE+1,63 ; IERAT parity error?
+ la r19,hwMckIEratPE(r2) ; Point to counter
+ bne mckInvERAT ; Go invalidate ERATs...
+
+ rldicl. r0,r25,cFIRIFUL2UE+1,63 ; IFetch got L2 UE?
+ bne mckhIFUE ; Go count and pass up...
+
+ rldicl. r0,r25,cFIRDCachePE+1,63 ; D-Cache PE?
+ bne mckL1D ; Handled, just go count...
+
+ rldicl. r0,r25,cFIRDTagPE+1,63 ; D-Cache tag PE?
+ bne mckL1T ; Handled, just go count...
+
+ rldicl. r0,r25,cFIRDEratPE+1,63 ; DERAT PE?
+ la r19,hwMckDEratPE(r2) ; Point to counter
+ bne mckInvERAT ; Go invalidate ERATs...
+
+ rldicl. r0,r25,cFIRTLBPE+1,63 ; TLB PE?
+ la r9,hwMckTLBPE(r2) ; Get TLB parity error count
+ bne mckInvDAR ; Go recover...
+
+ rldicl. r0,r25,cFIRSLBPE+1,63 ; SLB PE?
+ bne mckSLBparity ; Cope with it...
+
+ b mckUnk ; Have not a clue...
+