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