]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/cpu.c
xnu-344.49.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 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
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,
43866e37
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>
1c79356b 44#include <pexpert/pexpert.h>
9bccf70c 45#include <kern/cpu_data.h>
1c79356b
A
46
47/* TODO: BOGUS TO BE REMOVED */
48int real_ncpus = 1;
49
50int wncpu = NCPUS;
51resethandler_t resethandler_target;
52
53#define MMCR0_SUPPORT_MASK 0xf83f1fff
54#define MMCR1_SUPPORT_MASK 0xffc00000
55#define MMCR2_SUPPORT_MASK 0x80000000
56
57extern int debugger_pending[NCPUS];
58extern int debugger_is_slave[NCPUS];
59extern int debugger_holdoff[NCPUS];
60extern int debugger_sync;
61
62struct SIGtimebase {
63 boolean_t avail;
64 boolean_t ready;
65 boolean_t done;
0b4e3aa0 66 uint64_t abstime;
1c79356b
A
67};
68
9bccf70c
A
69struct per_proc_info *pper_proc_info = per_proc_info;
70
1c79356b
A
71extern struct SIGtimebase syncClkSpot;
72
73void cpu_sync_timebase(void);
74
75kern_return_t
76cpu_control(
77 int slot_num,
78 processor_info_t info,
79 unsigned int count)
80{
81 cpu_type_t cpu_type;
82 cpu_subtype_t cpu_subtype;
83 processor_pm_regs_t perf_regs;
84 processor_control_cmd_t cmd;
85 boolean_t oldlevel;
86
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;
90
91 if (count < PROCESSOR_CONTROL_CMD_COUNT)
92 return(KERN_FAILURE);
93
94 if ( cpu_type != cmd->cmd_cpu_type ||
95 cpu_subtype != cmd->cmd_cpu_subtype)
96 return(KERN_FAILURE);
97
98 switch (cmd->cmd_op)
99 {
100 case PROCESSOR_PM_CLR_PMC: /* Clear Performance Monitor Counters */
101 switch (cpu_subtype)
102 {
de355530
A
103 case CPU_SUBTYPE_POWERPC_604:
104 {
105 oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
106 mtpmc1(0x0);
107 mtpmc2(0x0);
108 ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
109 return(KERN_SUCCESS);
110 }
111 case CPU_SUBTYPE_POWERPC_604e:
1c79356b
A
112 case CPU_SUBTYPE_POWERPC_750:
113 case CPU_SUBTYPE_POWERPC_7400:
114 case CPU_SUBTYPE_POWERPC_7450:
115 {
116 oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
117 mtpmc1(0x0);
118 mtpmc2(0x0);
119 mtpmc3(0x0);
120 mtpmc4(0x0);
121 ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
122 return(KERN_SUCCESS);
123 }
124 default:
125 return(KERN_FAILURE);
126 } /* cpu_subtype */
127 case PROCESSOR_PM_SET_REGS: /* Set Performance Monitor Registors */
128 switch (cpu_subtype)
129 {
de355530
A
130 case CPU_SUBTYPE_POWERPC_604:
131 if (count < (PROCESSOR_CONTROL_CMD_COUNT
132 + PROCESSOR_PM_REGS_COUNT_POWERPC_604))
133 return(KERN_FAILURE);
134 else
135 {
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);
143 }
144 case CPU_SUBTYPE_POWERPC_604e:
1c79356b
A
145 case CPU_SUBTYPE_POWERPC_750:
146 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
147 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
148 return(KERN_FAILURE);
149 else
150 {
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);
161 }
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);
167 else
168 {
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);
180 }
181 default:
182 return(KERN_FAILURE);
183 } /* switch cpu_subtype */
184 case PROCESSOR_PM_SET_MMCR:
185 switch (cpu_subtype)
186 {
de355530
A
187 case CPU_SUBTYPE_POWERPC_604:
188 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
189 PROCESSOR_PM_REGS_COUNT_POWERPC_604))
190 return(KERN_FAILURE);
191 else
192 {
193 perf_regs = (processor_pm_regs_t)cmd->cmd_pm_regs;
194 mtmmcr0(PERFMON_MMCR0(perf_regs) & MMCR0_SUPPORT_MASK);
195 return(KERN_SUCCESS);
196 }
197 case CPU_SUBTYPE_POWERPC_604e:
1c79356b
A
198 case CPU_SUBTYPE_POWERPC_750:
199 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
200 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
201 return(KERN_FAILURE);
202 else
203 {
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);
210 }
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);
216 else
217 {
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);
225 }
226 default:
227 return(KERN_FAILURE);
228 } /* cpu_subtype */
229 default:
230 return(KERN_FAILURE);
231 } /* switch cmd_op */
232}
233
234kern_return_t
235cpu_info_count(
236 processor_flavor_t flavor,
237 unsigned int *count)
238{
239 cpu_subtype_t cpu_subtype;
240
241 /*
242 * For now, we just assume that all CPUs are of the same type
243 */
244 cpu_subtype = machine_slot[0].cpu_subtype;
245 switch (flavor) {
246 case PROCESSOR_PM_REGS_INFO:
247 switch (cpu_subtype) {
de355530
A
248 case CPU_SUBTYPE_POWERPC_604:
249 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_604;
250 return(KERN_SUCCESS);
251
252 case CPU_SUBTYPE_POWERPC_604e:
1c79356b
A
253 case CPU_SUBTYPE_POWERPC_750:
254
255 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
256 return(KERN_SUCCESS);
257
258 case CPU_SUBTYPE_POWERPC_7400:
259 case CPU_SUBTYPE_POWERPC_7450:
260
261 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
262 return(KERN_SUCCESS);
263
264 default:
265 *count = 0;
266 return(KERN_INVALID_ARGUMENT);
267 } /* switch cpu_subtype */
268
269 case PROCESSOR_TEMPERATURE:
270 *count = PROCESSOR_TEMPERATURE_COUNT;
271 return (KERN_SUCCESS);
272
273 default:
274 *count = 0;
275 return(KERN_INVALID_ARGUMENT);
276
277 }
278}
279
280kern_return_t
281cpu_info(
282 processor_flavor_t flavor,
283 int slot_num,
284 processor_info_t info,
285 unsigned int *count)
286{
287 cpu_subtype_t cpu_subtype;
288 processor_pm_regs_t perf_regs;
289 boolean_t oldlevel;
290 unsigned int temp[2];
291
292 cpu_subtype = machine_slot[slot_num].cpu_subtype;
293
294 switch (flavor) {
295 case PROCESSOR_PM_REGS_INFO:
296
297 perf_regs = (processor_pm_regs_t) info;
298
299 switch (cpu_subtype) {
de355530
A
300 case CPU_SUBTYPE_POWERPC_604:
301
302 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_604)
303 return(KERN_FAILURE);
304
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 */
310
311 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_604;
312 return(KERN_SUCCESS);
313
314 case CPU_SUBTYPE_POWERPC_604e:
1c79356b
A
315 case CPU_SUBTYPE_POWERPC_750:
316
317 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_750)
318 return(KERN_FAILURE);
319
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 */
328
329 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
330 return(KERN_SUCCESS);
331
332 case CPU_SUBTYPE_POWERPC_7400:
333 case CPU_SUBTYPE_POWERPC_7450:
334
335 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_7400)
336 return(KERN_FAILURE);
337
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 */
347
348 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
349 return(KERN_SUCCESS);
350
351 default:
352 return(KERN_FAILURE);
353 } /* switch cpu_subtype */
354
355 case PROCESSOR_TEMPERATURE: /* Get the temperature of a processor */
356
357 disable_preemption(); /* Don't move me now */
358
359 if(slot_num == cpu_number()) { /* Is this for the local CPU? */
360 *info = ml_read_temp(); /* Get the temperature */
361 }
362 else { /* For another CPU */
363 temp[0] = -1; /* Set sync flag */
364 eieio();
365 sync();
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 */
370 }
371
372 enable_preemption(); /* Ok to move now */
373 return(KERN_SUCCESS);
374
375 default:
376 return(KERN_INVALID_ARGUMENT);
377
378 } /* flavor */
379}
380
381void
382cpu_init(
383 void)
384{
385 int cpu;
386
387 cpu = cpu_number();
388
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;
392
393}
394
395void
396cpu_machine_init(
397 void)
398{
0b4e3aa0
A
399 struct per_proc_info *tproc_info;
400 volatile struct per_proc_info *mproc_info;
1c79356b
A
401 int cpu;
402
403 /* TODO: realese mutex lock reset_handler_lock */
404
405 cpu = cpu_number();
0b4e3aa0
A
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))
411 continue;
1c79356b 412 cpu_sync_timebase();
0b4e3aa0 413 }
1c79356b 414 ml_init_interrupt();
0b4e3aa0 415 tproc_info->cpu_flags |= BootDone|SignalReady;
1c79356b
A
416}
417
418kern_return_t
419cpu_register(
420 int *target_cpu
421)
422{
423 int cpu;
424
425 /*
426 * TODO:
427 * - Run cpu_register() in exclusion mode
428 */
429
430 *target_cpu = -1;
431 for(cpu=0; cpu < wncpu; cpu++) {
432 if(!machine_slot[cpu].is_cpu) {
433 machine_slot[cpu].is_cpu = TRUE;
434 *target_cpu = cpu;
435 break;
436 }
437 }
438 if (*target_cpu != -1) {
439 real_ncpus++;
440 return KERN_SUCCESS;
441 } else
442 return KERN_FAILURE;
443}
444
445kern_return_t
446cpu_start(
447 int cpu)
448{
449 struct per_proc_info *proc_info;
450 kern_return_t ret;
451
de355530 452 extern void (*exception_handlers[])(void);
1c79356b
A
453 extern vm_offset_t intstack;
454 extern vm_offset_t debstack;
455
456 proc_info = &per_proc_info[cpu];
457
458 if (cpu == cpu_number()) {
459 PE_cpu_machine_init(proc_info->cpu_id, !(proc_info->cpu_flags & BootDone));
460 ml_init_interrupt();
0b4e3aa0 461 proc_info->cpu_flags |= BootDone|SignalReady;
1c79356b
A
462
463 return KERN_SUCCESS;
464 } else {
465 extern void _start_cpu(void);
466
467 proc_info->cpu_number = cpu;
468 proc_info->cpu_flags &= BootDone;
9bccf70c 469 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
470 proc_info->intstack_top_ss = proc_info->istackptr;
471#if MACH_KDP || MACH_KDB
9bccf70c 472 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
473 proc_info->debstack_top_ss = proc_info->debstackptr;
474#endif /* MACH_KDP || MACH_KDB */
0b4e3aa0 475 proc_info->interrupts_enabled = 0;
1c79356b 476 proc_info->active_kloaded = (unsigned int)&active_kloaded[cpu];
1c79356b
A
477 proc_info->active_stacks = (unsigned int)&active_stacks[cpu];
478 proc_info->need_ast = (unsigned int)&need_ast[cpu];
9bccf70c
A
479 proc_info->FPU_owner = 0;
480 proc_info->VMX_owner = 0;
de355530 481
1c79356b
A
482
483 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
484
485 /* TODO: get mutex lock reset_handler_lock */
486
487 resethandler_target.type = RESET_HANDLER_START;
de355530
A
488 resethandler_target.call_paddr = kvtophys((vm_offset_t)_start_cpu);
489 resethandler_target.arg__paddr = kvtophys((vm_offset_t)proc_info);
1c79356b
A
490
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);
497
498 }
499/*
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.
504 */
505
9bccf70c 506 ml_get_timebase((unsigned long long *)&proc_info->ruptStamp); /* Pass our current time to the other guy */
1c79356b
A
507
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);
512
513 if (ret != KERN_SUCCESS &&
514 proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
515
516 /* TODO: realese mutex lock reset_handler_lock */
517 }
518 return(ret);
519 }
520}
521
522/*
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.
527 */
528
529void
530cpu_signal_handler(
531 void)
532{
533
534 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
535 unsigned int *parmAddr;
536 struct per_proc_info *pproc; /* Area for my per_proc address */
537 int cpu;
538 struct SIGtimebase *timebaseAddr;
539 natural_t tbu, tbu2, tbl;
540
541 cpu = cpu_number(); /* Get the CPU number */
542 pproc = &per_proc_info[cpu]; /* Point to our block */
543
544/*
90556fb8 545 * Since we've been signaled, wait about 31 ms for the signal lock to pass
1c79356b 546 */
9bccf70c 547 if(!hw_lock_mbits(&pproc->MPsigpStat, (MPsigpMsgp | MPsigpAck), (MPsigpBusy | MPsigpPass),
90556fb8 548 (MPsigpBusy | MPsigpPass | MPsigpAck), (gPEClockFrequencyInfo.timebase_frequency_hz >> 5))) {
1c79356b
A
549 panic("cpu_signal_handler: Lock pass timed out\n");
550 }
551
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 */
556
557 __asm__ volatile("isync"); /* Make sure we don't unlock until memory is in */
558
9bccf70c 559 pproc->MPsigpStat = holdStat & ~(MPsigpMsgp | MPsigpAck | MPsigpFunc); /* Release lock */
1c79356b
A
560
561 switch ((holdStat & MPsigpFunc) >> 8) { /* Decode function code */
562
563 case MPsigpIdle: /* Was function cancelled? */
564 return; /* Yup... */
565
566 case MPsigpSigp: /* Signal Processor message? */
567
568 switch (holdParm0) { /* Decode SIGP message order */
569
570 case SIGPast: /* Should we do an AST? */
de355530 571 pproc->numSIGPast++; /* Count this one */
1c79356b
A
572#if 0
573 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
574#endif
9bccf70c 575 ast_check(cpu_to_processor(cpu));
1c79356b
A
576 return; /* All done... */
577
578 case SIGPcpureq: /* CPU specific function? */
579
de355530 580 pproc->numSIGPcpureq++; /* Count this one */
1c79356b
A
581 switch (holdParm1) { /* Select specific function */
582
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 */
589 return;
590
591 case CPRQtimebase:
592
593 timebaseAddr = (struct SIGtimebase *)holdParm2;
594
595 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
596 pproc->time_base_enable(pproc->cpu_id, FALSE);
597
0b4e3aa0 598 timebaseAddr->abstime = 0; /* Touch to force into cache */
1c79356b
A
599 sync();
600
601 do {
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);
606
0b4e3aa0 607 timebaseAddr->abstime = ((uint64_t)tbu << 32) | tbl;
1c79356b
A
608 sync(); /* Force order */
609
610 timebaseAddr->avail = TRUE;
611
612 while (*(volatile int *)&(syncClkSpot.ready) == FALSE);
613
614 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
615 pproc->time_base_enable(pproc->cpu_id, TRUE);
616
617 timebaseAddr->done = TRUE;
618
619 return;
620
621 default:
622 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1);
623 return;
624 }
625
626
627 case SIGPdebug: /* Enter the debugger? */
628
de355530 629 pproc->numSIGPdebug++; /* Count this one */
1c79356b
A
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... */
634
635 case SIGPwake: /* Wake up CPU */
de355530 636 pproc->numSIGPwake++; /* Count this one */
1c79356b
A
637 return; /* No need to do anything, the interrupt does it all... */
638
639 default:
640 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0);
641 return;
642
643 }
644
645 default:
646 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat & MPsigpFunc) >> 8);
647 return;
648
649 }
650 panic("cpu_signal_handler: we should never get here\n");
651}
652
653/*
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.
657 *
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
664 * recover.
665 */
666
667kern_return_t
668cpu_signal(
669 int target,
670 int signal,
671 unsigned int p1,
672 unsigned int p2)
673{
674
675 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
676 struct per_proc_info *tpproc, *mpproc; /* Area for per_proc addresses */
677 int cpu;
9bccf70c 678 int busybitset =0;
1c79356b
A
679
680#if DEBUG
681 if(target > NCPUS) panic("cpu_signal: invalid target CPU - %08X\n", target);
682#endif
683
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 */
687
688 mpproc = &per_proc_info[cpu]; /* Point to our block */
689 tpproc = &per_proc_info[target]; /* Point to the target's block */
0b4e3aa0
A
690
691 if (!(tpproc->cpu_flags & SignalReady)) return KERN_FAILURE;
9bccf70c 692
7b1edb79
A
693 if((tpproc->MPsigpStat & MPsigpMsgp) == MPsigpMsgp) { /* Is there an unreceived message already pending? */
694
9bccf70c 695 if(signal == SIGPwake) { /* SIGPwake can merge into all others... */
de355530 696 mpproc->numSIGPmwake++; /* Account for merged wakes */
9bccf70c
A
697 return KERN_SUCCESS;
698 }
7b1edb79
A
699
700 if((signal == SIGPast) && (tpproc->MPsigpParm0 == SIGPast)) { /* We can merge ASTs */
de355530 701 mpproc->numSIGPmast++; /* Account for merged ASTs */
7b1edb79
A
702 return KERN_SUCCESS; /* Don't bother to send this one... */
703 }
9bccf70c
A
704
705 if (tpproc->MPsigpParm0 == SIGPwake) {
706 if (hw_lock_mbits(&tpproc->MPsigpStat, (MPsigpMsgp | MPsigpAck),
707 (MPsigpBusy | MPsigpPass ), MPsigpBusy, 0)) {
708 busybitset = 1;
de355530 709 mpproc->numSIGPmwake++;
9bccf70c
A
710 }
711 }
7b1edb79
A
712 }
713
9bccf70c
A
714 if((busybitset == 0) &&
715 (!hw_lock_mbits(&tpproc->MPsigpStat, MPsigpMsgp, 0, MPsigpBusy,
90556fb8 716 (gPEClockFrequencyInfo.timebase_frequency_hz >> 11)))) { /* Try to lock the message block with a .5ms timeout */
de355530 717 mpproc->numSIGPtimo++; /* Account for timeouts */
1c79356b
A
718 return KERN_FAILURE; /* Timed out, take your ball and go home... */
719 }
720
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 */
725
726 __asm__ volatile("sync"); /* Make sure it's all there */
727
728 tpproc->MPsigpStat = holdStat; /* Set status and pass the lock */
729 __asm__ volatile("eieio"); /* I'm a paraniod freak */
730
9bccf70c
A
731 if (busybitset == 0)
732 PE_cpu_signal(mpproc->cpu_id, tpproc->cpu_id); /* Kick the other processor */
1c79356b
A
733
734 return KERN_SUCCESS; /* All is goodness and rainbows... */
735}
736
737void
738cpu_doshutdown(
739 void)
740{
741 processor_doshutdown(current_processor());
742}
743
744void
745cpu_sleep(
746 void)
747{
748 struct per_proc_info *proc_info;
749 unsigned int cpu;
9bccf70c 750 facility_context *fowner;
de355530 751 extern void (*exception_handlers[])(void);
1c79356b
A
752 extern vm_offset_t intstack;
753 extern vm_offset_t debstack;
754 extern void _restart_cpu(void);
755
756 cpu = cpu_number();
de355530
A
757#if 0
758 kprintf("******* About to sleep cpu %d\n", cpu);
759#endif
1c79356b
A
760
761 proc_info = &per_proc_info[cpu];
762
9bccf70c
A
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 */
765c9de3 766
9bccf70c
A
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 */
765c9de3 770
1c79356b
A
771 if (proc_info->cpu_number == 0) {
772 proc_info->cpu_flags &= BootDone;
9bccf70c 773 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
774 proc_info->intstack_top_ss = proc_info->istackptr;
775#if MACH_KDP || MACH_KDB
9bccf70c 776 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
1c79356b
A
777 proc_info->debstack_top_ss = proc_info->debstackptr;
778#endif /* MACH_KDP || MACH_KDB */
0b4e3aa0 779 proc_info->interrupts_enabled = 0;
1c79356b 780
765c9de3 781 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
1c79356b 782 extern void _start_cpu(void);
765c9de3 783
1c79356b 784 resethandler_target.type = RESET_HANDLER_START;
de355530
A
785 resethandler_target.call_paddr = kvtophys((vm_offset_t)_start_cpu);
786 resethandler_target.arg__paddr = kvtophys((vm_offset_t)proc_info);
765c9de3 787
1c79356b 788 ml_phys_write((vm_offset_t)&ResetHandler + 0,
765c9de3 789 resethandler_target.type);
1c79356b 790 ml_phys_write((vm_offset_t)&ResetHandler + 4,
765c9de3 791 resethandler_target.call_paddr);
1c79356b 792 ml_phys_write((vm_offset_t)&ResetHandler + 8,
765c9de3 793 resethandler_target.arg__paddr);
1c79356b
A
794
795 __asm__ volatile("sync");
796 __asm__ volatile("isync");
765c9de3 797 }
1c79356b
A
798 }
799
800 PE_cpu_machine_quiesce(proc_info->cpu_id);
801}
802
803void
804cpu_sync_timebase(
805 void)
806{
807 natural_t tbu, tbl;
808 boolean_t intr;
809
810 intr = ml_set_interrupts_enabled(FALSE); /* No interruptions in here */
811
812 /* Note that syncClkSpot is in a cache aligned area */
813 syncClkSpot.avail = FALSE;
814 syncClkSpot.ready = FALSE;
815 syncClkSpot.done = FALSE;
816
0b4e3aa0
A
817 while (cpu_signal(master_cpu, SIGPcpureq, CPRQtimebase,
818 (unsigned int)&syncClkSpot) != KERN_SUCCESS)
819 continue;
1c79356b 820
0b4e3aa0
A
821 while (*(volatile int *)&(syncClkSpot.avail) == FALSE)
822 continue;
1c79356b 823
1c79356b
A
824 isync();
825
826 /*
827 * We do the following to keep the compiler from generating extra stuff
828 * in tb set part
829 */
0b4e3aa0
A
830 tbu = syncClkSpot.abstime >> 32;
831 tbl = (uint32_t)syncClkSpot.abstime;
1c79356b
A
832
833 mttb(0);
834 mttbu(tbu);
835 mttb(tbl);
836
837 syncClkSpot.ready = TRUE;
838
0b4e3aa0
A
839 while (*(volatile int *)&(syncClkSpot.done) == FALSE)
840 continue;
1c79356b
A
841
842 (void)ml_set_interrupts_enabled(intr);
843}