+ 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
+
+ lis r8,l2FIR ; Get the L2 FIR register address
+ ori r8,r8,0x8000 ; Set to read data
+
+ sync
+
+ mtspr scomc,r8 ; Request the L2 FIR
+ mfspr r26,scomd ; Get the source
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+ lis r8,l2FIRrst ; Get the L2 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
+
+ lis r8,busFIR ; Get the Bus FIR register address
+ ori r8,r8,0x8000 ; Set to read data
+
+ sync
+
+ mtspr scomc,r8 ; Request the Bus FIR
+ mfspr r27,scomd ; Get the source
+ mfspr r8,scomc ; Get back the status (we just ignore it)
+ sync
+ isync
+
+ lis r8,busFIRrst ; Get the Bus 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
+ sldi r26,r26,1 ; Shift left 1
+ sldi r27,r27,1 ; Shift left 1
+
+mckNoFix: std r24,savexdat0(r13) ; Save the MCK source in case we pass the error
+ std r25,savexdat1(r13) ; Save the Core FIR in case we pass the error
+ std r26,savexdat2(r13) ; Save the L2 FIR in case we pass the error
+ std r27,savexdat3(r13) ; Save the BUS 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 ceMck ; 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++ ceMck ; This was not a programming error, all recovered...
+ b ueMck ; 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 ceMck ; 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 ueMck ; 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 ceMck ; 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 ceMck ; 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...
+
+;
+; General recovery for I-Cache errors. Just flush it completely.
+;
+
+ .align 7 ; Force into cache line
+
+mckInvICache:
+ lis r0,0x0080 ; Get a 0x0080 (bit 9 >> 32)
+ mfspr r21,hid1 ; Get the current HID1
+ sldi r0,r0,32 ; Get the "forced ICBI match" bit
+ or r0,r0,r21 ; Set forced match
+
+ isync
+ mtspr hid1,r0 ; Stick it
+ mtspr hid1,r0 ; Stick it again
+ isync
+
+ li r6,0 ; Start at 0
+
+mckIcbi: icbi 0,r6 ; Kill I$
+ addi r6,r6,128 ; Next line
+ andis. r5,r6,1 ; Have we done them all?
+ beq++ mckIcbi ; Not yet...
+
+ isync
+ mtspr hid1,r21 ; Restore original HID1
+ mtspr hid1,r21 ; Stick it again
+ isync