]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/cpu.c
xnu-344.21.74.tar.gz
[apple/xnu.git] / osfmk / ppc / cpu.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
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
13 * file.
14 *
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * File: ppc/cpu.c
27 *
28 * cpu specific routines
29 */
30
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>
9bccf70c 43#include <ppc/asm.h>
d7e50217 44#include <ppc/hw_perfmon.h>
1c79356b 45#include <pexpert/pexpert.h>
9bccf70c 46#include <kern/cpu_data.h>
d7e50217
A
47#include <ppc/mappings.h>
48#include <ppc/Diagnostics.h>
1c79356b
A
49
50/* TODO: BOGUS TO BE REMOVED */
51int real_ncpus = 1;
52
53int wncpu = NCPUS;
54resethandler_t resethandler_target;
55
56#define MMCR0_SUPPORT_MASK 0xf83f1fff
57#define MMCR1_SUPPORT_MASK 0xffc00000
58#define MMCR2_SUPPORT_MASK 0x80000000
59
60extern int debugger_pending[NCPUS];
61extern int debugger_is_slave[NCPUS];
62extern int debugger_holdoff[NCPUS];
63extern int debugger_sync;
64
65struct SIGtimebase {
66 boolean_t avail;
67 boolean_t ready;
68 boolean_t done;
0b4e3aa0 69 uint64_t abstime;
1c79356b
A
70};
71
9bccf70c
A
72struct per_proc_info *pper_proc_info = per_proc_info;
73
1c79356b
A
74extern struct SIGtimebase syncClkSpot;
75
76void cpu_sync_timebase(void);
77
78kern_return_t
79cpu_control(
80 int slot_num,
81 processor_info_t info,
82 unsigned int count)
83{
84 cpu_type_t cpu_type;
85 cpu_subtype_t cpu_subtype;
86 processor_pm_regs_t perf_regs;
87 processor_control_cmd_t cmd;
88 boolean_t oldlevel;
89
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;
93
94 if (count < PROCESSOR_CONTROL_CMD_COUNT)
95 return(KERN_FAILURE);
96
97 if ( cpu_type != cmd->cmd_cpu_type ||
98 cpu_subtype != cmd->cmd_cpu_subtype)
99 return(KERN_FAILURE);
100
d7e50217
A
101 if (perfmon_acquire_facility(current_task()) != KERN_SUCCESS) {
102 return(KERN_RESOURCE_SHORTAGE); /* cpu performance facility in use by another task */
103 }
104
1c79356b
A
105 switch (cmd->cmd_op)
106 {
107 case PROCESSOR_PM_CLR_PMC: /* Clear Performance Monitor Counters */
108 switch (cpu_subtype)
109 {
1c79356b
A
110 case CPU_SUBTYPE_POWERPC_750:
111 case CPU_SUBTYPE_POWERPC_7400:
112 case CPU_SUBTYPE_POWERPC_7450:
113 {
114 oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
115 mtpmc1(0x0);
116 mtpmc2(0x0);
117 mtpmc3(0x0);
118 mtpmc4(0x0);
119 ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
120 return(KERN_SUCCESS);
121 }
122 default:
123 return(KERN_FAILURE);
124 } /* cpu_subtype */
125 case PROCESSOR_PM_SET_REGS: /* Set Performance Monitor Registors */
126 switch (cpu_subtype)
127 {
1c79356b
A
128 case CPU_SUBTYPE_POWERPC_750:
129 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
130 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
131 return(KERN_FAILURE);
132 else
133 {
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);
144 }
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);
150 else
151 {
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);
163 }
164 default:
165 return(KERN_FAILURE);
166 } /* switch cpu_subtype */
167 case PROCESSOR_PM_SET_MMCR:
168 switch (cpu_subtype)
169 {
1c79356b
A
170 case CPU_SUBTYPE_POWERPC_750:
171 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
172 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
173 return(KERN_FAILURE);
174 else
175 {
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);
182 }
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);
188 else
189 {
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);
197 }
198 default:
199 return(KERN_FAILURE);
200 } /* cpu_subtype */
201 default:
202 return(KERN_FAILURE);
203 } /* switch cmd_op */
204}
205
206kern_return_t
207cpu_info_count(
208 processor_flavor_t flavor,
209 unsigned int *count)
210{
211 cpu_subtype_t cpu_subtype;
212
213 /*
214 * For now, we just assume that all CPUs are of the same type
215 */
216 cpu_subtype = machine_slot[0].cpu_subtype;
217 switch (flavor) {
218 case PROCESSOR_PM_REGS_INFO:
219 switch (cpu_subtype) {
1c79356b
A
220 case CPU_SUBTYPE_POWERPC_750:
221
222 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
223 return(KERN_SUCCESS);
224
225 case CPU_SUBTYPE_POWERPC_7400:
226 case CPU_SUBTYPE_POWERPC_7450:
227
228 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
229 return(KERN_SUCCESS);
230
231 default:
232 *count = 0;
233 return(KERN_INVALID_ARGUMENT);
234 } /* switch cpu_subtype */
235
236 case PROCESSOR_TEMPERATURE:
237 *count = PROCESSOR_TEMPERATURE_COUNT;
238 return (KERN_SUCCESS);
239
240 default:
241 *count = 0;
242 return(KERN_INVALID_ARGUMENT);
243
244 }
245}
246
247kern_return_t
248cpu_info(
249 processor_flavor_t flavor,
250 int slot_num,
251 processor_info_t info,
252 unsigned int *count)
253{
254 cpu_subtype_t cpu_subtype;
255 processor_pm_regs_t perf_regs;
256 boolean_t oldlevel;
257 unsigned int temp[2];
258
259 cpu_subtype = machine_slot[slot_num].cpu_subtype;
260
261 switch (flavor) {
262 case PROCESSOR_PM_REGS_INFO:
263
264 perf_regs = (processor_pm_regs_t) info;
265
266 switch (cpu_subtype) {
1c79356b
A
267 case CPU_SUBTYPE_POWERPC_750:
268
269 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_750)
270 return(KERN_FAILURE);
271
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 */
280
281 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
282 return(KERN_SUCCESS);
283
284 case CPU_SUBTYPE_POWERPC_7400:
285 case CPU_SUBTYPE_POWERPC_7450:
286
287 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_7400)
288 return(KERN_FAILURE);
289
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 */
299
300 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
301 return(KERN_SUCCESS);
302
303 default:
304 return(KERN_FAILURE);
305 } /* switch cpu_subtype */
306
307 case PROCESSOR_TEMPERATURE: /* Get the temperature of a processor */
308
309 disable_preemption(); /* Don't move me now */
310
311 if(slot_num == cpu_number()) { /* Is this for the local CPU? */
312 *info = ml_read_temp(); /* Get the temperature */
313 }
314 else { /* For another CPU */
315 temp[0] = -1; /* Set sync flag */
316 eieio();
317 sync();
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 */
322 }
323
324 enable_preemption(); /* Ok to move now */
325 return(KERN_SUCCESS);
326
327 default:
328 return(KERN_INVALID_ARGUMENT);
329
330 } /* flavor */
331}
332
333void
334cpu_init(
335 void)
336{
337 int cpu;
338
339 cpu = cpu_number();
340
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;
344
345}
346
347void
348cpu_machine_init(
349 void)
350{
0b4e3aa0
A
351 struct per_proc_info *tproc_info;
352 volatile struct per_proc_info *mproc_info;
1c79356b
A
353 int cpu;
354
355 /* TODO: realese mutex lock reset_handler_lock */
356
357 cpu = cpu_number();
0b4e3aa0
A
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))
363 continue;
1c79356b 364 cpu_sync_timebase();
0b4e3aa0 365 }
1c79356b 366 ml_init_interrupt();
0b4e3aa0 367 tproc_info->cpu_flags |= BootDone|SignalReady;
1c79356b
A
368}
369
370kern_return_t
371cpu_register(
372 int *target_cpu
373)
374{
375 int cpu;
376
377 /*
378 * TODO:
379 * - Run cpu_register() in exclusion mode
380 */
381
382 *target_cpu = -1;
383 for(cpu=0; cpu < wncpu; cpu++) {
384 if(!machine_slot[cpu].is_cpu) {
385 machine_slot[cpu].is_cpu = TRUE;
386 *target_cpu = cpu;
387 break;
388 }
389 }
390 if (*target_cpu != -1) {
391 real_ncpus++;
392 return KERN_SUCCESS;
393 } else
394 return KERN_FAILURE;
395}
396
397kern_return_t
398cpu_start(
399 int cpu)
400{
401 struct per_proc_info *proc_info;
402 kern_return_t ret;
d7e50217 403 mapping *mp;
1c79356b 404
1c79356b
A
405 extern vm_offset_t intstack;
406 extern vm_offset_t debstack;
407
408 proc_info = &per_proc_info[cpu];
409
410 if (cpu == cpu_number()) {
411 PE_cpu_machine_init(proc_info->cpu_id, !(proc_info->cpu_flags & BootDone));
412 ml_init_interrupt();
0b4e3aa0 413 proc_info->cpu_flags |= BootDone|SignalReady;
1c79356b
A
414
415 return KERN_SUCCESS;
416 } else {
417 extern void _start_cpu(void);
418
419 proc_info->cpu_number = cpu;
420 proc_info->cpu_flags &= BootDone;
9bccf70c 421 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
422 proc_info->intstack_top_ss = proc_info->istackptr;
423#if MACH_KDP || MACH_KDB
9bccf70c 424 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
425 proc_info->debstack_top_ss = proc_info->debstackptr;
426#endif /* MACH_KDP || MACH_KDB */
0b4e3aa0 427 proc_info->interrupts_enabled = 0;
1c79356b 428 proc_info->active_kloaded = (unsigned int)&active_kloaded[cpu];
1c79356b
A
429 proc_info->active_stacks = (unsigned int)&active_stacks[cpu];
430 proc_info->need_ast = (unsigned int)&need_ast[cpu];
9bccf70c
A
431 proc_info->FPU_owner = 0;
432 proc_info->VMX_owner = 0;
d7e50217
A
433 mp = (mapping *)(&proc_info->ppCIOmp);
434 mp->mpFlags = 0x01000000 | mpSpecial | 1;
435 mp->mpSpace = invalSpace;
1c79356b
A
436
437 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
438
439 /* TODO: get mutex lock reset_handler_lock */
440
441 resethandler_target.type = RESET_HANDLER_START;
d7e50217
A
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 */
1c79356b
A
444
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);
451
452 }
453/*
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.
458 */
459
9bccf70c 460 ml_get_timebase((unsigned long long *)&proc_info->ruptStamp); /* Pass our current time to the other guy */
1c79356b
A
461
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);
466
467 if (ret != KERN_SUCCESS &&
468 proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
469
470 /* TODO: realese mutex lock reset_handler_lock */
471 }
472 return(ret);
473 }
474}
475
476/*
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.
481 */
482
483void
484cpu_signal_handler(
485 void)
486{
487
488 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
489 unsigned int *parmAddr;
490 struct per_proc_info *pproc; /* Area for my per_proc address */
491 int cpu;
492 struct SIGtimebase *timebaseAddr;
493 natural_t tbu, tbu2, tbl;
494
495 cpu = cpu_number(); /* Get the CPU number */
496 pproc = &per_proc_info[cpu]; /* Point to our block */
497
498/*
d7e50217 499 * Since we've been signaled, wait about 31 ms for the signal lock to pass
1c79356b 500 */
9bccf70c 501 if(!hw_lock_mbits(&pproc->MPsigpStat, (MPsigpMsgp | MPsigpAck), (MPsigpBusy | MPsigpPass),
d7e50217 502 (MPsigpBusy | MPsigpPass | MPsigpAck), (gPEClockFrequencyInfo.timebase_frequency_hz >> 5))) {
1c79356b
A
503 panic("cpu_signal_handler: Lock pass timed out\n");
504 }
505
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 */
510
511 __asm__ volatile("isync"); /* Make sure we don't unlock until memory is in */
512
9bccf70c 513 pproc->MPsigpStat = holdStat & ~(MPsigpMsgp | MPsigpAck | MPsigpFunc); /* Release lock */
1c79356b
A
514
515 switch ((holdStat & MPsigpFunc) >> 8) { /* Decode function code */
516
517 case MPsigpIdle: /* Was function cancelled? */
518 return; /* Yup... */
519
520 case MPsigpSigp: /* Signal Processor message? */
521
522 switch (holdParm0) { /* Decode SIGP message order */
523
524 case SIGPast: /* Should we do an AST? */
d7e50217 525 pproc->hwCtr.numSIGPast++; /* Count this one */
1c79356b
A
526#if 0
527 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
528#endif
9bccf70c 529 ast_check(cpu_to_processor(cpu));
1c79356b
A
530 return; /* All done... */
531
532 case SIGPcpureq: /* CPU specific function? */
533
d7e50217 534 pproc->hwCtr.numSIGPcpureq++; /* Count this one */
1c79356b
A
535 switch (holdParm1) { /* Select specific function */
536
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 */
543 return;
544
545 case CPRQtimebase:
546
547 timebaseAddr = (struct SIGtimebase *)holdParm2;
548
549 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
550 pproc->time_base_enable(pproc->cpu_id, FALSE);
551
0b4e3aa0 552 timebaseAddr->abstime = 0; /* Touch to force into cache */
1c79356b
A
553 sync();
554
555 do {
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);
560
0b4e3aa0 561 timebaseAddr->abstime = ((uint64_t)tbu << 32) | tbl;
1c79356b
A
562 sync(); /* Force order */
563
564 timebaseAddr->avail = TRUE;
565
566 while (*(volatile int *)&(syncClkSpot.ready) == FALSE);
567
568 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
569 pproc->time_base_enable(pproc->cpu_id, TRUE);
570
571 timebaseAddr->done = TRUE;
572
573 return;
d7e50217
A
574
575 case CPRQscom:
576 fwSCOM((scomcomm *)holdParm2); /* Do the function */
577 return;
1c79356b
A
578
579 default:
580 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1);
581 return;
582 }
583
584
585 case SIGPdebug: /* Enter the debugger? */
586
d7e50217 587 pproc->hwCtr.numSIGPdebug++; /* Count this one */
1c79356b
A
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... */
592
593 case SIGPwake: /* Wake up CPU */
d7e50217 594 pproc->hwCtr.numSIGPwake++; /* Count this one */
1c79356b
A
595 return; /* No need to do anything, the interrupt does it all... */
596
597 default:
598 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0);
599 return;
600
601 }
602
603 default:
604 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat & MPsigpFunc) >> 8);
605 return;
606
607 }
608 panic("cpu_signal_handler: we should never get here\n");
609}
610
611/*
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.
615 *
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
622 * recover.
623 */
624
625kern_return_t
626cpu_signal(
627 int target,
628 int signal,
629 unsigned int p1,
630 unsigned int p2)
631{
632
633 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
634 struct per_proc_info *tpproc, *mpproc; /* Area for per_proc addresses */
635 int cpu;
9bccf70c 636 int busybitset =0;
1c79356b
A
637
638#if DEBUG
639 if(target > NCPUS) panic("cpu_signal: invalid target CPU - %08X\n", target);
640#endif
641
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 */
645
646 mpproc = &per_proc_info[cpu]; /* Point to our block */
647 tpproc = &per_proc_info[target]; /* Point to the target's block */
0b4e3aa0
A
648
649 if (!(tpproc->cpu_flags & SignalReady)) return KERN_FAILURE;
9bccf70c 650
7b1edb79
A
651 if((tpproc->MPsigpStat & MPsigpMsgp) == MPsigpMsgp) { /* Is there an unreceived message already pending? */
652
9bccf70c 653 if(signal == SIGPwake) { /* SIGPwake can merge into all others... */
d7e50217 654 mpproc->hwCtr.numSIGPmwake++; /* Account for merged wakes */
9bccf70c
A
655 return KERN_SUCCESS;
656 }
7b1edb79
A
657
658 if((signal == SIGPast) && (tpproc->MPsigpParm0 == SIGPast)) { /* We can merge ASTs */
d7e50217 659 mpproc->hwCtr.numSIGPmast++; /* Account for merged ASTs */
7b1edb79
A
660 return KERN_SUCCESS; /* Don't bother to send this one... */
661 }
9bccf70c
A
662
663 if (tpproc->MPsigpParm0 == SIGPwake) {
664 if (hw_lock_mbits(&tpproc->MPsigpStat, (MPsigpMsgp | MPsigpAck),
665 (MPsigpBusy | MPsigpPass ), MPsigpBusy, 0)) {
666 busybitset = 1;
d7e50217 667 mpproc->hwCtr.numSIGPmwake++;
9bccf70c
A
668 }
669 }
7b1edb79
A
670 }
671
9bccf70c
A
672 if((busybitset == 0) &&
673 (!hw_lock_mbits(&tpproc->MPsigpStat, MPsigpMsgp, 0, MPsigpBusy,
d7e50217
A
674 (gPEClockFrequencyInfo.timebase_frequency_hz >> 11)))) { /* Try to lock the message block with a .5ms timeout */
675 mpproc->hwCtr.numSIGPtimo++; /* Account for timeouts */
1c79356b
A
676 return KERN_FAILURE; /* Timed out, take your ball and go home... */
677 }
678
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 */
683
684 __asm__ volatile("sync"); /* Make sure it's all there */
685
686 tpproc->MPsigpStat = holdStat; /* Set status and pass the lock */
687 __asm__ volatile("eieio"); /* I'm a paraniod freak */
688
9bccf70c
A
689 if (busybitset == 0)
690 PE_cpu_signal(mpproc->cpu_id, tpproc->cpu_id); /* Kick the other processor */
1c79356b
A
691
692 return KERN_SUCCESS; /* All is goodness and rainbows... */
693}
694
695void
696cpu_doshutdown(
697 void)
698{
d7e50217 699 enable_preemption();
1c79356b
A
700 processor_doshutdown(current_processor());
701}
702
703void
704cpu_sleep(
705 void)
706{
707 struct per_proc_info *proc_info;
708 unsigned int cpu;
9bccf70c 709 facility_context *fowner;
1c79356b
A
710 extern vm_offset_t intstack;
711 extern vm_offset_t debstack;
712 extern void _restart_cpu(void);
713
714 cpu = cpu_number();
1c79356b
A
715
716 proc_info = &per_proc_info[cpu];
717
9bccf70c
A
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 */
765c9de3 721
9bccf70c
A
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 */
765c9de3 725
1c79356b
A
726 if (proc_info->cpu_number == 0) {
727 proc_info->cpu_flags &= BootDone;
9bccf70c 728 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
729 proc_info->intstack_top_ss = proc_info->istackptr;
730#if MACH_KDP || MACH_KDB
9bccf70c 731 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
732 proc_info->debstack_top_ss = proc_info->debstackptr;
733#endif /* MACH_KDP || MACH_KDB */
0b4e3aa0 734 proc_info->interrupts_enabled = 0;
1c79356b 735
765c9de3 736 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
1c79356b 737 extern void _start_cpu(void);
765c9de3 738
1c79356b 739 resethandler_target.type = RESET_HANDLER_START;
d7e50217
A
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 */
765c9de3 742
1c79356b 743 ml_phys_write((vm_offset_t)&ResetHandler + 0,
765c9de3 744 resethandler_target.type);
1c79356b 745 ml_phys_write((vm_offset_t)&ResetHandler + 4,
765c9de3 746 resethandler_target.call_paddr);
1c79356b 747 ml_phys_write((vm_offset_t)&ResetHandler + 8,
765c9de3 748 resethandler_target.arg__paddr);
1c79356b
A
749
750 __asm__ volatile("sync");
751 __asm__ volatile("isync");
765c9de3 752 }
1c79356b
A
753 }
754
755 PE_cpu_machine_quiesce(proc_info->cpu_id);
756}
757
758void
759cpu_sync_timebase(
760 void)
761{
762 natural_t tbu, tbl;
763 boolean_t intr;
764
765 intr = ml_set_interrupts_enabled(FALSE); /* No interruptions in here */
766
767 /* Note that syncClkSpot is in a cache aligned area */
768 syncClkSpot.avail = FALSE;
769 syncClkSpot.ready = FALSE;
770 syncClkSpot.done = FALSE;
771
0b4e3aa0
A
772 while (cpu_signal(master_cpu, SIGPcpureq, CPRQtimebase,
773 (unsigned int)&syncClkSpot) != KERN_SUCCESS)
774 continue;
1c79356b 775
0b4e3aa0
A
776 while (*(volatile int *)&(syncClkSpot.avail) == FALSE)
777 continue;
1c79356b 778
1c79356b
A
779 isync();
780
781 /*
782 * We do the following to keep the compiler from generating extra stuff
783 * in tb set part
784 */
0b4e3aa0
A
785 tbu = syncClkSpot.abstime >> 32;
786 tbl = (uint32_t)syncClkSpot.abstime;
1c79356b
A
787
788 mttb(0);
789 mttbu(tbu);
790 mttb(tbl);
791
792 syncClkSpot.ready = TRUE;
793
0b4e3aa0
A
794 while (*(volatile int *)&(syncClkSpot.done) == FALSE)
795 continue;
1c79356b
A
796
797 (void)ml_set_interrupts_enabled(intr);
798}