2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 * cpu specific routines
31 #include <kern/machine.h>
32 #include <kern/misc_protos.h>
33 #include <kern/thread.h>
34 #include <kern/processor.h>
35 #include <mach/machine.h>
36 #include <mach/processor_info.h>
37 #include <mach/mach_types.h>
38 #include <ppc/proc_reg.h>
39 #include <ppc/misc_protos.h>
40 #include <ppc/machine_routines.h>
41 #include <ppc/machine_cpu.h>
42 #include <ppc/exception.h>
44 #include <ppc/hw_perfmon.h>
45 #include <pexpert/pexpert.h>
46 #include <kern/cpu_data.h>
47 #include <ppc/mappings.h>
48 #include <ppc/Diagnostics.h>
50 /* TODO: BOGUS TO BE REMOVED */
54 resethandler_t resethandler_target
;
56 #define MMCR0_SUPPORT_MASK 0xf83f1fff
57 #define MMCR1_SUPPORT_MASK 0xffc00000
58 #define MMCR2_SUPPORT_MASK 0x80000000
60 extern int debugger_pending
[NCPUS
];
61 extern int debugger_is_slave
[NCPUS
];
62 extern int debugger_holdoff
[NCPUS
];
63 extern int debugger_sync
;
72 struct per_proc_info
*pper_proc_info
= per_proc_info
;
74 extern struct SIGtimebase syncClkSpot
;
76 void cpu_sync_timebase(void);
81 processor_info_t info
,
85 cpu_subtype_t cpu_subtype
;
86 processor_pm_regs_t perf_regs
;
87 processor_control_cmd_t cmd
;
90 cpu_type
= machine_slot
[slot_num
].cpu_type
;
91 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
92 cmd
= (processor_control_cmd_t
) info
;
94 if (count
< PROCESSOR_CONTROL_CMD_COUNT
)
97 if ( cpu_type
!= cmd
->cmd_cpu_type
||
98 cpu_subtype
!= cmd
->cmd_cpu_subtype
)
101 if (perfmon_acquire_facility(current_task()) != KERN_SUCCESS
) {
102 return(KERN_RESOURCE_SHORTAGE
); /* cpu performance facility in use by another task */
107 case PROCESSOR_PM_CLR_PMC
: /* Clear Performance Monitor Counters */
110 case CPU_SUBTYPE_POWERPC_750
:
111 case CPU_SUBTYPE_POWERPC_7400
:
112 case CPU_SUBTYPE_POWERPC_7450
:
114 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
119 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
120 return(KERN_SUCCESS
);
123 return(KERN_FAILURE
);
125 case PROCESSOR_PM_SET_REGS
: /* Set Performance Monitor Registors */
128 case CPU_SUBTYPE_POWERPC_750
:
129 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
130 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
131 return(KERN_FAILURE
);
134 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
135 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
136 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
137 mtpmc1(PERFMON_PMC1(perf_regs
));
138 mtpmc2(PERFMON_PMC2(perf_regs
));
139 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
140 mtpmc3(PERFMON_PMC3(perf_regs
));
141 mtpmc4(PERFMON_PMC4(perf_regs
));
142 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
143 return(KERN_SUCCESS
);
145 case CPU_SUBTYPE_POWERPC_7400
:
146 case CPU_SUBTYPE_POWERPC_7450
:
147 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
148 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
149 return(KERN_FAILURE
);
152 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
153 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
154 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
155 mtpmc1(PERFMON_PMC1(perf_regs
));
156 mtpmc2(PERFMON_PMC2(perf_regs
));
157 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
158 mtpmc3(PERFMON_PMC3(perf_regs
));
159 mtpmc4(PERFMON_PMC4(perf_regs
));
160 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
161 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
162 return(KERN_SUCCESS
);
165 return(KERN_FAILURE
);
166 } /* switch cpu_subtype */
167 case PROCESSOR_PM_SET_MMCR
:
170 case CPU_SUBTYPE_POWERPC_750
:
171 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
172 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
173 return(KERN_FAILURE
);
176 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
177 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
178 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
179 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
180 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
181 return(KERN_SUCCESS
);
183 case CPU_SUBTYPE_POWERPC_7400
:
184 case CPU_SUBTYPE_POWERPC_7450
:
185 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
186 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
187 return(KERN_FAILURE
);
190 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
191 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
192 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
193 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
194 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
195 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
196 return(KERN_SUCCESS
);
199 return(KERN_FAILURE
);
202 return(KERN_FAILURE
);
203 } /* switch cmd_op */
208 processor_flavor_t flavor
,
211 cpu_subtype_t cpu_subtype
;
214 * For now, we just assume that all CPUs are of the same type
216 cpu_subtype
= machine_slot
[0].cpu_subtype
;
218 case PROCESSOR_PM_REGS_INFO
:
219 switch (cpu_subtype
) {
220 case CPU_SUBTYPE_POWERPC_750
:
222 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
223 return(KERN_SUCCESS
);
225 case CPU_SUBTYPE_POWERPC_7400
:
226 case CPU_SUBTYPE_POWERPC_7450
:
228 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
229 return(KERN_SUCCESS
);
233 return(KERN_INVALID_ARGUMENT
);
234 } /* switch cpu_subtype */
236 case PROCESSOR_TEMPERATURE
:
237 *count
= PROCESSOR_TEMPERATURE_COUNT
;
238 return (KERN_SUCCESS
);
242 return(KERN_INVALID_ARGUMENT
);
249 processor_flavor_t flavor
,
251 processor_info_t info
,
254 cpu_subtype_t cpu_subtype
;
255 processor_pm_regs_t perf_regs
;
257 unsigned int temp
[2];
259 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
262 case PROCESSOR_PM_REGS_INFO
:
264 perf_regs
= (processor_pm_regs_t
) info
;
266 switch (cpu_subtype
) {
267 case CPU_SUBTYPE_POWERPC_750
:
269 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_750
)
270 return(KERN_FAILURE
);
272 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
273 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
274 PERFMON_PMC1(perf_regs
) = mfpmc1();
275 PERFMON_PMC2(perf_regs
) = mfpmc2();
276 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
277 PERFMON_PMC3(perf_regs
) = mfpmc3();
278 PERFMON_PMC4(perf_regs
) = mfpmc4();
279 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
281 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
282 return(KERN_SUCCESS
);
284 case CPU_SUBTYPE_POWERPC_7400
:
285 case CPU_SUBTYPE_POWERPC_7450
:
287 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_7400
)
288 return(KERN_FAILURE
);
290 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
291 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
292 PERFMON_PMC1(perf_regs
) = mfpmc1();
293 PERFMON_PMC2(perf_regs
) = mfpmc2();
294 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
295 PERFMON_PMC3(perf_regs
) = mfpmc3();
296 PERFMON_PMC4(perf_regs
) = mfpmc4();
297 PERFMON_MMCR2(perf_regs
) = mfmmcr2();
298 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
300 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
301 return(KERN_SUCCESS
);
304 return(KERN_FAILURE
);
305 } /* switch cpu_subtype */
307 case PROCESSOR_TEMPERATURE
: /* Get the temperature of a processor */
309 disable_preemption(); /* Don't move me now */
311 if(slot_num
== cpu_number()) { /* Is this for the local CPU? */
312 *info
= ml_read_temp(); /* Get the temperature */
314 else { /* For another CPU */
315 temp
[0] = -1; /* Set sync flag */
318 temp
[1] = -1; /* Set invalid temperature */
319 (void)cpu_signal(slot_num
, SIGPcpureq
, CPRQtemp
,(unsigned int)&temp
); /* Ask him to take his temperature */
320 (void)hw_cpu_sync(temp
, LockTimeOut
); /* Wait for the other processor to get its temperature */
321 *info
= temp
[1]; /* Pass it back */
324 enable_preemption(); /* Ok to move now */
325 return(KERN_SUCCESS
);
328 return(KERN_INVALID_ARGUMENT
);
341 machine_slot
[cpu
].running
= TRUE
;
342 machine_slot
[cpu
].cpu_type
= CPU_TYPE_POWERPC
;
343 machine_slot
[cpu
].cpu_subtype
= (cpu_subtype_t
)per_proc_info
[cpu
].pf
.rptdProc
;
351 struct per_proc_info
*tproc_info
;
352 volatile struct per_proc_info
*mproc_info
;
355 /* TODO: realese mutex lock reset_handler_lock */
358 tproc_info
= &per_proc_info
[cpu
];
359 mproc_info
= &per_proc_info
[master_cpu
];
360 PE_cpu_machine_init(tproc_info
->cpu_id
, !(tproc_info
->cpu_flags
& BootDone
));
361 if (cpu
!= master_cpu
) {
362 while (!((mproc_info
->cpu_flags
) & SignalReady
))
367 tproc_info
->cpu_flags
|= BootDone
|SignalReady
;
379 * - Run cpu_register() in exclusion mode
383 for(cpu
=0; cpu
< wncpu
; cpu
++) {
384 if(!machine_slot
[cpu
].is_cpu
) {
385 machine_slot
[cpu
].is_cpu
= TRUE
;
390 if (*target_cpu
!= -1) {
401 struct per_proc_info
*proc_info
;
405 extern vm_offset_t intstack
;
406 extern vm_offset_t debstack
;
408 proc_info
= &per_proc_info
[cpu
];
410 if (cpu
== cpu_number()) {
411 PE_cpu_machine_init(proc_info
->cpu_id
, !(proc_info
->cpu_flags
& BootDone
));
413 proc_info
->cpu_flags
|= BootDone
|SignalReady
;
417 extern void _start_cpu(void);
419 proc_info
->cpu_number
= cpu
;
420 proc_info
->cpu_flags
&= BootDone
;
421 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
422 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
423 #if MACH_KDP || MACH_KDB
424 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
425 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
426 #endif /* MACH_KDP || MACH_KDB */
427 proc_info
->interrupts_enabled
= 0;
428 proc_info
->active_kloaded
= (unsigned int)&active_kloaded
[cpu
];
429 proc_info
->active_stacks
= (unsigned int)&active_stacks
[cpu
];
430 proc_info
->need_ast
= (unsigned int)&need_ast
[cpu
];
431 proc_info
->FPU_owner
= 0;
432 proc_info
->VMX_owner
= 0;
433 mp
= (mapping
*)(&proc_info
->ppCIOmp
);
434 mp
->mpFlags
= 0x01000000 | mpSpecial
| 1;
435 mp
->mpSpace
= invalSpace
;
437 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
439 /* TODO: get mutex lock reset_handler_lock */
441 resethandler_target
.type
= RESET_HANDLER_START
;
442 resethandler_target
.call_paddr
= (vm_offset_t
)_start_cpu
; /* Note: these routines are always V=R */
443 resethandler_target
.arg__paddr
= (vm_offset_t
)proc_info
; /* Note: these routines are always V=R */
445 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
446 resethandler_target
.type
);
447 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
448 resethandler_target
.call_paddr
);
449 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
450 resethandler_target
.arg__paddr
);
454 * Note: we pass the current time to the other processor here. He will load it
455 * as early as possible so that there is a chance that it is close to accurate.
456 * After the machine is up a while, we will officially resync the clocks so
457 * that all processors are the same. This is just to get close.
460 ml_get_timebase((unsigned long long *)&proc_info
->ruptStamp
); /* Pass our current time to the other guy */
462 __asm__
volatile("sync"); /* Commit to storage */
463 __asm__
volatile("isync"); /* Wait a second */
464 ret
= PE_cpu_start(proc_info
->cpu_id
,
465 proc_info
->start_paddr
, (vm_offset_t
)proc_info
);
467 if (ret
!= KERN_SUCCESS
&&
468 proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
470 /* TODO: realese mutex lock reset_handler_lock */
477 * Here is where we implement the receiver of the signaling protocol.
478 * We wait for the signal status area to be passed to us. Then we snarf
479 * up the status, the sender, and the 3 potential parms. Next we release
480 * the lock and signal the other guy.
488 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
489 unsigned int *parmAddr
;
490 struct per_proc_info
*pproc
; /* Area for my per_proc address */
492 struct SIGtimebase
*timebaseAddr
;
493 natural_t tbu
, tbu2
, tbl
;
495 cpu
= cpu_number(); /* Get the CPU number */
496 pproc
= &per_proc_info
[cpu
]; /* Point to our block */
499 * Since we've been signaled, wait about 31 ms for the signal lock to pass
501 if(!hw_lock_mbits(&pproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
), (MPsigpBusy
| MPsigpPass
),
502 (MPsigpBusy
| MPsigpPass
| MPsigpAck
), (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 5))) {
503 panic("cpu_signal_handler: Lock pass timed out\n");
506 holdStat
= pproc
->MPsigpStat
; /* Snarf stat word */
507 holdParm0
= pproc
->MPsigpParm0
; /* Snarf parameter */
508 holdParm1
= pproc
->MPsigpParm1
; /* Snarf parameter */
509 holdParm2
= pproc
->MPsigpParm2
; /* Snarf parameter */
511 __asm__
volatile("isync"); /* Make sure we don't unlock until memory is in */
513 pproc
->MPsigpStat
= holdStat
& ~(MPsigpMsgp
| MPsigpAck
| MPsigpFunc
); /* Release lock */
515 switch ((holdStat
& MPsigpFunc
) >> 8) { /* Decode function code */
517 case MPsigpIdle
: /* Was function cancelled? */
520 case MPsigpSigp
: /* Signal Processor message? */
522 switch (holdParm0
) { /* Decode SIGP message order */
524 case SIGPast
: /* Should we do an AST? */
525 pproc
->hwCtr
.numSIGPast
++; /* Count this one */
527 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
529 ast_check(cpu_to_processor(cpu
));
530 return; /* All done... */
532 case SIGPcpureq
: /* CPU specific function? */
534 pproc
->hwCtr
.numSIGPcpureq
++; /* Count this one */
535 switch (holdParm1
) { /* Select specific function */
537 case CPRQtemp
: /* Get the temperature */
538 parmAddr
= (unsigned int *)holdParm2
; /* Get the destination address */
539 parmAddr
[1] = ml_read_temp(); /* Get the core temperature */
540 eieio(); /* Force order */
541 sync(); /* Force to memory */
542 parmAddr
[0] = 0; /* Show we're done */
547 timebaseAddr
= (struct SIGtimebase
*)holdParm2
;
549 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
550 pproc
->time_base_enable(pproc
->cpu_id
, FALSE
);
552 timebaseAddr
->abstime
= 0; /* Touch to force into cache */
556 asm volatile(" mftbu %0" : "=r" (tbu
));
557 asm volatile(" mftb %0" : "=r" (tbl
));
558 asm volatile(" mftbu %0" : "=r" (tbu2
));
559 } while (tbu
!= tbu2
);
561 timebaseAddr
->abstime
= ((uint64_t)tbu
<< 32) | tbl
;
562 sync(); /* Force order */
564 timebaseAddr
->avail
= TRUE
;
566 while (*(volatile int *)&(syncClkSpot
.ready
) == FALSE
);
568 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
569 pproc
->time_base_enable(pproc
->cpu_id
, TRUE
);
571 timebaseAddr
->done
= TRUE
;
576 fwSCOM((scomcomm
*)holdParm2
); /* Do the function */
580 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1
);
585 case SIGPdebug
: /* Enter the debugger? */
587 pproc
->hwCtr
.numSIGPdebug
++; /* Count this one */
588 debugger_is_slave
[cpu
]++; /* Bump up the count to show we're here */
589 hw_atomic_sub(&debugger_sync
, 1); /* Show we've received the 'rupt */
590 __asm__
volatile("tw 4,r3,r3"); /* Enter the debugger */
591 return; /* All done now... */
593 case SIGPwake
: /* Wake up CPU */
594 pproc
->hwCtr
.numSIGPwake
++; /* Count this one */
595 return; /* No need to do anything, the interrupt does it all... */
598 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0
);
604 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat
& MPsigpFunc
) >> 8);
608 panic("cpu_signal_handler: we should never get here\n");
612 * Here is where we send a message to another processor. So far we only have two:
613 * SIGPast and SIGPdebug. SIGPast is used to preempt and kick off threads (this is
614 * currently disabled). SIGPdebug is used to enter the debugger.
616 * We set up the SIGP function to indicate that this is a simple message and set the
617 * order code (MPsigpParm0) to SIGPast or SIGPdebug). After finding the per_processor
618 * block for the target, we lock the message block. Then we set the parameter(s).
619 * Next we change the lock (also called "busy") to "passing" and finally signal
620 * the other processor. Note that we only wait about 1ms to get the message lock.
621 * If we time out, we return failure to our caller. It is their responsibility to
633 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
634 struct per_proc_info
*tpproc
, *mpproc
; /* Area for per_proc addresses */
639 if(target
> NCPUS
) panic("cpu_signal: invalid target CPU - %08X\n", target
);
642 cpu
= cpu_number(); /* Get our CPU number */
643 if(target
== cpu
) return KERN_FAILURE
; /* Don't play with ourselves */
644 if(!machine_slot
[target
].running
) return KERN_FAILURE
; /* These guys are too young */
646 mpproc
= &per_proc_info
[cpu
]; /* Point to our block */
647 tpproc
= &per_proc_info
[target
]; /* Point to the target's block */
649 if (!(tpproc
->cpu_flags
& SignalReady
)) return KERN_FAILURE
;
651 if((tpproc
->MPsigpStat
& MPsigpMsgp
) == MPsigpMsgp
) { /* Is there an unreceived message already pending? */
653 if(signal
== SIGPwake
) { /* SIGPwake can merge into all others... */
654 mpproc
->hwCtr
.numSIGPmwake
++; /* Account for merged wakes */
658 if((signal
== SIGPast
) && (tpproc
->MPsigpParm0
== SIGPast
)) { /* We can merge ASTs */
659 mpproc
->hwCtr
.numSIGPmast
++; /* Account for merged ASTs */
660 return KERN_SUCCESS
; /* Don't bother to send this one... */
663 if (tpproc
->MPsigpParm0
== SIGPwake
) {
664 if (hw_lock_mbits(&tpproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
),
665 (MPsigpBusy
| MPsigpPass
), MPsigpBusy
, 0)) {
667 mpproc
->hwCtr
.numSIGPmwake
++;
672 if((busybitset
== 0) &&
673 (!hw_lock_mbits(&tpproc
->MPsigpStat
, MPsigpMsgp
, 0, MPsigpBusy
,
674 (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 11)))) { /* Try to lock the message block with a .5ms timeout */
675 mpproc
->hwCtr
.numSIGPtimo
++; /* Account for timeouts */
676 return KERN_FAILURE
; /* Timed out, take your ball and go home... */
679 holdStat
= MPsigpBusy
| MPsigpPass
| (MPsigpSigp
<< 8) | cpu
; /* Set up the signal status word */
680 tpproc
->MPsigpParm0
= signal
; /* Set message order */
681 tpproc
->MPsigpParm1
= p1
; /* Set additional parm */
682 tpproc
->MPsigpParm2
= p2
; /* Set additional parm */
684 __asm__
volatile("sync"); /* Make sure it's all there */
686 tpproc
->MPsigpStat
= holdStat
; /* Set status and pass the lock */
687 __asm__
volatile("eieio"); /* I'm a paraniod freak */
690 PE_cpu_signal(mpproc
->cpu_id
, tpproc
->cpu_id
); /* Kick the other processor */
692 return KERN_SUCCESS
; /* All is goodness and rainbows... */
700 processor_doshutdown(current_processor());
707 struct per_proc_info
*proc_info
;
709 facility_context
*fowner
;
710 extern vm_offset_t intstack
;
711 extern vm_offset_t debstack
;
712 extern void _restart_cpu(void);
716 proc_info
= &per_proc_info
[cpu
];
718 fowner
= proc_info
->FPU_owner
; /* Cache this */
719 if(fowner
) fpu_save(fowner
); /* If anyone owns FPU, save it */
720 proc_info
->FPU_owner
= 0; /* Set no fpu owner now */
722 fowner
= proc_info
->VMX_owner
; /* Cache this */
723 if(fowner
) vec_save(fowner
); /* If anyone owns vectors, save it */
724 proc_info
->VMX_owner
= 0; /* Set no vector owner now */
726 if (proc_info
->cpu_number
== 0) {
727 proc_info
->cpu_flags
&= BootDone
;
728 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
729 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
730 #if MACH_KDP || MACH_KDB
731 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
732 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
733 #endif /* MACH_KDP || MACH_KDB */
734 proc_info
->interrupts_enabled
= 0;
736 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
737 extern void _start_cpu(void);
739 resethandler_target
.type
= RESET_HANDLER_START
;
740 resethandler_target
.call_paddr
= (vm_offset_t
)_start_cpu
; /* Note: these routines are always V=R */
741 resethandler_target
.arg__paddr
= (vm_offset_t
)proc_info
; /* Note: these routines are always V=R */
743 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
744 resethandler_target
.type
);
745 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
746 resethandler_target
.call_paddr
);
747 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
748 resethandler_target
.arg__paddr
);
750 __asm__
volatile("sync");
751 __asm__
volatile("isync");
755 PE_cpu_machine_quiesce(proc_info
->cpu_id
);
765 intr
= ml_set_interrupts_enabled(FALSE
); /* No interruptions in here */
767 /* Note that syncClkSpot is in a cache aligned area */
768 syncClkSpot
.avail
= FALSE
;
769 syncClkSpot
.ready
= FALSE
;
770 syncClkSpot
.done
= FALSE
;
772 while (cpu_signal(master_cpu
, SIGPcpureq
, CPRQtimebase
,
773 (unsigned int)&syncClkSpot
) != KERN_SUCCESS
)
776 while (*(volatile int *)&(syncClkSpot
.avail
) == FALSE
)
782 * We do the following to keep the compiler from generating extra stuff
785 tbu
= syncClkSpot
.abstime
>> 32;
786 tbl
= (uint32_t)syncClkSpot
.abstime
;
792 syncClkSpot
.ready
= TRUE
;
794 while (*(volatile int *)&(syncClkSpot
.done
) == FALSE
)
797 (void)ml_set_interrupts_enabled(intr
);