/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT_INTERNAL_USE_ONLY@
*/
/*
MP_2p.s
MP low-level signaling, configuration, et all. This is for a and Apple/Daystar 2p board
Lovingly crafted by Bill Angell using traditional methods
*/
#include <ppc/asm.h>
#include <ppc/proc_reg.h>
#include <ppc/POWERMAC/mp/MPPlugIn.h>
#include <assym.s>
#include <mach/machine/vm_param.h>
.set MPPlugInVersion,0 /* Current version code */
/* */
/* Interfaces to hardware */
/* */
.set PCI1ARdisp, 0x00800000 /* Displacement from Bandit to PCI1 address configuiration register */
.set GrandCdisp, 0x01000000 /* Displacement from Bandit to Grand Central */
.set EventsReg, 0x20 /* Interruption events register (latched) */
.set LevelsReg, 0x2C /* Interruption levels register (unlatched) */
.set MaskReg, 0x24 /* Interruption mask register */
.set ClearReg, 0x28 /* Interruption clear register */
.set TicksPerMic, 11 /* We'll use 11 ticks per µS - 120MHz is really 10, 180MHz is 11.24 */
.set EtherNRdisp, 0x01019000 /* Displacement into bandit of EtherNet ROM */
#ifdef __ELF__
.section ".data"
#else
.data
#endif
.align 5 /* Get us out to the end */
.globl MPPIwork
#ifdef __ELF__
.type MPPIwork,@function
#endif
MPPIwork:
MPPIstatus: .byte 0 /* Global MP board status */
.set MPPIinit, 0x80 /* Global initialization complete */
.set MPPI2Pv2, 0x40 /* Second rev of 2P board (no watchdog and different state machine) */
.byte 0 /* Reserved */
MPPIinst: .byte 0 /* Mask of CPUs installed */
MPPIonline: .byte 0 /* Mask of CPUs online (i.e., initialized) */
MPPIlogCPU: .long 0 /* Used to configure CPU addresses */
MPPITBsync: .long 0 /* Used to sync time bases */
.long 0
MPPIHammer: .long 0 /* Address of HammerHead */
MPPIGrandC: .long 0 /* Address of GrandCentral */
MPPIPCI1Adr: .long 0 /* Address of PCI1's config reg addr */
MPPIEther: .long 0 /* Address of EtherNet ROM */
.align 5
MPPISncFght: .fill 4,4,0 /* Space for 9 passes of a TB sync fight + 1 guard pass */
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.fill 4,4,0
.align 7 /* Point to the start of the CPU status */
.globl EXT(MPPICPUs)
#ifdef __ELF__
.type EXT(MPPICPUs),@function
#endif
EXT(MPPICPUs): /* Start of Processor specific areas */
/* There are 8 of these indexed by processor number */
MPPICPU0: .fill 8,4,0 /* First processor */
MPPICPU1: .fill 8,4,0 /* Second processor */
MPPICPU2: .fill 8,4,0 /* Third processor */
MPPICPU3: .fill 8,4,0 /* Fourth processor */
.set MPPIMaxCPU, (.-EXT(MPPICPUs)-32)/32 /* Get the maximum CPU address */
.text
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Here starteth ye stuff */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Validate that the hardware matches with our code. At this point, we cannot check */
/* for anything other than the possibility of this working. There's no version code */
/* or nothin'. So, if we have a second processor and are a 604 or 604e, we'll say */
/* we're capable. Also we'll check version codes for our code. */
/* */
/* When we get here, DDAT and IDAT are both on, 'rupts are disabled. */
/* */
/* We're called like this: */
/* OSStatus MP_probe(MPPlugInSpecPtr spec, UInt32 HammerheadAddr)/******************************************************************************************************** */
ENTRY(MPprobe, TAG_NO_FRAME_USED)
MPPIbase: mfpvr r7 /* Get the processor version */
rlwinm r7,r7,16,16,31 /* Isolate the processor type */
lbz r5,ArbConfig(r4) /* See if there is another processor */
andi. r5,r5,TwoCPU /* Are we a real live two processor? */
beq OneWay /* Nope, we be gone... */
cmplwi cr0,r7,4 /* Are we a 604? */
beq SeemsOK /* Yeah, we're cool... */
cmplwi cr0,r7,9 /* Are we a 604E? */
beq SeemsOK /* Yeah, go finish up... */
OneWay: li r3,0 /* Say we can't find the proper CPU */
blr /* Leave... */
SeemsOK: mr r10,r3 /* Save the parameter list */
lwz r4,MPSversionID(r10) /* Get the version ID */
cmplwi cr0,r4,kMPPlugInVersionID /* Correct version? */
beq IsOK /* Yeah, we think we're ok... */
li r3,0 /* Set bad version' */
blr /* Leave... */
IsOK: mflr r11 /* Save the LR */
lis r9,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
bl SetBase1 /* Jump to the next instruction */
SetBase1: mflr r12 /* Get the base register */
ori r9,r9,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
addi r12,r12,LOW_ADDR(MPPIbase-SetBase1) /* Adjust to the start of all our code */
stw r12,MPSbaseAddr(r10) /* Save off the common base for all functions */
la r5,LOW_ADDR(MPPIFunctions-MPPIbase)(r12) /* Point to the base of all functions */
stw r5,MPSareaAddr(r10) /* Pass back the code address */
la r5,LOW_ADDR(MPPIFuncOffs-MPPIbase)(r12) /* Point to the function offset table */
stw r5,MPSoffsetTableAddr(r10) /* Pass back the pointer to the offset table */
li r5,LOW_ADDR(MPPISize-MPPIFunctions) /* Get our size without data area */
stw r5,MPSareaSize(r10) /* Save it */
stw r9,MPSdataArea(r10) /* Save it */
la r5,LOW_ADDR(EXT(MPPICPUs)-MPPIwork)(r9) /* Point to the CPU area base */
stw r5,MPSCPUArea(r10) /* Save it */
mtlr r11 /* Restore that return address */
li r3,1 /* Set no error */
blr /* Leave, we're all done... */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Here starteth ye code that starteth up ye second prothether. */
/* Yea, though ye prothether executeth asynchronously, it appears unto men */
/* in ye shape of a synchronous process. By ye instruction of He who gave it */
/* form and being, it stopeth to worship and praise its Lord, to joyously */
/* receive His blessings and teachings, to guide its way along the path to */
/* righteous execution. */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Initialize the MP hardware. This will bring the other processor online. */
/* */
/* First we will tick the board to its 5th state the "TBEN off" state. */
/* */
/* Just for giggles, here's the states: */
/* */
/* 1) 1st ROM - This state exists after motherboard reset */
/* 2) Open Firmware - Transitions here when the SecInt line is first asserted */
/* Open Firmware attempts to execute some code on the secondary */
/* processor to obtain the PVR register. It's got some problems */
/* and hangs the secondary disabled. */
/* 3) Reset (my name) - Entered when the SecInt line is deasserted. A timer starts and */
/* 468µS later the reset line is pulled. I may have this wrong here, */
/* it may be that the reset line is held for 468µS. Either way, */
/* this state is invisible to us. */
/* 4) 2nd ROM - This state exists when the secondary processor begins executing */
/* after the reset. */
/* 5) TBEN off - We transition here when SecInt is asserted in the 2nd ROM state. */
/* In this state, the TBEN pin is set to disable the timebase from */
/* running on all processors, thus freezing time. (Performace analysis */
/* note: here would be the best time to run stats, all tests would */
/* run in 0 time giving us infinite speed.) Also the "primary arbitration" */
/* mode is set. This mode causes the CPU board to arbitrate both processors */
/* using a single bus master. This gets us around the L2 cache dumbness. */
/* We should also note that because of this, there is now no way to */
/* tell if we are on the secondary processor, the WhoAmI register will */
/* always indicate the primary processor. We need to have sewn */
/* name tags into our underwear before now. */
/* Finally, this state is the only way we can tell if we are executing */
/* on the older version of the 2-way board. When it is in this state */
/* "primary arbitration" has not been enabled yet. The WhoAmI register */
/* will indicate if we are on the secondary processor on not. We should */
/* check this because we need to do signals differently. */
/* 6) TBEN on - The next assertion of SecInt brings us to our final destination. For */
/* those of you who will be deplaning, please remember that timebases */
/* are running and primary arbitration is enabled. Always remember: */
/* buckle up for safety and if you're tired pull over for a rest. */
/* */
/******************************************************************************************************** */
ENTRY(MPinstall, TAG_NO_FRAME_USED)
/* int MP_install(unsigned int *physAddr, unsigned int band1, unsigned int hammerh, unsigned int grandc,
* unsigned int pci1ar, unsigned int enetr)
lis r11,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
mflr r0 /* Save the LR */
ori r11,r11,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
stw r5,MPPIHammer-MPPIwork(r11) /* Save the HammerHead address for later */
stw r6,MPPIGrandC-MPPIwork(r11) /* Save address of Grand Central */
stw r7,MPPIPCI1Adr-MPPIwork(r11) /* Save the PCI1 address register address */
stw r8,MPPIEther-MPPIwork(r11) /* Save Ethernet ROM address */
li r4,LOW_ADDR(0xC080) /* Set CPU 0&1 installed, CPU 0 online */
lis r10,(MPPICOnline+MPPICReady)>>16 /* Set CPU 0 online and ready */
mfspr r6,pir /* Get the PIR contents */
sth r4,MPPIinst-MPPIwork(r11) /* Set 'em for later */
rlwinm r6,r6,0,0,27 /* Clear to use processor 0 */
stw r10,EXT(MPPICPUs)-MPPIwork(r11) /* Preset CPU 0 online and ready */
mtspr pir,r6 /* Set our PIR */
/* */
/* Ok, ok, enough of this. Let's really start 'em up. */
/* */
lis r9,HIGH_ADDR(CPUInit) /* Top of init code */
li r6,1 /* Get the other guy's CPU address */
ori r9,r9,LOW_ADDR(CPUInit) /* Get physical address of init code */
mfmsr r8 /* Get the MSR */
stw r6,MPPIlogCPU-MPPIwork(r11) /* Set the logical CPU address to assign */
rlwinm r6,r8,0,17,15 /* Turn off interruptions */
sync /* Make sure the work area is updated */
mtmsr r6 /* Flip the EE bit off */
isync /* Chill a bit */
stw r9,0(r7) /* Pass the initialization code address to our friend */
sync /* Fence off the pig */
li r6,0 /* Clear this out */
stb r6,IntReg(r5) /* Kick the other processor */
eieio /* Pig in the sty */
/* At this point we should be in the "TBEN off" state. The second processor should be starting */
/* to come up. */
/* Note that we are assuming that the secondary processor will reset the interrupt request. */
/* If we are on one of the old boards, we will die in about 256µS if it is not reset, 'cause */
/* of that silly watchchihuahua timer. We can't use the TB or decrimenter here to set a */
/* timeout because when we are in "TBEN off" state these guys don't run. */
lis r4,HIGH_ADDR(SpinTimeOut) /* Get about 1 second at 200MHz */
/* At 120 MHz this is 1.66 seconds, at 400MHz it is .5 */
/* All these are more than enough time for this handshake */
ori r4,r4,LOW_ADDR(SpinTimeOut) /* Get the bottom part */
WaitReady: lwz r9,0(r7) /* Get this back */
mr. r9,r9 /* The other processor will set to 0 */
/* when it is ready for the work area address */
beq CodeUp /* The code is up on the other side */
subi r4,r4,1 /* Count the try */
mr. r4,r4 /* Did we timeout? */
bne+ WaitReady /* Nope... */
li r3,kMPPInitTO1 /* Set that we timed out with initial code bringup */
mtmsr r8 /* Restore the interrupt state */
mtlr r0 /* Restore the return addess */
blr /* Return a failure... */
CodeUp: isync /* Make sure we don't prefetch past here */
/* Timebase is stopped here, no need for the funky "get time base right" loop */
mftbu r4 /* Get upper timebase half */
mftb r9 /* Get bottom */
stw r4,MPPITBsync-MPPIwork(r11) /* Save the top */
stw r9,MPPITBsync+4-MPPIwork(r11) /* Save the second half */
sync /* Be very sure it's there */
stw r11,0(r7) /* Set the PCI1 adr reg non-zero - this releases the spin */
/* loop and allows the timebase to be set. */
eieio
lis r9,HIGH_ADDR(SpinTimeOut) /* Get the spin time */
ori r9,r9,LOW_ADDR(SpinTimeOut) /* Get the bottom part */
WaitTBset: lwz r4,0(r7) /* Get this back */
mr. r4,r4 /* When zero, the other guy's TB is set up */
beq- TBSetUp /* She's'a all done... */
subi r9,r9,1 /* Count the try */
mr. r9,r9 /* Did we timeout? */
bne+ WaitTBset /* Nope... */
li r3,kMPPInitTO3 /* Set that we timed out setting clock */
mtmsr r8 /* Restore the interrupt state */
isync
mtlr r0 /* Restore the return addess */
blr /* Return a failure... */
TBSetUp: stb r6,IntReg(r5) /* Kick the other processor again */
/* This will tick us to the next state */
eieio
SpinDelay: addi r6,r6,1 /* Bump spin count (we finally are trashing R6) */
cmplwi cr0,r6,4096 /* Spun enough? */
ble+ SpinDelay /* Nope... */
li r6,SecInt /* Set the interrupt bit */
stb r6,IntReg(r5) /* Deassert the external signal */
/* */
/* Ok, the other processor should be online in a spin waiting for a start signal from */
/* us. It should be in the reset state with no external interruptions pending. There may */
/* be a decrimenter pop waiting in the wings though. */
/* */
lwz r7,MPPIGrandC-MPPIwork(r11) /* Point to GrandCentral */
lwz r4,MaskReg(r7) /* Get the grand central mask register (note that this */
/* is a little-endian area, but I'm too lazy to access it that way */
/* so I'll document what it really should be, but, probably, it would */
/* have been much, much easier just to code up the lwbrx and be done */
/* with it rather than producing this monograph describing my alternate */
/* access method that I really don't explain anyway. */
ori r4,r4,0x0040 /* Flip on bit 30 (hah, figure that one out). This enables the */
/* Ext10 interrupt which is connected to the MACE ethernet chip's */
/* chip-select pin. */
stw r4,MaskReg(r7) /* Stick it on back */
eieio
mtlr r0 /* Get back the original LR */
sync /* Make sure all storage ops are done */
mtmsr r8 /* Restore the MSR */
isync
li r3,kSIGPnoErr /* Set that we worked jest fine and dandy */
blr /* Bye now... */
.align 5
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* This is where the individual SIGP function calls reside. */
/* Also, it is where we cram the second processor's initialization code wo'w we */
/* can use physical addressing. */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
MPPIFunctions: /* Start of all externally called functions and interrupt handling code */
/******************************************************************************************************** */
/* */
/* Count the number of processors. This hardwires to 2 (or 1 if no secondary) */
/* */
/******************************************************************************************************** */
CountProcessors:
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
mfmsr r9 /* Get the MSR */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
ori r10,r9,0x0010 /* Turn on DDAT */
lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the HammerHead controller */
mtmsr r10 /* Turn on DDAT */
isync /* Kill speculation */
li r3,2 /* Assume we have them all */
lbz r5,ArbConfig(r8) /* Check if we've seen a second processor */
andi. r5,r5,TwoCPU /* Are we a real live two processor? */
mtmsr r9 /* Put back the DDAT */
isync
bnelr+ /* Yeah... */
li r3,1 /* Nope, set a count of 1 */
blr /* Leave, we're inadequate... */
/******************************************************************************************************** */
/* */
/* Start up the selected processor (R3=processor/******************************************************************************************************** */
StartProcessor:
mr r7,r5 /* Copy pass-thru parameter */
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplw cr0,r3,r10 /* Trying to start ourselves? */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
beqlr- /* Self abuse... */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
mflr r11 /* Save the return address */
add r9,r9,r12 /* Point right at the entry */
SPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
li r3,kMPPBadState /* Set bad state */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
stwcx. r5,0,r9 /* Try to set busy */
bne- SPretry
ori r6,r10,MPPICfStrt<<8 /* Put the Start function in front of the processor ID */
rlwimi r5,r6,0,16,31 /* Put these behind the status flags */
stw r4,MPPICParm0(r9) /* Set the starting physical address parameter */
stw r7,MPPICParm2(r9) /* Set pass-thru parameter */
sync /* Make sure it's all out there */
b KickAndGo /* We're done now... */
/******************************************************************************************************** */
/* */
/* Reset the selected processor (R3=processor). You can't reset yourself or the primary. */
/* We're gonna try, try real hard... This is not for the faint-of-heart. */
/* If there's ever any way to yank a reset line, we'll do it here. */
/* */
/******************************************************************************************************** */
ResetProcessor:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
rlwinm r10,r10,0,28,31 /* Clean up the PIR */
cmplw cr0,r3,r10 /* Trying to start ourselves? */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
beqlr- /* Self abuse... */
mr. r9,r9 /* Trying to reset the primary?!? Dude, that's insubordination!!!! */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
li r3,kMPPInvalCPU /* Say that that's a major offense */
beqlr- /* Bye now... */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
mflr r11 /* Save the return address */
add r9,r9,r12 /* Point right at the entry */
li r4,16 /* Try for 16 times to get the busy lock */
RSlockS: mftb r6 /* Time stamp start */
RSlock: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
rlwinm. r0,r5,0,2,2 /* Are we online */
li r3,kMPPOffline /* Set offline */
cmplwi cr1,r5,0 /* Check for busy */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
bge+ cr1,RSnotBusy /* Not busy, make it so... */
mftb r7 /* Stamp the time */
sub r7,r7,r6 /* Get elapsed time */
rlwinm. r7,r7,16,16,31 /* Divide ticks by microseconds (this is pretty darn "kinda-in-the-ballpark") */
cmplwi cr0,r7,TicksPerMic /* See if we hit 65536µS yet */
blt+ RSlock /* Not yet... */
RSatmtCnt: subi r4,r4,1 /* Count the retries */
mr. r4,r4 /* Are we done yet? */
bgt+ RSlockS /* Start the lock attempt again... */
li r3,kMPPCantLock /* Say we can't get the lock */
b ErrorReturn /* Bye, dude... */
RSnotBusy: rlwinm r5,r5,0,0,15 /* Clear out the function and requestor */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Set busy */
or r5,r10,r5 /* Add in our processor */
ori r5,r5,MPPICfReset<<8 /* Set the reset function */
stwcx. r5,0,r9 /* Cram it back */
bne- RSatmtCnt /* We lost the reservation... */
b KickAndGo /* Try to send it across... */
/******************************************************************************************************** */
/* */
/* Here we will try to resume execution of a stopped processor (R3=processor). */
/* */
/******************************************************************************************************** */
ResumeProcessor:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplw cr0,r3,r10 /* Trying to resume ourselves? */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
beqlr- /* Self abuse... */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
mflr r11 /* Save the link register */
add r9,r9,r12 /* Point right at the entry */
RPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
lis r6,MPPICReady>>16 /* Get the ready bit */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
and. r0,r5,r6 /* Are we ready? */
li r3,kMPPNotReady /* Set not ready */
lis r6,MPPICStop>>16 /* Get the stopped bit */
beq- ErrorReturn /* Ain't ready, buzz off... */
and. r0,r5,r6 /* Are we stopped? */
li r3,kMPPNotStopped /* Set not stopped */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
beq- ErrorReturn /* Nope, not stopped, so how do we resume? */
stwcx. r5,0,r9 /* Try to set busy */
bne- RPretry
ori r6,r10,MPPICfResm<<8 /* Put the resume function in front of the processor ID */
rlwimi r5,r6,0,16,31 /* Put these behind the status flags */
b KickAndGo /* We're done now... */
/******************************************************************************************************** */
/* */
/* Here we will try to stop execution of a running processor (R3=processor). */
/* */
/******************************************************************************************************** */
StopProcessor:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplw cr0,r3,r10 /* Are we doing ourselves? */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kMPPHairyPalms /* Set trying to do it to ourselves */
beqlr- /* Self abuse... */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
mflr r11 /* Save the link register */
add r9,r9,r12 /* Point right at the entry */
PPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
lis r6,MPPICReady>>16 /* Get the ready bit */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
and. r0,r5,r6 /* Are we ready? */
li r3,kMPPNotReady /* Set not ready */
lis r6,MPPICStop>>16 /* Get the stopped bit */
beq- ErrorReturn /* Ain't ready, buzz off... */
and. r0,r5,r6 /* Are we stopped? */
li r3,kMPPNotRunning /* Set not running */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
bne- ErrorReturn /* Nope, already stopped, so how do we stop? */
stwcx. r5,0,r9 /* Try to set busy */
ori r10,r10,MPPICfStop<<8 /* Put the stop function in front of the processor ID */
bne- PPretry
rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
b KickAndGo /* We're done now... */
/******************************************************************************************************** */
/* */
/* Here we will try to signal a running processor (R3=processor). */
/* Note that this should have good performace. Well, actually, seeing as how slow we really are, it */
/* probably is moot anyhow. */
/* Another note: this function (and all most others as well) will return a timeout when the */
/* second processor tries to do itself on the old version of the board. This happens because */
/* In order to keep the watchchihuahua from popping (just imagine the scene: that little runt-dog just so */
/* excited that its veins and eyes bulge and then explode) signaling to the secondary */
/* is done syncronously and disabled. If the secondary signals the secondary, it will never enable so */
/* it will never see the 'rupt, so it will never clear it, so it will time out, so there... */
/* */
/******************************************************************************************************** */
SignalProcessor:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
mflr r11 /* Save the link register */
add r9,r9,r12 /* Point right at the entry */
SiPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
lis r6,MPPICReady>>16 /* Get the ready bit */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
and. r0,r5,r6 /* Are we ready? */
li r3,kMPPNotReady /* Set not ready */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
beq- ErrorReturn /* Ain't ready, buzz off... */
stwcx. r5,0,r9 /* Try to set busy */
ori r10,r10,MPPICfSigp<<8 /* Put the SIGP function in front of the processor ID */
bne- SiPretry
stw r4,MPPICParm0(r9) /* Pass along the SIGP parameter */
rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
b KickAndGo /* We're done now... */
/******************************************************************************************************** */
/* */
/* Here we will store the state of a processor (R3=processor/* */
/******************************************************************************************************** */
StoreProcessorStatus:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplw cr0,r3,r10 /* Saving our own state??? Abusing oneself??? */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
mflr r11 /* Save the link register */
beq Flagellant /* Oh baby, oh baby... */
bgtlr- cr1 /* Sure are... (Get our address also) */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
add r9,r9,r12 /* Point right at the entry */
SSretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
beq- ErrorReturn /* Ain't online, buzz off... */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
stwcx. r5,0,r9 /* Try to set busy */
ori r10,r10,MPPICfStat<<8 /* Put the store status function in front of the processor ID */
bne- SSretry /* Lost reservation, return busy... */
li r0,0 /* Get false */
stb r0,CSAregsAreValid(r4) /* Set that the registers ain't valid */
stw r4,MPPICParm0(r9) /* Set the status area physical address parameter */
rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
b KickAndGo /* We're done now... */
/* Spill one's seed upon the soil */
Flagellant: bl StoreStatus /* Go store off all the registers 'n' stuff */
mtlr r11 /* Restore the return address */
li r3,kSIGPnoErr /* Return no error */
blr /* Leave... */
/******************************************************************************************************** */
/* */
/* Here we will attempt to syncronize clocks (R3=processor). */
/* Self abuse will just return with an all-ok code. */
/* */
/******************************************************************************************************** */
SynchClock:
mfspr r10,pir /* Get our processor number */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplw cr0,r3,r10 /* Cleaning our own clock?? */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
li r3,kSIGPnoErr /* Assume self-cleaning clock */
beqlr /* Oh baby, oh baby... */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
mflr r11 /* Save the link register */
add r9,r9,r12 /* Point right at the entry */
SyCretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */
li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */
rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */
lis r6,MPPICOnline>>16 /* Get the online flag */
bne- ErrorReturn /* Yeah, go leave, don't bother me now... */
and. r0,r5,r6 /* Are we online */
li r3,kMPPOffline /* Set offline */
beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */
oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */
li r0,0 /* Clear this */
stwcx. r5,0,r9 /* Try to set busy */
ori r10,r10,MPPICfTBsy<<8 /* Put the timebase sync function in front of the processor ID */
bne- SyCretry /* Lost reservation, return busy... */
stw r0,MPPITBsync+4-MPPIwork(r12) /* Make sure the parm area is 0 */
mr r0,r11 /* Save the LR */
bl SyCbase /* Get a base register */
SyCbase: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */
mflr r11 /* Get the base */
la r11,(4*4)(r11) /* DON'T MESS WITH THESE INSTRUCTIONS Make up the return point */
b KickAndGo /* Go signal the other side */
SyCKrtrn: mr r11,r0 /* Restore the return */
/* */
/* Start sync'ing 'er up */
/* */
mftb r4 /* Take a timeout stamp (don't need top half, we have at least 13 hours) */
SyCInP0: lwz r5,0(r9) /* Get the CPU status word */
rlwinm r5,r5,24,24,31 /* Isolate the command byte */
cmplwi cr0,r5,MPPICfTBsy1 /* Have we reached time base sync phase 1 yet? */
beq SyCInP1 /* Yeah, we're in phase 1... */
mftb r5 /* Get the bottom half of the timer again */
sub r5,r5,r4 /* How long we been messin' around? */
cmplwi cr0,r5,1000*TicksPerMic /* Don't try more'n' a 1000µS */
blt+ SyCInP0 /* We haven't, so wait some more... */
li r3,kMPPTimeOut /* Signal timeout */
b ErrorReturn /* By dude... */
/* */
/* Here we make sure there is enough time to sync the clocks before the lower part of the TB ticks */
/* up into the high part. This eliminates the need for any funky */
/* "get-the-top-then-get-the-bottom-then-get-the-top-again-to-see-if-it-changed" stuff. That would */
/* only make the sync harder to do. */
/* */
/* Also, because we use the lower TB value for the signal, we also need to make sure we do not have */
/* a value of 0, we would be ever-so-sorry if it was. */
/* */
SyCInP1: li r4,lo16(0xC000) /* Get the minimum time left on clock before tick ('bout 1 1/4 ms) */
li r8,0 /* Get a 0 constant */
SyCdelay: mftb r5 /* Get the time left */
cmplw cr0,r5,r4 /* See if there is sufficient time before carry into high clock */
bgt- SyCdelay /* Nope, hang until it is... */
mr. r5,r5 /* Did we just tick, however? */
beq- SyCdelay /* Yeah, wait until it is at least 1... */
mftbu r4 /* Get the upper */
stw r4,MPPITBsync-MPPIwork(r12) /* Make sure the top half is set */
sync /* Wait until it is done */
mftb r5 /* Get the lower timebase now */
stw r5,MPPITBsync+4-MPPIwork(r12) /* Shove it out for the other processor */
la r6,MPPISncFght-MPPIwork(r12) /* Point to the courtroom area */
li r5,0 /* Point to the first line */
SyCclear: dcbz r5,r6 /* Clear the court */
addi r5,r5,32 /* Point to the next line */
cmplwi cr0,r5,10*2*32 /* Enough for 9 iterations, 2 chunks at a time */
blt+ SyCclear /* Clear the whole smear... */
sync /* Make sure everyone's out */
mftb r5 /* Get the lower timebase now */
SyCWait: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get it back */
mftb r6 /* Get the bottom half again */
mr. r7,r7 /* Have they set their clock yet? */
sub r0,r6,r5 /* See if we're hung up */
beq- SyCdonesync /* Clock is set */
cmplwi cr0,r0,1000*TicksPerMic /* Timeout if we spend more than 1000µS doing this */
blt+ SyCWait /* No timeout, wait some more... */
li r3,kMPPTimeOut /* Set timeout */
b ErrorReturn /* Leave... */
/* */
/* Ok, so now we have set a preliminary TB value on the second processor. It's close, but only */
/* within handgranade range. */
/* */
/* What we will do now is to let the processors (starting with the other guy) argue about the time for */
/* a while (10 passes-we use the middle 8). We'll look at the results and try to adjust the other processor's */
/* time such that the timing windows are overlapping evenly. This should put the TBs close enough together */
/* (0-2 ticks) that the difference is undetectable. */
/* */
SyCdonesync:
li r4,0 /* Clear this */
la r5,MPPISncFght-MPPIwork(r12) /* Point to the squared circle */
SyCWtArg:
dcbf 0,r5 /* Make sure of it */
sync /* Doubly shure */
lwz r6,0(r5) /* Listen for the defence argument */
mr. r6,r6 /* See if they are done */
beq+ SyCWtArg /* Nope, still going... */
mftb r7 /* They're done, time for rebuttal */
stw r7,32(r5) /* Make rebuttle */
addi r4,r4,1 /* Count rounds */
cmplwi cr0,r4,10 /* See if we've gone 8 rounds plus an extra one */
addi r5,r5,64 /* Point to the next round areas */
blt+ SyCWtArg /* Not yet, come out of your corners fighting... */
mftb r5 /* Stamp the wait */
SyCWadj: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get adjustment flag */
mftb r6 /* Get timebase again */
mr. r7,r7 /* Have they set their timebase with adjusted time yet? */
sub r6,r6,r5 /* Get elapsed time */
bne+ SyCdone /* They say it, sync done... */
cmplwi cr0,r6,1000*TicksPerMic /* Timeout if we spend more than 1000µS doing this */
blt+ SyCWadj /* Still time, wait until adjustment is done... */
li r3,kMPPTimeOut /* Set timeout */
b ErrorReturn /* Pass it back... */
SyCdone: li r3,kSIGPnoErr /* No errors */
mtlr r11 /* Restore LR */
blr /* Leave... */
/******************************************************************************************************** */
/* */
/* Here we will get the physical address of the interrupt handler. */
/* */
/******************************************************************************************************** */
GetExtHandlerAddress:
mflr r11 /* Save our return */
bl GEXbase /* Make a base address */
GEXbase: mflr r3 /* Get address into our base */
addi r3,r3,LOW_ADDR(GotSignal-GEXbase) /* Get the logical address of the 'rupt handler */
mtlr r11 /* Restore LR */
blr
/******************************************************************************************************** */
/* */
/* Here we will get a snapshot of the processor's current signaling state (R3=processor). */
/* */
/******************************************************************************************************** */
ProcessorState:
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */
li r3,kSIGPTargetAddrErr /* CPU number is too big */
bgtlr- cr1 /* Sure are... (Get our address also) */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
add r9,r9,r12 /* Point right at the entry */
lwz r4,MPPICStat(r9) /* Get the status word */
li r3,kSIGPnoErr /* Set no errors */
rlwinm. r4,r4,0,0,0 /* Test for busy status */
beqlr /* Return kSIGPnoErr if not busy */
li r3,kSIGPInterfaceBusyErr /* Otherwise, return busy */
blr /* Return it */
/******************************************************************************************************** */
/* */
/* Here we will try to handle any pending messages (just as if an interruption occurred). */
/* The purpose of this function is to assure the message passing system runs even */
/* though external interrupts are disabled. Lacking a separate physical signalling */
/* class, we have to share the external interrupt signal. Unfortunately, there are */
/* times when disabled loops occur (in spin locks, in the debugger, etc.), and when they */
/* happen, a low level message sent to a processor will not get processed, hence this */
/* function exists to be called from those disabled loops. Since the calls are often */
/* from disabled code, all that can be done is to process any pending *message*. Any */
/* pending notification interruption (referred to throughtout this code as a SIGP */
/* interruption) must remain pending. */
/* */
/******************************************************************************************************** */
RunSIGPRun:
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
mfspr r3,pir /* Get our CPU address */
rlwinm r9,r3,5,23,26 /* Get index into CPU array */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
mflr r11 /* Save the link register */
add r9,r9,r12 /* Point right at our entry */
lwz r3,MPPICPriv(r9) /* Get our privates */
cmplw cr1,r11,r11 /* Make sure IdleWait doesn't try to clear 'rupt request */
oris r3,r3,MPPICXRun>>16 /* Diddle with them and show we entered here */
stw r3,MPPICPriv(r9) /* Put away our privates */
b IdleWait /* Go pretend there was an interrupt... */
/******************************************************************************************************** */
/* */
/* Error return. We only need this when we leave with a reservation. We really SHOULD clear it... */
/* */
/******************************************************************************************************** */
ErrorReturn:
mtlr r11 /* Restore LR */
blr
/******************************************************************************************************** */
/* */
/* Kick the target processor. Note that we won't set the passing bit until we are ready to exit. */
/* The reason for this is that we have the silly, old watchchihuahua board to deal with. Because */
/* we can't just set the interrupt and leave, we gotta wait for it to be seen on the other side. */
/* This means that there could be a timeout and if so, we need to back off the function request else */
/* we'd see busy when they tried to redrive it. We'll have to deal with a tad of spin on the secondary side. */
/* note that this just applies to a primary to secondary function on the old board. */
/* */
/******************************************************************************************************** */
KickAndGo:
la r8,MPPICPU0-MPPIwork(r12) /* Get the primary work area address */
mtlr r11 /* Restore the link register */
cmplw cr0,r8,r9 /* Which is target? primary or secondary? */
mfmsr r11 /* Save off the MSR */
oris r5,r5,MPPICPass>>16 /* Set the passing bit on */
stw r5,MPPICStat(r9) /* Store the pass and let the other processor go on */
beq KickPrimary /* The target is the primary... */
ori r3,r11,0x0010 /* Turn on DDAT bit */
lbz r4,MPPIstatus-MPPIwork(r12) /* Load up the global status byte */
lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the Hammerhead area */
mtmsr r3 /* Turn on DDAT */
isync
andi. r4,r4,MPPI2Pv2 /* Are we on the new or old board? */
li r3,0 /* Set the bit for an interrupt request */
beq KickOld /* Ok, it's the old board... */
sync /* Make sure this is out there */
stb r3,IntReg(r8) /* Set the interruption signal */
eieio
mtmsr r11 /* Set DDAT back to what it was */
isync
li r3,kSIGPnoErr /* Set no errors */
blr /* Leave... */
KickOld: li r4,8 /* Set the number of tries */
KickAgain: mftb r6 /* Stamp the bottom half of time base */
stb r3,IntReg(r8) /* Stick the interrupt */
eieio /* Fence me in */
CheckKick: lbz r10,IntReg(r8) /* Get the interrupt request back again */
mr. r10,r10 /* Yes? Got it? */
bne FinalDelay /* Yeah, do the final delay and then go away... */
mftb r7 /* Get the time again */
sub r7,r7,r6 /* Get time-so-far */
cmplwi cr0,r7,75*TicksPerMic /* Hold it for 75µS (average disable is supposed to be 100µS or so) */
blt+ CheckKick /* Keep waiting the whole time... */
li r10,SecInt /* Set the deassert bit */
mftb r6 /* Stamp start of deassert time */
stb r10,IntReg(r8) /* Deassert the interrupt request */
eieio
DeassertWT: mftb r7 /* Stamp out the time */
sub r7,r7,r6 /* Get elapsed */
cmplwi cr0,r7,16*TicksPerMic /* Hold off 16µS (minimum is 12µS) */
blt+ DeassertWT /* Keep spinning... */
subi r4,r4,1 /* See if we have another retry we can do */
mr. r4,r4 /* Are we there yet? */
blt+ KickAgain /* Retry one more time... */
rlwinm r5,r5,0,2,31 /* Clear busy and passing bits */
rlwinm r5,r5,0,24,15 /* Clear the function request to idle */
mtmsr r11 /* Restore DDAT stuff */
isync
stw r5,MPPICStat(r9) /* Rescind the request */
li r3,kMPPTimeOut /* Set timeout */
blr /* Leave... */
FinalDelay: mftb r6 /* Stamp the start of the final delay */
FinalDelayW:
mftb r7 /* Stamp out the time */
sub r7,r7,r6 /* Get elapsed */
cmplwi cr0,r7,16*TicksPerMic /* Hold off 16µS (minimum is 12µS) */
blt+ FinalDelayW /* Keep spinning... */
mtmsr r11 /* Restore DDAT stuff */
isync
li r3,kSIGPnoErr /* Set no errors */
blr /* Leave... */
KickPrimary:
ori r3,r11,0x0010 /* Turn on the DDAT bit */
lwz r8,MPPIEther-MPPIwork(r12) /* Get the address of the ethernet ROM */
mtmsr r3 /* Turn on DDAT */
isync
li r4,4 /* Get flip count */
sync /* Make sure the status word is out there */
FlipOff: lbz r3,0(r8) /* Reference ethernet ROM to get chip select twiddled */
eieio /* Make sure of this (Hmm, this is chip select, not memory-mapped */
/* storage. Do we even need the eieio?) */
addic. r4,r4,-1 /* Have we flipped them off enough? */
bgt+ FlipOff /* Not yet, they deserve more... */
mtmsr r11 /* Restore DDAT stuff */
isync
li r3,kSIGPnoErr /* Set no errors */
blr /* Return... */
/******************************************************************************************************** */
/* */
/* This is the code for the secondary processor */
/* */
/******************************************************************************************************** */
/* Note that none of this code needs locks because there's kind of a synchronization */
/* shuffle going on. */
/* */
/* First, we need to do a bit of initialization of the processor. */
/* */
CPUInit:
li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */
mtmsr r27 /* Load 'em on in */
isync
lis r28,-32768 /* Turn on machine checks */
/* should be 0x8000 */
ori r28,r28,0xCC84 /* Enable caches, clear them, */
/* disable serial execution and turn BHT on */
sync
mtspr HID0,r28 /* Start the cache clear */
sync
/* */
/* Clear out the TLB. They be garbage after hard reset. */
/* */
li r0,512 /* Get number of TLB entries (FIX THIS) */
li r3,0 /* Start at 0 */
mtctr r0 /* Set the CTR */
purgeTLB: tlbie r3 /* Purge this entry */
addi r3,r3,4096 /* Next page */
bdnz purgeTLB /* Do 'em all... */
sync /* Make sure all TLB purges are done */
tlbsync /* Make sure on other processors also */
sync /* Make sure the TLBSYNC is done */
/* */
/* Clear out the BATs. They are garbage after hard reset. */
/* */
li r3,0 /* Clear a register */
mtspr DBAT0L,r3 /* Clear BAT */
mtspr DBAT0U,r3 /* Clear BAT */
mtspr DBAT1L,r3 /* Clear BAT */
mtspr DBAT1U,r3 /* Clear BAT */
mtspr DBAT2L,r3 /* Clear BAT */
mtspr DBAT2U,r3 /* Clear BAT */
mtspr DBAT3L,r3 /* Clear BAT */
mtspr DBAT3U,r3 /* Clear BAT */
mtspr IBAT0L,r3 /* Clear BAT */
mtspr IBAT0U,r3 /* Clear BAT */
mtspr IBAT1L,r3 /* Clear BAT */
mtspr IBAT1U,r3 /* Clear BAT */
mtspr IBAT2L,r3 /* Clear BAT */
mtspr IBAT2U,r3 /* Clear BAT */
mtspr IBAT3L,r3 /* Clear BAT */
mtspr IBAT3U,r3 /* Clear BAT */
/* */
/* Map 0xF0000000 to 0xFFFFFFFF for I/O/* */
lis r6,0xF000 /* Set RPN to last segment */
ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */
lis r7,0xF000 /* Set RPN to last segment */
ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */
mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */
mtspr DBAT0U,r6 /* Now do the upper DBAT */
sync
li r6,0x1FFF /* Set up upper BAT for 256M, access both */
li r7,0x0012 /* Set up lower BAT for r/w access */
mtspr DBAT1L,r7 /* Set up an initial view of mainstore */
mtspr DBAT1U,r6 /* Now do the upper DBAT */
sync
/* */
/* Clean up SDR and segment registers */
/* */
li r3,0 /* Clear a register */
mtspr SDR1,r3 /* Clear SDR1 */
li r4,0 /* Clear index for segment registers */
lis r5,0x1000 /* Set the segment indexer */
clearSR: mtsrin r3,r4 /* Zero out the SR */
add. r4,r4,r5 /* Point to the next segment */
bne- clearSR /* Keep going until we wrap back to 0 */
lis r5,HIGH_ADDR(EXT(FloatInit)) /* Get top of floating point init value */
ori r5,r5,LOW_ADDR(EXT(FloatInit)) /* Slam bottom */
lfd f0,0(r5) /* Initialize FP0 */
fmr f1,f0 /* Ours in not */
fmr f2,f0 /* to wonder why, */
fmr f3,f0 /* ours is but to */
fmr f4,f0 /* do or die! */
fmr f5,f0
fmr f6,f0
fmr f7,f0
fmr f8,f0
fmr f9,f0
fmr f10,f0
fmr f11,f0
fmr f12,f0
fmr f13,f0
fmr f14,f0
fmr f15,f0
fmr f16,f0
fmr f17,f0
fmr f18,f0
fmr f19,f0
fmr f20,f0
fmr f21,f0
fmr f22,f0
fmr f23,f0
fmr f24,f0
fmr f25,f0
fmr f26,f0
fmr f27,f0
fmr f28,f0
fmr f29,f0
fmr f30,f0
fmr f31,f0
/* */
/* Whew, that was like, work, man! What a cleaning job, I should be neater */
/* when I reset. */
/* */
/* Finally we can get some data DAT turned on and we can reset the interrupt */
/* (which may have been done before we get here) and get into the bring up */
/* handshakes. */
/* */
/* Note that here we need to use the actual V=R addresses for HammerHead */
/* and PCI1 adr. There are no virtual mappings set up on this processor. */
/* We need to switch once the firmware is initialized. Also, we don't know */
/* where our control block is yet. */
/* */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
mfmsr r3 /* Get the MSR */
ori r3,r3,0x0010 /* Turn data DAT on */
mtmsr r3 /* DAT is on (well, almost) */
isync /* Now it is for sure */
lis r8,HammerHead>>16 /* Point to the HammerHead controller */
li r7,SecInt /* Get value to reset */
stb r7,IntReg(r8) /* Reset the interrupt */
eieio /* Fence it off */
/* */
/* Now we can plant and harvest some bits. */
/* */
lwz r6,MPPIlogCPU-MPPIwork(r12) /* Get the logical CPU address to assign */
mfspr r7,pir /* Get the old PIR */
rlwimi r7,r6,0,27,31 /* Copy all of the reserved parts */
mtspr pir,r7 /* Set it */
/* */
/* This little piece of code here determines if we are on the first or second version */
/* of the two processor board. The old one shouldn't ever be shipped (well, maybe by */
/* DayStar) but there are some around here. */
/* */
/* The newer version of the 2P board has a different state machine than the older one. */
/* When we are in the board state we're in now, primary arbitration is turned on while */
/* it is not until the next state in the old board. By checking the our bus address */
/* (WhoAmI) we can tell. */
/* */
lbz r7,WhoAmI(r8) /* Get the current bus master ID */
andi. r7,r7,PriCPU /* Do we think we're the primary? */
beq On2Pv1 /* No, that means we're on the old 2P board */
lbz r7,MPPIstatus-MPPIwork(r12) /* Get the status byte */
ori r7,r7,MPPI2Pv2 /* Show we're on the new board */
stb r7,MPPIstatus-MPPIwork(r12) /* Set the board version */
On2Pv1: rlwinm r9,r6,5,23,26 /* Get index into the CPU specific area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Index to processor */
add r9,r9,r12 /* Get a base for our CPU specific area */
oris r6,r6,((MPPICBusy+MPPICOnline+MPPICStop)>>16)&0x0000FFFF /* Set CPU busy, online, stopped, */
/* and busy set by himself */
stw r6,MPPICStat(r9) /* Save the whole status word */
li r4,0x80 /* Get beginnings of a CPU address mask */
lhz r11,MPPIinst-MPPIwork(r12) /* Get the installed and online status flags */
srw r4,r4,r6 /* Make a mask */
rlwimi r4,r4,8,16,23 /* Double up the mask for both flags */
or r11,r11,r4 /* Set that we are installed and online */
sync /* Make sure the main processor sees the rest of the stuff */
sth r11,MPPIinst-MPPIwork(r12) /* We're almost done, just need to set the TB */
lis r5,PCI1AdrReg>>16 /* Point to the PCI1 address register */
li r4,0 /* Clear this out */
stw r4,0(r5) /* Set PCI register to 0 to show we're ready for TB sync */
eieio /* Fence it off */
Wait4TB: lwz r7,0(r5) /* Get the PCI1 reg to see if time to set time */
mr. r7,r7 /* Is it ready yet? */
beq Wait4TB /* Nope, wait for it... */
isync /* No peeking... */
lwz r3,MPPITBsync-MPPIwork(r12) /* Get the high word of TB */
lwz r4,MPPITBsync+4-MPPIwork(r12) /* Get the low word */
/* Note that we need no TB magic here 'cause they ain't running */
mttbu r3 /* Set the high part */
mttbl r4 /* Set the low part */
rlwinm r6,r6,0,2,31 /* Clear the busy bit and passed */
stw r6,MPPICStat(r9) /* Store the status word */
sync /* Make sure all is right with the world */
li r3,0 /* Set the init done signal */
stw r3,0(r5) /* Feed the dog and let him out */
sync /* Make sure this is pushed on out */
li r27,0x3040 /* Make MSR the way we likes it */
mtmsr r27 /* Load 'em on in */
isync
/* */
/* Jump on to the idle wait loop. We're online and ready, but we're */
/* still in the reset state. We need to wait until we see a start signal. */
/* */
/* Note that the idle loop expects R9 to be our CPU-specific work area/* */
cmplw cr1,r11,r12 /* Make sure IdleWait knows to clear 'rupt request */
b IdleWait
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Here is the interruption handler. */
/* */
/* What we'll do here is to get our registers into a standard state and figure out which */
/* which processor we are on. The processors have pretty much the same code. The primary */
/* will reset the the secondary to primary interruption bit and the secondary will reset the SecInt */
/* flags. */
/* */
/* The primary to secondary interrupt is an exception interruption contolled by a bit in the */
/* Hammerhead IntReg. The only bit in here is SecInt which is active low. Writing a 0 into the */
/* bit (bit 0) yanks on the external pin on the secondary. Note that it is the only external */
/* connected on the secondary. SecInt must be set to 1 to clear the interruption. On the old */
/* 2P board, asserting the external interrupt causes a watchdog timer to start which expires unless */
/* the interrupt request is withdrawn. On a 180Mhz system the time to expire is about 256µS, */
/* not very long. So, what we need to do is to time the assertion and if it has not been reset */
/* reset, do it ourself. Unfortunatelty we need to keep it deasserted for at least 12µS or the */
/* watchdog will not stop. This leads to another problem: even if the secondary processor sees */
/* the interrupt and deasserts the request itself, we cannot reassert before the 12µS limit, */
/* else havoc will be wrought. We just gotta make sure. */
/* */
/* So, the secondary to primary interrupt is megafunky. The mother board is wired with the */
/* MACE ethernet chip's chip-select pin wired to Grand Centeral's external interrrupt #10 pin. */
/* This causes a transient interrupt whenever MACE is diddled. GC latches the interrupt into the */
/* events register where we can see it and clear it. */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
GotSignal: mfspr r9,pir /* Get our processor ID */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */
rlwinm r9,r9,5,23,26 /* Clean this up */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */
la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */
mflr r11 /* Save our return */
add r9,r9,r12 /* Point right at the entry */
/* We'll come in here if we're stopped and found the 'rupt via polling */
/* or we were kicked off by the PollSIGP call. We need */
/* to wipe out the interrupt request no matter how we got here. */
SimRupt: mfmsr r4 /* Get the MSR */
la r8,MPPICPU0-MPPIwork(r12) /* Get address of main processor's work area */
ori r5,r4,0x0010 /* Turn on the DDAT bit */
cmplw cr0,r8,r9 /* Are we on the main? */
cmplw cr1,r4,r4 /* Set CR1 to indicate we've cleared any 'rupts */
bne SecondarySig /* Go if we are not on main processor... */
/* */
/* Handle the secondary to primary signal */
/* */
PrimarySig:
lwz r8,MPPIGrandC-MPPIwork(r12) /* Get the address of the Grand Central area base */
mtmsr r5 /* Turn on DDAT */
isync /* Now don't be usin' dem speculative executions */
li r7,EventsReg /* Get address of the interrupt events register */
lwbrx r6,r7,r8 /* Grab the interruption events */
lis r5,0x4000 /* Get the mask for the Ext10 pin */
and. r0,r6,r5 /* See if our bit is on */
li r7,ClearReg /* Point to the interruption clear register */
beq+ SkpClr /* Skip the clear 'cause it's supposed to be soooo slow... */
stwbrx r5,r7,r8 /* Reset the interrupt latch */
eieio /* Fence off the last 'rupt */
SkpClr: mtmsr r4 /* Set MSR to entry state */
isync /* Make sure we ain't gunked up no future storage references */
bne+ IdleWait /* Go join up and decode the function... */
mtlr r11 /* Restore return address */
andc. r0,r6,r5 /* Any other bits on? */
li r3,kMPVainInterrupt /* Assume we got nothing */
beqlr /* We got nothing, tell 'em to eat 'rupt... */
li r3,kMPIOInterruptPending /* Tell them to process an I/O 'rupt */
blr /* Ignore the interrupt... */
/* */
/* Handle the primary to secondary signal */
/* */
SecondarySig:
lwz r3,MPPICStat(r9) /* Pick up our status word */
lis r8,HammerHead>>16 /* Get the address of the hammerhead (used during INIT on non-main processor) */
rlwinm. r3,r3,0,3,3 /* Check if we are already "in-the-know" (all started up) */
beq- UseAltAddr /* Nope, use hardcoded Hammerhead address */
lwz r8,MPPIHammer-MPPIwork(r12) /* Get the kernel's HammerHead area */
UseAltAddr: mtmsr r5 /* Turn on DDAT */
isync /* Now don't be usin' dem speculative executions */
li r0,SecInt /* Get the Secondary interrupt bit */
stb r0,IntReg(r8) /* Reset the interrupt request */
mtmsr r4 /* Set MSR to entry state */
eieio /* Fence me in */
isync /* Make sure we ain't gunked up no future storage references */
b IdleWait /* Go decode this request... */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* This is the idle wait. */
/* */
/* We're stuck in here so long as we are stopped or reset. */
/* All functions except for "start" pass back through here. Start is weird because */
/* it is an initial thing, i.e., we can't have gotten here via any kind of exception, */
/* so there is no state to restore. The "started" code is expected to require no know */
/* state and will take care of all initialization/fixup required. */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
BadRuptState: /* We don't do anything special yet for a bad state, just eat request */
KillBusy: rlwinm r3, r3, 0, 2, 31 /* Remove the message pending flags. */
rlwinm r3, r3, 0, 24, 16 /* Set the function to idle. */
stw r3,MPPICStat(r9) /* Update/unlock the status word. */
ReenterWait: cmplwi cr1,r9,0 /* Turn off the 'rupt cleared flag */
IdleWait: lis r4,MPPICBusy>>16 /* Get busy status */
SpinIdle:
lwz r3,MPPICStat(r9) /* Pick up our status word */
and. r5,r3,r4 /* Isolate the busy bit */
lis r6,MPPICPass>>16 /* Get the passed busy flag */
bne TooBusy /* Work, work, work, that's all we do is work... */
rlwinm. r5,r3,0,4,4 /* See if we are stopped */
lwz r8,MPPICPriv(r9) /* Pick up our private flags */
bne- SpinIdle /* Yeah, keep spinning... */
/* */
/* Restore the state and get outta here. Now, we shouldn't be in a reset state and not be stopped, */
/* so we can go ahead and safely return up a level because it exists. If we are reset, no state exists */
/* and we should always be stopped. */
/* */
rlwinm r4, r8, 1, 0, 0 /* Get the explicit run bit, shifted left one. */
rlwinm. r5, r8, 0, 0, 0 /* See if there is a SIGP signal pending */
and r4, r8, r4 /* Turn off the SIGP pending bit if this was not an explicit run */
/* Also the explicit run bit is cleared */
mtlr r11 /* Restore the return point */
li r3,kMPVainInterrupt /* Tell the interrupt handler to ignore the interrupt */
stw r4,MPPICPriv(r9) /* Set that flag back for later */
beqlr /* Time to leave if we ate the 'rupt... */
li r3,kMPSignalPending /* Set that there is a SIGP interruption pending */
blr /* Go away, let our caller handle this thing... QED!!!!!!!!! */
/* */
/* QQQQQ EEEEEEEEEE DDDDDDDDD */
/* QQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */
/* QQQQ QQQQ EEEE DDD DDD */
/* QQQQ QQQQ EEEEEEEEEE DDD DDD */
/* QQQQ Q QQQQ EEEEEEEEEE DDD DDD */
/* QQQQ QQQQQ EEEE DDD DDD */
/* QQQQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */
/* QQQQQ QQQ EEEEEEEEEE DDDDDDDDD */
/* */
/* (I finished here) */
/* */
/* */
/* This is where we decode the function and do what's right. */
/* First we need to check if it's really time to do something. */
/* */
TooBusy: and. r5,r3,r6 /* See if the passed flag is on */
beq SpinIdle /* No, not yet, try the whole smear again... */
beq+ cr1,KeepRupt /* Don't clear 'rupt if we already did (or entered via RunSIGRun) */
lwz r5,MPPICPriv(r9) /* Get the private flags */
rlwinm. r5, r5, 0, 1, 1 /* Did we enter via RunSIGPRun? */
beq SimRupt /* Nope, 's'ok, go clear physical 'rupt... */
KeepRupt:
bl GetOurBase /* Get our address */
GetOurBase: rlwinm r4,r3,26,22,29 /* Get the opcode index * 4 */
mflr r12 /* Get the base address */
la r7,LOW_ADDR(IFuncTable-GetOurBase)(r12) /* Point to the function table */
cmplwi cr0,r4,7*4 /* See if they sent us some bogus junk */
/* Change 7 if we add more functions */
add r7,r7,r4 /* Point right at the entry */
bgt- KillBusy /* Bad request code, reset busy and eat it... */
mtlr r7 /* Set up the LR */
blr /* Go execute the function... */
IFuncTable:
b KillBusy /* This handles the signal in vain... */
b IStart /* This handles the start function */
b IResume /* This handles the resume function */
b IStop /* This handles the stop function */
b ISIGP /* This handles the SIGP function */
b IStatus /* This handles the store status function */
b ITBsync /* This handles the synchronize timer base function */
b IReset /* This handles the reset function */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* Here are the functions handled at interrupt time */
/* */
/******************************************************************************************************** */
/******************************************************************************************************** */
/******************************************************************************************************** */
/* */
/* The Start function. This guy requires that the processor be in the reset and online state. */
/* */
/******************************************************************************************************** */
IStart: lis r4,MPPICOnline>>16 /* Get bits required to be on */
isync /* Make sure we haven't gone past here */
and r6,r3,r4 /* See if they are on */
cmplw cr1,r6,r4 /* Are they all on? */
lwz r4,MPPICParm0(r9) /* Get the physical address of the code to go to */
bne- cr1,BadRuptState /* Some required state bits are off */
rlwinm r3,r3,0,2,31 /* Kill the busy bits */
rlwinm r3,r3,0,24,15 /* Set the function to idle */
oris r3,r3,MPPICReady>>16 /* Set ready state */
rlwinm r3,r3,0,5,3 /* Clear out the stop bit */
mtlr r4 /* Set the LR */
stw r3,MPPICStat(r9) /* Clear out the status flags */
lwz r3,MPPICParm2(r9) /* Get pass-thru parameter */
blrl /* Start up the code... */
/* */
/* The rules for coming back here via BLR are just opposite the normal way: you can trash R0-R3 and */
/* R13-R31, all the CRs/* We only come back here if there is some kind of startup failure so's we can try again later */
/* */
lwz r3,MPPICStat(r9) /* Get back the status word */
cmplw cr1,r4,r4 /* Show that we have already taken care of the 'rupt */
rlwinm r3,r3,0,4,2 /* Reset the ready bit */
b KillBusy /* Back into the fold... */
/******************************************************************************************************** */
/* */
/* The Resume function. This guy requires that the processor be online and ready. */
/* */
/******************************************************************************************************** */
IResume: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */
and r6,r3,r4 /* See if they are on */
cmplw cr0,r6,r4 /* Are they all on? */
bne- BadRuptState /* Some required off state bits are on */
rlwinm r3,r3,0,5,3 /* Clear out the stop bit */
b KillBusy /* Get going... */
/******************************************************************************************************** */
/* */
/* The Stop function. All we care about here is that the guy is online. */
/* */
/******************************************************************************************************** */
IStop: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */
and. r6,r3,r4 /* See if we are online */
beq- BadRuptState /* Some required off state bits are on */
oris r3,r3,MPPICStop>>16 /* Set the stop bit */
b KillBusy /* Get stopped... */
/******************************************************************************************************** */
/* */
/* The SIGP function. All we care about here is that the guy is online. */
/* */
/******************************************************************************************************** */
ISIGP: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */
and r6,r3,r4 /* See if they are on */
lwz r7,MPPICPriv(r9) /* Get the private flags */
cmplw cr0,r6,r4 /* Are they all on? */
oris r6,r7,(MPPICSigp>>16)&0x0000FFFF /* Set the SIGP pending bit */
bne- BadRuptState /* Some required off state bits are on */
lwz r4,MPPICParm0(r9) /* Get the SIGP parameter */
stw r6,MPPICPriv(r9) /* Stick the pending bit back */
stw r4,MPPICParm0BU(r9) /* Back up parm 0 so it is safe once we unlock */
b KillBusy /* Get stopped... */
/******************************************************************************************************** */
/* */
/* The store status function. This guy requires that the processor be in the stopped state. */
/* */
/******************************************************************************************************** */
IStatus: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */
and. r6,r3,r4 /* See if we are online */
isync /* Make sure we havn't gone past here */
beq- BadRuptState /* Some required off state bits are on */
lwz r4,MPPICParm0(r9) /* Get the status area physical address */
rlwinm. r6,r3,0,3,3 /* Test processor ready */
beq INotReady /* Not ready, don't assume valid exception save area */
bl StoreStatus /* Go store off all the registers 'n' stuff */
b KillBusy /* All done... */
INotReady:
lis r7,0xDEAD /* Get 0xDEAD + 1 */
ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */
stw r7,CSAgpr+(0*4)(r4) /* Store invalid R0 */
stw r7,CSAgpr+(1*4)(r4) /* Store invalid R1 */
stw r7,CSAgpr+(2*4)(r4) /* Store invalid R2 */
stw r7,CSAgpr+(3*4)(r4) /* Store invalid R3 */
stw r7,CSAgpr+(4*4)(r4) /* Store invalid R4 */
stw r7,CSAgpr+(5*4)(r4) /* Store invalid R5 */
stw r7,CSAgpr+(6*4)(r4) /* Store invalid R6 */
stw r7,CSAgpr+(7*4)(r4) /* Store invalid R7 */
stw r7,CSAgpr+(8*4)(r4) /* Store invalid R8 */
stw r7,CSAgpr+(9*4)(r4) /* Store invalid R9 */
stw r7,CSAgpr+(10*4)(r4) /* Store invalid R10 */
stw r7,CSAgpr+(11*4)(r4) /* Store invalid R11 */
stw r7,CSAgpr+(12*4)(r4) /* Store invalid R12 */
stw r13,CSAgpr+(13*4)(r4) /* Save general registers */
stw r14,CSAgpr+(14*4)(r4) /* Save general registers */
stw r15,CSAgpr+(15*4)(r4) /* Save general registers */
stw r16,CSAgpr+(16*4)(r4) /* Save general registers */
stw r17,CSAgpr+(17*4)(r4) /* Save general registers */
stw r18,CSAgpr+(18*4)(r4) /* Save general registers */
stw r19,CSAgpr+(19*4)(r4) /* Save general registers */
stw r20,CSAgpr+(20*4)(r4) /* Save general registers */
stw r21,CSAgpr+(21*4)(r4) /* Save general registers */
stw r22,CSAgpr+(22*4)(r4) /* Save general registers */
stw r23,CSAgpr+(23*4)(r4) /* Save general registers */
stw r24,CSAgpr+(24*4)(r4) /* Save general registers */
stw r25,CSAgpr+(25*4)(r4) /* Save general registers */
stw r26,CSAgpr+(26*4)(r4) /* Save general registers */
stw r27,CSAgpr+(27*4)(r4) /* Save general registers */
stw r28,CSAgpr+(28*4)(r4) /* Save general registers */
stw r29,CSAgpr+(29*4)(r4) /* Save general registers */
stw r30,CSAgpr+(30*4)(r4) /* Save general registers */
stw r31,CSAgpr+(31*4)(r4) /* Save general registers */
bl StoreLiveStatus
b KillBusy
/* */
/* Save the whole status. Lot's of busy work. */
/* Anything marked unclean is of the devil and should be shunned. Actually, it depends upon */
/* knowledge of firmware control areas and is no good for a plug in. But, we've sacrificed the */
/* white ram and are standing within a circle made of his skin, so we can dance with the devil */
/* safely. */
/* */
StoreStatus:
mfspr r10,sprg0 /* Get the pointer to the exception save area (unclean) */
lwz r5,saver0(r13) /* Get R0 (unclean) */
lwz r6,saver1(r13) /* Get R1 (unclean) */
lwz r7,saver2(r13) /* Get R2 (unclean) */
stw r5,CSAgpr+(0*4)(r4) /* Save R0 */
stw r6,CSAgpr+(1*4)(r4) /* Save R1 */
stw r7,CSAgpr+(2*4)(r4) /* Save R2 */
lwz r5,saver3(r13) /* Get R3 (unclean) */
lwz r6,saver4(r13) /* Get R4 (unclean) */
lwz r7,saver5(r13) /* Get R5 (unclean) */
stw r5,CSAgpr+(3*4)(r4) /* Save R3 */
stw r6,CSAgpr+(4*4)(r4) /* Save R4 */
stw r7,CSAgpr+(5*4)(r4) /* Save R5 */
lwz r5,saver6(r13) /* Get R6 (unclean) */
lwz r6,saver7(r13) /* Get R7 (unclean) */
lwz r7,saver8(r13) /* Get R8 (unclean) */
stw r5,CSAgpr+(6*4)(r4) /* Save R6 */
stw r6,CSAgpr+(7*4)(r4) /* Save R7 */
stw r7,CSAgpr+(8*4)(r4) /* Save R8 */
lwz r5,saver9(r13) /* Get R9 (unclean) */
lwz r6,saver10(r13) /* Get R10 (unclean) */
lwz r7,saver11(r13) /* Get R11 (unclean) */
stw r5,CSAgpr+(9*4)(r4) /* Save R9 */
stw r6,CSAgpr+(10*4)(r4) /* Save R10 */
lwz r5,saver12(r13) /* Get R12 (unclean) */
stw r7,CSAgpr+(11*4)(r4) /* Save R11 */
stw r5,CSAgpr+(12*4)(r4) /* Save R12 */
lwz r5,saver13(r13) /* Get R13 (unclean) */
lwz r6,saver14(r13) /* Get R14 (unclean) */
lwz r7,saver15(r13) /* Get R15 (unclean) */
stw r5,CSAgpr+(13*4)(r4) /* Save R13 */
stw r6,CSAgpr+(14*4)(r4) /* Save R14 */
stw r7,CSAgpr+(15*4)(r4) /* Save R15 */
lwz r5,saver16(r13) /* Get R16 (unclean) */
lwz r6,saver17(r13) /* Get R17 (unclean) */
lwz r7,saver18(r13) /* Get R18 (unclean) */
stw r5,CSAgpr+(16*4)(r4) /* Save R16 */
stw r6,CSAgpr+(17*4)(r4) /* Save R17 */
stw r7,CSAgpr+(18*4)(r4) /* Save R18 */
lwz r5,saver19(r13) /* Get R19 (unclean) */
lwz r6,saver20(r13) /* Get R20 (unclean) */
lwz r7,saver21(r13) /* Get R21 (unclean) */
stw r5,CSAgpr+(19*4)(r4) /* Save R19 */
stw r6,CSAgpr+(20*4)(r4) /* Save R20 */
stw r7,CSAgpr+(21*4)(r4) /* Save R21 */
lwz r5,saver22(r13) /* Get R22 (unclean) */
lwz r6,saver23(r13) /* Get R23 (unclean) */
lwz r7,saver24(r13) /* Get R24 (unclean) */
stw r5,CSAgpr+(22*4)(r4) /* Save R22 */
stw r6,CSAgpr+(23*4)(r4) /* Save R23*/
stw r7,CSAgpr+(24*4)(r4) /* Save R24 */
lwz r5,saver25(r13) /* Get R25 (unclean) */
lwz r6,saver26(r13) /* Get R26 (unclean) */
lwz r7,saver27(r13) /* Get R27 (unclean) */
stw r5,CSAgpr+(25*4)(r4) /* Save R25 */
stw r6,CSAgpr+(26*4)(r4) /* Save R26 */
stw r7,CSAgpr+(27*4)(r4) /* Save R27 */
lwz r5,saver28(r13) /* Get R28 (unclean) */
lwz r6,saver29(r13) /* Get R29 (unclean) */
lwz r7,saver30(r13) /* Get R30 (unclean) */
stw r5,CSAgpr+(28*4)(r4) /* Save R28 */
lwz r5,saver31(r13) /* Get R31(unclean) */
stw r6,CSAgpr+(29*4)(r4) /* Save R29 */
stw r7,CSAgpr+(30*4)(r4) /* Save R30 */
stw r5,CSAgpr+(31*4)(r4) /* Save R31 */
StoreLiveStatus:
mfmsr r5 /* Get the current MSR */
ori r6,r5,0x2000 /* Turn on floating point instructions */
mtmsr r6 /* Turn them on */
isync /* Make sure they're on */
stfd f0,CSAfpr+(0*8)(r4) /* Save floating point registers */
stfd f1,CSAfpr+(1*8)(r4) /* Save floating point registers */
stfd f2,CSAfpr+(2*8)(r4) /* Save floating point registers */
stfd f3,CSAfpr+(3*8)(r4) /* Save floating point registers */
stfd f4,CSAfpr+(4*8)(r4) /* Save floating point registers */
stfd f5,CSAfpr+(5*8)(r4) /* Save floating point registers */
stfd f6,CSAfpr+(6*8)(r4) /* Save floating point registers */
stfd f7,CSAfpr+(7*8)(r4) /* Save floating point registers */
stfd f8,CSAfpr+(8*8)(r4) /* Save floating point registers */
stfd f9,CSAfpr+(9*8)(r4) /* Save floating point registers */
stfd f10,CSAfpr+(10*8)(r4) /* Save floating point registers */
stfd f11,CSAfpr+(11*8)(r4) /* Save floating point registers */
stfd f12,CSAfpr+(12*8)(r4) /* Save floating point registers */
stfd f13,CSAfpr+(13*8)(r4) /* Save floating point registers */
stfd f14,CSAfpr+(14*8)(r4) /* Save floating point registers */
stfd f15,CSAfpr+(15*8)(r4) /* Save floating point registers */
stfd f16,CSAfpr+(16*8)(r4) /* Save floating point registers */
stfd f17,CSAfpr+(17*8)(r4) /* Save floating point registers */
stfd f18,CSAfpr+(18*8)(r4) /* Save floating point registers */
stfd f19,CSAfpr+(19*8)(r4) /* Save floating point registers */
stfd f20,CSAfpr+(20*8)(r4) /* Save floating point registers */
stfd f21,CSAfpr+(21*8)(r4) /* Save floating point registers */
stfd f22,CSAfpr+(22*8)(r4) /* Save floating point registers */
stfd f23,CSAfpr+(23*8)(r4) /* Save floating point registers */
stfd f24,CSAfpr+(24*8)(r4) /* Save floating point registers */
stfd f25,CSAfpr+(25*8)(r4) /* Save floating point registers */
stfd f26,CSAfpr+(26*8)(r4) /* Save floating point registers */
stfd f27,CSAfpr+(27*8)(r4) /* Save floating point registers */
stfd f28,CSAfpr+(28*8)(r4) /* Save floating point registers */
stfd f29,CSAfpr+(29*8)(r4) /* Save floating point registers */
stfd f30,CSAfpr+(30*8)(r4) /* Save floating point registers */
stfd f31,CSAfpr+(31*8)(r4) /* Save floating point registers */
mffs f1 /* Get the FPSCR */
stfd f1,CSAfpscr-4(r4) /* Save the whole thing (we'll overlay the first half with CR later) */
lfd f1,CSAfpr+(1*4)(r4) /* Restore F1 */
mtmsr r5 /* Put the floating point back to what it was before */
isync /* Wait for it */
lwz r6,savecr(r13) /* Get the old CR (unclean) */
stw r6,CSAcr(r4) /* Save the CR */
mfxer r6 /* Get the XER */
stw r6,CSAxer(r4) /* Save the XER */
lwz r6,savelr(r13) /* Get the old LR (unclean) */
stw r6,CSAlr(r4) /* Save the LR */
mfctr r6 /* Get the CTR */
stw r6,CSActr(r4) /* Save the CTR */
STtbase: mftbu r5 /* Get the upper timebase */
mftb r6 /* Get the lower */
mftbu r7 /* Get the top again */
cmplw cr0,r5,r7 /* Did it tick? */
bne- STtbase /* Yeah, do it again... */
mfdec r7 /* Get the decrimenter (make it at about the same time as the TB) */
stw r7,CSAdec(r4) /* Save the decrimenter */
stw r5,CSAtbu(r4) /* Stash the top part */
stw r6,CSAtbl(r4) /* Stash the lower part */
lwz r5,savesrr1(r13) /* SRR1 at exception is as close as we get to the MSR (unclean) */
lwz r6,savesrr0(r13) /* Get SRR0 also */
stw r5,CSAmsr(r4) /* Save the MSR */
stw r6,CSApc(r4) /* Save the PC */
stw r5,CSAsrr1(r4) /* Set SRR1 also */
stw r6,CSAsrr0(r4) /* Save SRR0 */
mfpvr r5 /* Get the PVR */
stw r5,CSApvr(r4) /* Save the PVR */
mfspr r5,pir /* Get the PIR */
stw r5,CSApir(r4) /* Save the PIR */
mfspr r5,ibat0u /* Get the upper IBAT0 */
mfspr r6,ibat0l /* Get the lower IBAT0 */
stw r5,CSAibat+(0*8+0)(r4) /* Save the upper IBAT0 */
stw r6,CSAibat+(0*8+4)(r4) /* Save the upper IBAT0 */
mfspr r5,ibat1u /* Get the upper IBAT1 */
mfspr r6,ibat1l /* Get the lower IBAT1 */
stw r5,CSAibat+(1*8+0)(r4) /* Save the upper IBAT1 */
stw r6,CSAibat+(1*8+4)(r4) /* Save the upper IBAT1 */
mfspr r5,ibat2u /* Get the upper IBAT2 */
mfspr r6,ibat2l /* Get the lower IBAT2 */
stw r5,CSAibat+(2*8+0)(r4) /* Save the upper IBAT2 */
stw r6,CSAibat+(2*8+4)(r4) /* Save the upper IBAT2 */
mfspr r5,ibat3u /* Get the upper IBAT3 */
mfspr r6,ibat3l /* Get the lower IBAT3 */
stw r5,CSAibat+(3*8+0)(r4) /* Save the upper IBAT3 */
stw r6,CSAibat+(3*8+4)(r4) /* Save the upper IBAT3 */
mfspr r5,dbat0u /* Get the upper DBAT0 */
mfspr r6,dbat0l /* Get the lower DBAT0 */
stw r5,CSAdbat+(0*8+0)(r4) /* Save the upper DBAT0 */
stw r6,CSAdbat+(0*8+4)(r4) /* Save the upper DBAT0 */
mfspr r5,dbat1u /* Get the upper DBAT1 */
mfspr r6,dbat1l /* Get the lower DBAT1 */
stw r5,CSAdbat+(1*8+0)(r4) /* Save the upper DBAT1 */
stw r6,CSAdbat+(1*8+4)(r4) /* Save the upper DBAT1 */
mfspr r5,dbat2u /* Get the upper DBAT2 */
mfspr r6,dbat2l /* Get the lower DBAT2 */
stw r5,CSAdbat+(2*8+0)(r4) /* Save the upper DBAT2 */
stw r6,CSAdbat+(2*8+4)(r4) /* Save the upper DBAT2 */
mfspr r5,dbat3u /* Get the upper DBAT3 */
mfspr r6,dbat3l /* Get the lower DBAT3 */
stw r5,CSAdbat+(3*8+0)(r4) /* Save the upper DBAT3 */
stw r6,CSAdbat+(3*8+4)(r4) /* Save the upper DBAT3 */
mfsdr1 r5 /* Get the SDR1 */
stw r5,CSAsdr1(r4) /* Save the SDR1 */
mfsr r5,sr0 /* Get SR 0 */
mfsr r6,sr1 /* Get SR 1 */
mfsr r7,sr2 /* Get SR 2 */
stw r5,CSAsr+(0*4)(r4) /* Save SR 0 */
stw r6,CSAsr+(1*4)(r4) /* Save SR 1 */
mfsr r5,sr3 /* Get SR 3 */
mfsr r6,sr4 /* Get SR 4 */
stw r7,CSAsr+(2*4)(r4) /* Save SR 2 */
mfsr r7,sr5 /* Get SR 5 */
stw r5,CSAsr+(3*4)(r4) /* Save SR 3 */
stw r6,CSAsr+(4*4)(r4) /* Save SR 4 */
mfsr r5,sr6 /* Get SR 6 */
mfsr r6,sr7 /* Get SR 7 */
stw r7,CSAsr+(5*4)(r4) /* Save SR 5 */
mfsr r7,sr8 /* Get SR 8 */
stw r5,CSAsr+(6*4)(r4) /* Save SR 6 */
stw r6,CSAsr+(7*4)(r4) /* Save SR 7 */
mfsr r5,sr9 /* Get SR 9 */
mfsr r6,sr10 /* Get SR 11 */
stw r7,CSAsr+(8*4)(r4) /* Save SR 8 */
mfsr r7,sr11 /* Get SR 11 */
stw r5,CSAsr+(9*4)(r4) /* Save SR 9 */
stw r6,CSAsr+(10*4)(r4) /* Save SR 10 */
mfsr r5,sr12 /* Get SR 12 */
mfsr r6,sr13 /* Get SR 13 */
stw r7,CSAsr+(11*4)(r4) /* Save SR 11 */
mfsr r7,sr14 /* Get SR 14 */
stw r5,CSAsr+(12*4)(r4) /* Save SR 12 */
stw r6,CSAsr+(13*4)(r4) /* Save SR 13 */
mfsr r5,sr15 /* Get SR 15 */
stw r7,CSAsr+(14*4)(r4) /* Save SR 14 */
stw r5,CSAsr+(15*4)(r4) /* Save SR 15 */
mfdar r6 /* Get the DAR */
stw r6,CSAdar(r4) /* Save it */
mfdsisr r5 /* Get the DSISR */
stw r5,CSAdsisr(r4) /* Save it */
stw r10,CSAsprg+(1*4)(r4) /* Save SPRG1 */
mfspr r7,sprg0 /* Get SPRG0 */
mfspr r6,sprg2 /* Get SPRG2 */
stw r7,CSAsprg+(0*4)(r4) /* Save SPRG0 */
mfspr r5,sprg3 /* Get SPRG3 */
stw r6,CSAsprg+(2*4)(r4) /* Save SPRG2 */
stw r5,CSAsprg+(3*4)(r4) /* Save SPRG4 */
mfspr r6,1013 /* Get the DABR */
mfspr r7,1010 /* Get the IABR */
stw r6,CSAdabr(r4) /* Save the DABR */
stw r7,CSAiabr(r4) /* Save the IABR */
mfspr r5,282 /* Get the EAR */
stw r5,CSAear(r4) /* Save the EAR */
lis r7,0xDEAD /* Get 0xDEAD */
ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */
mfpvr r5 /* Get the processor type */
rlwinm r5,r5,16,16,31 /* Isolate the processor */
cmplwi cr1,r5,4 /* Set CR1_EQ if this is a plain 604, something else if it's a 604E */
mfspr r6,hid0 /* Get HID0 */
mr r5,r7 /* Assume 604 */
beq cr1,NoHID1 /* It is... */
mfspr r5,hid1 /* Get the HID1 */
NoHID1: stw r6,CSAhid+(0*4)(r4) /* Save HID0 */
stw r5,CSAhid+(1*4)(r4) /* Save HID1 */
stw r7,CSAhid+(2*4)(r4) /* Save HID2 */
stw r7,CSAhid+(3*4)(r4) /* Save HID3 */
stw r7,CSAhid+(4*4)(r4) /* Save HID4 */
stw r7,CSAhid+(5*4)(r4) /* Save HID5 */
stw r7,CSAhid+(6*4)(r4) /* Save HID6 */
stw r7,CSAhid+(7*4)(r4) /* Save HID7 */
stw r7,CSAhid+(8*4)(r4) /* Save HID8 */
stw r7,CSAhid+(9*4)(r4) /* Save HID9 */
stw r7,CSAhid+(10*4)(r4) /* Save HID10 */
stw r7,CSAhid+(11*4)(r4) /* Save HID11 */
stw r7,CSAhid+(12*4)(r4) /* Save HID12 */
stw r7,CSAhid+(13*4)(r4) /* Save HID13 */
stw r7,CSAhid+(14*4)(r4) /* Save HID14 */
stw r7,CSAhid+(15*4)(r4) /* Save HID15 */
mfspr r6,952 /* Get MMCR0 */
mr r5,r7 /* Assume 604 */
beq NoMMCR1 /* It is... */
mfspr r5,956 /* Get the MMCR1 */
NoMMCR1: stw r6,CSAmmcr+(0*4)(r4) /* Save MMCR0 */
stw r5,CSAmmcr+(1*4)(r4) /* Save MMCR1 */
mfspr r6,953 /* Get PMC1 */
mfspr r5,954 /* Get PMC2 */
stw r6,CSApmc+(0*4)(r4) /* Save PMC1 */
stw r5,CSApmc+(1*4)(r4) /* Save PMC2 */
mr r6,r7 /* Assume 604 */
mr r5,r7 /* Assume 604 */
beq NoPMC3 /* Yeah... */
mfspr r6,957 /* Get the PMC3 for a 604E */
mfspr r5,958 /* Get the PMC4 for a 604E */
NoPMC3: stw r6,CSApmc+(2*4)(r4) /* Save PMC3 */
stw r5,CSApmc+(3*4)(r4) /* Save PMC4 */
mfspr r6,955 /* Get SIA */
mfspr r5,959 /* Get SDA */
stw r6,CSAsia(r4) /* Save the SIA */
stw r5,CSAsda(r4) /* Save the SDA */
stw r7,CSAmq(r4) /* There is no MQ on either the 604 or 604E */
lwz r6,MPPICStat(r9) /* Get the status of this processor */
lis r10,MPPICReady>>16 /* Get the flag for reset or not */
li r5,kSIGPResetState /* Assume we're operating */
and. r0,r6,r10 /* See if the ready bit is set */
lis r10,MPPICStop>>16 /* Get the flag for stopped or not */
beq SetStateInf /* Go set that we are reset... */
and. r0,r6,r10 /* Are we stopped? */
li r5,kSIGPStoppedState /* Assume we area */
bne SetStateInf /* We are, go set it... */
li r5,kSIGPOperatingState /* Not stopped, so we're going */
SetStateInf: stb r5,CSAstate(r4) /* Set the state byte */
li r0,1 /* Set the truth */
sync /* Make sure it's stored */
stb r0,CSAregsAreValid(r4) /* Set that the status is valid */
blr /* We're done here... */
/******************************************************************************************************** */
/* */
/* The synchronize time base function. No state requirements for this one. */
/* */
/******************************************************************************************************** */
ITBsync: /* This handles the synchronize time base function */
lis r12,HIGH_ADDR(MPPIwork) /* Get the top of work area */
li r0,MPPICfTBsy1 /* Get the flag for TB sync state 1 */
li r7,0 /* Get a 0 */
ori r12,r12,LOW_ADDR(MPPIwork) /* Get low part of work area */
mttbl r7 /* Clear the bottom of the TB so's there's noupper ticks */
mttbu r7 /* Clear the top part, just 'cause I wanna */
sync /* Make sure all is saved */
stb r0,MPPICStat+2(r9) /* Tell the main dude to tell us the time */
isync /* Make sure we don't go nowhere's */
/* */
/* Remember that the sync'ing processor insures that the TB won't tick the high part for at least */
/* 16k ticks. That should be way longer than we need for the whole process here */
/* */
WaitTBLower: lwz r5,MPPITBsync+4-MPPIwork(r12) /* Get the lower part of the TB */
mttbl r5 /* Put it in just in case it's set now */
mr. r5,r5 /* Was it actually? */
beq+ WaitTBLower /* Nope, go check again... */
lwz r4,MPPITBsync-MPPIwork(r12) /* Get the high order part */
mttbu r4 /* Set the top half also */
stw r7,MPPITBsync+4-MPPIwork(r12) /* Tell 'em we've got it */
sync
li r4,0 /* Clear this */
la r5,MPPISncFght-32-MPPIwork(r12) /* Point to the squared circle (our corner) */
b TB1stPnch /* Go take the first punch... */
TBSargue:
dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */
sync /* *** Fix cache coherency (data integrity) HW bug *** */
lwz r6,0(r5) /* Listen for the procecution's argument */
mr. r6,r6 /* See if they are done */
beq+ TBSargue /* Nope, still going... */
TB1stPnch: mftb r7 /* They're done, time for rebuttal */
stw r7,32(r5) /* Make rebuttle */
addi r4,r4,1 /* Count rounds */
cmplwi cr0,r4,10 /* See if we've gone 9 more rounds */
addi r5,r5,64 /* Point to the next round areas */
blt+ TBSargue /* Not yet, come out of your corners fighting... */
/* */
/* We'll set the latest-up-to-datest from the other processor now */
/* */
TBSetTB:
dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */
sync /* *** Fix cache coherency (data integrity) HW bug *** */
lwz r6,0(r5) /* Listen for the procecution's argument */
mttbl r6 /* Set it just in case it's ok */
mr. r6,r6 /* See if they are done */
beq+ TBSetTB /* Nope, still going... */
/* */
/* Get average duration for each processor. We skip the first pass on the asumption */
/* that the caches were not warmed up and it would take longer. In proctice this */
/* is what was seen. */
/* */
mr r0,r11 /* Move return address to a safe register */
li r4,0 /* Clear a counter */
li r3,0 /* Clear accumulator for duration */
li r10,0 /* Clear start time accumulator top half */
li r11,0 /* Clear start time accumulator bottom half */
li r1,0 /* Clear start time accumulator top half */
li r2,0 /* Clear start time accumulator bottom half */
li r10,0 /* Clear accumulator for durations */
la r5,MPPISncFght+64-MPPIwork(r12) /* Get second round start time address */
TBSaccumU: lwz r6,0(r5) /* Get start time */
lwz r11,32(r5) /* Get the other processor's start time */
lwz r7,64(r5) /* Get end time */
lwz r8,96(r5) /* Other proc's end time */
sub r7,r7,r6 /* Get duration */
sub r8,r8,r11 /* Get other side's duration */
addi r4,r4,1 /* Count arguments */
add r3,r3,r7 /* Accumulate durations */
add r2,r2,r7 /* Accumulate other side's durations */
cmplwi cr0,r4,8 /* Have we gotten them all yet? */
addi r5,r5,64 /* Step to the next argument */
blt+ TBSaccumU /* We're not done yet... */
add r7,r2,r3 /* Sum the two differences */
addi r7,r7,0x10 /* Round up */
rlwinm r7,r7,27,5,31 /* Get the average difference divided in half */
mftb r8 /* Get the time now */
add r8,r8,r7 /* Slide the window */
mttbl r8 /* Set the time */
stw r12,MPPITBsync+4-MPPIwork(r12) /* Show that we are done */
lwz r3,MPPICStat(r9) /* Get back our status */
mr r11,r0 /* Restore the return register */
b KillBusy /* We're all done now, done for it, c'est la vie... */
/******************************************************************************************************** */
/* */
/* The reset function. No state requirements for this one. */
/* This suicides the processor. Our caller is never returned to (good english). The only way out of */
/* this is a start function subsequently. So, we give a flying f**k about the registers 'n' sutff. */
/* */
/******************************************************************************************************** */
IReset: lis r28,0x8000 /* Turn on machine checks */
ori r28,r28,0xCC84 /* Enable caches, clear them, */
/* disable serial execution and turn BHT on */
sync
mtspr HID0,r28 /* Start the cache clear */
sync
/* */
/* Clear out the TLB. They be garbage after hard reset. */
/* */
li r0,512 /* Get number of TLB entries (FIX THIS) */
li r3,0 /* Start at 0 */
mtctr r0 /* Set the CTR */
IRpurgeTLB: tlbie r3 /* Purge this entry */
addi r3,r3,4096 /* Next page */
bdnz IRpurgeTLB /* Do 'em all... */
sync /* Make sure all TLB purges are done */
tlbsync /* Make sure on other processors also */
sync /* Make sure the TLBSYNC is done */
/* */
/* Clear out the BATs. */
/* */
li r3,0 /* Clear a register */
mtspr DBAT0L,r3 /* Clear BAT */
mtspr DBAT0U,r3 /* Clear BAT */
mtspr DBAT1L,r3 /* Clear BAT */
mtspr DBAT1U,r3 /* Clear BAT */
mtspr DBAT2L,r3 /* Clear BAT */
mtspr DBAT2U,r3 /* Clear BAT */
mtspr DBAT3L,r3 /* Clear BAT */
mtspr DBAT3U,r3 /* Clear BAT */
mtspr IBAT0L,r3 /* Clear BAT */
mtspr IBAT0U,r3 /* Clear BAT */
mtspr IBAT1L,r3 /* Clear BAT */
mtspr IBAT1U,r3 /* Clear BAT */
mtspr IBAT2L,r3 /* Clear BAT */
mtspr IBAT2U,r3 /* Clear BAT */
mtspr IBAT3L,r3 /* Clear BAT */
mtspr IBAT3U,r3 /* Clear BAT */
/* */
/* Map 0xF0000000 to 0xFFFFFFFF for I/O/* */
lis r6,0xF000 /* Set RPN to last segment */
ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */
lis r7,0xF000 /* Set RPN to last segment */
ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */
mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */
mtspr DBAT0U,r6 /* Now do the upper DBAT */
sync
li r6,0x1FFF /* Set up upper BAT for 256M, access both */
li r7,0x0012 /* Set up lower BAT for r/w access */
mtspr DBAT1L,r7 /* Set up an initial view of mainstore */
mtspr DBAT1U,r6 /* Now do the upper DBAT */
sync
/* */
/* Clean up SDR and segment registers */
/* */
li r3,0 /* Clear a register */
mtspr SDR1,r3 /* Clear SDR1 */
li r4,0 /* Clear index for segment registers */
lis r5,0x1000 /* Set the segment indexer */
IRclearSR: mtsrin r3,r4 /* Zero out the SR */
add. r4,r4,r5 /* Point to the next segment */
bne- IRclearSR /* Keep going until we wrap back to 0 */
lis r3,(MPPICOnline+MPPICStop)>>16 /* Set the reset/online state flags */
b KillBusy /* Go wipe out the busy flags... */
/* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
/* */
/* Here lies the Phoney Firmware used to test SIGPs. Take this out later. */
/* */
/* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
mp_PhoneyFirmware:
li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */
mtmsr r27 /* Load 'em on in */
isync
bl PhoneyBase /* Make a base register */
PhoneyBase: mflr r26 /* Get it */
addi r26,r26,LOW_ADDR(MPPIbase-PhoneyBase) /* Adjust it back */
la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the address of the interrupt table */
la r21,LOW_ADDR(rupttabend-MPPIbase)(r26) /* Get the end of the table */
relocate: lwz r22,0(r20) /* Get the displacement to routine */
add r22,r22,r12 /* Relocate to the physical address */
stw r22,0(r20) /* Stick it back */
addi r20,r20,4 /* Point to the next one */
cmplw cr0,r20,r21 /* Still in table? */
ble+ cr0,relocate /* Yeah... */
la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the interrupt table back again */
mtsprg 3,r20 /* Activate the phoney Rupt table */
lis r24,hi16(HammerHead) /* Get the actual hammerhead address */
ori r24,r24,0x0032 /* Make R/W non-cachable */
lwz r23,MPPIHammer-MPPIwork(r12) /* Get the address mapped on the main processor */
ori r23,r23,0x0003 /* Set both super and user valid for 128KB */
mtspr DBAT0L,r24 /* Setup hammerhead's real address */
mtspr DBAT0U,r23 /* Map hammerhead to the same virtual address as on the main processor */
sync /* Make sure it is done */
la r25,MPPICPU2-MPPIwork(r12) /* Point to a phoney register save area */
mtsprg 1,r25 /* Phoney up initialized processor state */
lis r24,0xFEED /* Get 0xFEED */
ori r24,r24,0xF1D0 /* Get 0xFEEDF1D0 */
stw r24,CSAgpr+(0*4)(r25) /* Store invalid R0 */
stw r24,CSAgpr+(1*4)(r25) /* Store invalid R1 */
stw r24,CSAgpr+(2*4)(r25) /* Store invalid R2 */
stw r24,CSAgpr+(3*4)(r25) /* Store invalid R3 */
stw r24,CSAgpr+(4*4)(r25) /* Store invalid r4 */
stw r24,CSAgpr+(5*4)(r25) /* Store invalid R5 */
stw r24,CSAgpr+(6*4)(r25) /* Store invalid R6 */
stw r24,CSAgpr+(7*4)(r25) /* Store invalid r7 */
stw r24,CSAgpr+(8*4)(r25) /* Store invalid R8 */
stw r24,CSAgpr+(9*4)(r25) /* Store invalid R9 */
stw r24,CSAgpr+(10*4)(r25) /* Store invalid R10 */
stw r24,CSAgpr+(11*4)(r25) /* Store invalid R11 */
stw r24,CSAgpr+(12*4)(r25) /* Store invalid R12 */
waititout: lwz r25,0x30(br0) /* Get wait count */
mfmsr r24 /* Get the MSR */
addi r25,r25,1 /* Bounce it up */
ori r24,r24,0x8000 /* Turn on external interruptions */
stw r25,0x30(br0) /* Save back the count */
mtmsr r24 /* Set it */
isync /* Stop until we're here */
b waititout /* Loop forever... */
/* */
/* Phoney interrupt handlers */
/* */
pexternal: mflr r29 /* Get the LR value */
lwz r29,0(r29) /* Get the rupt code */
stw r29,0x0B0(br0) /* Save the code */
bl GotSignal /* Call the signal handler */
oris r3,r3,0x8000 /* Turn on high bit so we see a code 0 */
stw r3,0xA8(br0) /* Save return code in debug area */
ignorerupt: mflr r29 /* Get the LR value */
lwz r29,0(r29) /* Get the rupt code */
stw r29,0x0B0(br0) /* Save the code */
rfi /* Bail to from whence we commest... */
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
rupttab: .long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long pexternal /* Phoney external handler */
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
.long ignorerupt
rupttabend: .long ignorerupt
/* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
/* */
/* Here lies the end of the Phoney Firmware used to test SIGPs. Take this out later. */
/* */
/* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */
/* */
/* Table of function offsets */
/* */
MPPIFuncOffs:
.long CountProcessors-MPPIFunctions /* Offset to routine */
.long StartProcessor-MPPIFunctions /* Offset to routine */
.long ResumeProcessor-MPPIFunctions /* Offset to routine */
.long StopProcessor-MPPIFunctions /* Offset to routine */
.long ResetProcessor-MPPIFunctions /* Offset to routine */
.long SignalProcessor-MPPIFunctions /* Offset to routine */
.long StoreProcessorStatus-MPPIFunctions /* Offset to routine */
.long SynchClock-MPPIFunctions /* Offset to routine */
.long GetExtHandlerAddress-MPPIFunctions /* Offset to routine */
.long GotSignal-MPPIFunctions /* Offset to routine */
.long ProcessorState-MPPIFunctions /* Offset to routine */
.long RunSIGPRun-MPPIFunctions /* Offset to routine */
.long mp_PhoneyFirmware-MPPIFunctions /* (TEST/DEBUG) */
MPPISize: