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>
51 /* TODO: BOGUS TO BE REMOVED */
55 resethandler_t resethandler_target
;
57 #define MMCR0_SUPPORT_MASK 0xf83f1fff
58 #define MMCR1_SUPPORT_MASK 0xffc00000
59 #define MMCR2_SUPPORT_MASK 0x80000000
61 extern int debugger_pending
[NCPUS
];
62 extern int debugger_is_slave
[NCPUS
];
63 extern int debugger_holdoff
[NCPUS
];
64 extern int debugger_sync
;
73 struct per_proc_info
*pper_proc_info
= per_proc_info
;
75 extern struct SIGtimebase syncClkSpot
;
77 void cpu_sync_timebase(void);
82 processor_info_t info
,
86 cpu_subtype_t cpu_subtype
;
87 processor_pm_regs_t perf_regs
;
88 processor_control_cmd_t cmd
;
91 cpu_type
= machine_slot
[slot_num
].cpu_type
;
92 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
93 cmd
= (processor_control_cmd_t
) info
;
95 if (count
< PROCESSOR_CONTROL_CMD_COUNT
)
98 if ( cpu_type
!= cmd
->cmd_cpu_type
||
99 cpu_subtype
!= cmd
->cmd_cpu_subtype
)
100 return(KERN_FAILURE
);
102 if (perfmon_acquire_facility(current_task()) != KERN_SUCCESS
) {
103 return(KERN_RESOURCE_SHORTAGE
); /* cpu performance facility in use by another task */
108 case PROCESSOR_PM_CLR_PMC
: /* Clear Performance Monitor Counters */
111 case CPU_SUBTYPE_POWERPC_750
:
112 case CPU_SUBTYPE_POWERPC_7400
:
113 case CPU_SUBTYPE_POWERPC_7450
:
115 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
120 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
121 return(KERN_SUCCESS
);
124 return(KERN_FAILURE
);
126 case PROCESSOR_PM_SET_REGS
: /* Set Performance Monitor Registors */
129 case CPU_SUBTYPE_POWERPC_750
:
130 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
131 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
132 return(KERN_FAILURE
);
135 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
136 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
137 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
138 mtpmc1(PERFMON_PMC1(perf_regs
));
139 mtpmc2(PERFMON_PMC2(perf_regs
));
140 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
141 mtpmc3(PERFMON_PMC3(perf_regs
));
142 mtpmc4(PERFMON_PMC4(perf_regs
));
143 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
144 return(KERN_SUCCESS
);
146 case CPU_SUBTYPE_POWERPC_7400
:
147 case CPU_SUBTYPE_POWERPC_7450
:
148 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
149 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
150 return(KERN_FAILURE
);
153 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
154 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
155 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
156 mtpmc1(PERFMON_PMC1(perf_regs
));
157 mtpmc2(PERFMON_PMC2(perf_regs
));
158 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
159 mtpmc3(PERFMON_PMC3(perf_regs
));
160 mtpmc4(PERFMON_PMC4(perf_regs
));
161 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
162 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
163 return(KERN_SUCCESS
);
166 return(KERN_FAILURE
);
167 } /* switch cpu_subtype */
168 case PROCESSOR_PM_SET_MMCR
:
171 case CPU_SUBTYPE_POWERPC_750
:
172 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
173 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
174 return(KERN_FAILURE
);
177 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
178 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
179 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
180 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
181 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
182 return(KERN_SUCCESS
);
184 case CPU_SUBTYPE_POWERPC_7400
:
185 case CPU_SUBTYPE_POWERPC_7450
:
186 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
187 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
188 return(KERN_FAILURE
);
191 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
192 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
193 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
194 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
195 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
196 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
197 return(KERN_SUCCESS
);
200 return(KERN_FAILURE
);
203 return(KERN_FAILURE
);
204 } /* switch cmd_op */
209 processor_flavor_t flavor
,
212 cpu_subtype_t cpu_subtype
;
215 * For now, we just assume that all CPUs are of the same type
217 cpu_subtype
= machine_slot
[0].cpu_subtype
;
219 case PROCESSOR_PM_REGS_INFO
:
220 switch (cpu_subtype
) {
221 case CPU_SUBTYPE_POWERPC_750
:
223 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
224 return(KERN_SUCCESS
);
226 case CPU_SUBTYPE_POWERPC_7400
:
227 case CPU_SUBTYPE_POWERPC_7450
:
229 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
230 return(KERN_SUCCESS
);
234 return(KERN_INVALID_ARGUMENT
);
235 } /* switch cpu_subtype */
237 case PROCESSOR_TEMPERATURE
:
238 *count
= PROCESSOR_TEMPERATURE_COUNT
;
239 return (KERN_SUCCESS
);
243 return(KERN_INVALID_ARGUMENT
);
250 processor_flavor_t flavor
,
252 processor_info_t info
,
255 cpu_subtype_t cpu_subtype
;
256 processor_pm_regs_t perf_regs
;
258 unsigned int temp
[2];
260 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
263 case PROCESSOR_PM_REGS_INFO
:
265 perf_regs
= (processor_pm_regs_t
) info
;
267 switch (cpu_subtype
) {
268 case CPU_SUBTYPE_POWERPC_750
:
270 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_750
)
271 return(KERN_FAILURE
);
273 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
274 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
275 PERFMON_PMC1(perf_regs
) = mfpmc1();
276 PERFMON_PMC2(perf_regs
) = mfpmc2();
277 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
278 PERFMON_PMC3(perf_regs
) = mfpmc3();
279 PERFMON_PMC4(perf_regs
) = mfpmc4();
280 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
282 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
283 return(KERN_SUCCESS
);
285 case CPU_SUBTYPE_POWERPC_7400
:
286 case CPU_SUBTYPE_POWERPC_7450
:
288 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_7400
)
289 return(KERN_FAILURE
);
291 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
292 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
293 PERFMON_PMC1(perf_regs
) = mfpmc1();
294 PERFMON_PMC2(perf_regs
) = mfpmc2();
295 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
296 PERFMON_PMC3(perf_regs
) = mfpmc3();
297 PERFMON_PMC4(perf_regs
) = mfpmc4();
298 PERFMON_MMCR2(perf_regs
) = mfmmcr2();
299 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
301 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
302 return(KERN_SUCCESS
);
305 return(KERN_FAILURE
);
306 } /* switch cpu_subtype */
308 case PROCESSOR_TEMPERATURE
: /* Get the temperature of a processor */
310 disable_preemption(); /* Don't move me now */
312 if(slot_num
== cpu_number()) { /* Is this for the local CPU? */
313 *info
= ml_read_temp(); /* Get the temperature */
315 else { /* For another CPU */
316 temp
[0] = -1; /* Set sync flag */
319 temp
[1] = -1; /* Set invalid temperature */
320 (void)cpu_signal(slot_num
, SIGPcpureq
, CPRQtemp
,(unsigned int)&temp
); /* Ask him to take his temperature */
321 (void)hw_cpu_sync(temp
, LockTimeOut
); /* Wait for the other processor to get its temperature */
322 *info
= temp
[1]; /* Pass it back */
325 enable_preemption(); /* Ok to move now */
326 return(KERN_SUCCESS
);
329 return(KERN_INVALID_ARGUMENT
);
342 machine_slot
[cpu
].running
= TRUE
;
343 machine_slot
[cpu
].cpu_type
= CPU_TYPE_POWERPC
;
344 machine_slot
[cpu
].cpu_subtype
= (cpu_subtype_t
)per_proc_info
[cpu
].pf
.rptdProc
;
352 struct per_proc_info
*tproc_info
;
353 volatile struct per_proc_info
*mproc_info
;
356 /* TODO: realese mutex lock reset_handler_lock */
359 tproc_info
= &per_proc_info
[cpu
];
360 mproc_info
= &per_proc_info
[master_cpu
];
361 PE_cpu_machine_init(tproc_info
->cpu_id
, !(tproc_info
->cpu_flags
& BootDone
));
362 if (cpu
!= master_cpu
) {
363 while (!((mproc_info
->cpu_flags
) & SignalReady
))
368 tproc_info
->cpu_flags
|= BootDone
|SignalReady
;
380 * - Run cpu_register() in exclusion mode
384 for(cpu
=0; cpu
< wncpu
; cpu
++) {
385 if(!machine_slot
[cpu
].is_cpu
) {
386 machine_slot
[cpu
].is_cpu
= TRUE
;
391 if (*target_cpu
!= -1) {
402 struct per_proc_info
*proc_info
;
406 extern vm_offset_t intstack
;
407 extern vm_offset_t debstack
;
409 proc_info
= &per_proc_info
[cpu
];
411 if (cpu
== cpu_number()) {
412 PE_cpu_machine_init(proc_info
->cpu_id
, !(proc_info
->cpu_flags
& BootDone
));
414 proc_info
->cpu_flags
|= BootDone
|SignalReady
;
418 extern void _start_cpu(void);
420 proc_info
->cpu_number
= cpu
;
421 proc_info
->cpu_flags
&= BootDone
;
422 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
423 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
424 #if MACH_KDP || MACH_KDB
425 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
426 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
427 #endif /* MACH_KDP || MACH_KDB */
428 proc_info
->interrupts_enabled
= 0;
429 proc_info
->need_ast
= (unsigned int)&need_ast
[cpu
];
430 proc_info
->FPU_owner
= 0;
431 proc_info
->VMX_owner
= 0;
432 mp
= (mapping
*)(&proc_info
->ppCIOmp
);
433 mp
->mpFlags
= 0x01000000 | mpSpecial
| 1;
434 mp
->mpSpace
= invalSpace
;
436 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
438 /* TODO: get mutex lock reset_handler_lock */
440 resethandler_target
.type
= RESET_HANDLER_START
;
441 resethandler_target
.call_paddr
= (vm_offset_t
)_start_cpu
; /* Note: these routines are always V=R */
442 resethandler_target
.arg__paddr
= (vm_offset_t
)proc_info
; /* Note: these routines are always V=R */
444 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
445 resethandler_target
.type
);
446 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
447 resethandler_target
.call_paddr
);
448 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
449 resethandler_target
.arg__paddr
);
453 * Note: we pass the current time to the other processor here. He will load it
454 * as early as possible so that there is a chance that it is close to accurate.
455 * After the machine is up a while, we will officially resync the clocks so
456 * that all processors are the same. This is just to get close.
459 ml_get_timebase((unsigned long long *)&proc_info
->ruptStamp
); /* Pass our current time to the other guy */
461 __asm__
volatile("sync"); /* Commit to storage */
462 __asm__
volatile("isync"); /* Wait a second */
463 ret
= PE_cpu_start(proc_info
->cpu_id
,
464 proc_info
->start_paddr
, (vm_offset_t
)proc_info
);
466 if (ret
!= KERN_SUCCESS
&&
467 proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
469 /* TODO: realese mutex lock reset_handler_lock */
475 perfTrap perfCpuSigHook
= 0; /* Pointer to CHUD cpu signal hook routine */
478 * Here is where we implement the receiver of the signaling protocol.
479 * We wait for the signal status area to be passed to us. Then we snarf
480 * up the status, the sender, and the 3 potential parms. Next we release
481 * the lock and signal the other guy.
489 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
490 unsigned int *parmAddr
;
491 struct per_proc_info
*pproc
; /* Area for my per_proc address */
493 struct SIGtimebase
*timebaseAddr
;
494 natural_t tbu
, tbu2
, tbl
;
496 cpu
= cpu_number(); /* Get the CPU number */
497 pproc
= &per_proc_info
[cpu
]; /* Point to our block */
500 * Since we've been signaled, wait about 31 ms for the signal lock to pass
502 if(!hw_lock_mbits(&pproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
), (MPsigpBusy
| MPsigpPass
),
503 (MPsigpBusy
| MPsigpPass
| MPsigpAck
), (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 5))) {
504 panic("cpu_signal_handler: Lock pass timed out\n");
507 holdStat
= pproc
->MPsigpStat
; /* Snarf stat word */
508 holdParm0
= pproc
->MPsigpParm0
; /* Snarf parameter */
509 holdParm1
= pproc
->MPsigpParm1
; /* Snarf parameter */
510 holdParm2
= pproc
->MPsigpParm2
; /* Snarf parameter */
512 __asm__
volatile("isync"); /* Make sure we don't unlock until memory is in */
514 pproc
->MPsigpStat
= holdStat
& ~(MPsigpMsgp
| MPsigpAck
| MPsigpFunc
); /* Release lock */
516 switch ((holdStat
& MPsigpFunc
) >> 8) { /* Decode function code */
518 case MPsigpIdle
: /* Was function cancelled? */
521 case MPsigpSigp
: /* Signal Processor message? */
523 switch (holdParm0
) { /* Decode SIGP message order */
525 case SIGPast
: /* Should we do an AST? */
526 pproc
->hwCtr
.numSIGPast
++; /* Count this one */
528 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
530 ast_check(cpu_to_processor(cpu
));
531 return; /* All done... */
533 case SIGPcpureq
: /* CPU specific function? */
535 pproc
->hwCtr
.numSIGPcpureq
++; /* Count this one */
536 switch (holdParm1
) { /* Select specific function */
538 case CPRQtemp
: /* Get the temperature */
539 parmAddr
= (unsigned int *)holdParm2
; /* Get the destination address */
540 parmAddr
[1] = ml_read_temp(); /* Get the core temperature */
541 eieio(); /* Force order */
542 sync(); /* Force to memory */
543 parmAddr
[0] = 0; /* Show we're done */
548 timebaseAddr
= (struct SIGtimebase
*)holdParm2
;
550 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
551 pproc
->time_base_enable(pproc
->cpu_id
, FALSE
);
553 timebaseAddr
->abstime
= 0; /* Touch to force into cache */
557 asm volatile(" mftbu %0" : "=r" (tbu
));
558 asm volatile(" mftb %0" : "=r" (tbl
));
559 asm volatile(" mftbu %0" : "=r" (tbu2
));
560 } while (tbu
!= tbu2
);
562 timebaseAddr
->abstime
= ((uint64_t)tbu
<< 32) | tbl
;
563 sync(); /* Force order */
565 timebaseAddr
->avail
= TRUE
;
567 while (*(volatile int *)&(syncClkSpot
.ready
) == FALSE
);
569 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
570 pproc
->time_base_enable(pproc
->cpu_id
, TRUE
);
572 timebaseAddr
->done
= TRUE
;
580 parmAddr
= (unsigned int *)holdParm2
; /* Get the destination address */
582 struct savearea
*ssp
= current_act()->mact
.pcb
;
584 (perfCpuSigHook
)(parmAddr
[1] /* request */, ssp
, 0, 0);
588 parmAddr
[0] = 0; /* Show we're done */
592 fwSCOM((scomcomm
*)holdParm2
); /* Do the function */
596 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1
);
601 case SIGPdebug
: /* Enter the debugger? */
603 pproc
->hwCtr
.numSIGPdebug
++; /* Count this one */
604 debugger_is_slave
[cpu
]++; /* Bump up the count to show we're here */
605 hw_atomic_sub(&debugger_sync
, 1); /* Show we've received the 'rupt */
606 __asm__
volatile("tw 4,r3,r3"); /* Enter the debugger */
607 return; /* All done now... */
609 case SIGPwake
: /* Wake up CPU */
610 pproc
->hwCtr
.numSIGPwake
++; /* Count this one */
611 return; /* No need to do anything, the interrupt does it all... */
614 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0
);
620 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat
& MPsigpFunc
) >> 8);
624 panic("cpu_signal_handler: we should never get here\n");
628 * Here is where we send a message to another processor. So far we only have two:
629 * SIGPast and SIGPdebug. SIGPast is used to preempt and kick off threads (this is
630 * currently disabled). SIGPdebug is used to enter the debugger.
632 * We set up the SIGP function to indicate that this is a simple message and set the
633 * order code (MPsigpParm0) to SIGPast or SIGPdebug). After finding the per_processor
634 * block for the target, we lock the message block. Then we set the parameter(s).
635 * Next we change the lock (also called "busy") to "passing" and finally signal
636 * the other processor. Note that we only wait about 1ms to get the message lock.
637 * If we time out, we return failure to our caller. It is their responsibility to
649 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
650 struct per_proc_info
*tpproc
, *mpproc
; /* Area for per_proc addresses */
655 if(target
> NCPUS
) panic("cpu_signal: invalid target CPU - %08X\n", target
);
658 cpu
= cpu_number(); /* Get our CPU number */
659 if(target
== cpu
) return KERN_FAILURE
; /* Don't play with ourselves */
660 if(!machine_slot
[target
].running
) return KERN_FAILURE
; /* These guys are too young */
662 mpproc
= &per_proc_info
[cpu
]; /* Point to our block */
663 tpproc
= &per_proc_info
[target
]; /* Point to the target's block */
665 if (!(tpproc
->cpu_flags
& SignalReady
)) return KERN_FAILURE
;
667 if((tpproc
->MPsigpStat
& MPsigpMsgp
) == MPsigpMsgp
) { /* Is there an unreceived message already pending? */
669 if(signal
== SIGPwake
) { /* SIGPwake can merge into all others... */
670 mpproc
->hwCtr
.numSIGPmwake
++; /* Account for merged wakes */
674 if((signal
== SIGPast
) && (tpproc
->MPsigpParm0
== SIGPast
)) { /* We can merge ASTs */
675 mpproc
->hwCtr
.numSIGPmast
++; /* Account for merged ASTs */
676 return KERN_SUCCESS
; /* Don't bother to send this one... */
679 if (tpproc
->MPsigpParm0
== SIGPwake
) {
680 if (hw_lock_mbits(&tpproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
),
681 (MPsigpBusy
| MPsigpPass
), MPsigpBusy
, 0)) {
683 mpproc
->hwCtr
.numSIGPmwake
++;
688 if((busybitset
== 0) &&
689 (!hw_lock_mbits(&tpproc
->MPsigpStat
, MPsigpMsgp
, 0, MPsigpBusy
,
690 (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 11)))) { /* Try to lock the message block with a .5ms timeout */
691 mpproc
->hwCtr
.numSIGPtimo
++; /* Account for timeouts */
692 return KERN_FAILURE
; /* Timed out, take your ball and go home... */
695 holdStat
= MPsigpBusy
| MPsigpPass
| (MPsigpSigp
<< 8) | cpu
; /* Set up the signal status word */
696 tpproc
->MPsigpParm0
= signal
; /* Set message order */
697 tpproc
->MPsigpParm1
= p1
; /* Set additional parm */
698 tpproc
->MPsigpParm2
= p2
; /* Set additional parm */
700 __asm__
volatile("sync"); /* Make sure it's all there */
702 tpproc
->MPsigpStat
= holdStat
; /* Set status and pass the lock */
703 __asm__
volatile("eieio"); /* I'm a paraniod freak */
706 PE_cpu_signal(mpproc
->cpu_id
, tpproc
->cpu_id
); /* Kick the other processor */
708 return KERN_SUCCESS
; /* All is goodness and rainbows... */
716 processor_offline(current_processor());
723 struct per_proc_info
*proc_info
;
725 unsigned int wait_ncpus_sleep
, ncpus_sleep
;
726 facility_context
*fowner
;
727 extern vm_offset_t intstack
;
728 extern vm_offset_t debstack
;
729 extern void _restart_cpu(void);
733 proc_info
= &per_proc_info
[cpu
];
735 fowner
= proc_info
->FPU_owner
; /* Cache this */
736 if(fowner
) fpu_save(fowner
); /* If anyone owns FPU, save it */
737 proc_info
->FPU_owner
= 0; /* Set no fpu owner now */
739 fowner
= proc_info
->VMX_owner
; /* Cache this */
740 if(fowner
) vec_save(fowner
); /* If anyone owns vectors, save it */
741 proc_info
->VMX_owner
= 0; /* Set no vector owner now */
743 if (proc_info
->cpu_number
== 0) {
744 proc_info
->cpu_flags
&= BootDone
;
745 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
746 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
747 #if MACH_KDP || MACH_KDB
748 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
749 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
750 #endif /* MACH_KDP || MACH_KDB */
751 proc_info
->interrupts_enabled
= 0;
753 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
754 extern void _start_cpu(void);
756 resethandler_target
.type
= RESET_HANDLER_START
;
757 resethandler_target
.call_paddr
= (vm_offset_t
)_start_cpu
; /* Note: these routines are always V=R */
758 resethandler_target
.arg__paddr
= (vm_offset_t
)proc_info
; /* Note: these routines are always V=R */
760 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
761 resethandler_target
.type
);
762 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
763 resethandler_target
.call_paddr
);
764 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
765 resethandler_target
.arg__paddr
);
767 __asm__
volatile("sync");
768 __asm__
volatile("isync");
771 wait_ncpus_sleep
= real_ncpus
-1;
773 while (wait_ncpus_sleep
!= ncpus_sleep
) {
775 for(i
=1; i
< real_ncpus
; i
++) {
776 if ((*(volatile short *)&per_proc_info
[i
].cpu_flags
) & SleepState
)
782 PE_cpu_machine_quiesce(proc_info
->cpu_id
);
792 intr
= ml_set_interrupts_enabled(FALSE
); /* No interruptions in here */
794 /* Note that syncClkSpot is in a cache aligned area */
795 syncClkSpot
.avail
= FALSE
;
796 syncClkSpot
.ready
= FALSE
;
797 syncClkSpot
.done
= FALSE
;
799 while (cpu_signal(master_cpu
, SIGPcpureq
, CPRQtimebase
,
800 (unsigned int)&syncClkSpot
) != KERN_SUCCESS
)
803 while (*(volatile int *)&(syncClkSpot
.avail
) == FALSE
)
809 * We do the following to keep the compiler from generating extra stuff
812 tbu
= syncClkSpot
.abstime
>> 32;
813 tbl
= (uint32_t)syncClkSpot
.abstime
;
819 syncClkSpot
.ready
= TRUE
;
821 while (*(volatile int *)&(syncClkSpot
.done
) == FALSE
)
824 (void)ml_set_interrupts_enabled(intr
);