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 <pexpert/pexpert.h>
45 #include <kern/cpu_data.h>
47 /* TODO: BOGUS TO BE REMOVED */
51 resethandler_t resethandler_target
;
53 #define MMCR0_SUPPORT_MASK 0xf83f1fff
54 #define MMCR1_SUPPORT_MASK 0xffc00000
55 #define MMCR2_SUPPORT_MASK 0x80000000
57 extern int debugger_pending
[NCPUS
];
58 extern int debugger_is_slave
[NCPUS
];
59 extern int debugger_holdoff
[NCPUS
];
60 extern int debugger_sync
;
69 struct per_proc_info
*pper_proc_info
= per_proc_info
;
71 extern struct SIGtimebase syncClkSpot
;
73 void cpu_sync_timebase(void);
78 processor_info_t info
,
82 cpu_subtype_t cpu_subtype
;
83 processor_pm_regs_t perf_regs
;
84 processor_control_cmd_t cmd
;
87 cpu_type
= machine_slot
[slot_num
].cpu_type
;
88 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
89 cmd
= (processor_control_cmd_t
) info
;
91 if (count
< PROCESSOR_CONTROL_CMD_COUNT
)
94 if ( cpu_type
!= cmd
->cmd_cpu_type
||
95 cpu_subtype
!= cmd
->cmd_cpu_subtype
)
100 case PROCESSOR_PM_CLR_PMC
: /* Clear Performance Monitor Counters */
103 case CPU_SUBTYPE_POWERPC_604
:
105 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
108 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
109 return(KERN_SUCCESS
);
111 case CPU_SUBTYPE_POWERPC_604e
:
112 case CPU_SUBTYPE_POWERPC_750
:
113 case CPU_SUBTYPE_POWERPC_7400
:
114 case CPU_SUBTYPE_POWERPC_7450
:
116 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
121 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
122 return(KERN_SUCCESS
);
125 return(KERN_FAILURE
);
127 case PROCESSOR_PM_SET_REGS
: /* Set Performance Monitor Registors */
130 case CPU_SUBTYPE_POWERPC_604
:
131 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
132 + PROCESSOR_PM_REGS_COUNT_POWERPC_604
))
133 return(KERN_FAILURE
);
136 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
137 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
138 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
139 mtpmc1(PERFMON_PMC1(perf_regs
));
140 mtpmc2(PERFMON_PMC2(perf_regs
));
141 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
142 return(KERN_SUCCESS
);
144 case CPU_SUBTYPE_POWERPC_604e
:
145 case CPU_SUBTYPE_POWERPC_750
:
146 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
147 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
148 return(KERN_FAILURE
);
151 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
152 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
153 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
154 mtpmc1(PERFMON_PMC1(perf_regs
));
155 mtpmc2(PERFMON_PMC2(perf_regs
));
156 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
157 mtpmc3(PERFMON_PMC3(perf_regs
));
158 mtpmc4(PERFMON_PMC4(perf_regs
));
159 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
160 return(KERN_SUCCESS
);
162 case CPU_SUBTYPE_POWERPC_7400
:
163 case CPU_SUBTYPE_POWERPC_7450
:
164 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
165 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
166 return(KERN_FAILURE
);
169 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
170 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
171 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
172 mtpmc1(PERFMON_PMC1(perf_regs
));
173 mtpmc2(PERFMON_PMC2(perf_regs
));
174 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
175 mtpmc3(PERFMON_PMC3(perf_regs
));
176 mtpmc4(PERFMON_PMC4(perf_regs
));
177 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
178 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
179 return(KERN_SUCCESS
);
182 return(KERN_FAILURE
);
183 } /* switch cpu_subtype */
184 case PROCESSOR_PM_SET_MMCR
:
187 case CPU_SUBTYPE_POWERPC_604
:
188 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
189 PROCESSOR_PM_REGS_COUNT_POWERPC_604
))
190 return(KERN_FAILURE
);
193 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
194 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
195 return(KERN_SUCCESS
);
197 case CPU_SUBTYPE_POWERPC_604e
:
198 case CPU_SUBTYPE_POWERPC_750
:
199 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
200 PROCESSOR_PM_REGS_COUNT_POWERPC_750
))
201 return(KERN_FAILURE
);
204 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
205 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
206 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
207 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
208 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
209 return(KERN_SUCCESS
);
211 case CPU_SUBTYPE_POWERPC_7400
:
212 case CPU_SUBTYPE_POWERPC_7450
:
213 if (count
< (PROCESSOR_CONTROL_CMD_COUNT
+
214 PROCESSOR_PM_REGS_COUNT_POWERPC_7400
))
215 return(KERN_FAILURE
);
218 perf_regs
= (processor_pm_regs_t
)cmd
->cmd_pm_regs
;
219 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
220 mtmmcr0(PERFMON_MMCR0(perf_regs
) & MMCR0_SUPPORT_MASK
);
221 mtmmcr1(PERFMON_MMCR1(perf_regs
) & MMCR1_SUPPORT_MASK
);
222 mtmmcr2(PERFMON_MMCR2(perf_regs
) & MMCR2_SUPPORT_MASK
);
223 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
224 return(KERN_SUCCESS
);
227 return(KERN_FAILURE
);
230 return(KERN_FAILURE
);
231 } /* switch cmd_op */
236 processor_flavor_t flavor
,
239 cpu_subtype_t cpu_subtype
;
242 * For now, we just assume that all CPUs are of the same type
244 cpu_subtype
= machine_slot
[0].cpu_subtype
;
246 case PROCESSOR_PM_REGS_INFO
:
247 switch (cpu_subtype
) {
248 case CPU_SUBTYPE_POWERPC_604
:
249 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_604
;
250 return(KERN_SUCCESS
);
252 case CPU_SUBTYPE_POWERPC_604e
:
253 case CPU_SUBTYPE_POWERPC_750
:
255 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
256 return(KERN_SUCCESS
);
258 case CPU_SUBTYPE_POWERPC_7400
:
259 case CPU_SUBTYPE_POWERPC_7450
:
261 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
262 return(KERN_SUCCESS
);
266 return(KERN_INVALID_ARGUMENT
);
267 } /* switch cpu_subtype */
269 case PROCESSOR_TEMPERATURE
:
270 *count
= PROCESSOR_TEMPERATURE_COUNT
;
271 return (KERN_SUCCESS
);
275 return(KERN_INVALID_ARGUMENT
);
282 processor_flavor_t flavor
,
284 processor_info_t info
,
287 cpu_subtype_t cpu_subtype
;
288 processor_pm_regs_t perf_regs
;
290 unsigned int temp
[2];
292 cpu_subtype
= machine_slot
[slot_num
].cpu_subtype
;
295 case PROCESSOR_PM_REGS_INFO
:
297 perf_regs
= (processor_pm_regs_t
) info
;
299 switch (cpu_subtype
) {
300 case CPU_SUBTYPE_POWERPC_604
:
302 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_604
)
303 return(KERN_FAILURE
);
305 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
306 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
307 PERFMON_PMC1(perf_regs
) = mfpmc1();
308 PERFMON_PMC2(perf_regs
) = mfpmc2();
309 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
311 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_604
;
312 return(KERN_SUCCESS
);
314 case CPU_SUBTYPE_POWERPC_604e
:
315 case CPU_SUBTYPE_POWERPC_750
:
317 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_750
)
318 return(KERN_FAILURE
);
320 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
321 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
322 PERFMON_PMC1(perf_regs
) = mfpmc1();
323 PERFMON_PMC2(perf_regs
) = mfpmc2();
324 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
325 PERFMON_PMC3(perf_regs
) = mfpmc3();
326 PERFMON_PMC4(perf_regs
) = mfpmc4();
327 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
329 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_750
;
330 return(KERN_SUCCESS
);
332 case CPU_SUBTYPE_POWERPC_7400
:
333 case CPU_SUBTYPE_POWERPC_7450
:
335 if (*count
< PROCESSOR_PM_REGS_COUNT_POWERPC_7400
)
336 return(KERN_FAILURE
);
338 oldlevel
= ml_set_interrupts_enabled(FALSE
); /* disable interrupts */
339 PERFMON_MMCR0(perf_regs
) = mfmmcr0();
340 PERFMON_PMC1(perf_regs
) = mfpmc1();
341 PERFMON_PMC2(perf_regs
) = mfpmc2();
342 PERFMON_MMCR1(perf_regs
) = mfmmcr1();
343 PERFMON_PMC3(perf_regs
) = mfpmc3();
344 PERFMON_PMC4(perf_regs
) = mfpmc4();
345 PERFMON_MMCR2(perf_regs
) = mfmmcr2();
346 ml_set_interrupts_enabled(oldlevel
); /* enable interrupts */
348 *count
= PROCESSOR_PM_REGS_COUNT_POWERPC_7400
;
349 return(KERN_SUCCESS
);
352 return(KERN_FAILURE
);
353 } /* switch cpu_subtype */
355 case PROCESSOR_TEMPERATURE
: /* Get the temperature of a processor */
357 disable_preemption(); /* Don't move me now */
359 if(slot_num
== cpu_number()) { /* Is this for the local CPU? */
360 *info
= ml_read_temp(); /* Get the temperature */
362 else { /* For another CPU */
363 temp
[0] = -1; /* Set sync flag */
366 temp
[1] = -1; /* Set invalid temperature */
367 (void)cpu_signal(slot_num
, SIGPcpureq
, CPRQtemp
,(unsigned int)&temp
); /* Ask him to take his temperature */
368 (void)hw_cpu_sync(temp
, LockTimeOut
); /* Wait for the other processor to get its temperature */
369 *info
= temp
[1]; /* Pass it back */
372 enable_preemption(); /* Ok to move now */
373 return(KERN_SUCCESS
);
376 return(KERN_INVALID_ARGUMENT
);
389 machine_slot
[cpu
].running
= TRUE
;
390 machine_slot
[cpu
].cpu_type
= CPU_TYPE_POWERPC
;
391 machine_slot
[cpu
].cpu_subtype
= (cpu_subtype_t
)per_proc_info
[cpu
].pf
.rptdProc
;
399 struct per_proc_info
*tproc_info
;
400 volatile struct per_proc_info
*mproc_info
;
403 /* TODO: realese mutex lock reset_handler_lock */
406 tproc_info
= &per_proc_info
[cpu
];
407 mproc_info
= &per_proc_info
[master_cpu
];
408 PE_cpu_machine_init(tproc_info
->cpu_id
, !(tproc_info
->cpu_flags
& BootDone
));
409 if (cpu
!= master_cpu
) {
410 while (!((mproc_info
->cpu_flags
) & SignalReady
))
415 tproc_info
->cpu_flags
|= BootDone
|SignalReady
;
427 * - Run cpu_register() in exclusion mode
431 for(cpu
=0; cpu
< wncpu
; cpu
++) {
432 if(!machine_slot
[cpu
].is_cpu
) {
433 machine_slot
[cpu
].is_cpu
= TRUE
;
438 if (*target_cpu
!= -1) {
449 struct per_proc_info
*proc_info
;
452 extern void (*exception_handlers
[])(void);
453 extern vm_offset_t intstack
;
454 extern vm_offset_t debstack
;
456 proc_info
= &per_proc_info
[cpu
];
458 if (cpu
== cpu_number()) {
459 PE_cpu_machine_init(proc_info
->cpu_id
, !(proc_info
->cpu_flags
& BootDone
));
461 proc_info
->cpu_flags
|= BootDone
|SignalReady
;
465 extern void _start_cpu(void);
467 proc_info
->cpu_number
= cpu
;
468 proc_info
->cpu_flags
&= BootDone
;
469 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
470 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
471 #if MACH_KDP || MACH_KDB
472 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
473 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
474 #endif /* MACH_KDP || MACH_KDB */
475 proc_info
->interrupts_enabled
= 0;
476 proc_info
->active_kloaded
= (unsigned int)&active_kloaded
[cpu
];
477 proc_info
->active_stacks
= (unsigned int)&active_stacks
[cpu
];
478 proc_info
->need_ast
= (unsigned int)&need_ast
[cpu
];
479 proc_info
->FPU_owner
= 0;
480 proc_info
->VMX_owner
= 0;
483 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
485 /* TODO: get mutex lock reset_handler_lock */
487 resethandler_target
.type
= RESET_HANDLER_START
;
488 resethandler_target
.call_paddr
= kvtophys((vm_offset_t
)_start_cpu
);
489 resethandler_target
.arg__paddr
= kvtophys((vm_offset_t
)proc_info
);
491 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
492 resethandler_target
.type
);
493 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
494 resethandler_target
.call_paddr
);
495 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
496 resethandler_target
.arg__paddr
);
500 * Note: we pass the current time to the other processor here. He will load it
501 * as early as possible so that there is a chance that it is close to accurate.
502 * After the machine is up a while, we will officially resync the clocks so
503 * that all processors are the same. This is just to get close.
506 ml_get_timebase((unsigned long long *)&proc_info
->ruptStamp
); /* Pass our current time to the other guy */
508 __asm__
volatile("sync"); /* Commit to storage */
509 __asm__
volatile("isync"); /* Wait a second */
510 ret
= PE_cpu_start(proc_info
->cpu_id
,
511 proc_info
->start_paddr
, (vm_offset_t
)proc_info
);
513 if (ret
!= KERN_SUCCESS
&&
514 proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
516 /* TODO: realese mutex lock reset_handler_lock */
523 * Here is where we implement the receiver of the signaling protocol.
524 * We wait for the signal status area to be passed to us. Then we snarf
525 * up the status, the sender, and the 3 potential parms. Next we release
526 * the lock and signal the other guy.
534 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
535 unsigned int *parmAddr
;
536 struct per_proc_info
*pproc
; /* Area for my per_proc address */
538 struct SIGtimebase
*timebaseAddr
;
539 natural_t tbu
, tbu2
, tbl
;
541 cpu
= cpu_number(); /* Get the CPU number */
542 pproc
= &per_proc_info
[cpu
]; /* Point to our block */
545 * Since we've been signaled, wait about 31 ms for the signal lock to pass
547 if(!hw_lock_mbits(&pproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
), (MPsigpBusy
| MPsigpPass
),
548 (MPsigpBusy
| MPsigpPass
| MPsigpAck
), (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 5))) {
549 panic("cpu_signal_handler: Lock pass timed out\n");
552 holdStat
= pproc
->MPsigpStat
; /* Snarf stat word */
553 holdParm0
= pproc
->MPsigpParm0
; /* Snarf parameter */
554 holdParm1
= pproc
->MPsigpParm1
; /* Snarf parameter */
555 holdParm2
= pproc
->MPsigpParm2
; /* Snarf parameter */
557 __asm__
volatile("isync"); /* Make sure we don't unlock until memory is in */
559 pproc
->MPsigpStat
= holdStat
& ~(MPsigpMsgp
| MPsigpAck
| MPsigpFunc
); /* Release lock */
561 switch ((holdStat
& MPsigpFunc
) >> 8) { /* Decode function code */
563 case MPsigpIdle
: /* Was function cancelled? */
566 case MPsigpSigp
: /* Signal Processor message? */
568 switch (holdParm0
) { /* Decode SIGP message order */
570 case SIGPast
: /* Should we do an AST? */
571 pproc
->numSIGPast
++; /* Count this one */
573 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
575 ast_check(cpu_to_processor(cpu
));
576 return; /* All done... */
578 case SIGPcpureq
: /* CPU specific function? */
580 pproc
->numSIGPcpureq
++; /* Count this one */
581 switch (holdParm1
) { /* Select specific function */
583 case CPRQtemp
: /* Get the temperature */
584 parmAddr
= (unsigned int *)holdParm2
; /* Get the destination address */
585 parmAddr
[1] = ml_read_temp(); /* Get the core temperature */
586 eieio(); /* Force order */
587 sync(); /* Force to memory */
588 parmAddr
[0] = 0; /* Show we're done */
593 timebaseAddr
= (struct SIGtimebase
*)holdParm2
;
595 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
596 pproc
->time_base_enable(pproc
->cpu_id
, FALSE
);
598 timebaseAddr
->abstime
= 0; /* Touch to force into cache */
602 asm volatile(" mftbu %0" : "=r" (tbu
));
603 asm volatile(" mftb %0" : "=r" (tbl
));
604 asm volatile(" mftbu %0" : "=r" (tbu2
));
605 } while (tbu
!= tbu2
);
607 timebaseAddr
->abstime
= ((uint64_t)tbu
<< 32) | tbl
;
608 sync(); /* Force order */
610 timebaseAddr
->avail
= TRUE
;
612 while (*(volatile int *)&(syncClkSpot
.ready
) == FALSE
);
614 if(pproc
->time_base_enable
!= (void(*)(cpu_id_t
, boolean_t
))NULL
)
615 pproc
->time_base_enable(pproc
->cpu_id
, TRUE
);
617 timebaseAddr
->done
= TRUE
;
622 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1
);
627 case SIGPdebug
: /* Enter the debugger? */
629 pproc
->numSIGPdebug
++; /* Count this one */
630 debugger_is_slave
[cpu
]++; /* Bump up the count to show we're here */
631 hw_atomic_sub(&debugger_sync
, 1); /* Show we've received the 'rupt */
632 __asm__
volatile("tw 4,r3,r3"); /* Enter the debugger */
633 return; /* All done now... */
635 case SIGPwake
: /* Wake up CPU */
636 pproc
->numSIGPwake
++; /* Count this one */
637 return; /* No need to do anything, the interrupt does it all... */
640 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0
);
646 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat
& MPsigpFunc
) >> 8);
650 panic("cpu_signal_handler: we should never get here\n");
654 * Here is where we send a message to another processor. So far we only have two:
655 * SIGPast and SIGPdebug. SIGPast is used to preempt and kick off threads (this is
656 * currently disabled). SIGPdebug is used to enter the debugger.
658 * We set up the SIGP function to indicate that this is a simple message and set the
659 * order code (MPsigpParm0) to SIGPast or SIGPdebug). After finding the per_processor
660 * block for the target, we lock the message block. Then we set the parameter(s).
661 * Next we change the lock (also called "busy") to "passing" and finally signal
662 * the other processor. Note that we only wait about 1ms to get the message lock.
663 * If we time out, we return failure to our caller. It is their responsibility to
675 unsigned int holdStat
, holdParm0
, holdParm1
, holdParm2
, mtype
;
676 struct per_proc_info
*tpproc
, *mpproc
; /* Area for per_proc addresses */
681 if(target
> NCPUS
) panic("cpu_signal: invalid target CPU - %08X\n", target
);
684 cpu
= cpu_number(); /* Get our CPU number */
685 if(target
== cpu
) return KERN_FAILURE
; /* Don't play with ourselves */
686 if(!machine_slot
[target
].running
) return KERN_FAILURE
; /* These guys are too young */
688 mpproc
= &per_proc_info
[cpu
]; /* Point to our block */
689 tpproc
= &per_proc_info
[target
]; /* Point to the target's block */
691 if (!(tpproc
->cpu_flags
& SignalReady
)) return KERN_FAILURE
;
693 if((tpproc
->MPsigpStat
& MPsigpMsgp
) == MPsigpMsgp
) { /* Is there an unreceived message already pending? */
695 if(signal
== SIGPwake
) { /* SIGPwake can merge into all others... */
696 mpproc
->numSIGPmwake
++; /* Account for merged wakes */
700 if((signal
== SIGPast
) && (tpproc
->MPsigpParm0
== SIGPast
)) { /* We can merge ASTs */
701 mpproc
->numSIGPmast
++; /* Account for merged ASTs */
702 return KERN_SUCCESS
; /* Don't bother to send this one... */
705 if (tpproc
->MPsigpParm0
== SIGPwake
) {
706 if (hw_lock_mbits(&tpproc
->MPsigpStat
, (MPsigpMsgp
| MPsigpAck
),
707 (MPsigpBusy
| MPsigpPass
), MPsigpBusy
, 0)) {
709 mpproc
->numSIGPmwake
++;
714 if((busybitset
== 0) &&
715 (!hw_lock_mbits(&tpproc
->MPsigpStat
, MPsigpMsgp
, 0, MPsigpBusy
,
716 (gPEClockFrequencyInfo
.timebase_frequency_hz
>> 11)))) { /* Try to lock the message block with a .5ms timeout */
717 mpproc
->numSIGPtimo
++; /* Account for timeouts */
718 return KERN_FAILURE
; /* Timed out, take your ball and go home... */
721 holdStat
= MPsigpBusy
| MPsigpPass
| (MPsigpSigp
<< 8) | cpu
; /* Set up the signal status word */
722 tpproc
->MPsigpParm0
= signal
; /* Set message order */
723 tpproc
->MPsigpParm1
= p1
; /* Set additional parm */
724 tpproc
->MPsigpParm2
= p2
; /* Set additional parm */
726 __asm__
volatile("sync"); /* Make sure it's all there */
728 tpproc
->MPsigpStat
= holdStat
; /* Set status and pass the lock */
729 __asm__
volatile("eieio"); /* I'm a paraniod freak */
732 PE_cpu_signal(mpproc
->cpu_id
, tpproc
->cpu_id
); /* Kick the other processor */
734 return KERN_SUCCESS
; /* All is goodness and rainbows... */
741 processor_doshutdown(current_processor());
748 struct per_proc_info
*proc_info
;
750 facility_context
*fowner
;
751 extern void (*exception_handlers
[])(void);
752 extern vm_offset_t intstack
;
753 extern vm_offset_t debstack
;
754 extern void _restart_cpu(void);
758 kprintf("******* About to sleep cpu %d\n", cpu
);
761 proc_info
= &per_proc_info
[cpu
];
763 fowner
= proc_info
->FPU_owner
; /* Cache this */
764 if(fowner
) fpu_save(fowner
); /* If anyone owns FPU, save it */
765 proc_info
->FPU_owner
= 0; /* Set no fpu owner now */
767 fowner
= proc_info
->VMX_owner
; /* Cache this */
768 if(fowner
) vec_save(fowner
); /* If anyone owns vectors, save it */
769 proc_info
->VMX_owner
= 0; /* Set no vector owner now */
771 if (proc_info
->cpu_number
== 0) {
772 proc_info
->cpu_flags
&= BootDone
;
773 proc_info
->istackptr
= (vm_offset_t
)&intstack
+ (INTSTACK_SIZE
*(cpu
+1)) - FM_SIZE
;
774 proc_info
->intstack_top_ss
= proc_info
->istackptr
;
775 #if MACH_KDP || MACH_KDB
776 proc_info
->debstackptr
= (vm_offset_t
)&debstack
+ (KERNEL_STACK_SIZE
*(cpu
+1)) - FM_SIZE
;
777 proc_info
->debstack_top_ss
= proc_info
->debstackptr
;
778 #endif /* MACH_KDP || MACH_KDB */
779 proc_info
->interrupts_enabled
= 0;
781 if (proc_info
->start_paddr
== EXCEPTION_VECTOR(T_RESET
)) {
782 extern void _start_cpu(void);
784 resethandler_target
.type
= RESET_HANDLER_START
;
785 resethandler_target
.call_paddr
= kvtophys((vm_offset_t
)_start_cpu
);
786 resethandler_target
.arg__paddr
= kvtophys((vm_offset_t
)proc_info
);
788 ml_phys_write((vm_offset_t
)&ResetHandler
+ 0,
789 resethandler_target
.type
);
790 ml_phys_write((vm_offset_t
)&ResetHandler
+ 4,
791 resethandler_target
.call_paddr
);
792 ml_phys_write((vm_offset_t
)&ResetHandler
+ 8,
793 resethandler_target
.arg__paddr
);
795 __asm__
volatile("sync");
796 __asm__
volatile("isync");
800 PE_cpu_machine_quiesce(proc_info
->cpu_id
);
810 intr
= ml_set_interrupts_enabled(FALSE
); /* No interruptions in here */
812 /* Note that syncClkSpot is in a cache aligned area */
813 syncClkSpot
.avail
= FALSE
;
814 syncClkSpot
.ready
= FALSE
;
815 syncClkSpot
.done
= FALSE
;
817 while (cpu_signal(master_cpu
, SIGPcpureq
, CPRQtimebase
,
818 (unsigned int)&syncClkSpot
) != KERN_SUCCESS
)
821 while (*(volatile int *)&(syncClkSpot
.avail
) == FALSE
)
827 * We do the following to keep the compiler from generating extra stuff
830 tbu
= syncClkSpot
.abstime
>> 32;
831 tbl
= (uint32_t)syncClkSpot
.abstime
;
837 syncClkSpot
.ready
= TRUE
;
839 while (*(volatile int *)&(syncClkSpot
.done
) == FALSE
)
842 (void)ml_set_interrupts_enabled(intr
);