|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT_INTERNAL_USE_ONLY@ ! 24: */ ! 25: ! 26: /* ! 27: MP_2p.s ! 28: ! 29: MP low-level signaling, configuration, et all. This is for a and Apple/Daystar 2p board ! 30: ! 31: Lovingly crafted by Bill Angell using traditional methods ! 32: ! 33: */ ! 34: ! 35: #include <ppc/asm.h> ! 36: #include <ppc/proc_reg.h> ! 37: #include <ppc/POWERMAC/mp/MPPlugIn.h> ! 38: #include <assym.s> ! 39: #include <mach/machine/vm_param.h> ! 40: ! 41: ! 42: ! 43: .set MPPlugInVersion,0 /* Current version code */ ! 44: ! 45: /* */ ! 46: /* Interfaces to hardware */ ! 47: /* */ ! 48: ! 49: .set PCI1ARdisp, 0x00800000 /* Displacement from Bandit to PCI1 address configuiration register */ ! 50: .set GrandCdisp, 0x01000000 /* Displacement from Bandit to Grand Central */ ! 51: .set EventsReg, 0x20 /* Interruption events register (latched) */ ! 52: .set LevelsReg, 0x2C /* Interruption levels register (unlatched) */ ! 53: .set MaskReg, 0x24 /* Interruption mask register */ ! 54: .set ClearReg, 0x28 /* Interruption clear register */ ! 55: .set TicksPerMic, 11 /* We'll use 11 ticks per �S - 120MHz is really 10, 180MHz is 11.24 */ ! 56: .set EtherNRdisp, 0x01019000 /* Displacement into bandit of EtherNet ROM */ ! 57: ! 58: #ifdef __ELF__ ! 59: .section ".data" ! 60: #else ! 61: .data ! 62: #endif ! 63: ! 64: .align 5 /* Get us out to the end */ ! 65: ! 66: .globl MPPIwork ! 67: #ifdef __ELF__ ! 68: .type MPPIwork,@function ! 69: #endif ! 70: ! 71: MPPIwork: ! 72: MPPIstatus: .byte 0 /* Global MP board status */ ! 73: .set MPPIinit, 0x80 /* Global initialization complete */ ! 74: .set MPPI2Pv2, 0x40 /* Second rev of 2P board (no watchdog and different state machine) */ ! 75: .byte 0 /* Reserved */ ! 76: MPPIinst: .byte 0 /* Mask of CPUs installed */ ! 77: MPPIonline: .byte 0 /* Mask of CPUs online (i.e., initialized) */ ! 78: MPPIlogCPU: .long 0 /* Used to configure CPU addresses */ ! 79: MPPITBsync: .long 0 /* Used to sync time bases */ ! 80: .long 0 ! 81: MPPIHammer: .long 0 /* Address of HammerHead */ ! 82: MPPIGrandC: .long 0 /* Address of GrandCentral */ ! 83: MPPIPCI1Adr: .long 0 /* Address of PCI1's config reg addr */ ! 84: MPPIEther: .long 0 /* Address of EtherNet ROM */ ! 85: ! 86: .align 5 ! 87: MPPISncFght: .fill 4,4,0 /* Space for 9 passes of a TB sync fight + 1 guard pass */ ! 88: .fill 4,4,0 ! 89: .fill 4,4,0 ! 90: .fill 4,4,0 ! 91: .fill 4,4,0 ! 92: .fill 4,4,0 ! 93: .fill 4,4,0 ! 94: .fill 4,4,0 ! 95: .fill 4,4,0 ! 96: .fill 4,4,0 ! 97: .align 7 /* Point to the start of the CPU status */ ! 98: ! 99: .globl EXT(MPPICPUs) ! 100: #ifdef __ELF__ ! 101: .type EXT(MPPICPUs),@function ! 102: #endif ! 103: EXT(MPPICPUs): /* Start of Processor specific areas */ ! 104: /* There are 8 of these indexed by processor number */ ! 105: ! 106: ! 107: MPPICPU0: .fill 8,4,0 /* First processor */ ! 108: MPPICPU1: .fill 8,4,0 /* Second processor */ ! 109: MPPICPU2: .fill 8,4,0 /* Third processor */ ! 110: MPPICPU3: .fill 8,4,0 /* Fourth processor */ ! 111: .set MPPIMaxCPU, (.-EXT(MPPICPUs)-32)/32 /* Get the maximum CPU address */ ! 112: ! 113: ! 114: .text ! 115: ! 116: /******************************************************************************************************** */ ! 117: /******************************************************************************************************** */ ! 118: /* */ ! 119: /* Here starteth ye stuff */ ! 120: /* */ ! 121: /******************************************************************************************************** */ ! 122: /******************************************************************************************************** */ ! 123: ! 124: /******************************************************************************************************** */ ! 125: /* */ ! 126: /* Validate that the hardware matches with our code. At this point, we cannot check */ ! 127: /* for anything other than the possibility of this working. There's no version code */ ! 128: /* or nothin'. So, if we have a second processor and are a 604 or 604e, we'll say */ ! 129: /* we're capable. Also we'll check version codes for our code. */ ! 130: /* */ ! 131: /* When we get here, DDAT and IDAT are both on, 'rupts are disabled. */ ! 132: /* */ ! 133: /* We're called like this: */ ! 134: /* OSStatus MP_probe(MPPlugInSpecPtr spec, UInt32 HammerheadAddr); */ ! 135: /* */ ! 136: /******************************************************************************************************** */ ! 137: ! 138: ENTRY(MPprobe, TAG_NO_FRAME_USED) ! 139: ! 140: ! 141: MPPIbase: mfpvr r7 /* Get the processor version */ ! 142: rlwinm r7,r7,16,16,31 /* Isolate the processor type */ ! 143: ! 144: lbz r5,ArbConfig(r4) /* See if there is another processor */ ! 145: ! 146: andi. r5,r5,TwoCPU /* Are we a real live two processor? */ ! 147: beq OneWay /* Nope, we be gone... */ ! 148: ! 149: cmplwi cr0,r7,4 /* Are we a 604? */ ! 150: beq SeemsOK /* Yeah, we're cool... */ ! 151: cmplwi cr0,r7,9 /* Are we a 604E? */ ! 152: beq SeemsOK /* Yeah, go finish up... */ ! 153: ! 154: OneWay: li r3,0 /* Say we can't find the proper CPU */ ! 155: blr /* Leave... */ ! 156: ! 157: SeemsOK: mr r10,r3 /* Save the parameter list */ ! 158: ! 159: lwz r4,MPSversionID(r10) /* Get the version ID */ ! 160: cmplwi cr0,r4,kMPPlugInVersionID /* Correct version? */ ! 161: beq IsOK /* Yeah, we think we're ok... */ ! 162: ! 163: li r3,0 /* Set bad version' */ ! 164: blr /* Leave... */ ! 165: ! 166: IsOK: mflr r11 /* Save the LR */ ! 167: lis r9,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 168: bl SetBase1 /* Jump to the next instruction */ ! 169: SetBase1: mflr r12 /* Get the base register */ ! 170: ori r9,r9,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 171: addi r12,r12,LOW_ADDR(MPPIbase-SetBase1) /* Adjust to the start of all our code */ ! 172: ! 173: stw r12,MPSbaseAddr(r10) /* Save off the common base for all functions */ ! 174: ! 175: la r5,LOW_ADDR(MPPIFunctions-MPPIbase)(r12) /* Point to the base of all functions */ ! 176: stw r5,MPSareaAddr(r10) /* Pass back the code address */ ! 177: ! 178: la r5,LOW_ADDR(MPPIFuncOffs-MPPIbase)(r12) /* Point to the function offset table */ ! 179: stw r5,MPSoffsetTableAddr(r10) /* Pass back the pointer to the offset table */ ! 180: ! 181: li r5,LOW_ADDR(MPPISize-MPPIFunctions) /* Get our size without data area */ ! 182: stw r5,MPSareaSize(r10) /* Save it */ ! 183: ! 184: stw r9,MPSdataArea(r10) /* Save it */ ! 185: ! 186: la r5,LOW_ADDR(EXT(MPPICPUs)-MPPIwork)(r9) /* Point to the CPU area base */ ! 187: stw r5,MPSCPUArea(r10) /* Save it */ ! 188: ! 189: mtlr r11 /* Restore that return address */ ! 190: li r3,1 /* Set no error */ ! 191: blr /* Leave, we're all done... */ ! 192: ! 193: /******************************************************************************************************** */ ! 194: /******************************************************************************************************** */ ! 195: /* */ ! 196: /* Here starteth ye code that starteth up ye second prothether. */ ! 197: /* Yea, though ye prothether executeth asynchronously, it appears unto men */ ! 198: /* in ye shape of a synchronous process. By ye instruction of He who gave it */ ! 199: /* form and being, it stopeth to worship and praise its Lord, to joyously */ ! 200: /* receive His blessings and teachings, to guide its way along the path to */ ! 201: /* righteous execution. */ ! 202: /* */ ! 203: /******************************************************************************************************** */ ! 204: /******************************************************************************************************** */ ! 205: ! 206: ! 207: /******************************************************************************************************** */ ! 208: /* */ ! 209: /* Initialize the MP hardware. This will bring the other processor online. */ ! 210: /* */ ! 211: /* First we will tick the board to its 5th state the "TBEN off" state. */ ! 212: /* */ ! 213: /* Just for giggles, here's the states: */ ! 214: /* */ ! 215: /* 1) 1st ROM - This state exists after motherboard reset */ ! 216: /* 2) Open Firmware - Transitions here when the SecInt line is first asserted */ ! 217: /* Open Firmware attempts to execute some code on the secondary */ ! 218: /* processor to obtain the PVR register. It's got some problems */ ! 219: /* and hangs the secondary disabled. */ ! 220: /* 3) Reset (my name) - Entered when the SecInt line is deasserted. A timer starts and */ ! 221: /* 468�S later the reset line is pulled. I may have this wrong here, */ ! 222: /* it may be that the reset line is held for 468�S. Either way, */ ! 223: /* this state is invisible to us. */ ! 224: /* 4) 2nd ROM - This state exists when the secondary processor begins executing */ ! 225: /* after the reset. */ ! 226: /* 5) TBEN off - We transition here when SecInt is asserted in the 2nd ROM state. */ ! 227: /* In this state, the TBEN pin is set to disable the timebase from */ ! 228: /* running on all processors, thus freezing time. (Performace analysis */ ! 229: /* note: here would be the best time to run stats, all tests would */ ! 230: /* run in 0 time giving us infinite speed.) Also the "primary arbitration" */ ! 231: /* mode is set. This mode causes the CPU board to arbitrate both processors */ ! 232: /* using a single bus master. This gets us around the L2 cache dumbness. */ ! 233: /* We should also note that because of this, there is now no way to */ ! 234: /* tell if we are on the secondary processor, the WhoAmI register will */ ! 235: /* always indicate the primary processor. We need to have sewn */ ! 236: /* name tags into our underwear before now. */ ! 237: /* Finally, this state is the only way we can tell if we are executing */ ! 238: /* on the older version of the 2-way board. When it is in this state */ ! 239: /* "primary arbitration" has not been enabled yet. The WhoAmI register */ ! 240: /* will indicate if we are on the secondary processor on not. We should */ ! 241: /* check this because we need to do signals differently. */ ! 242: /* 6) TBEN on - The next assertion of SecInt brings us to our final destination. For */ ! 243: /* those of you who will be deplaning, please remember that timebases */ ! 244: /* are running and primary arbitration is enabled. Always remember: */ ! 245: /* buckle up for safety and if you're tired pull over for a rest. */ ! 246: /* */ ! 247: /******************************************************************************************************** */ ! 248: ! 249: ENTRY(MPinstall, TAG_NO_FRAME_USED) ! 250: ! 251: /* int MP_install(unsigned int *physAddr, unsigned int band1, unsigned int hammerh, unsigned int grandc, ! 252: * unsigned int pci1ar, unsigned int enetr); ! 253: */ ! 254: ! 255: lis r11,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 256: mflr r0 /* Save the LR */ ! 257: ori r11,r11,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 258: ! 259: stw r5,MPPIHammer-MPPIwork(r11) /* Save the HammerHead address for later */ ! 260: stw r6,MPPIGrandC-MPPIwork(r11) /* Save address of Grand Central */ ! 261: stw r7,MPPIPCI1Adr-MPPIwork(r11) /* Save the PCI1 address register address */ ! 262: stw r8,MPPIEther-MPPIwork(r11) /* Save Ethernet ROM address */ ! 263: ! 264: li r4,LOW_ADDR(0xC080) /* Set CPU 0&1 installed, CPU 0 online */ ! 265: lis r10,(MPPICOnline+MPPICReady)>>16 /* Set CPU 0 online and ready */ ! 266: ! 267: mfspr r6,pir /* Get the PIR contents */ ! 268: ! 269: sth r4,MPPIinst-MPPIwork(r11) /* Set 'em for later */ ! 270: rlwinm r6,r6,0,0,27 /* Clear to use processor 0 */ ! 271: stw r10,EXT(MPPICPUs)-MPPIwork(r11) /* Preset CPU 0 online and ready */ ! 272: ! 273: mtspr pir,r6 /* Set our PIR */ ! 274: ! 275: /* */ ! 276: /* Ok, ok, enough of this. Let's really start 'em up. */ ! 277: /* */ ! 278: ! 279: lis r9,HIGH_ADDR(CPUInit) /* Top of init code */ ! 280: li r6,1 /* Get the other guy's CPU address */ ! 281: ori r9,r9,LOW_ADDR(CPUInit) /* Get physical address of init code */ ! 282: ! 283: mfmsr r8 /* Get the MSR */ ! 284: ! 285: stw r6,MPPIlogCPU-MPPIwork(r11) /* Set the logical CPU address to assign */ ! 286: ! 287: rlwinm r6,r8,0,17,15 /* Turn off interruptions */ ! 288: sync /* Make sure the work area is updated */ ! 289: mtmsr r6 /* Flip the EE bit off */ ! 290: isync /* Chill a bit */ ! 291: ! 292: stw r9,0(r7) /* Pass the initialization code address to our friend */ ! 293: sync /* Fence off the pig */ ! 294: ! 295: li r6,0 /* Clear this out */ ! 296: stb r6,IntReg(r5) /* Kick the other processor */ ! 297: eieio /* Pig in the sty */ ! 298: ! 299: /* At this point we should be in the "TBEN off" state. The second processor should be starting */ ! 300: /* to come up. */ ! 301: ! 302: /* Note that we are assuming that the secondary processor will reset the interrupt request. */ ! 303: /* If we are on one of the old boards, we will die in about 256�S if it is not reset, 'cause */ ! 304: /* of that silly watchchihuahua timer. We can't use the TB or decrimenter here to set a */ ! 305: /* timeout because when we are in "TBEN off" state these guys don't run. */ ! 306: ! 307: lis r4,HIGH_ADDR(SpinTimeOut) /* Get about 1 second at 200MHz */ ! 308: /* At 120 MHz this is 1.66 seconds, at 400MHz it is .5 */ ! 309: /* All these are more than enough time for this handshake */ ! 310: ori r4,r4,LOW_ADDR(SpinTimeOut) /* Get the bottom part */ ! 311: ! 312: WaitReady: lwz r9,0(r7) /* Get this back */ ! 313: mr. r9,r9 /* The other processor will set to 0 */ ! 314: /* when it is ready for the work area address */ ! 315: beq CodeUp /* The code is up on the other side */ ! 316: subi r4,r4,1 /* Count the try */ ! 317: mr. r4,r4 /* Did we timeout? */ ! 318: bne+ WaitReady /* Nope... */ ! 319: ! 320: li r3,kMPPInitTO1 /* Set that we timed out with initial code bringup */ ! 321: mtmsr r8 /* Restore the interrupt state */ ! 322: mtlr r0 /* Restore the return addess */ ! 323: blr /* Return a failure... */ ! 324: ! 325: CodeUp: isync /* Make sure we don't prefetch past here */ ! 326: ! 327: /* Timebase is stopped here, no need for the funky "get time base right" loop */ ! 328: ! 329: mftbu r4 /* Get upper timebase half */ ! 330: mftb r9 /* Get bottom */ ! 331: stw r4,MPPITBsync-MPPIwork(r11) /* Save the top */ ! 332: stw r9,MPPITBsync+4-MPPIwork(r11) /* Save the second half */ ! 333: sync /* Be very sure it's there */ ! 334: ! 335: stw r11,0(r7) /* Set the PCI1 adr reg non-zero - this releases the spin */ ! 336: /* loop and allows the timebase to be set. */ ! 337: eieio ! 338: ! 339: lis r9,HIGH_ADDR(SpinTimeOut) /* Get the spin time */ ! 340: ori r9,r9,LOW_ADDR(SpinTimeOut) /* Get the bottom part */ ! 341: ! 342: WaitTBset: lwz r4,0(r7) /* Get this back */ ! 343: mr. r4,r4 /* When zero, the other guy's TB is set up */ ! 344: beq- TBSetUp /* She's'a all done... */ ! 345: subi r9,r9,1 /* Count the try */ ! 346: mr. r9,r9 /* Did we timeout? */ ! 347: bne+ WaitTBset /* Nope... */ ! 348: ! 349: li r3,kMPPInitTO3 /* Set that we timed out setting clock */ ! 350: mtmsr r8 /* Restore the interrupt state */ ! 351: isync ! 352: mtlr r0 /* Restore the return addess */ ! 353: blr /* Return a failure... */ ! 354: ! 355: TBSetUp: stb r6,IntReg(r5) /* Kick the other processor again */ ! 356: /* This will tick us to the next state */ ! 357: eieio ! 358: ! 359: SpinDelay: addi r6,r6,1 /* Bump spin count (we finally are trashing R6) */ ! 360: cmplwi cr0,r6,4096 /* Spun enough? */ ! 361: ble+ SpinDelay /* Nope... */ ! 362: ! 363: li r6,SecInt /* Set the interrupt bit */ ! 364: stb r6,IntReg(r5) /* Deassert the external signal */ ! 365: /* */ ! 366: /* Ok, the other processor should be online in a spin waiting for a start signal from */ ! 367: /* us. It should be in the reset state with no external interruptions pending. There may */ ! 368: /* be a decrimenter pop waiting in the wings though. */ ! 369: /* */ ! 370: ! 371: lwz r7,MPPIGrandC-MPPIwork(r11) /* Point to GrandCentral */ ! 372: lwz r4,MaskReg(r7) /* Get the grand central mask register (note that this */ ! 373: /* is a little-endian area, but I'm too lazy to access it that way */ ! 374: /* so I'll document what it really should be, but, probably, it would */ ! 375: /* have been much, much easier just to code up the lwbrx and be done */ ! 376: /* with it rather than producing this monograph describing my alternate */ ! 377: /* access method that I really don't explain anyway. */ ! 378: ori r4,r4,0x0040 /* Flip on bit 30 (hah, figure that one out). This enables the */ ! 379: /* Ext10 interrupt which is connected to the MACE ethernet chip's */ ! 380: /* chip-select pin. */ ! 381: stw r4,MaskReg(r7) /* Stick it on back */ ! 382: eieio ! 383: ! 384: mtlr r0 /* Get back the original LR */ ! 385: sync /* Make sure all storage ops are done */ ! 386: mtmsr r8 /* Restore the MSR */ ! 387: isync ! 388: li r3,kSIGPnoErr /* Set that we worked jest fine and dandy */ ! 389: blr /* Bye now... */ ! 390: ! 391: .align 5 ! 392: /******************************************************************************************************** */ ! 393: /******************************************************************************************************** */ ! 394: /* */ ! 395: /* This is where the individual SIGP function calls reside. */ ! 396: /* Also, it is where we cram the second processor's initialization code wo'w we */ ! 397: /* can use physical addressing. */ ! 398: /* */ ! 399: /******************************************************************************************************** */ ! 400: /******************************************************************************************************** */ ! 401: ! 402: MPPIFunctions: /* Start of all externally called functions and interrupt handling code */ ! 403: ! 404: ! 405: /******************************************************************************************************** */ ! 406: /* */ ! 407: /* Count the number of processors. This hardwires to 2 (or 1 if no secondary) */ ! 408: /* */ ! 409: /******************************************************************************************************** */ ! 410: ! 411: CountProcessors: ! 412: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 413: mfmsr r9 /* Get the MSR */ ! 414: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 415: ! 416: ori r10,r9,0x0010 /* Turn on DDAT */ ! 417: ! 418: lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the HammerHead controller */ ! 419: ! 420: mtmsr r10 /* Turn on DDAT */ ! 421: isync /* Kill speculation */ ! 422: ! 423: li r3,2 /* Assume we have them all */ ! 424: lbz r5,ArbConfig(r8) /* Check if we've seen a second processor */ ! 425: andi. r5,r5,TwoCPU /* Are we a real live two processor? */ ! 426: mtmsr r9 /* Put back the DDAT */ ! 427: isync ! 428: ! 429: bnelr+ /* Yeah... */ ! 430: li r3,1 /* Nope, set a count of 1 */ ! 431: blr /* Leave, we're inadequate... */ ! 432: ! 433: /******************************************************************************************************** */ ! 434: /* */ ! 435: /* Start up the selected processor (R3=processor; R4=physical start address; R5=pass-thru parm) */ ! 436: /* */ ! 437: /******************************************************************************************************** */ ! 438: ! 439: StartProcessor: ! 440: ! 441: mr r7,r5 /* Copy pass-thru parameter */ ! 442: mfspr r10,pir /* Get our processor number */ ! 443: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 444: cmplw cr0,r3,r10 /* Trying to start ourselves? */ ! 445: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 446: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 447: li r3,kMPPHairyPalms /* Set trying to do it to ourselves */ ! 448: beqlr- /* Self abuse... */ ! 449: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 450: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 451: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 452: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 453: mflr r11 /* Save the return address */ ! 454: add r9,r9,r12 /* Point right at the entry */ ! 455: ! 456: SPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 457: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 458: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 459: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 460: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 461: and. r0,r5,r6 /* Are we online */ ! 462: li r3,kMPPOffline /* Set offline */ ! 463: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 464: li r3,kMPPBadState /* Set bad state */ ! 465: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 466: ! 467: stwcx. r5,0,r9 /* Try to set busy */ ! 468: bne- SPretry ! 469: ! 470: ori r6,r10,MPPICfStrt<<8 /* Put the Start function in front of the processor ID */ ! 471: rlwimi r5,r6,0,16,31 /* Put these behind the status flags */ ! 472: stw r4,MPPICParm0(r9) /* Set the starting physical address parameter */ ! 473: stw r7,MPPICParm2(r9) /* Set pass-thru parameter */ ! 474: ! 475: sync /* Make sure it's all out there */ ! 476: b KickAndGo /* We're done now... */ ! 477: ! 478: /******************************************************************************************************** */ ! 479: /* */ ! 480: /* Reset the selected processor (R3=processor). You can't reset yourself or the primary. */ ! 481: /* We're gonna try, try real hard... This is not for the faint-of-heart. */ ! 482: /* If there's ever any way to yank a reset line, we'll do it here. */ ! 483: /* */ ! 484: /******************************************************************************************************** */ ! 485: ! 486: ResetProcessor: ! 487: mfspr r10,pir /* Get our processor number */ ! 488: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 489: rlwinm r10,r10,0,28,31 /* Clean up the PIR */ ! 490: cmplw cr0,r3,r10 /* Trying to start ourselves? */ ! 491: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 492: li r3,kMPPHairyPalms /* Set trying to do it to ourselves */ ! 493: beqlr- /* Self abuse... */ ! 494: mr. r9,r9 /* Trying to reset the primary?!? Dude, that's insubordination!!!! */ ! 495: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 496: li r3,kMPPInvalCPU /* Say that that's a major offense */ ! 497: beqlr- /* Bye now... */ ! 498: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 499: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 500: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 501: ! 502: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 503: mflr r11 /* Save the return address */ ! 504: add r9,r9,r12 /* Point right at the entry */ ! 505: ! 506: li r4,16 /* Try for 16 times to get the busy lock */ ! 507: ! 508: RSlockS: mftb r6 /* Time stamp start */ ! 509: ! 510: RSlock: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 511: rlwinm. r0,r5,0,2,2 /* Are we online */ ! 512: li r3,kMPPOffline /* Set offline */ ! 513: cmplwi cr1,r5,0 /* Check for busy */ ! 514: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 515: bge+ cr1,RSnotBusy /* Not busy, make it so... */ ! 516: ! 517: mftb r7 /* Stamp the time */ ! 518: sub r7,r7,r6 /* Get elapsed time */ ! 519: rlwinm. r7,r7,16,16,31 /* Divide ticks by microseconds (this is pretty darn "kinda-in-the-ballpark") */ ! 520: cmplwi cr0,r7,TicksPerMic /* See if we hit 65536�S yet */ ! 521: blt+ RSlock /* Not yet... */ ! 522: ! 523: RSatmtCnt: subi r4,r4,1 /* Count the retries */ ! 524: mr. r4,r4 /* Are we done yet? */ ! 525: bgt+ RSlockS /* Start the lock attempt again... */ ! 526: ! 527: li r3,kMPPCantLock /* Say we can't get the lock */ ! 528: b ErrorReturn /* Bye, dude... */ ! 529: ! 530: RSnotBusy: rlwinm r5,r5,0,0,15 /* Clear out the function and requestor */ ! 531: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Set busy */ ! 532: or r5,r10,r5 /* Add in our processor */ ! 533: ori r5,r5,MPPICfReset<<8 /* Set the reset function */ ! 534: stwcx. r5,0,r9 /* Cram it back */ ! 535: bne- RSatmtCnt /* We lost the reservation... */ ! 536: b KickAndGo /* Try to send it across... */ ! 537: ! 538: ! 539: /******************************************************************************************************** */ ! 540: /* */ ! 541: /* Here we will try to resume execution of a stopped processor (R3=processor). */ ! 542: /* */ ! 543: /******************************************************************************************************** */ ! 544: ! 545: ResumeProcessor: ! 546: mfspr r10,pir /* Get our processor number */ ! 547: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 548: cmplw cr0,r3,r10 /* Trying to resume ourselves? */ ! 549: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 550: li r3,kMPPHairyPalms /* Set trying to do it to ourselves */ ! 551: beqlr- /* Self abuse... */ ! 552: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 553: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 554: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 555: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 556: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 557: mflr r11 /* Save the link register */ ! 558: add r9,r9,r12 /* Point right at the entry */ ! 559: ! 560: RPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 561: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 562: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 563: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 564: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 565: and. r0,r5,r6 /* Are we online */ ! 566: li r3,kMPPOffline /* Set offline */ ! 567: lis r6,MPPICReady>>16 /* Get the ready bit */ ! 568: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 569: and. r0,r5,r6 /* Are we ready? */ ! 570: li r3,kMPPNotReady /* Set not ready */ ! 571: lis r6,MPPICStop>>16 /* Get the stopped bit */ ! 572: beq- ErrorReturn /* Ain't ready, buzz off... */ ! 573: and. r0,r5,r6 /* Are we stopped? */ ! 574: li r3,kMPPNotStopped /* Set not stopped */ ! 575: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 576: beq- ErrorReturn /* Nope, not stopped, so how do we resume? */ ! 577: ! 578: stwcx. r5,0,r9 /* Try to set busy */ ! 579: bne- RPretry ! 580: ! 581: ori r6,r10,MPPICfResm<<8 /* Put the resume function in front of the processor ID */ ! 582: rlwimi r5,r6,0,16,31 /* Put these behind the status flags */ ! 583: b KickAndGo /* We're done now... */ ! 584: ! 585: ! 586: ! 587: /******************************************************************************************************** */ ! 588: /* */ ! 589: /* Here we will try to stop execution of a running processor (R3=processor). */ ! 590: /* */ ! 591: /******************************************************************************************************** */ ! 592: ! 593: StopProcessor: ! 594: mfspr r10,pir /* Get our processor number */ ! 595: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 596: cmplw cr0,r3,r10 /* Are we doing ourselves? */ ! 597: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 598: li r3,kMPPHairyPalms /* Set trying to do it to ourselves */ ! 599: beqlr- /* Self abuse... */ ! 600: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 601: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 602: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 603: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 604: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 605: mflr r11 /* Save the link register */ ! 606: add r9,r9,r12 /* Point right at the entry */ ! 607: ! 608: PPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 609: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 610: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 611: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 612: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 613: and. r0,r5,r6 /* Are we online */ ! 614: li r3,kMPPOffline /* Set offline */ ! 615: lis r6,MPPICReady>>16 /* Get the ready bit */ ! 616: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 617: and. r0,r5,r6 /* Are we ready? */ ! 618: li r3,kMPPNotReady /* Set not ready */ ! 619: lis r6,MPPICStop>>16 /* Get the stopped bit */ ! 620: beq- ErrorReturn /* Ain't ready, buzz off... */ ! 621: and. r0,r5,r6 /* Are we stopped? */ ! 622: li r3,kMPPNotRunning /* Set not running */ ! 623: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 624: bne- ErrorReturn /* Nope, already stopped, so how do we stop? */ ! 625: ! 626: stwcx. r5,0,r9 /* Try to set busy */ ! 627: ori r10,r10,MPPICfStop<<8 /* Put the stop function in front of the processor ID */ ! 628: bne- PPretry ! 629: ! 630: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */ ! 631: b KickAndGo /* We're done now... */ ! 632: ! 633: ! 634: /******************************************************************************************************** */ ! 635: /* */ ! 636: /* Here we will try to signal a running processor (R3=processor). */ ! 637: /* Note that this should have good performace. Well, actually, seeing as how slow we really are, it */ ! 638: /* probably is moot anyhow. */ ! 639: /* Another note: this function (and all most others as well) will return a timeout when the */ ! 640: /* second processor tries to do itself on the old version of the board. This happens because */ ! 641: /* In order to keep the watchchihuahua from popping (just imagine the scene: that little runt-dog just so */ ! 642: /* excited that its veins and eyes bulge and then explode) signaling to the secondary */ ! 643: /* is done syncronously and disabled. If the secondary signals the secondary, it will never enable so */ ! 644: /* it will never see the 'rupt, so it will never clear it, so it will time out, so there... */ ! 645: /* */ ! 646: /******************************************************************************************************** */ ! 647: ! 648: SignalProcessor: ! 649: mfspr r10,pir /* Get our processor number */ ! 650: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 651: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 652: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 653: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 654: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 655: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 656: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 657: mflr r11 /* Save the link register */ ! 658: add r9,r9,r12 /* Point right at the entry */ ! 659: ! 660: SiPretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 661: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 662: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 663: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 664: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 665: and. r0,r5,r6 /* Are we online */ ! 666: li r3,kMPPOffline /* Set offline */ ! 667: lis r6,MPPICReady>>16 /* Get the ready bit */ ! 668: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 669: and. r0,r5,r6 /* Are we ready? */ ! 670: li r3,kMPPNotReady /* Set not ready */ ! 671: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 672: beq- ErrorReturn /* Ain't ready, buzz off... */ ! 673: ! 674: stwcx. r5,0,r9 /* Try to set busy */ ! 675: ori r10,r10,MPPICfSigp<<8 /* Put the SIGP function in front of the processor ID */ ! 676: bne- SiPretry ! 677: ! 678: stw r4,MPPICParm0(r9) /* Pass along the SIGP parameter */ ! 679: ! 680: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */ ! 681: b KickAndGo /* We're done now... */ ! 682: ! 683: ! 684: /******************************************************************************************************** */ ! 685: /* */ ! 686: /* Here we will store the state of a processor (R3=processor; R4=status area). */ ! 687: /* Self abuse will store the state as is, is not asynchronous, and grows hair on your palms. */ ! 688: /* */ ! 689: /******************************************************************************************************** */ ! 690: ! 691: StoreProcessorStatus: ! 692: mfspr r10,pir /* Get our processor number */ ! 693: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 694: cmplw cr0,r3,r10 /* Saving our own state??? Abusing oneself??? */ ! 695: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 696: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 697: mflr r11 /* Save the link register */ ! 698: beq Flagellant /* Oh baby, oh baby... */ ! 699: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 700: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 701: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 702: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 703: add r9,r9,r12 /* Point right at the entry */ ! 704: ! 705: SSretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 706: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 707: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 708: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 709: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 710: and. r0,r5,r6 /* Are we online */ ! 711: li r3,kMPPOffline /* Set offline */ ! 712: beq- ErrorReturn /* Ain't online, buzz off... */ ! 713: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 714: ! 715: stwcx. r5,0,r9 /* Try to set busy */ ! 716: ori r10,r10,MPPICfStat<<8 /* Put the store status function in front of the processor ID */ ! 717: bne- SSretry /* Lost reservation, return busy... */ ! 718: ! 719: li r0,0 /* Get false */ ! 720: stb r0,CSAregsAreValid(r4) /* Set that the registers ain't valid */ ! 721: stw r4,MPPICParm0(r9) /* Set the status area physical address parameter */ ! 722: ! 723: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */ ! 724: b KickAndGo /* We're done now... */ ! 725: ! 726: /* Spill one's seed upon the soil */ ! 727: ! 728: Flagellant: bl StoreStatus /* Go store off all the registers 'n' stuff */ ! 729: mtlr r11 /* Restore the return address */ ! 730: li r3,kSIGPnoErr /* Return no error */ ! 731: blr /* Leave... */ ! 732: ! 733: ! 734: /******************************************************************************************************** */ ! 735: /* */ ! 736: /* Here we will attempt to syncronize clocks (R3=processor). */ ! 737: /* Self abuse will just return with an all-ok code. */ ! 738: /* */ ! 739: /******************************************************************************************************** */ ! 740: ! 741: SynchClock: ! 742: mfspr r10,pir /* Get our processor number */ ! 743: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 744: cmplw cr0,r3,r10 /* Cleaning our own clock?? */ ! 745: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 746: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 747: li r3,kSIGPnoErr /* Assume self-cleaning clock */ ! 748: beqlr /* Oh baby, oh baby... */ ! 749: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 750: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 751: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 752: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 753: mflr r11 /* Save the link register */ ! 754: add r9,r9,r12 /* Point right at the entry */ ! 755: ! 756: SyCretry: lwarx r5,0,r9 /* Pick up the status flags (MPPICStat) and reserve it */ ! 757: li r3,kSIGPInterfaceBusyErr /* Fill dead space and get busy return code */ ! 758: rlwinm. r0,r5,0,0,0 /* Are we marked as busy? */ ! 759: lis r6,MPPICOnline>>16 /* Get the online flag */ ! 760: bne- ErrorReturn /* Yeah, go leave, don't bother me now... */ ! 761: and. r0,r5,r6 /* Are we online */ ! 762: li r3,kMPPOffline /* Set offline */ ! 763: beq- ErrorReturn /* Ain't online, ain't ready, buzz off... */ ! 764: oris r5,r5,(MPPICBusy>>16)&0x0000FFFF /* Turn on the busy bit */ ! 765: li r0,0 /* Clear this */ ! 766: ! 767: stwcx. r5,0,r9 /* Try to set busy */ ! 768: ori r10,r10,MPPICfTBsy<<8 /* Put the timebase sync function in front of the processor ID */ ! 769: bne- SyCretry /* Lost reservation, return busy... */ ! 770: ! 771: stw r0,MPPITBsync+4-MPPIwork(r12) /* Make sure the parm area is 0 */ ! 772: mr r0,r11 /* Save the LR */ ! 773: bl SyCbase /* Get a base register */ ! 774: SyCbase: rlwimi r5,r10,0,16,31 /* Put these behind the status flags */ ! 775: mflr r11 /* Get the base */ ! 776: la r11,(4*4)(r11) /* DON'T MESS WITH THESE INSTRUCTIONS Make up the return point */ ! 777: b KickAndGo /* Go signal the other side */ ! 778: ! 779: SyCKrtrn: mr r11,r0 /* Restore the return */ ! 780: ! 781: /* */ ! 782: /* Start sync'ing 'er up */ ! 783: /* */ ! 784: ! 785: mftb r4 /* Take a timeout stamp (don't need top half, we have at least 13 hours) */ ! 786: ! 787: SyCInP0: lwz r5,0(r9) /* Get the CPU status word */ ! 788: rlwinm r5,r5,24,24,31 /* Isolate the command byte */ ! 789: cmplwi cr0,r5,MPPICfTBsy1 /* Have we reached time base sync phase 1 yet? */ ! 790: beq SyCInP1 /* Yeah, we're in phase 1... */ ! 791: mftb r5 /* Get the bottom half of the timer again */ ! 792: sub r5,r5,r4 /* How long we been messin' around? */ ! 793: cmplwi cr0,r5,1000*TicksPerMic /* Don't try more'n' a 1000�S */ ! 794: blt+ SyCInP0 /* We haven't, so wait some more... */ ! 795: li r3,kMPPTimeOut /* Signal timeout */ ! 796: b ErrorReturn /* By dude... */ ! 797: ! 798: /* */ ! 799: /* Here we make sure there is enough time to sync the clocks before the lower part of the TB ticks */ ! 800: /* up into the high part. This eliminates the need for any funky */ ! 801: /* "get-the-top-then-get-the-bottom-then-get-the-top-again-to-see-if-it-changed" stuff. That would */ ! 802: /* only make the sync harder to do. */ ! 803: /* */ ! 804: /* Also, because we use the lower TB value for the signal, we also need to make sure we do not have */ ! 805: /* a value of 0, we would be ever-so-sorry if it was. */ ! 806: /* */ ! 807: ! 808: SyCInP1: li r4,lo16(0xC000) /* Get the minimum time left on clock before tick ('bout 1 1/4 ms) */ ! 809: li r8,0 /* Get a 0 constant */ ! 810: ! 811: SyCdelay: mftb r5 /* Get the time left */ ! 812: cmplw cr0,r5,r4 /* See if there is sufficient time before carry into high clock */ ! 813: bgt- SyCdelay /* Nope, hang until it is... */ ! 814: mr. r5,r5 /* Did we just tick, however? */ ! 815: beq- SyCdelay /* Yeah, wait until it is at least 1... */ ! 816: ! 817: mftbu r4 /* Get the upper */ ! 818: stw r4,MPPITBsync-MPPIwork(r12) /* Make sure the top half is set */ ! 819: sync /* Wait until it is done */ ! 820: ! 821: mftb r5 /* Get the lower timebase now */ ! 822: stw r5,MPPITBsync+4-MPPIwork(r12) /* Shove it out for the other processor */ ! 823: ! 824: la r6,MPPISncFght-MPPIwork(r12) /* Point to the courtroom area */ ! 825: li r5,0 /* Point to the first line */ ! 826: ! 827: SyCclear: dcbz r5,r6 /* Clear the court */ ! 828: addi r5,r5,32 /* Point to the next line */ ! 829: cmplwi cr0,r5,10*2*32 /* Enough for 9 iterations, 2 chunks at a time */ ! 830: blt+ SyCclear /* Clear the whole smear... */ ! 831: sync /* Make sure everyone's out */ ! 832: ! 833: mftb r5 /* Get the lower timebase now */ ! 834: ! 835: SyCWait: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get it back */ ! 836: mftb r6 /* Get the bottom half again */ ! 837: mr. r7,r7 /* Have they set their clock yet? */ ! 838: sub r0,r6,r5 /* See if we're hung up */ ! 839: beq- SyCdonesync /* Clock is set */ ! 840: cmplwi cr0,r0,1000*TicksPerMic /* Timeout if we spend more than 1000�S doing this */ ! 841: blt+ SyCWait /* No timeout, wait some more... */ ! 842: li r3,kMPPTimeOut /* Set timeout */ ! 843: b ErrorReturn /* Leave... */ ! 844: ! 845: /* */ ! 846: /* Ok, so now we have set a preliminary TB value on the second processor. It's close, but only */ ! 847: /* within handgranade range. */ ! 848: /* */ ! 849: /* What we will do now is to let the processors (starting with the other guy) argue about the time for */ ! 850: /* a while (10 passes-we use the middle 8). We'll look at the results and try to adjust the other processor's */ ! 851: /* time such that the timing windows are overlapping evenly. This should put the TBs close enough together */ ! 852: /* (0-2 ticks) that the difference is undetectable. */ ! 853: /* */ ! 854: ! 855: ! 856: ! 857: SyCdonesync: ! 858: li r4,0 /* Clear this */ ! 859: la r5,MPPISncFght-MPPIwork(r12) /* Point to the squared circle */ ! 860: ! 861: SyCWtArg: ! 862: dcbf 0,r5 /* Make sure of it */ ! 863: sync /* Doubly shure */ ! 864: lwz r6,0(r5) /* Listen for the defence argument */ ! 865: ! 866: mr. r6,r6 /* See if they are done */ ! 867: beq+ SyCWtArg /* Nope, still going... */ ! 868: ! 869: mftb r7 /* They're done, time for rebuttal */ ! 870: stw r7,32(r5) /* Make rebuttle */ ! 871: ! 872: addi r4,r4,1 /* Count rounds */ ! 873: ! 874: cmplwi cr0,r4,10 /* See if we've gone 8 rounds plus an extra one */ ! 875: addi r5,r5,64 /* Point to the next round areas */ ! 876: ! 877: blt+ SyCWtArg /* Not yet, come out of your corners fighting... */ ! 878: ! 879: mftb r5 /* Stamp the wait */ ! 880: ! 881: SyCWadj: lwz r7,MPPITBsync+4-MPPIwork(r12) /* Get adjustment flag */ ! 882: mftb r6 /* Get timebase again */ ! 883: ! 884: mr. r7,r7 /* Have they set their timebase with adjusted time yet? */ ! 885: sub r6,r6,r5 /* Get elapsed time */ ! 886: bne+ SyCdone /* They say it, sync done... */ ! 887: cmplwi cr0,r6,1000*TicksPerMic /* Timeout if we spend more than 1000�S doing this */ ! 888: blt+ SyCWadj /* Still time, wait until adjustment is done... */ ! 889: ! 890: li r3,kMPPTimeOut /* Set timeout */ ! 891: b ErrorReturn /* Pass it back... */ ! 892: ! 893: SyCdone: li r3,kSIGPnoErr /* No errors */ ! 894: mtlr r11 /* Restore LR */ ! 895: blr /* Leave... */ ! 896: ! 897: ! 898: /******************************************************************************************************** */ ! 899: /* */ ! 900: /* Here we will get the physical address of the interrupt handler. */ ! 901: /* */ ! 902: /******************************************************************************************************** */ ! 903: ! 904: GetExtHandlerAddress: ! 905: mflr r11 /* Save our return */ ! 906: bl GEXbase /* Make a base address */ ! 907: GEXbase: mflr r3 /* Get address into our base */ ! 908: addi r3,r3,LOW_ADDR(GotSignal-GEXbase) /* Get the logical address of the 'rupt handler */ ! 909: ! 910: mtlr r11 /* Restore LR */ ! 911: blr ! 912: ! 913: ! 914: /******************************************************************************************************** */ ! 915: /* */ ! 916: /* Here we will get a snapshot of the processor's current signaling state (R3=processor). */ ! 917: /* */ ! 918: /******************************************************************************************************** */ ! 919: ! 920: ProcessorState: ! 921: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 922: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 923: cmplwi cr1,r3,MPPIMaxCPU /* See if we are bigger than max */ ! 924: li r3,kSIGPTargetAddrErr /* CPU number is too big */ ! 925: bgtlr- cr1 /* Sure are... (Get our address also) */ ! 926: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 927: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 928: add r9,r9,r12 /* Point right at the entry */ ! 929: lwz r4,MPPICStat(r9) /* Get the status word */ ! 930: li r3,kSIGPnoErr /* Set no errors */ ! 931: rlwinm. r4,r4,0,0,0 /* Test for busy status */ ! 932: beqlr /* Return kSIGPnoErr if not busy */ ! 933: li r3,kSIGPInterfaceBusyErr /* Otherwise, return busy */ ! 934: blr /* Return it */ ! 935: ! 936: /******************************************************************************************************** */ ! 937: /* */ ! 938: /* Here we will try to handle any pending messages (just as if an interruption occurred). */ ! 939: /* The purpose of this function is to assure the message passing system runs even */ ! 940: /* though external interrupts are disabled. Lacking a separate physical signalling */ ! 941: /* class, we have to share the external interrupt signal. Unfortunately, there are */ ! 942: /* times when disabled loops occur (in spin locks, in the debugger, etc.), and when they */ ! 943: /* happen, a low level message sent to a processor will not get processed, hence this */ ! 944: /* function exists to be called from those disabled loops. Since the calls are often */ ! 945: /* from disabled code, all that can be done is to process any pending *message*. Any */ ! 946: /* pending notification interruption (referred to throughtout this code as a SIGP */ ! 947: /* interruption) must remain pending. */ ! 948: /* */ ! 949: /******************************************************************************************************** */ ! 950: ! 951: RunSIGPRun: ! 952: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 953: mfspr r3,pir /* Get our CPU address */ ! 954: rlwinm r9,r3,5,23,26 /* Get index into CPU array */ ! 955: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 956: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 957: mflr r11 /* Save the link register */ ! 958: add r9,r9,r12 /* Point right at our entry */ ! 959: lwz r3,MPPICPriv(r9) /* Get our privates */ ! 960: cmplw cr1,r11,r11 /* Make sure IdleWait doesn't try to clear 'rupt request */ ! 961: oris r3,r3,MPPICXRun>>16 /* Diddle with them and show we entered here */ ! 962: stw r3,MPPICPriv(r9) /* Put away our privates */ ! 963: b IdleWait /* Go pretend there was an interrupt... */ ! 964: ! 965: /******************************************************************************************************** */ ! 966: /* */ ! 967: /* Error return. We only need this when we leave with a reservation. We really SHOULD clear it... */ ! 968: /* */ ! 969: /******************************************************************************************************** */ ! 970: ! 971: ErrorReturn: ! 972: mtlr r11 /* Restore LR */ ! 973: blr ! 974: ! 975: /******************************************************************************************************** */ ! 976: /* */ ! 977: /* Kick the target processor. Note that we won't set the passing bit until we are ready to exit. */ ! 978: /* The reason for this is that we have the silly, old watchchihuahua board to deal with. Because */ ! 979: /* we can't just set the interrupt and leave, we gotta wait for it to be seen on the other side. */ ! 980: /* This means that there could be a timeout and if so, we need to back off the function request else */ ! 981: /* we'd see busy when they tried to redrive it. We'll have to deal with a tad of spin on the secondary side. */ ! 982: /* note that this just applies to a primary to secondary function on the old board. */ ! 983: /* */ ! 984: /******************************************************************************************************** */ ! 985: ! 986: KickAndGo: ! 987: la r8,MPPICPU0-MPPIwork(r12) /* Get the primary work area address */ ! 988: mtlr r11 /* Restore the link register */ ! 989: cmplw cr0,r8,r9 /* Which is target? primary or secondary? */ ! 990: mfmsr r11 /* Save off the MSR */ ! 991: oris r5,r5,MPPICPass>>16 /* Set the passing bit on */ ! 992: stw r5,MPPICStat(r9) /* Store the pass and let the other processor go on */ ! 993: ! 994: beq KickPrimary /* The target is the primary... */ ! 995: ! 996: ori r3,r11,0x0010 /* Turn on DDAT bit */ ! 997: lbz r4,MPPIstatus-MPPIwork(r12) /* Load up the global status byte */ ! 998: lwz r8,MPPIHammer-MPPIwork(r12) /* Point to the Hammerhead area */ ! 999: ! 1000: mtmsr r3 /* Turn on DDAT */ ! 1001: isync ! 1002: ! 1003: andi. r4,r4,MPPI2Pv2 /* Are we on the new or old board? */ ! 1004: li r3,0 /* Set the bit for an interrupt request */ ! 1005: beq KickOld /* Ok, it's the old board... */ ! 1006: ! 1007: sync /* Make sure this is out there */ ! 1008: stb r3,IntReg(r8) /* Set the interruption signal */ ! 1009: eieio ! 1010: ! 1011: mtmsr r11 /* Set DDAT back to what it was */ ! 1012: isync ! 1013: li r3,kSIGPnoErr /* Set no errors */ ! 1014: blr /* Leave... */ ! 1015: ! 1016: KickOld: li r4,8 /* Set the number of tries */ ! 1017: ! 1018: KickAgain: mftb r6 /* Stamp the bottom half of time base */ ! 1019: stb r3,IntReg(r8) /* Stick the interrupt */ ! 1020: eieio /* Fence me in */ ! 1021: ! 1022: CheckKick: lbz r10,IntReg(r8) /* Get the interrupt request back again */ ! 1023: mr. r10,r10 /* Yes? Got it? */ ! 1024: bne FinalDelay /* Yeah, do the final delay and then go away... */ ! 1025: ! 1026: mftb r7 /* Get the time again */ ! 1027: sub r7,r7,r6 /* Get time-so-far */ ! 1028: cmplwi cr0,r7,75*TicksPerMic /* Hold it for 75�S (average disable is supposed to be 100�S or so) */ ! 1029: blt+ CheckKick /* Keep waiting the whole time... */ ! 1030: ! 1031: li r10,SecInt /* Set the deassert bit */ ! 1032: mftb r6 /* Stamp start of deassert time */ ! 1033: stb r10,IntReg(r8) /* Deassert the interrupt request */ ! 1034: eieio ! 1035: ! 1036: DeassertWT: mftb r7 /* Stamp out the time */ ! 1037: sub r7,r7,r6 /* Get elapsed */ ! 1038: cmplwi cr0,r7,16*TicksPerMic /* Hold off 16�S (minimum is 12�S) */ ! 1039: blt+ DeassertWT /* Keep spinning... */ ! 1040: ! 1041: subi r4,r4,1 /* See if we have another retry we can do */ ! 1042: mr. r4,r4 /* Are we there yet? */ ! 1043: blt+ KickAgain /* Retry one more time... */ ! 1044: ! 1045: rlwinm r5,r5,0,2,31 /* Clear busy and passing bits */ ! 1046: rlwinm r5,r5,0,24,15 /* Clear the function request to idle */ ! 1047: ! 1048: mtmsr r11 /* Restore DDAT stuff */ ! 1049: isync ! 1050: ! 1051: stw r5,MPPICStat(r9) /* Rescind the request */ ! 1052: li r3,kMPPTimeOut /* Set timeout */ ! 1053: blr /* Leave... */ ! 1054: ! 1055: FinalDelay: mftb r6 /* Stamp the start of the final delay */ ! 1056: ! 1057: FinalDelayW: ! 1058: mftb r7 /* Stamp out the time */ ! 1059: sub r7,r7,r6 /* Get elapsed */ ! 1060: cmplwi cr0,r7,16*TicksPerMic /* Hold off 16�S (minimum is 12�S) */ ! 1061: blt+ FinalDelayW /* Keep spinning... */ ! 1062: ! 1063: mtmsr r11 /* Restore DDAT stuff */ ! 1064: isync ! 1065: li r3,kSIGPnoErr /* Set no errors */ ! 1066: blr /* Leave... */ ! 1067: ! 1068: KickPrimary: ! 1069: ori r3,r11,0x0010 /* Turn on the DDAT bit */ ! 1070: lwz r8,MPPIEther-MPPIwork(r12) /* Get the address of the ethernet ROM */ ! 1071: ! 1072: mtmsr r3 /* Turn on DDAT */ ! 1073: isync ! 1074: ! 1075: li r4,4 /* Get flip count */ ! 1076: ! 1077: sync /* Make sure the status word is out there */ ! 1078: ! 1079: FlipOff: lbz r3,0(r8) /* Reference ethernet ROM to get chip select twiddled */ ! 1080: eieio /* Make sure of this (Hmm, this is chip select, not memory-mapped */ ! 1081: /* storage. Do we even need the eieio?) */ ! 1082: ! 1083: addic. r4,r4,-1 /* Have we flipped them off enough? */ ! 1084: bgt+ FlipOff /* Not yet, they deserve more... */ ! 1085: ! 1086: mtmsr r11 /* Restore DDAT stuff */ ! 1087: isync ! 1088: li r3,kSIGPnoErr /* Set no errors */ ! 1089: blr /* Return... */ ! 1090: ! 1091: /******************************************************************************************************** */ ! 1092: /* */ ! 1093: /* This is the code for the secondary processor */ ! 1094: /* */ ! 1095: /******************************************************************************************************** */ ! 1096: ! 1097: /* Note that none of this code needs locks because there's kind of a synchronization */ ! 1098: /* shuffle going on. */ ! 1099: ! 1100: /* */ ! 1101: /* First, we need to do a bit of initialization of the processor. */ ! 1102: /* */ ! 1103: ! 1104: ! 1105: CPUInit: ! 1106: li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */ ! 1107: mtmsr r27 /* Load 'em on in */ ! 1108: isync ! 1109: ! 1110: lis r28,-32768 /* Turn on machine checks */ ! 1111: /* should be 0x8000 */ ! 1112: ori r28,r28,0xCC84 /* Enable caches, clear them, */ ! 1113: /* disable serial execution and turn BHT on */ ! 1114: sync ! 1115: mtspr HID0,r28 /* Start the cache clear */ ! 1116: sync ! 1117: ! 1118: /* */ ! 1119: /* Clear out the TLB. They be garbage after hard reset. */ ! 1120: /* */ ! 1121: ! 1122: li r0,512 /* Get number of TLB entries (FIX THIS) */ ! 1123: li r3,0 /* Start at 0 */ ! 1124: mtctr r0 /* Set the CTR */ ! 1125: ! 1126: purgeTLB: tlbie r3 /* Purge this entry */ ! 1127: addi r3,r3,4096 /* Next page */ ! 1128: bdnz purgeTLB /* Do 'em all... */ ! 1129: ! 1130: sync /* Make sure all TLB purges are done */ ! 1131: tlbsync /* Make sure on other processors also */ ! 1132: sync /* Make sure the TLBSYNC is done */ ! 1133: ! 1134: /* */ ! 1135: /* Clear out the BATs. They are garbage after hard reset. */ ! 1136: /* */ ! 1137: ! 1138: li r3,0 /* Clear a register */ ! 1139: ! 1140: mtspr DBAT0L,r3 /* Clear BAT */ ! 1141: mtspr DBAT0U,r3 /* Clear BAT */ ! 1142: mtspr DBAT1L,r3 /* Clear BAT */ ! 1143: mtspr DBAT1U,r3 /* Clear BAT */ ! 1144: mtspr DBAT2L,r3 /* Clear BAT */ ! 1145: mtspr DBAT2U,r3 /* Clear BAT */ ! 1146: mtspr DBAT3L,r3 /* Clear BAT */ ! 1147: mtspr DBAT3U,r3 /* Clear BAT */ ! 1148: ! 1149: mtspr IBAT0L,r3 /* Clear BAT */ ! 1150: mtspr IBAT0U,r3 /* Clear BAT */ ! 1151: mtspr IBAT1L,r3 /* Clear BAT */ ! 1152: mtspr IBAT1U,r3 /* Clear BAT */ ! 1153: mtspr IBAT2L,r3 /* Clear BAT */ ! 1154: mtspr IBAT2U,r3 /* Clear BAT */ ! 1155: mtspr IBAT3L,r3 /* Clear BAT */ ! 1156: mtspr IBAT3U,r3 /* Clear BAT */ ! 1157: ! 1158: /* */ ! 1159: /* Map 0xF0000000 to 0xFFFFFFFF for I/O; make it R/W non-cacheable */ ! 1160: /* Map 0x00000000 to 0x0FFFFFFF for mainstore; make it R/W cachable */ ! 1161: /* */ ! 1162: ! 1163: lis r6,0xF000 /* Set RPN to last segment */ ! 1164: ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */ ! 1165: ! 1166: lis r7,0xF000 /* Set RPN to last segment */ ! 1167: ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */ ! 1168: ! 1169: mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */ ! 1170: mtspr DBAT0U,r6 /* Now do the upper DBAT */ ! 1171: sync ! 1172: ! 1173: li r6,0x1FFF /* Set up upper BAT for 256M, access both */ ! 1174: li r7,0x0012 /* Set up lower BAT for r/w access */ ! 1175: ! 1176: mtspr DBAT1L,r7 /* Set up an initial view of mainstore */ ! 1177: mtspr DBAT1U,r6 /* Now do the upper DBAT */ ! 1178: sync ! 1179: ! 1180: /* */ ! 1181: /* Clean up SDR and segment registers */ ! 1182: /* */ ! 1183: ! 1184: li r3,0 /* Clear a register */ ! 1185: mtspr SDR1,r3 /* Clear SDR1 */ ! 1186: ! 1187: li r4,0 /* Clear index for segment registers */ ! 1188: lis r5,0x1000 /* Set the segment indexer */ ! 1189: ! 1190: clearSR: mtsrin r3,r4 /* Zero out the SR */ ! 1191: add. r4,r4,r5 /* Point to the next segment */ ! 1192: bne- clearSR /* Keep going until we wrap back to 0 */ ! 1193: ! 1194: lis r5,HIGH_ADDR(EXT(FloatInit)) /* Get top of floating point init value */ ! 1195: ori r5,r5,LOW_ADDR(EXT(FloatInit)) /* Slam bottom */ ! 1196: lfd f0,0(r5) /* Initialize FP0 */ ! 1197: fmr f1,f0 /* Ours in not */ ! 1198: fmr f2,f0 /* to wonder why, */ ! 1199: fmr f3,f0 /* ours is but to */ ! 1200: fmr f4,f0 /* do or die! */ ! 1201: fmr f5,f0 ! 1202: fmr f6,f0 ! 1203: fmr f7,f0 ! 1204: fmr f8,f0 ! 1205: fmr f9,f0 ! 1206: fmr f10,f0 ! 1207: fmr f11,f0 ! 1208: fmr f12,f0 ! 1209: fmr f13,f0 ! 1210: fmr f14,f0 ! 1211: fmr f15,f0 ! 1212: fmr f16,f0 ! 1213: fmr f17,f0 ! 1214: fmr f18,f0 ! 1215: fmr f19,f0 ! 1216: fmr f20,f0 ! 1217: fmr f21,f0 ! 1218: fmr f22,f0 ! 1219: fmr f23,f0 ! 1220: fmr f24,f0 ! 1221: fmr f25,f0 ! 1222: fmr f26,f0 ! 1223: fmr f27,f0 ! 1224: fmr f28,f0 ! 1225: fmr f29,f0 ! 1226: fmr f30,f0 ! 1227: fmr f31,f0 ! 1228: ! 1229: /* */ ! 1230: /* Whew, that was like, work, man! What a cleaning job, I should be neater */ ! 1231: /* when I reset. */ ! 1232: /* */ ! 1233: /* Finally we can get some data DAT turned on and we can reset the interrupt */ ! 1234: /* (which may have been done before we get here) and get into the bring up */ ! 1235: /* handshakes. */ ! 1236: /* */ ! 1237: /* Note that here we need to use the actual V=R addresses for HammerHead */ ! 1238: /* and PCI1 adr. There are no virtual mappings set up on this processor. */ ! 1239: /* We need to switch once the firmware is initialized. Also, we don't know */ ! 1240: /* where our control block is yet. */ ! 1241: /* */ ! 1242: ! 1243: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 1244: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 1245: ! 1246: mfmsr r3 /* Get the MSR */ ! 1247: ori r3,r3,0x0010 /* Turn data DAT on */ ! 1248: mtmsr r3 /* DAT is on (well, almost) */ ! 1249: isync /* Now it is for sure */ ! 1250: ! 1251: lis r8,HammerHead>>16 /* Point to the HammerHead controller */ ! 1252: li r7,SecInt /* Get value to reset */ ! 1253: stb r7,IntReg(r8) /* Reset the interrupt */ ! 1254: eieio /* Fence it off */ ! 1255: ! 1256: /* */ ! 1257: /* Now we can plant and harvest some bits. */ ! 1258: /* */ ! 1259: ! 1260: lwz r6,MPPIlogCPU-MPPIwork(r12) /* Get the logical CPU address to assign */ ! 1261: mfspr r7,pir /* Get the old PIR */ ! 1262: rlwimi r7,r6,0,27,31 /* Copy all of the reserved parts */ ! 1263: mtspr pir,r7 /* Set it */ ! 1264: ! 1265: /* */ ! 1266: /* This little piece of code here determines if we are on the first or second version */ ! 1267: /* of the two processor board. The old one shouldn't ever be shipped (well, maybe by */ ! 1268: /* DayStar) but there are some around here. */ ! 1269: /* */ ! 1270: /* The newer version of the 2P board has a different state machine than the older one. */ ! 1271: /* When we are in the board state we're in now, primary arbitration is turned on while */ ! 1272: /* it is not until the next state in the old board. By checking the our bus address */ ! 1273: /* (WhoAmI) we can tell. */ ! 1274: /* */ ! 1275: ! 1276: lbz r7,WhoAmI(r8) /* Get the current bus master ID */ ! 1277: andi. r7,r7,PriCPU /* Do we think we're the primary? */ ! 1278: beq On2Pv1 /* No, that means we're on the old 2P board */ ! 1279: ! 1280: lbz r7,MPPIstatus-MPPIwork(r12) /* Get the status byte */ ! 1281: ori r7,r7,MPPI2Pv2 /* Show we're on the new board */ ! 1282: stb r7,MPPIstatus-MPPIwork(r12) /* Set the board version */ ! 1283: ! 1284: On2Pv1: rlwinm r9,r6,5,23,26 /* Get index into the CPU specific area */ ! 1285: ! 1286: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Index to processor */ ! 1287: add r9,r9,r12 /* Get a base for our CPU specific area */ ! 1288: ! 1289: oris r6,r6,((MPPICBusy+MPPICOnline+MPPICStop)>>16)&0x0000FFFF /* Set CPU busy, online, stopped, */ ! 1290: /* and busy set by himself */ ! 1291: stw r6,MPPICStat(r9) /* Save the whole status word */ ! 1292: ! 1293: li r4,0x80 /* Get beginnings of a CPU address mask */ ! 1294: lhz r11,MPPIinst-MPPIwork(r12) /* Get the installed and online status flags */ ! 1295: srw r4,r4,r6 /* Make a mask */ ! 1296: rlwimi r4,r4,8,16,23 /* Double up the mask for both flags */ ! 1297: or r11,r11,r4 /* Set that we are installed and online */ ! 1298: sync /* Make sure the main processor sees the rest of the stuff */ ! 1299: ! 1300: sth r11,MPPIinst-MPPIwork(r12) /* We're almost done, just need to set the TB */ ! 1301: ! 1302: lis r5,PCI1AdrReg>>16 /* Point to the PCI1 address register */ ! 1303: li r4,0 /* Clear this out */ ! 1304: stw r4,0(r5) /* Set PCI register to 0 to show we're ready for TB sync */ ! 1305: eieio /* Fence it off */ ! 1306: ! 1307: Wait4TB: lwz r7,0(r5) /* Get the PCI1 reg to see if time to set time */ ! 1308: mr. r7,r7 /* Is it ready yet? */ ! 1309: beq Wait4TB /* Nope, wait for it... */ ! 1310: isync /* No peeking... */ ! 1311: ! 1312: lwz r3,MPPITBsync-MPPIwork(r12) /* Get the high word of TB */ ! 1313: lwz r4,MPPITBsync+4-MPPIwork(r12) /* Get the low word */ ! 1314: ! 1315: /* Note that we need no TB magic here 'cause they ain't running */ ! 1316: ! 1317: mttbu r3 /* Set the high part */ ! 1318: mttbl r4 /* Set the low part */ ! 1319: ! 1320: rlwinm r6,r6,0,2,31 /* Clear the busy bit and passed */ ! 1321: stw r6,MPPICStat(r9) /* Store the status word */ ! 1322: ! 1323: sync /* Make sure all is right with the world */ ! 1324: ! 1325: li r3,0 /* Set the init done signal */ ! 1326: stw r3,0(r5) /* Feed the dog and let him out */ ! 1327: sync /* Make sure this is pushed on out */ ! 1328: ! 1329: li r27,0x3040 /* Make MSR the way we likes it */ ! 1330: mtmsr r27 /* Load 'em on in */ ! 1331: isync ! 1332: ! 1333: /* */ ! 1334: /* Jump on to the idle wait loop. We're online and ready, but we're */ ! 1335: /* still in the reset state. We need to wait until we see a start signal. */ ! 1336: /* */ ! 1337: /* Note that the idle loop expects R9 to be our CPU-specific work area; */ ! 1338: /* R12 is the base of the code and global work area */ ! 1339: /* */ ! 1340: ! 1341: cmplw cr1,r11,r12 /* Make sure IdleWait knows to clear 'rupt request */ ! 1342: b IdleWait ! 1343: ! 1344: ! 1345: /******************************************************************************************************** */ ! 1346: /******************************************************************************************************** */ ! 1347: /* */ ! 1348: /* Here is the interruption handler. */ ! 1349: /* */ ! 1350: /* What we'll do here is to get our registers into a standard state and figure out which */ ! 1351: /* which processor we are on. The processors have pretty much the same code. The primary */ ! 1352: /* will reset the the secondary to primary interruption bit and the secondary will reset the SecInt */ ! 1353: /* flags. */ ! 1354: /* */ ! 1355: /* The primary to secondary interrupt is an exception interruption contolled by a bit in the */ ! 1356: /* Hammerhead IntReg. The only bit in here is SecInt which is active low. Writing a 0 into the */ ! 1357: /* bit (bit 0) yanks on the external pin on the secondary. Note that it is the only external */ ! 1358: /* connected on the secondary. SecInt must be set to 1 to clear the interruption. On the old */ ! 1359: /* 2P board, asserting the external interrupt causes a watchdog timer to start which expires unless */ ! 1360: /* the interrupt request is withdrawn. On a 180Mhz system the time to expire is about 256�S, */ ! 1361: /* not very long. So, what we need to do is to time the assertion and if it has not been reset */ ! 1362: /* reset, do it ourself. Unfortunatelty we need to keep it deasserted for at least 12�S or the */ ! 1363: /* watchdog will not stop. This leads to another problem: even if the secondary processor sees */ ! 1364: /* the interrupt and deasserts the request itself, we cannot reassert before the 12�S limit, */ ! 1365: /* else havoc will be wrought. We just gotta make sure. */ ! 1366: /* */ ! 1367: /* So, the secondary to primary interrupt is megafunky. The mother board is wired with the */ ! 1368: /* MACE ethernet chip's chip-select pin wired to Grand Centeral's external interrrupt #10 pin. */ ! 1369: /* This causes a transient interrupt whenever MACE is diddled. GC latches the interrupt into the */ ! 1370: /* events register where we can see it and clear it. */ ! 1371: /* */ ! 1372: /******************************************************************************************************** */ ! 1373: /******************************************************************************************************** */ ! 1374: ! 1375: GotSignal: mfspr r9,pir /* Get our processor ID */ ! 1376: lis r12,HIGH_ADDR(MPPIwork) /* Get the top half of the data area */ ! 1377: rlwinm r9,r9,5,23,26 /* Clean this up */ ! 1378: ori r12,r12,LOW_ADDR(MPPIwork) /* Get the bottom half of the data area */ ! 1379: la r9,EXT(MPPICPUs)-MPPIwork(r9) /* Point into the proccessor control area */ ! 1380: mflr r11 /* Save our return */ ! 1381: add r9,r9,r12 /* Point right at the entry */ ! 1382: ! 1383: /* We'll come in here if we're stopped and found the 'rupt via polling */ ! 1384: /* or we were kicked off by the PollSIGP call. We need */ ! 1385: /* to wipe out the interrupt request no matter how we got here. */ ! 1386: ! 1387: SimRupt: mfmsr r4 /* Get the MSR */ ! 1388: ! 1389: la r8,MPPICPU0-MPPIwork(r12) /* Get address of main processor's work area */ ! 1390: ori r5,r4,0x0010 /* Turn on the DDAT bit */ ! 1391: cmplw cr0,r8,r9 /* Are we on the main? */ ! 1392: cmplw cr1,r4,r4 /* Set CR1 to indicate we've cleared any 'rupts */ ! 1393: bne SecondarySig /* Go if we are not on main processor... */ ! 1394: ! 1395: /* */ ! 1396: /* Handle the secondary to primary signal */ ! 1397: /* */ ! 1398: ! 1399: PrimarySig: ! 1400: ! 1401: lwz r8,MPPIGrandC-MPPIwork(r12) /* Get the address of the Grand Central area base */ ! 1402: mtmsr r5 /* Turn on DDAT */ ! 1403: isync /* Now don't be usin' dem speculative executions */ ! 1404: li r7,EventsReg /* Get address of the interrupt events register */ ! 1405: lwbrx r6,r7,r8 /* Grab the interruption events */ ! 1406: ! 1407: lis r5,0x4000 /* Get the mask for the Ext10 pin */ ! 1408: and. r0,r6,r5 /* See if our bit is on */ ! 1409: li r7,ClearReg /* Point to the interruption clear register */ ! 1410: ! 1411: beq+ SkpClr /* Skip the clear 'cause it's supposed to be soooo slow... */ ! 1412: ! 1413: stwbrx r5,r7,r8 /* Reset the interrupt latch */ ! 1414: eieio /* Fence off the last 'rupt */ ! 1415: ! 1416: SkpClr: mtmsr r4 /* Set MSR to entry state */ ! 1417: isync /* Make sure we ain't gunked up no future storage references */ ! 1418: ! 1419: bne+ IdleWait /* Go join up and decode the function... */ ! 1420: ! 1421: mtlr r11 /* Restore return address */ ! 1422: andc. r0,r6,r5 /* Any other bits on? */ ! 1423: li r3,kMPVainInterrupt /* Assume we got nothing */ ! 1424: beqlr /* We got nothing, tell 'em to eat 'rupt... */ ! 1425: li r3,kMPIOInterruptPending /* Tell them to process an I/O 'rupt */ ! 1426: blr /* Ignore the interrupt... */ ! 1427: ! 1428: /* */ ! 1429: /* Handle the primary to secondary signal */ ! 1430: /* */ ! 1431: ! 1432: SecondarySig: ! 1433: lwz r3,MPPICStat(r9) /* Pick up our status word */ ! 1434: lis r8,HammerHead>>16 /* Get the address of the hammerhead (used during INIT on non-main processor) */ ! 1435: rlwinm. r3,r3,0,3,3 /* Check if we are already "in-the-know" (all started up) */ ! 1436: beq- UseAltAddr /* Nope, use hardcoded Hammerhead address */ ! 1437: lwz r8,MPPIHammer-MPPIwork(r12) /* Get the kernel's HammerHead area */ ! 1438: ! 1439: UseAltAddr: mtmsr r5 /* Turn on DDAT */ ! 1440: isync /* Now don't be usin' dem speculative executions */ ! 1441: li r0,SecInt /* Get the Secondary interrupt bit */ ! 1442: stb r0,IntReg(r8) /* Reset the interrupt request */ ! 1443: mtmsr r4 /* Set MSR to entry state */ ! 1444: eieio /* Fence me in */ ! 1445: isync /* Make sure we ain't gunked up no future storage references */ ! 1446: ! 1447: b IdleWait /* Go decode this request... */ ! 1448: ! 1449: /******************************************************************************************************** */ ! 1450: /******************************************************************************************************** */ ! 1451: /* */ ! 1452: /* This is the idle wait. */ ! 1453: /* */ ! 1454: /* We're stuck in here so long as we are stopped or reset. */ ! 1455: /* All functions except for "start" pass back through here. Start is weird because */ ! 1456: /* it is an initial thing, i.e., we can't have gotten here via any kind of exception, */ ! 1457: /* so there is no state to restore. The "started" code is expected to require no know */ ! 1458: /* state and will take care of all initialization/fixup required. */ ! 1459: /* */ ! 1460: /******************************************************************************************************** */ ! 1461: /******************************************************************************************************** */ ! 1462: ! 1463: BadRuptState: /* We don't do anything special yet for a bad state, just eat request */ ! 1464: KillBusy: rlwinm r3, r3, 0, 2, 31 /* Remove the message pending flags. */ ! 1465: rlwinm r3, r3, 0, 24, 16 /* Set the function to idle. */ ! 1466: stw r3,MPPICStat(r9) /* Update/unlock the status word. */ ! 1467: ! 1468: ReenterWait: cmplwi cr1,r9,0 /* Turn off the 'rupt cleared flag */ ! 1469: ! 1470: IdleWait: lis r4,MPPICBusy>>16 /* Get busy status */ ! 1471: ! 1472: SpinIdle: ! 1473: lwz r3,MPPICStat(r9) /* Pick up our status word */ ! 1474: ! 1475: and. r5,r3,r4 /* Isolate the busy bit */ ! 1476: lis r6,MPPICPass>>16 /* Get the passed busy flag */ ! 1477: bne TooBusy /* Work, work, work, that's all we do is work... */ ! 1478: ! 1479: rlwinm. r5,r3,0,4,4 /* See if we are stopped */ ! 1480: lwz r8,MPPICPriv(r9) /* Pick up our private flags */ ! 1481: bne- SpinIdle /* Yeah, keep spinning... */ ! 1482: ! 1483: ! 1484: /* */ ! 1485: /* Restore the state and get outta here. Now, we shouldn't be in a reset state and not be stopped, */ ! 1486: /* so we can go ahead and safely return up a level because it exists. If we are reset, no state exists */ ! 1487: /* and we should always be stopped. */ ! 1488: /* */ ! 1489: ! 1490: rlwinm r4, r8, 1, 0, 0 /* Get the explicit run bit, shifted left one. */ ! 1491: rlwinm. r5, r8, 0, 0, 0 /* See if there is a SIGP signal pending */ ! 1492: and r4, r8, r4 /* Turn off the SIGP pending bit if this was not an explicit run */ ! 1493: /* Also the explicit run bit is cleared */ ! 1494: mtlr r11 /* Restore the return point */ ! 1495: li r3,kMPVainInterrupt /* Tell the interrupt handler to ignore the interrupt */ ! 1496: stw r4,MPPICPriv(r9) /* Set that flag back for later */ ! 1497: beqlr /* Time to leave if we ate the 'rupt... */ ! 1498: ! 1499: li r3,kMPSignalPending /* Set that there is a SIGP interruption pending */ ! 1500: ! 1501: blr /* Go away, let our caller handle this thing... QED!!!!!!!!! */ ! 1502: ! 1503: /* */ ! 1504: /* QQQQQ EEEEEEEEEE DDDDDDDDD */ ! 1505: /* QQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */ ! 1506: /* QQQQ QQQQ EEEE DDD DDD */ ! 1507: /* QQQQ QQQQ EEEEEEEEEE DDD DDD */ ! 1508: /* QQQQ Q QQQQ EEEEEEEEEE DDD DDD */ ! 1509: /* QQQQ QQQQQ EEEE DDD DDD */ ! 1510: /* QQQQQQQQQQQ EEEEEEEEEE DDDDDDDDDDD */ ! 1511: /* QQQQQ QQQ EEEEEEEEEE DDDDDDDDD */ ! 1512: /* */ ! 1513: /* (I finished here) */ ! 1514: /* */ ! 1515: ! 1516: ! 1517: /* */ ! 1518: /* This is where we decode the function and do what's right. */ ! 1519: /* First we need to check if it's really time to do something. */ ! 1520: /* */ ! 1521: ! 1522: TooBusy: and. r5,r3,r6 /* See if the passed flag is on */ ! 1523: beq SpinIdle /* No, not yet, try the whole smear again... */ ! 1524: ! 1525: beq+ cr1,KeepRupt /* Don't clear 'rupt if we already did (or entered via RunSIGRun) */ ! 1526: ! 1527: lwz r5,MPPICPriv(r9) /* Get the private flags */ ! 1528: rlwinm. r5, r5, 0, 1, 1 /* Did we enter via RunSIGPRun? */ ! 1529: beq SimRupt /* Nope, 's'ok, go clear physical 'rupt... */ ! 1530: ! 1531: KeepRupt: ! 1532: bl GetOurBase /* Get our address */ ! 1533: GetOurBase: rlwinm r4,r3,26,22,29 /* Get the opcode index * 4 */ ! 1534: mflr r12 /* Get the base address */ ! 1535: la r7,LOW_ADDR(IFuncTable-GetOurBase)(r12) /* Point to the function table */ ! 1536: ! 1537: cmplwi cr0,r4,7*4 /* See if they sent us some bogus junk */ ! 1538: /* Change 7 if we add more functions */ ! 1539: add r7,r7,r4 /* Point right at the entry */ ! 1540: bgt- KillBusy /* Bad request code, reset busy and eat it... */ ! 1541: ! 1542: mtlr r7 /* Set up the LR */ ! 1543: ! 1544: blr /* Go execute the function... */ ! 1545: ! 1546: IFuncTable: ! 1547: b KillBusy /* This handles the signal in vain... */ ! 1548: b IStart /* This handles the start function */ ! 1549: b IResume /* This handles the resume function */ ! 1550: b IStop /* This handles the stop function */ ! 1551: b ISIGP /* This handles the SIGP function */ ! 1552: b IStatus /* This handles the store status function */ ! 1553: b ITBsync /* This handles the synchronize timer base function */ ! 1554: b IReset /* This handles the reset function */ ! 1555: ! 1556: /******************************************************************************************************** */ ! 1557: /******************************************************************************************************** */ ! 1558: /* */ ! 1559: /* Here are the functions handled at interrupt time */ ! 1560: /* */ ! 1561: /******************************************************************************************************** */ ! 1562: /******************************************************************************************************** */ ! 1563: ! 1564: /******************************************************************************************************** */ ! 1565: /* */ ! 1566: /* The Start function. This guy requires that the processor be in the reset and online state. */ ! 1567: /* */ ! 1568: /******************************************************************************************************** */ ! 1569: ! 1570: IStart: lis r4,MPPICOnline>>16 /* Get bits required to be on */ ! 1571: isync /* Make sure we haven't gone past here */ ! 1572: and r6,r3,r4 /* See if they are on */ ! 1573: cmplw cr1,r6,r4 /* Are they all on? */ ! 1574: lwz r4,MPPICParm0(r9) /* Get the physical address of the code to go to */ ! 1575: bne- cr1,BadRuptState /* Some required state bits are off */ ! 1576: rlwinm r3,r3,0,2,31 /* Kill the busy bits */ ! 1577: rlwinm r3,r3,0,24,15 /* Set the function to idle */ ! 1578: oris r3,r3,MPPICReady>>16 /* Set ready state */ ! 1579: rlwinm r3,r3,0,5,3 /* Clear out the stop bit */ ! 1580: mtlr r4 /* Set the LR */ ! 1581: stw r3,MPPICStat(r9) /* Clear out the status flags */ ! 1582: lwz r3,MPPICParm2(r9) /* Get pass-thru parameter */ ! 1583: blrl /* Start up the code... */ ! 1584: /* */ ! 1585: /* The rules for coming back here via BLR are just opposite the normal way: you can trash R0-R3 and */ ! 1586: /* R13-R31, all the CRs; don't touch SPRG1 or SPRG3, the MSR, the SRs or BATs 0 and 1. */ ! 1587: /* Follow these simple rules and you allowed back; don't follow them and die. */ ! 1588: /* We only come back here if there is some kind of startup failure so's we can try again later */ ! 1589: /* */ ! 1590: ! 1591: lwz r3,MPPICStat(r9) /* Get back the status word */ ! 1592: cmplw cr1,r4,r4 /* Show that we have already taken care of the 'rupt */ ! 1593: rlwinm r3,r3,0,4,2 /* Reset the ready bit */ ! 1594: b KillBusy /* Back into the fold... */ ! 1595: ! 1596: /******************************************************************************************************** */ ! 1597: /* */ ! 1598: /* The Resume function. This guy requires that the processor be online and ready. */ ! 1599: /* */ ! 1600: /******************************************************************************************************** */ ! 1601: ! 1602: IResume: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */ ! 1603: and r6,r3,r4 /* See if they are on */ ! 1604: cmplw cr0,r6,r4 /* Are they all on? */ ! 1605: bne- BadRuptState /* Some required off state bits are on */ ! 1606: rlwinm r3,r3,0,5,3 /* Clear out the stop bit */ ! 1607: b KillBusy /* Get going... */ ! 1608: ! 1609: /******************************************************************************************************** */ ! 1610: /* */ ! 1611: /* The Stop function. All we care about here is that the guy is online. */ ! 1612: /* */ ! 1613: /******************************************************************************************************** */ ! 1614: ! 1615: IStop: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */ ! 1616: and. r6,r3,r4 /* See if we are online */ ! 1617: beq- BadRuptState /* Some required off state bits are on */ ! 1618: oris r3,r3,MPPICStop>>16 /* Set the stop bit */ ! 1619: b KillBusy /* Get stopped... */ ! 1620: ! 1621: ! 1622: /******************************************************************************************************** */ ! 1623: /* */ ! 1624: /* The SIGP function. All we care about here is that the guy is online. */ ! 1625: /* */ ! 1626: /******************************************************************************************************** */ ! 1627: ! 1628: ISIGP: lis r4,(MPPICOnline+MPPICReady)>>16 /* Get states required to be set */ ! 1629: and r6,r3,r4 /* See if they are on */ ! 1630: lwz r7,MPPICPriv(r9) /* Get the private flags */ ! 1631: cmplw cr0,r6,r4 /* Are they all on? */ ! 1632: oris r6,r7,(MPPICSigp>>16)&0x0000FFFF /* Set the SIGP pending bit */ ! 1633: bne- BadRuptState /* Some required off state bits are on */ ! 1634: lwz r4,MPPICParm0(r9) /* Get the SIGP parameter */ ! 1635: stw r6,MPPICPriv(r9) /* Stick the pending bit back */ ! 1636: stw r4,MPPICParm0BU(r9) /* Back up parm 0 so it is safe once we unlock */ ! 1637: b KillBusy /* Get stopped... */ ! 1638: ! 1639: /******************************************************************************************************** */ ! 1640: /* */ ! 1641: /* The store status function. This guy requires that the processor be in the stopped state. */ ! 1642: /* */ ! 1643: /******************************************************************************************************** */ ! 1644: ! 1645: IStatus: lis r4,MPPICOnline>>16 /* All we care about is if we are online or not */ ! 1646: and. r6,r3,r4 /* See if we are online */ ! 1647: isync /* Make sure we havn't gone past here */ ! 1648: beq- BadRuptState /* Some required off state bits are on */ ! 1649: lwz r4,MPPICParm0(r9) /* Get the status area physical address */ ! 1650: rlwinm. r6,r3,0,3,3 /* Test processor ready */ ! 1651: ! 1652: beq INotReady /* Not ready, don't assume valid exception save area */ ! 1653: bl StoreStatus /* Go store off all the registers 'n' stuff */ ! 1654: b KillBusy /* All done... */ ! 1655: ! 1656: INotReady: ! 1657: lis r7,0xDEAD /* Get 0xDEAD + 1 */ ! 1658: ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */ ! 1659: stw r7,CSAgpr+(0*4)(r4) /* Store invalid R0 */ ! 1660: stw r7,CSAgpr+(1*4)(r4) /* Store invalid R1 */ ! 1661: stw r7,CSAgpr+(2*4)(r4) /* Store invalid R2 */ ! 1662: stw r7,CSAgpr+(3*4)(r4) /* Store invalid R3 */ ! 1663: stw r7,CSAgpr+(4*4)(r4) /* Store invalid R4 */ ! 1664: stw r7,CSAgpr+(5*4)(r4) /* Store invalid R5 */ ! 1665: stw r7,CSAgpr+(6*4)(r4) /* Store invalid R6 */ ! 1666: stw r7,CSAgpr+(7*4)(r4) /* Store invalid R7 */ ! 1667: stw r7,CSAgpr+(8*4)(r4) /* Store invalid R8 */ ! 1668: stw r7,CSAgpr+(9*4)(r4) /* Store invalid R9 */ ! 1669: stw r7,CSAgpr+(10*4)(r4) /* Store invalid R10 */ ! 1670: stw r7,CSAgpr+(11*4)(r4) /* Store invalid R11 */ ! 1671: stw r7,CSAgpr+(12*4)(r4) /* Store invalid R12 */ ! 1672: stw r13,CSAgpr+(13*4)(r4) /* Save general registers */ ! 1673: stw r14,CSAgpr+(14*4)(r4) /* Save general registers */ ! 1674: stw r15,CSAgpr+(15*4)(r4) /* Save general registers */ ! 1675: stw r16,CSAgpr+(16*4)(r4) /* Save general registers */ ! 1676: stw r17,CSAgpr+(17*4)(r4) /* Save general registers */ ! 1677: stw r18,CSAgpr+(18*4)(r4) /* Save general registers */ ! 1678: stw r19,CSAgpr+(19*4)(r4) /* Save general registers */ ! 1679: stw r20,CSAgpr+(20*4)(r4) /* Save general registers */ ! 1680: stw r21,CSAgpr+(21*4)(r4) /* Save general registers */ ! 1681: stw r22,CSAgpr+(22*4)(r4) /* Save general registers */ ! 1682: stw r23,CSAgpr+(23*4)(r4) /* Save general registers */ ! 1683: stw r24,CSAgpr+(24*4)(r4) /* Save general registers */ ! 1684: stw r25,CSAgpr+(25*4)(r4) /* Save general registers */ ! 1685: stw r26,CSAgpr+(26*4)(r4) /* Save general registers */ ! 1686: stw r27,CSAgpr+(27*4)(r4) /* Save general registers */ ! 1687: stw r28,CSAgpr+(28*4)(r4) /* Save general registers */ ! 1688: stw r29,CSAgpr+(29*4)(r4) /* Save general registers */ ! 1689: stw r30,CSAgpr+(30*4)(r4) /* Save general registers */ ! 1690: stw r31,CSAgpr+(31*4)(r4) /* Save general registers */ ! 1691: bl StoreLiveStatus ! 1692: b KillBusy ! 1693: ! 1694: /* */ ! 1695: /* Save the whole status. Lot's of busy work. */ ! 1696: /* Anything marked unclean is of the devil and should be shunned. Actually, it depends upon */ ! 1697: /* knowledge of firmware control areas and is no good for a plug in. But, we've sacrificed the */ ! 1698: /* white ram and are standing within a circle made of his skin, so we can dance with the devil */ ! 1699: /* safely. */ ! 1700: /* */ ! 1701: ! 1702: StoreStatus: ! 1703: mfspr r10,sprg0 /* Get the pointer to the exception save area (unclean) */ ! 1704: ! 1705: lwz r5,saver0(r13) /* Get R0 (unclean) */ ! 1706: lwz r6,saver1(r13) /* Get R1 (unclean) */ ! 1707: lwz r7,saver2(r13) /* Get R2 (unclean) */ ! 1708: stw r5,CSAgpr+(0*4)(r4) /* Save R0 */ ! 1709: stw r6,CSAgpr+(1*4)(r4) /* Save R1 */ ! 1710: stw r7,CSAgpr+(2*4)(r4) /* Save R2 */ ! 1711: lwz r5,saver3(r13) /* Get R3 (unclean) */ ! 1712: lwz r6,saver4(r13) /* Get R4 (unclean) */ ! 1713: lwz r7,saver5(r13) /* Get R5 (unclean) */ ! 1714: stw r5,CSAgpr+(3*4)(r4) /* Save R3 */ ! 1715: stw r6,CSAgpr+(4*4)(r4) /* Save R4 */ ! 1716: stw r7,CSAgpr+(5*4)(r4) /* Save R5 */ ! 1717: lwz r5,saver6(r13) /* Get R6 (unclean) */ ! 1718: lwz r6,saver7(r13) /* Get R7 (unclean) */ ! 1719: lwz r7,saver8(r13) /* Get R8 (unclean) */ ! 1720: stw r5,CSAgpr+(6*4)(r4) /* Save R6 */ ! 1721: stw r6,CSAgpr+(7*4)(r4) /* Save R7 */ ! 1722: stw r7,CSAgpr+(8*4)(r4) /* Save R8 */ ! 1723: lwz r5,saver9(r13) /* Get R9 (unclean) */ ! 1724: lwz r6,saver10(r13) /* Get R10 (unclean) */ ! 1725: lwz r7,saver11(r13) /* Get R11 (unclean) */ ! 1726: stw r5,CSAgpr+(9*4)(r4) /* Save R9 */ ! 1727: stw r6,CSAgpr+(10*4)(r4) /* Save R10 */ ! 1728: lwz r5,saver12(r13) /* Get R12 (unclean) */ ! 1729: stw r7,CSAgpr+(11*4)(r4) /* Save R11 */ ! 1730: stw r5,CSAgpr+(12*4)(r4) /* Save R12 */ ! 1731: ! 1732: lwz r5,saver13(r13) /* Get R13 (unclean) */ ! 1733: lwz r6,saver14(r13) /* Get R14 (unclean) */ ! 1734: lwz r7,saver15(r13) /* Get R15 (unclean) */ ! 1735: stw r5,CSAgpr+(13*4)(r4) /* Save R13 */ ! 1736: stw r6,CSAgpr+(14*4)(r4) /* Save R14 */ ! 1737: stw r7,CSAgpr+(15*4)(r4) /* Save R15 */ ! 1738: lwz r5,saver16(r13) /* Get R16 (unclean) */ ! 1739: lwz r6,saver17(r13) /* Get R17 (unclean) */ ! 1740: lwz r7,saver18(r13) /* Get R18 (unclean) */ ! 1741: stw r5,CSAgpr+(16*4)(r4) /* Save R16 */ ! 1742: stw r6,CSAgpr+(17*4)(r4) /* Save R17 */ ! 1743: stw r7,CSAgpr+(18*4)(r4) /* Save R18 */ ! 1744: lwz r5,saver19(r13) /* Get R19 (unclean) */ ! 1745: lwz r6,saver20(r13) /* Get R20 (unclean) */ ! 1746: lwz r7,saver21(r13) /* Get R21 (unclean) */ ! 1747: stw r5,CSAgpr+(19*4)(r4) /* Save R19 */ ! 1748: stw r6,CSAgpr+(20*4)(r4) /* Save R20 */ ! 1749: stw r7,CSAgpr+(21*4)(r4) /* Save R21 */ ! 1750: lwz r5,saver22(r13) /* Get R22 (unclean) */ ! 1751: lwz r6,saver23(r13) /* Get R23 (unclean) */ ! 1752: lwz r7,saver24(r13) /* Get R24 (unclean) */ ! 1753: stw r5,CSAgpr+(22*4)(r4) /* Save R22 */ ! 1754: stw r6,CSAgpr+(23*4)(r4) /* Save R23*/ ! 1755: stw r7,CSAgpr+(24*4)(r4) /* Save R24 */ ! 1756: lwz r5,saver25(r13) /* Get R25 (unclean) */ ! 1757: lwz r6,saver26(r13) /* Get R26 (unclean) */ ! 1758: lwz r7,saver27(r13) /* Get R27 (unclean) */ ! 1759: stw r5,CSAgpr+(25*4)(r4) /* Save R25 */ ! 1760: stw r6,CSAgpr+(26*4)(r4) /* Save R26 */ ! 1761: stw r7,CSAgpr+(27*4)(r4) /* Save R27 */ ! 1762: ! 1763: lwz r5,saver28(r13) /* Get R28 (unclean) */ ! 1764: lwz r6,saver29(r13) /* Get R29 (unclean) */ ! 1765: lwz r7,saver30(r13) /* Get R30 (unclean) */ ! 1766: stw r5,CSAgpr+(28*4)(r4) /* Save R28 */ ! 1767: lwz r5,saver31(r13) /* Get R31(unclean) */ ! 1768: stw r6,CSAgpr+(29*4)(r4) /* Save R29 */ ! 1769: stw r7,CSAgpr+(30*4)(r4) /* Save R30 */ ! 1770: stw r5,CSAgpr+(31*4)(r4) /* Save R31 */ ! 1771: ! 1772: StoreLiveStatus: ! 1773: mfmsr r5 /* Get the current MSR */ ! 1774: ori r6,r5,0x2000 /* Turn on floating point instructions */ ! 1775: mtmsr r6 /* Turn them on */ ! 1776: isync /* Make sure they're on */ ! 1777: ! 1778: stfd f0,CSAfpr+(0*8)(r4) /* Save floating point registers */ ! 1779: stfd f1,CSAfpr+(1*8)(r4) /* Save floating point registers */ ! 1780: stfd f2,CSAfpr+(2*8)(r4) /* Save floating point registers */ ! 1781: stfd f3,CSAfpr+(3*8)(r4) /* Save floating point registers */ ! 1782: stfd f4,CSAfpr+(4*8)(r4) /* Save floating point registers */ ! 1783: stfd f5,CSAfpr+(5*8)(r4) /* Save floating point registers */ ! 1784: stfd f6,CSAfpr+(6*8)(r4) /* Save floating point registers */ ! 1785: stfd f7,CSAfpr+(7*8)(r4) /* Save floating point registers */ ! 1786: stfd f8,CSAfpr+(8*8)(r4) /* Save floating point registers */ ! 1787: stfd f9,CSAfpr+(9*8)(r4) /* Save floating point registers */ ! 1788: stfd f10,CSAfpr+(10*8)(r4) /* Save floating point registers */ ! 1789: stfd f11,CSAfpr+(11*8)(r4) /* Save floating point registers */ ! 1790: stfd f12,CSAfpr+(12*8)(r4) /* Save floating point registers */ ! 1791: stfd f13,CSAfpr+(13*8)(r4) /* Save floating point registers */ ! 1792: stfd f14,CSAfpr+(14*8)(r4) /* Save floating point registers */ ! 1793: stfd f15,CSAfpr+(15*8)(r4) /* Save floating point registers */ ! 1794: stfd f16,CSAfpr+(16*8)(r4) /* Save floating point registers */ ! 1795: stfd f17,CSAfpr+(17*8)(r4) /* Save floating point registers */ ! 1796: stfd f18,CSAfpr+(18*8)(r4) /* Save floating point registers */ ! 1797: stfd f19,CSAfpr+(19*8)(r4) /* Save floating point registers */ ! 1798: stfd f20,CSAfpr+(20*8)(r4) /* Save floating point registers */ ! 1799: stfd f21,CSAfpr+(21*8)(r4) /* Save floating point registers */ ! 1800: stfd f22,CSAfpr+(22*8)(r4) /* Save floating point registers */ ! 1801: stfd f23,CSAfpr+(23*8)(r4) /* Save floating point registers */ ! 1802: stfd f24,CSAfpr+(24*8)(r4) /* Save floating point registers */ ! 1803: stfd f25,CSAfpr+(25*8)(r4) /* Save floating point registers */ ! 1804: stfd f26,CSAfpr+(26*8)(r4) /* Save floating point registers */ ! 1805: stfd f27,CSAfpr+(27*8)(r4) /* Save floating point registers */ ! 1806: stfd f28,CSAfpr+(28*8)(r4) /* Save floating point registers */ ! 1807: stfd f29,CSAfpr+(29*8)(r4) /* Save floating point registers */ ! 1808: stfd f30,CSAfpr+(30*8)(r4) /* Save floating point registers */ ! 1809: stfd f31,CSAfpr+(31*8)(r4) /* Save floating point registers */ ! 1810: ! 1811: mffs f1 /* Get the FPSCR */ ! 1812: stfd f1,CSAfpscr-4(r4) /* Save the whole thing (we'll overlay the first half with CR later) */ ! 1813: ! 1814: lfd f1,CSAfpr+(1*4)(r4) /* Restore F1 */ ! 1815: ! 1816: mtmsr r5 /* Put the floating point back to what it was before */ ! 1817: isync /* Wait for it */ ! 1818: ! 1819: lwz r6,savecr(r13) /* Get the old CR (unclean) */ ! 1820: stw r6,CSAcr(r4) /* Save the CR */ ! 1821: ! 1822: mfxer r6 /* Get the XER */ ! 1823: stw r6,CSAxer(r4) /* Save the XER */ ! 1824: ! 1825: lwz r6,savelr(r13) /* Get the old LR (unclean) */ ! 1826: stw r6,CSAlr(r4) /* Save the LR */ ! 1827: ! 1828: mfctr r6 /* Get the CTR */ ! 1829: stw r6,CSActr(r4) /* Save the CTR */ ! 1830: ! 1831: STtbase: mftbu r5 /* Get the upper timebase */ ! 1832: mftb r6 /* Get the lower */ ! 1833: mftbu r7 /* Get the top again */ ! 1834: cmplw cr0,r5,r7 /* Did it tick? */ ! 1835: bne- STtbase /* Yeah, do it again... */ ! 1836: ! 1837: mfdec r7 /* Get the decrimenter (make it at about the same time as the TB) */ ! 1838: stw r7,CSAdec(r4) /* Save the decrimenter */ ! 1839: ! 1840: ! 1841: stw r5,CSAtbu(r4) /* Stash the top part */ ! 1842: stw r6,CSAtbl(r4) /* Stash the lower part */ ! 1843: ! 1844: lwz r5,savesrr1(r13) /* SRR1 at exception is as close as we get to the MSR (unclean) */ ! 1845: lwz r6,savesrr0(r13) /* Get SRR0 also */ ! 1846: stw r5,CSAmsr(r4) /* Save the MSR */ ! 1847: stw r6,CSApc(r4) /* Save the PC */ ! 1848: stw r5,CSAsrr1(r4) /* Set SRR1 also */ ! 1849: stw r6,CSAsrr0(r4) /* Save SRR0 */ ! 1850: ! 1851: mfpvr r5 /* Get the PVR */ ! 1852: stw r5,CSApvr(r4) /* Save the PVR */ ! 1853: ! 1854: mfspr r5,pir /* Get the PIR */ ! 1855: stw r5,CSApir(r4) /* Save the PIR */ ! 1856: ! 1857: mfspr r5,ibat0u /* Get the upper IBAT0 */ ! 1858: mfspr r6,ibat0l /* Get the lower IBAT0 */ ! 1859: stw r5,CSAibat+(0*8+0)(r4) /* Save the upper IBAT0 */ ! 1860: stw r6,CSAibat+(0*8+4)(r4) /* Save the upper IBAT0 */ ! 1861: ! 1862: mfspr r5,ibat1u /* Get the upper IBAT1 */ ! 1863: mfspr r6,ibat1l /* Get the lower IBAT1 */ ! 1864: stw r5,CSAibat+(1*8+0)(r4) /* Save the upper IBAT1 */ ! 1865: stw r6,CSAibat+(1*8+4)(r4) /* Save the upper IBAT1 */ ! 1866: ! 1867: mfspr r5,ibat2u /* Get the upper IBAT2 */ ! 1868: mfspr r6,ibat2l /* Get the lower IBAT2 */ ! 1869: stw r5,CSAibat+(2*8+0)(r4) /* Save the upper IBAT2 */ ! 1870: stw r6,CSAibat+(2*8+4)(r4) /* Save the upper IBAT2 */ ! 1871: ! 1872: mfspr r5,ibat3u /* Get the upper IBAT3 */ ! 1873: mfspr r6,ibat3l /* Get the lower IBAT3 */ ! 1874: stw r5,CSAibat+(3*8+0)(r4) /* Save the upper IBAT3 */ ! 1875: stw r6,CSAibat+(3*8+4)(r4) /* Save the upper IBAT3 */ ! 1876: ! 1877: mfspr r5,dbat0u /* Get the upper DBAT0 */ ! 1878: mfspr r6,dbat0l /* Get the lower DBAT0 */ ! 1879: stw r5,CSAdbat+(0*8+0)(r4) /* Save the upper DBAT0 */ ! 1880: stw r6,CSAdbat+(0*8+4)(r4) /* Save the upper DBAT0 */ ! 1881: ! 1882: mfspr r5,dbat1u /* Get the upper DBAT1 */ ! 1883: mfspr r6,dbat1l /* Get the lower DBAT1 */ ! 1884: stw r5,CSAdbat+(1*8+0)(r4) /* Save the upper DBAT1 */ ! 1885: stw r6,CSAdbat+(1*8+4)(r4) /* Save the upper DBAT1 */ ! 1886: ! 1887: mfspr r5,dbat2u /* Get the upper DBAT2 */ ! 1888: mfspr r6,dbat2l /* Get the lower DBAT2 */ ! 1889: stw r5,CSAdbat+(2*8+0)(r4) /* Save the upper DBAT2 */ ! 1890: stw r6,CSAdbat+(2*8+4)(r4) /* Save the upper DBAT2 */ ! 1891: ! 1892: mfspr r5,dbat3u /* Get the upper DBAT3 */ ! 1893: mfspr r6,dbat3l /* Get the lower DBAT3 */ ! 1894: stw r5,CSAdbat+(3*8+0)(r4) /* Save the upper DBAT3 */ ! 1895: stw r6,CSAdbat+(3*8+4)(r4) /* Save the upper DBAT3 */ ! 1896: ! 1897: mfsdr1 r5 /* Get the SDR1 */ ! 1898: stw r5,CSAsdr1(r4) /* Save the SDR1 */ ! 1899: ! 1900: mfsr r5,sr0 /* Get SR 0 */ ! 1901: mfsr r6,sr1 /* Get SR 1 */ ! 1902: mfsr r7,sr2 /* Get SR 2 */ ! 1903: stw r5,CSAsr+(0*4)(r4) /* Save SR 0 */ ! 1904: stw r6,CSAsr+(1*4)(r4) /* Save SR 1 */ ! 1905: mfsr r5,sr3 /* Get SR 3 */ ! 1906: mfsr r6,sr4 /* Get SR 4 */ ! 1907: stw r7,CSAsr+(2*4)(r4) /* Save SR 2 */ ! 1908: mfsr r7,sr5 /* Get SR 5 */ ! 1909: stw r5,CSAsr+(3*4)(r4) /* Save SR 3 */ ! 1910: stw r6,CSAsr+(4*4)(r4) /* Save SR 4 */ ! 1911: mfsr r5,sr6 /* Get SR 6 */ ! 1912: mfsr r6,sr7 /* Get SR 7 */ ! 1913: stw r7,CSAsr+(5*4)(r4) /* Save SR 5 */ ! 1914: mfsr r7,sr8 /* Get SR 8 */ ! 1915: stw r5,CSAsr+(6*4)(r4) /* Save SR 6 */ ! 1916: stw r6,CSAsr+(7*4)(r4) /* Save SR 7 */ ! 1917: mfsr r5,sr9 /* Get SR 9 */ ! 1918: mfsr r6,sr10 /* Get SR 11 */ ! 1919: stw r7,CSAsr+(8*4)(r4) /* Save SR 8 */ ! 1920: mfsr r7,sr11 /* Get SR 11 */ ! 1921: stw r5,CSAsr+(9*4)(r4) /* Save SR 9 */ ! 1922: stw r6,CSAsr+(10*4)(r4) /* Save SR 10 */ ! 1923: mfsr r5,sr12 /* Get SR 12 */ ! 1924: mfsr r6,sr13 /* Get SR 13 */ ! 1925: stw r7,CSAsr+(11*4)(r4) /* Save SR 11 */ ! 1926: mfsr r7,sr14 /* Get SR 14 */ ! 1927: stw r5,CSAsr+(12*4)(r4) /* Save SR 12 */ ! 1928: stw r6,CSAsr+(13*4)(r4) /* Save SR 13 */ ! 1929: mfsr r5,sr15 /* Get SR 15 */ ! 1930: stw r7,CSAsr+(14*4)(r4) /* Save SR 14 */ ! 1931: stw r5,CSAsr+(15*4)(r4) /* Save SR 15 */ ! 1932: ! 1933: mfdar r6 /* Get the DAR */ ! 1934: stw r6,CSAdar(r4) /* Save it */ ! 1935: ! 1936: mfdsisr r5 /* Get the DSISR */ ! 1937: stw r5,CSAdsisr(r4) /* Save it */ ! 1938: ! 1939: stw r10,CSAsprg+(1*4)(r4) /* Save SPRG1 */ ! 1940: mfspr r7,sprg0 /* Get SPRG0 */ ! 1941: mfspr r6,sprg2 /* Get SPRG2 */ ! 1942: stw r7,CSAsprg+(0*4)(r4) /* Save SPRG0 */ ! 1943: mfspr r5,sprg3 /* Get SPRG3 */ ! 1944: stw r6,CSAsprg+(2*4)(r4) /* Save SPRG2 */ ! 1945: stw r5,CSAsprg+(3*4)(r4) /* Save SPRG4 */ ! 1946: ! 1947: mfspr r6,1013 /* Get the DABR */ ! 1948: mfspr r7,1010 /* Get the IABR */ ! 1949: stw r6,CSAdabr(r4) /* Save the DABR */ ! 1950: stw r7,CSAiabr(r4) /* Save the IABR */ ! 1951: ! 1952: mfspr r5,282 /* Get the EAR */ ! 1953: stw r5,CSAear(r4) /* Save the EAR */ ! 1954: ! 1955: lis r7,0xDEAD /* Get 0xDEAD */ ! 1956: ori r7,r7,0xF1D0 /* Get 0xDEADF1D0 */ ! 1957: ! 1958: mfpvr r5 /* Get the processor type */ ! 1959: rlwinm r5,r5,16,16,31 /* Isolate the processor */ ! 1960: cmplwi cr1,r5,4 /* Set CR1_EQ if this is a plain 604, something else if it's a 604E */ ! 1961: ! 1962: mfspr r6,hid0 /* Get HID0 */ ! 1963: mr r5,r7 /* Assume 604 */ ! 1964: beq cr1,NoHID1 /* It is... */ ! 1965: mfspr r5,hid1 /* Get the HID1 */ ! 1966: ! 1967: NoHID1: stw r6,CSAhid+(0*4)(r4) /* Save HID0 */ ! 1968: stw r5,CSAhid+(1*4)(r4) /* Save HID1 */ ! 1969: stw r7,CSAhid+(2*4)(r4) /* Save HID2 */ ! 1970: stw r7,CSAhid+(3*4)(r4) /* Save HID3 */ ! 1971: stw r7,CSAhid+(4*4)(r4) /* Save HID4 */ ! 1972: stw r7,CSAhid+(5*4)(r4) /* Save HID5 */ ! 1973: stw r7,CSAhid+(6*4)(r4) /* Save HID6 */ ! 1974: stw r7,CSAhid+(7*4)(r4) /* Save HID7 */ ! 1975: stw r7,CSAhid+(8*4)(r4) /* Save HID8 */ ! 1976: stw r7,CSAhid+(9*4)(r4) /* Save HID9 */ ! 1977: stw r7,CSAhid+(10*4)(r4) /* Save HID10 */ ! 1978: stw r7,CSAhid+(11*4)(r4) /* Save HID11 */ ! 1979: stw r7,CSAhid+(12*4)(r4) /* Save HID12 */ ! 1980: stw r7,CSAhid+(13*4)(r4) /* Save HID13 */ ! 1981: stw r7,CSAhid+(14*4)(r4) /* Save HID14 */ ! 1982: stw r7,CSAhid+(15*4)(r4) /* Save HID15 */ ! 1983: ! 1984: mfspr r6,952 /* Get MMCR0 */ ! 1985: mr r5,r7 /* Assume 604 */ ! 1986: beq NoMMCR1 /* It is... */ ! 1987: mfspr r5,956 /* Get the MMCR1 */ ! 1988: ! 1989: NoMMCR1: stw r6,CSAmmcr+(0*4)(r4) /* Save MMCR0 */ ! 1990: stw r5,CSAmmcr+(1*4)(r4) /* Save MMCR1 */ ! 1991: ! 1992: mfspr r6,953 /* Get PMC1 */ ! 1993: mfspr r5,954 /* Get PMC2 */ ! 1994: stw r6,CSApmc+(0*4)(r4) /* Save PMC1 */ ! 1995: stw r5,CSApmc+(1*4)(r4) /* Save PMC2 */ ! 1996: ! 1997: mr r6,r7 /* Assume 604 */ ! 1998: mr r5,r7 /* Assume 604 */ ! 1999: beq NoPMC3 /* Yeah... */ ! 2000: mfspr r6,957 /* Get the PMC3 for a 604E */ ! 2001: mfspr r5,958 /* Get the PMC4 for a 604E */ ! 2002: ! 2003: NoPMC3: stw r6,CSApmc+(2*4)(r4) /* Save PMC3 */ ! 2004: stw r5,CSApmc+(3*4)(r4) /* Save PMC4 */ ! 2005: ! 2006: mfspr r6,955 /* Get SIA */ ! 2007: mfspr r5,959 /* Get SDA */ ! 2008: stw r6,CSAsia(r4) /* Save the SIA */ ! 2009: stw r5,CSAsda(r4) /* Save the SDA */ ! 2010: ! 2011: stw r7,CSAmq(r4) /* There is no MQ on either the 604 or 604E */ ! 2012: ! 2013: ! 2014: lwz r6,MPPICStat(r9) /* Get the status of this processor */ ! 2015: lis r10,MPPICReady>>16 /* Get the flag for reset or not */ ! 2016: li r5,kSIGPResetState /* Assume we're operating */ ! 2017: and. r0,r6,r10 /* See if the ready bit is set */ ! 2018: lis r10,MPPICStop>>16 /* Get the flag for stopped or not */ ! 2019: beq SetStateInf /* Go set that we are reset... */ ! 2020: and. r0,r6,r10 /* Are we stopped? */ ! 2021: li r5,kSIGPStoppedState /* Assume we area */ ! 2022: bne SetStateInf /* We are, go set it... */ ! 2023: li r5,kSIGPOperatingState /* Not stopped, so we're going */ ! 2024: ! 2025: SetStateInf: stb r5,CSAstate(r4) /* Set the state byte */ ! 2026: ! 2027: li r0,1 /* Set the truth */ ! 2028: sync /* Make sure it's stored */ ! 2029: ! 2030: stb r0,CSAregsAreValid(r4) /* Set that the status is valid */ ! 2031: ! 2032: blr /* We're done here... */ ! 2033: ! 2034: ! 2035: /******************************************************************************************************** */ ! 2036: /* */ ! 2037: /* The synchronize time base function. No state requirements for this one. */ ! 2038: /* */ ! 2039: /******************************************************************************************************** */ ! 2040: ! 2041: ITBsync: /* This handles the synchronize time base function */ ! 2042: lis r12,HIGH_ADDR(MPPIwork) /* Get the top of work area */ ! 2043: li r0,MPPICfTBsy1 /* Get the flag for TB sync state 1 */ ! 2044: li r7,0 /* Get a 0 */ ! 2045: ori r12,r12,LOW_ADDR(MPPIwork) /* Get low part of work area */ ! 2046: mttbl r7 /* Clear the bottom of the TB so's there's noupper ticks */ ! 2047: mttbu r7 /* Clear the top part, just 'cause I wanna */ ! 2048: ! 2049: sync /* Make sure all is saved */ ! 2050: stb r0,MPPICStat+2(r9) /* Tell the main dude to tell us the time */ ! 2051: isync /* Make sure we don't go nowhere's */ ! 2052: ! 2053: /* */ ! 2054: /* Remember that the sync'ing processor insures that the TB won't tick the high part for at least */ ! 2055: /* 16k ticks. That should be way longer than we need for the whole process here */ ! 2056: /* */ ! 2057: ! 2058: WaitTBLower: lwz r5,MPPITBsync+4-MPPIwork(r12) /* Get the lower part of the TB */ ! 2059: mttbl r5 /* Put it in just in case it's set now */ ! 2060: mr. r5,r5 /* Was it actually? */ ! 2061: beq+ WaitTBLower /* Nope, go check again... */ ! 2062: lwz r4,MPPITBsync-MPPIwork(r12) /* Get the high order part */ ! 2063: mttbu r4 /* Set the top half also */ ! 2064: ! 2065: stw r7,MPPITBsync+4-MPPIwork(r12) /* Tell 'em we've got it */ ! 2066: ! 2067: sync ! 2068: ! 2069: li r4,0 /* Clear this */ ! 2070: la r5,MPPISncFght-32-MPPIwork(r12) /* Point to the squared circle (our corner) */ ! 2071: ! 2072: b TB1stPnch /* Go take the first punch... */ ! 2073: ! 2074: TBSargue: ! 2075: dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */ ! 2076: sync /* *** Fix cache coherency (data integrity) HW bug *** */ ! 2077: lwz r6,0(r5) /* Listen for the procecution's argument */ ! 2078: mr. r6,r6 /* See if they are done */ ! 2079: beq+ TBSargue /* Nope, still going... */ ! 2080: ! 2081: TB1stPnch: mftb r7 /* They're done, time for rebuttal */ ! 2082: stw r7,32(r5) /* Make rebuttle */ ! 2083: ! 2084: addi r4,r4,1 /* Count rounds */ ! 2085: ! 2086: cmplwi cr0,r4,10 /* See if we've gone 9 more rounds */ ! 2087: addi r5,r5,64 /* Point to the next round areas */ ! 2088: ! 2089: blt+ TBSargue /* Not yet, come out of your corners fighting... */ ! 2090: ! 2091: /* */ ! 2092: /* We'll set the latest-up-to-datest from the other processor now */ ! 2093: /* */ ! 2094: TBSetTB: ! 2095: dcbf 0,r5 /* *** Fix cache coherency (data integrity) HW bug *** */ ! 2096: sync /* *** Fix cache coherency (data integrity) HW bug *** */ ! 2097: lwz r6,0(r5) /* Listen for the procecution's argument */ ! 2098: mttbl r6 /* Set it just in case it's ok */ ! 2099: mr. r6,r6 /* See if they are done */ ! 2100: beq+ TBSetTB /* Nope, still going... */ ! 2101: ! 2102: /* */ ! 2103: /* Get average duration for each processor. We skip the first pass on the asumption */ ! 2104: /* that the caches were not warmed up and it would take longer. In proctice this */ ! 2105: /* is what was seen. */ ! 2106: /* */ ! 2107: ! 2108: mr r0,r11 /* Move return address to a safe register */ ! 2109: ! 2110: li r4,0 /* Clear a counter */ ! 2111: li r3,0 /* Clear accumulator for duration */ ! 2112: li r10,0 /* Clear start time accumulator top half */ ! 2113: li r11,0 /* Clear start time accumulator bottom half */ ! 2114: li r1,0 /* Clear start time accumulator top half */ ! 2115: li r2,0 /* Clear start time accumulator bottom half */ ! 2116: li r10,0 /* Clear accumulator for durations */ ! 2117: la r5,MPPISncFght+64-MPPIwork(r12) /* Get second round start time address */ ! 2118: ! 2119: TBSaccumU: lwz r6,0(r5) /* Get start time */ ! 2120: lwz r11,32(r5) /* Get the other processor's start time */ ! 2121: lwz r7,64(r5) /* Get end time */ ! 2122: lwz r8,96(r5) /* Other proc's end time */ ! 2123: sub r7,r7,r6 /* Get duration */ ! 2124: sub r8,r8,r11 /* Get other side's duration */ ! 2125: addi r4,r4,1 /* Count arguments */ ! 2126: add r3,r3,r7 /* Accumulate durations */ ! 2127: add r2,r2,r7 /* Accumulate other side's durations */ ! 2128: cmplwi cr0,r4,8 /* Have we gotten them all yet? */ ! 2129: addi r5,r5,64 /* Step to the next argument */ ! 2130: blt+ TBSaccumU /* We're not done yet... */ ! 2131: ! 2132: add r7,r2,r3 /* Sum the two differences */ ! 2133: addi r7,r7,0x10 /* Round up */ ! 2134: rlwinm r7,r7,27,5,31 /* Get the average difference divided in half */ ! 2135: ! 2136: mftb r8 /* Get the time now */ ! 2137: add r8,r8,r7 /* Slide the window */ ! 2138: mttbl r8 /* Set the time */ ! 2139: ! 2140: stw r12,MPPITBsync+4-MPPIwork(r12) /* Show that we are done */ ! 2141: ! 2142: lwz r3,MPPICStat(r9) /* Get back our status */ ! 2143: mr r11,r0 /* Restore the return register */ ! 2144: b KillBusy /* We're all done now, done for it, c'est la vie... */ ! 2145: ! 2146: ! 2147: /******************************************************************************************************** */ ! 2148: /* */ ! 2149: /* The reset function. No state requirements for this one. */ ! 2150: /* This suicides the processor. Our caller is never returned to (good english). The only way out of */ ! 2151: /* this is a start function subsequently. So, we give a flying f**k about the registers 'n' sutff. */ ! 2152: /* */ ! 2153: /******************************************************************************************************** */ ! 2154: ! 2155: IReset: lis r28,0x8000 /* Turn on machine checks */ ! 2156: ! 2157: ori r28,r28,0xCC84 /* Enable caches, clear them, */ ! 2158: /* disable serial execution and turn BHT on */ ! 2159: sync ! 2160: mtspr HID0,r28 /* Start the cache clear */ ! 2161: sync ! 2162: ! 2163: /* */ ! 2164: /* Clear out the TLB. They be garbage after hard reset. */ ! 2165: /* */ ! 2166: ! 2167: li r0,512 /* Get number of TLB entries (FIX THIS) */ ! 2168: li r3,0 /* Start at 0 */ ! 2169: mtctr r0 /* Set the CTR */ ! 2170: ! 2171: IRpurgeTLB: tlbie r3 /* Purge this entry */ ! 2172: addi r3,r3,4096 /* Next page */ ! 2173: bdnz IRpurgeTLB /* Do 'em all... */ ! 2174: ! 2175: sync /* Make sure all TLB purges are done */ ! 2176: tlbsync /* Make sure on other processors also */ ! 2177: sync /* Make sure the TLBSYNC is done */ ! 2178: ! 2179: /* */ ! 2180: /* Clear out the BATs. */ ! 2181: /* */ ! 2182: ! 2183: li r3,0 /* Clear a register */ ! 2184: ! 2185: mtspr DBAT0L,r3 /* Clear BAT */ ! 2186: mtspr DBAT0U,r3 /* Clear BAT */ ! 2187: mtspr DBAT1L,r3 /* Clear BAT */ ! 2188: mtspr DBAT1U,r3 /* Clear BAT */ ! 2189: mtspr DBAT2L,r3 /* Clear BAT */ ! 2190: mtspr DBAT2U,r3 /* Clear BAT */ ! 2191: mtspr DBAT3L,r3 /* Clear BAT */ ! 2192: mtspr DBAT3U,r3 /* Clear BAT */ ! 2193: ! 2194: mtspr IBAT0L,r3 /* Clear BAT */ ! 2195: mtspr IBAT0U,r3 /* Clear BAT */ ! 2196: mtspr IBAT1L,r3 /* Clear BAT */ ! 2197: mtspr IBAT1U,r3 /* Clear BAT */ ! 2198: mtspr IBAT2L,r3 /* Clear BAT */ ! 2199: mtspr IBAT2U,r3 /* Clear BAT */ ! 2200: mtspr IBAT3L,r3 /* Clear BAT */ ! 2201: mtspr IBAT3U,r3 /* Clear BAT */ ! 2202: ! 2203: /* */ ! 2204: /* Map 0xF0000000 to 0xFFFFFFFF for I/O; make it R/W non-cacheable */ ! 2205: /* Map 0x00000000 to 0x0FFFFFFF for mainstore; make it R/W cachable */ ! 2206: /* */ ! 2207: ! 2208: lis r6,0xF000 /* Set RPN to last segment */ ! 2209: ori r6,r6,0x1FFF /* Set up upper BAT for 256M, access both */ ! 2210: ! 2211: lis r7,0xF000 /* Set RPN to last segment */ ! 2212: ori r7,r7,0x0032 /* Set up lower BAT for 256M, access both, non-cachable */ ! 2213: ! 2214: mtspr DBAT0L,r7 /* Setup ROM and I/O mapped areas */ ! 2215: mtspr DBAT0U,r6 /* Now do the upper DBAT */ ! 2216: sync ! 2217: ! 2218: li r6,0x1FFF /* Set up upper BAT for 256M, access both */ ! 2219: li r7,0x0012 /* Set up lower BAT for r/w access */ ! 2220: ! 2221: mtspr DBAT1L,r7 /* Set up an initial view of mainstore */ ! 2222: mtspr DBAT1U,r6 /* Now do the upper DBAT */ ! 2223: sync ! 2224: ! 2225: /* */ ! 2226: /* Clean up SDR and segment registers */ ! 2227: /* */ ! 2228: ! 2229: li r3,0 /* Clear a register */ ! 2230: mtspr SDR1,r3 /* Clear SDR1 */ ! 2231: ! 2232: li r4,0 /* Clear index for segment registers */ ! 2233: lis r5,0x1000 /* Set the segment indexer */ ! 2234: ! 2235: IRclearSR: mtsrin r3,r4 /* Zero out the SR */ ! 2236: add. r4,r4,r5 /* Point to the next segment */ ! 2237: bne- IRclearSR /* Keep going until we wrap back to 0 */ ! 2238: ! 2239: lis r3,(MPPICOnline+MPPICStop)>>16 /* Set the reset/online state flags */ ! 2240: b KillBusy /* Go wipe out the busy flags... */ ! 2241: ! 2242: /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */ ! 2243: /* */ ! 2244: /* Here lies the Phoney Firmware used to test SIGPs. Take this out later. */ ! 2245: /* */ ! 2246: /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */ ! 2247: ! 2248: mp_PhoneyFirmware: ! 2249: ! 2250: li r27,0x3040 /* Set floating point and machine checks on, IP to 0xFFF0xxxx */ ! 2251: mtmsr r27 /* Load 'em on in */ ! 2252: isync ! 2253: ! 2254: bl PhoneyBase /* Make a base register */ ! 2255: PhoneyBase: mflr r26 /* Get it */ ! 2256: addi r26,r26,LOW_ADDR(MPPIbase-PhoneyBase) /* Adjust it back */ ! 2257: ! 2258: la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the address of the interrupt table */ ! 2259: la r21,LOW_ADDR(rupttabend-MPPIbase)(r26) /* Get the end of the table */ ! 2260: ! 2261: relocate: lwz r22,0(r20) /* Get the displacement to routine */ ! 2262: add r22,r22,r12 /* Relocate to the physical address */ ! 2263: stw r22,0(r20) /* Stick it back */ ! 2264: addi r20,r20,4 /* Point to the next one */ ! 2265: cmplw cr0,r20,r21 /* Still in table? */ ! 2266: ble+ cr0,relocate /* Yeah... */ ! 2267: ! 2268: la r20,LOW_ADDR(rupttab-MPPIbase)(r26) /* Get the interrupt table back again */ ! 2269: mtsprg 3,r20 /* Activate the phoney Rupt table */ ! 2270: ! 2271: lis r24,hi16(HammerHead) /* Get the actual hammerhead address */ ! 2272: ori r24,r24,0x0032 /* Make R/W non-cachable */ ! 2273: lwz r23,MPPIHammer-MPPIwork(r12) /* Get the address mapped on the main processor */ ! 2274: ori r23,r23,0x0003 /* Set both super and user valid for 128KB */ ! 2275: ! 2276: mtspr DBAT0L,r24 /* Setup hammerhead's real address */ ! 2277: mtspr DBAT0U,r23 /* Map hammerhead to the same virtual address as on the main processor */ ! 2278: sync /* Make sure it is done */ ! 2279: ! 2280: la r25,MPPICPU2-MPPIwork(r12) /* Point to a phoney register save area */ ! 2281: mtsprg 1,r25 /* Phoney up initialized processor state */ ! 2282: ! 2283: lis r24,0xFEED /* Get 0xFEED */ ! 2284: ori r24,r24,0xF1D0 /* Get 0xFEEDF1D0 */ ! 2285: ! 2286: stw r24,CSAgpr+(0*4)(r25) /* Store invalid R0 */ ! 2287: stw r24,CSAgpr+(1*4)(r25) /* Store invalid R1 */ ! 2288: stw r24,CSAgpr+(2*4)(r25) /* Store invalid R2 */ ! 2289: stw r24,CSAgpr+(3*4)(r25) /* Store invalid R3 */ ! 2290: stw r24,CSAgpr+(4*4)(r25) /* Store invalid r4 */ ! 2291: stw r24,CSAgpr+(5*4)(r25) /* Store invalid R5 */ ! 2292: stw r24,CSAgpr+(6*4)(r25) /* Store invalid R6 */ ! 2293: stw r24,CSAgpr+(7*4)(r25) /* Store invalid r7 */ ! 2294: stw r24,CSAgpr+(8*4)(r25) /* Store invalid R8 */ ! 2295: stw r24,CSAgpr+(9*4)(r25) /* Store invalid R9 */ ! 2296: stw r24,CSAgpr+(10*4)(r25) /* Store invalid R10 */ ! 2297: stw r24,CSAgpr+(11*4)(r25) /* Store invalid R11 */ ! 2298: stw r24,CSAgpr+(12*4)(r25) /* Store invalid R12 */ ! 2299: ! 2300: waititout: lwz r25,0x30(br0) /* Get wait count */ ! 2301: mfmsr r24 /* Get the MSR */ ! 2302: addi r25,r25,1 /* Bounce it up */ ! 2303: ori r24,r24,0x8000 /* Turn on external interruptions */ ! 2304: stw r25,0x30(br0) /* Save back the count */ ! 2305: mtmsr r24 /* Set it */ ! 2306: isync /* Stop until we're here */ ! 2307: b waititout /* Loop forever... */ ! 2308: ! 2309: /* */ ! 2310: /* Phoney interrupt handlers */ ! 2311: /* */ ! 2312: ! 2313: pexternal: mflr r29 /* Get the LR value */ ! 2314: lwz r29,0(r29) /* Get the rupt code */ ! 2315: stw r29,0x0B0(br0) /* Save the code */ ! 2316: bl GotSignal /* Call the signal handler */ ! 2317: oris r3,r3,0x8000 /* Turn on high bit so we see a code 0 */ ! 2318: stw r3,0xA8(br0) /* Save return code in debug area */ ! 2319: ! 2320: ignorerupt: mflr r29 /* Get the LR value */ ! 2321: lwz r29,0(r29) /* Get the rupt code */ ! 2322: stw r29,0x0B0(br0) /* Save the code */ ! 2323: rfi /* Bail to from whence we commest... */ ! 2324: .long 0 ! 2325: .long 0 ! 2326: .long 0 ! 2327: .long 0 ! 2328: .long 0 ! 2329: .long 0 ! 2330: .long 0 ! 2331: ! 2332: rupttab: .long ignorerupt ! 2333: .long ignorerupt ! 2334: .long ignorerupt ! 2335: .long ignorerupt ! 2336: .long ignorerupt ! 2337: .long pexternal /* Phoney external handler */ ! 2338: .long ignorerupt ! 2339: .long ignorerupt ! 2340: .long ignorerupt ! 2341: .long ignorerupt ! 2342: .long ignorerupt ! 2343: .long ignorerupt ! 2344: .long ignorerupt ! 2345: .long ignorerupt ! 2346: .long ignorerupt ! 2347: .long ignorerupt ! 2348: .long ignorerupt ! 2349: .long ignorerupt ! 2350: .long ignorerupt ! 2351: .long ignorerupt ! 2352: .long ignorerupt ! 2353: .long ignorerupt ! 2354: .long ignorerupt ! 2355: .long ignorerupt ! 2356: .long ignorerupt ! 2357: .long ignorerupt ! 2358: .long ignorerupt ! 2359: .long ignorerupt ! 2360: .long ignorerupt ! 2361: .long ignorerupt ! 2362: .long ignorerupt ! 2363: .long ignorerupt ! 2364: .long ignorerupt ! 2365: .long ignorerupt ! 2366: .long ignorerupt ! 2367: .long ignorerupt ! 2368: .long ignorerupt ! 2369: .long ignorerupt ! 2370: .long ignorerupt ! 2371: .long ignorerupt ! 2372: .long ignorerupt ! 2373: .long ignorerupt ! 2374: .long ignorerupt ! 2375: .long ignorerupt ! 2376: .long ignorerupt ! 2377: .long ignorerupt ! 2378: .long ignorerupt ! 2379: rupttabend: .long ignorerupt ! 2380: ! 2381: /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */ ! 2382: /* */ ! 2383: /* Here lies the end of the Phoney Firmware used to test SIGPs. Take this out later. */ ! 2384: /* */ ! 2385: /* (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) (TEST/DEBUG) */ ! 2386: ! 2387: ! 2388: /* */ ! 2389: /* Table of function offsets */ ! 2390: /* */ ! 2391: ! 2392: MPPIFuncOffs: ! 2393: ! 2394: .long CountProcessors-MPPIFunctions /* Offset to routine */ ! 2395: .long StartProcessor-MPPIFunctions /* Offset to routine */ ! 2396: .long ResumeProcessor-MPPIFunctions /* Offset to routine */ ! 2397: .long StopProcessor-MPPIFunctions /* Offset to routine */ ! 2398: .long ResetProcessor-MPPIFunctions /* Offset to routine */ ! 2399: .long SignalProcessor-MPPIFunctions /* Offset to routine */ ! 2400: .long StoreProcessorStatus-MPPIFunctions /* Offset to routine */ ! 2401: .long SynchClock-MPPIFunctions /* Offset to routine */ ! 2402: .long GetExtHandlerAddress-MPPIFunctions /* Offset to routine */ ! 2403: .long GotSignal-MPPIFunctions /* Offset to routine */ ! 2404: .long ProcessorState-MPPIFunctions /* Offset to routine */ ! 2405: .long RunSIGPRun-MPPIFunctions /* Offset to routine */ ! 2406: .long mp_PhoneyFirmware-MPPIFunctions /* (TEST/DEBUG) */ ! 2407: ! 2408: MPPISize: ! 2409:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.