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