]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/cpu.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / osfmk / ppc / cpu.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * File: ppc/cpu.c
24 *
25 * cpu specific routines
26 */
27
28 #include <kern/machine.h>
29 #include <kern/misc_protos.h>
30 #include <kern/thread.h>
31 #include <kern/processor.h>
32 #include <mach/machine.h>
33 #include <mach/processor_info.h>
34 #include <mach/mach_types.h>
35 #include <ppc/proc_reg.h>
36 #include <ppc/misc_protos.h>
37 #include <ppc/machine_routines.h>
38 #include <ppc/machine_cpu.h>
39 #include <ppc/exception.h>
40 #include <ppc/asm.h>
41 #include <ppc/hw_perfmon.h>
42 #include <pexpert/pexpert.h>
43 #include <kern/cpu_data.h>
44 #include <ppc/mappings.h>
45 #include <ppc/Diagnostics.h>
46 #include <ppc/trap.h>
47
48 /* TODO: BOGUS TO BE REMOVED */
49 int real_ncpus = 1;
50
51 int wncpu = NCPUS;
52 resethandler_t resethandler_target;
53
54 decl_simple_lock_data(static,SignalReadyLock);
55 static unsigned int SignalReadyWait = 0xFFFFFFFFU;
56
57 #define MMCR0_SUPPORT_MASK 0xf83f1fff
58 #define MMCR1_SUPPORT_MASK 0xffc00000
59 #define MMCR2_SUPPORT_MASK 0x80000000
60
61 extern int debugger_pending[NCPUS];
62 extern int debugger_is_slave[NCPUS];
63 extern int debugger_holdoff[NCPUS];
64 extern int debugger_sync;
65
66 struct SIGtimebase {
67 boolean_t avail;
68 boolean_t ready;
69 boolean_t done;
70 uint64_t abstime;
71 };
72
73 struct per_proc_info *pper_proc_info = per_proc_info;
74
75 extern struct SIGtimebase syncClkSpot;
76
77 void cpu_sync_timebase(void);
78
79 kern_return_t
80 cpu_control(
81 int slot_num,
82 processor_info_t info,
83 unsigned int count)
84 {
85 cpu_type_t cpu_type;
86 cpu_subtype_t cpu_subtype;
87 processor_pm_regs_t perf_regs;
88 processor_control_cmd_t cmd;
89 boolean_t oldlevel;
90
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;
94
95 if (count < PROCESSOR_CONTROL_CMD_COUNT)
96 return(KERN_FAILURE);
97
98 if ( cpu_type != cmd->cmd_cpu_type ||
99 cpu_subtype != cmd->cmd_cpu_subtype)
100 return(KERN_FAILURE);
101
102 if (perfmon_acquire_facility(current_task()) != KERN_SUCCESS) {
103 return(KERN_RESOURCE_SHORTAGE); /* cpu performance facility in use by another task */
104 }
105
106 switch (cmd->cmd_op)
107 {
108 case PROCESSOR_PM_CLR_PMC: /* Clear Performance Monitor Counters */
109 switch (cpu_subtype)
110 {
111 case CPU_SUBTYPE_POWERPC_750:
112 case CPU_SUBTYPE_POWERPC_7400:
113 case CPU_SUBTYPE_POWERPC_7450:
114 {
115 oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
116 mtpmc1(0x0);
117 mtpmc2(0x0);
118 mtpmc3(0x0);
119 mtpmc4(0x0);
120 ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
121 return(KERN_SUCCESS);
122 }
123 default:
124 return(KERN_FAILURE);
125 } /* cpu_subtype */
126 case PROCESSOR_PM_SET_REGS: /* Set Performance Monitor Registors */
127 switch (cpu_subtype)
128 {
129 case CPU_SUBTYPE_POWERPC_750:
130 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
131 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
132 return(KERN_FAILURE);
133 else
134 {
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);
145 }
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);
151 else
152 {
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);
164 }
165 default:
166 return(KERN_FAILURE);
167 } /* switch cpu_subtype */
168 case PROCESSOR_PM_SET_MMCR:
169 switch (cpu_subtype)
170 {
171 case CPU_SUBTYPE_POWERPC_750:
172 if (count < (PROCESSOR_CONTROL_CMD_COUNT +
173 PROCESSOR_PM_REGS_COUNT_POWERPC_750))
174 return(KERN_FAILURE);
175 else
176 {
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);
183 }
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);
189 else
190 {
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);
198 }
199 default:
200 return(KERN_FAILURE);
201 } /* cpu_subtype */
202 default:
203 return(KERN_FAILURE);
204 } /* switch cmd_op */
205 }
206
207 kern_return_t
208 cpu_info_count(
209 processor_flavor_t flavor,
210 unsigned int *count)
211 {
212 cpu_subtype_t cpu_subtype;
213
214 /*
215 * For now, we just assume that all CPUs are of the same type
216 */
217 cpu_subtype = machine_slot[0].cpu_subtype;
218 switch (flavor) {
219 case PROCESSOR_PM_REGS_INFO:
220 switch (cpu_subtype) {
221 case CPU_SUBTYPE_POWERPC_750:
222
223 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
224 return(KERN_SUCCESS);
225
226 case CPU_SUBTYPE_POWERPC_7400:
227 case CPU_SUBTYPE_POWERPC_7450:
228
229 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
230 return(KERN_SUCCESS);
231
232 default:
233 *count = 0;
234 return(KERN_INVALID_ARGUMENT);
235 } /* switch cpu_subtype */
236
237 case PROCESSOR_TEMPERATURE:
238 *count = PROCESSOR_TEMPERATURE_COUNT;
239 return (KERN_SUCCESS);
240
241 default:
242 *count = 0;
243 return(KERN_INVALID_ARGUMENT);
244
245 }
246 }
247
248 kern_return_t
249 cpu_info(
250 processor_flavor_t flavor,
251 int slot_num,
252 processor_info_t info,
253 unsigned int *count)
254 {
255 cpu_subtype_t cpu_subtype;
256 processor_pm_regs_t perf_regs;
257 boolean_t oldlevel;
258 unsigned int temp[2];
259
260 cpu_subtype = machine_slot[slot_num].cpu_subtype;
261
262 switch (flavor) {
263 case PROCESSOR_PM_REGS_INFO:
264
265 perf_regs = (processor_pm_regs_t) info;
266
267 switch (cpu_subtype) {
268 case CPU_SUBTYPE_POWERPC_750:
269
270 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_750)
271 return(KERN_FAILURE);
272
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 */
281
282 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
283 return(KERN_SUCCESS);
284
285 case CPU_SUBTYPE_POWERPC_7400:
286 case CPU_SUBTYPE_POWERPC_7450:
287
288 if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_7400)
289 return(KERN_FAILURE);
290
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 */
300
301 *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
302 return(KERN_SUCCESS);
303
304 default:
305 return(KERN_FAILURE);
306 } /* switch cpu_subtype */
307
308 case PROCESSOR_TEMPERATURE: /* Get the temperature of a processor */
309
310 disable_preemption(); /* Don't move me now */
311
312 if(slot_num == cpu_number()) { /* Is this for the local CPU? */
313 *info = ml_read_temp(); /* Get the temperature */
314 }
315 else { /* For another CPU */
316 temp[0] = -1; /* Set sync flag */
317 eieio();
318 sync();
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 */
323 }
324
325 enable_preemption(); /* Ok to move now */
326 return(KERN_SUCCESS);
327
328 default:
329 return(KERN_INVALID_ARGUMENT);
330
331 } /* flavor */
332 }
333
334 void
335 cpu_init(
336 void)
337 {
338 int cpu;
339
340 cpu = cpu_number();
341
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;
345
346 }
347
348 void
349 cpu_machine_init(
350 void)
351 {
352 struct per_proc_info *tproc_info;
353 volatile struct per_proc_info *mproc_info;
354 int cpu;
355
356 /* TODO: realese mutex lock reset_handler_lock */
357
358 cpu = cpu_number();
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))
364 continue;
365 cpu_sync_timebase();
366 }
367 ml_init_interrupt();
368 if (cpu != master_cpu)
369 simple_lock(&SignalReadyLock);
370 tproc_info->cpu_flags |= BootDone|SignalReady;
371 if (cpu != master_cpu) {
372 if (SignalReadyWait != 0) {
373 SignalReadyWait--;
374 thread_wakeup(&tproc_info->cpu_flags);
375 }
376 simple_unlock(&SignalReadyLock);
377 }
378 }
379
380 kern_return_t
381 cpu_register(
382 int *target_cpu
383 )
384 {
385 int cpu;
386
387 /*
388 * TODO:
389 * - Run cpu_register() in exclusion mode
390 */
391
392 *target_cpu = -1;
393 for(cpu=0; cpu < wncpu; cpu++) {
394 if(!machine_slot[cpu].is_cpu) {
395 machine_slot[cpu].is_cpu = TRUE;
396 *target_cpu = cpu;
397 break;
398 }
399 }
400 if (*target_cpu != -1) {
401 real_ncpus++;
402 return KERN_SUCCESS;
403 } else
404 return KERN_FAILURE;
405 }
406
407 kern_return_t
408 cpu_start(
409 int cpu)
410 {
411 struct per_proc_info *proc_info;
412 kern_return_t ret;
413 mapping *mp;
414
415 extern vm_offset_t intstack;
416 extern vm_offset_t debstack;
417
418 proc_info = &per_proc_info[cpu];
419
420 if (cpu == cpu_number()) {
421 PE_cpu_machine_init(proc_info->cpu_id, !(proc_info->cpu_flags & BootDone));
422 ml_init_interrupt();
423 proc_info->cpu_flags |= BootDone|SignalReady;
424
425 return KERN_SUCCESS;
426 } else {
427 extern void _start_cpu(void);
428
429 if (SignalReadyWait == 0xFFFFFFFFU) {
430 SignalReadyWait = 0;
431 simple_lock_init(&SignalReadyLock,0);
432 }
433
434 proc_info->cpu_number = cpu;
435 proc_info->cpu_flags &= BootDone;
436 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
437 proc_info->intstack_top_ss = proc_info->istackptr;
438 #if MACH_KDP || MACH_KDB
439 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
440 proc_info->debstack_top_ss = proc_info->debstackptr;
441 #endif /* MACH_KDP || MACH_KDB */
442 proc_info->interrupts_enabled = 0;
443 proc_info->need_ast = (unsigned int)&need_ast[cpu];
444 proc_info->FPU_owner = 0;
445 proc_info->VMX_owner = 0;
446 proc_info->rtcPop = 0xFFFFFFFFFFFFFFFFULL;
447 mp = (mapping *)(&proc_info->ppCIOmp);
448 mp->mpFlags = 0x01000000 | mpSpecial | 1;
449 mp->mpSpace = invalSpace;
450
451 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
452
453 /* TODO: get mutex lock reset_handler_lock */
454
455 resethandler_target.type = RESET_HANDLER_START;
456 resethandler_target.call_paddr = (vm_offset_t)_start_cpu; /* Note: these routines are always V=R */
457 resethandler_target.arg__paddr = (vm_offset_t)proc_info; /* Note: these routines are always V=R */
458
459 ml_phys_write((vm_offset_t)&ResetHandler + 0,
460 resethandler_target.type);
461 ml_phys_write((vm_offset_t)&ResetHandler + 4,
462 resethandler_target.call_paddr);
463 ml_phys_write((vm_offset_t)&ResetHandler + 8,
464 resethandler_target.arg__paddr);
465
466 }
467 /*
468 * Note: we pass the current time to the other processor here. He will load it
469 * as early as possible so that there is a chance that it is close to accurate.
470 * After the machine is up a while, we will officially resync the clocks so
471 * that all processors are the same. This is just to get close.
472 */
473
474 ml_get_timebase((unsigned long long *)&proc_info->ruptStamp); /* Pass our current time to the other guy */
475
476 __asm__ volatile("sync"); /* Commit to storage */
477 __asm__ volatile("isync"); /* Wait a second */
478 ret = PE_cpu_start(proc_info->cpu_id,
479 proc_info->start_paddr, (vm_offset_t)proc_info);
480
481 if (ret != KERN_SUCCESS &&
482 proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
483
484 /* TODO: realese mutex lock reset_handler_lock */
485 } else {
486 simple_lock(&SignalReadyLock);
487
488 while (!((*(volatile short *)&per_proc_info[cpu].cpu_flags) & SignalReady)) {
489 SignalReadyWait++;
490 thread_sleep_simple_lock((event_t)&per_proc_info[cpu].cpu_flags,
491 &SignalReadyLock, THREAD_UNINT);
492 }
493 simple_unlock(&SignalReadyLock);
494 }
495 return(ret);
496 }
497 }
498
499 void
500 cpu_exit_wait(
501 int cpu)
502 {
503 if ( cpu != master_cpu)
504 while (!((*(volatile short *)&per_proc_info[cpu].cpu_flags) & SleepState)) {};
505 }
506
507 perfTrap perfCpuSigHook = 0; /* Pointer to CHUD cpu signal hook routine */
508
509 /*
510 * Here is where we implement the receiver of the signaling protocol.
511 * We wait for the signal status area to be passed to us. Then we snarf
512 * up the status, the sender, and the 3 potential parms. Next we release
513 * the lock and signal the other guy.
514 */
515
516 void
517 cpu_signal_handler(
518 void)
519 {
520
521 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
522 unsigned int *parmAddr;
523 struct per_proc_info *pproc; /* Area for my per_proc address */
524 int cpu;
525 struct SIGtimebase *timebaseAddr;
526 natural_t tbu, tbu2, tbl;
527 broadcastFunc xfunc;
528 cpu = cpu_number(); /* Get the CPU number */
529 pproc = &per_proc_info[cpu]; /* Point to our block */
530
531 /*
532 * Since we've been signaled, wait about 31 ms for the signal lock to pass
533 */
534 if(!hw_lock_mbits(&pproc->MPsigpStat, (MPsigpMsgp | MPsigpAck), (MPsigpBusy | MPsigpPass),
535 (MPsigpBusy | MPsigpPass | MPsigpAck), (gPEClockFrequencyInfo.timebase_frequency_hz >> 5))) {
536 panic("cpu_signal_handler: Lock pass timed out\n");
537 }
538
539 holdStat = pproc->MPsigpStat; /* Snarf stat word */
540 holdParm0 = pproc->MPsigpParm0; /* Snarf parameter */
541 holdParm1 = pproc->MPsigpParm1; /* Snarf parameter */
542 holdParm2 = pproc->MPsigpParm2; /* Snarf parameter */
543
544 __asm__ volatile("isync"); /* Make sure we don't unlock until memory is in */
545
546 pproc->MPsigpStat = holdStat & ~(MPsigpMsgp | MPsigpAck | MPsigpFunc); /* Release lock */
547
548 switch ((holdStat & MPsigpFunc) >> 8) { /* Decode function code */
549
550 case MPsigpIdle: /* Was function cancelled? */
551 return; /* Yup... */
552
553 case MPsigpSigp: /* Signal Processor message? */
554
555 switch (holdParm0) { /* Decode SIGP message order */
556
557 case SIGPast: /* Should we do an AST? */
558 pproc->hwCtr.numSIGPast++; /* Count this one */
559 #if 0
560 kprintf("cpu_signal_handler: AST check on cpu %x\n", cpu_number());
561 #endif
562 ast_check(cpu_to_processor(cpu));
563 return; /* All done... */
564
565 case SIGPcpureq: /* CPU specific function? */
566
567 pproc->hwCtr.numSIGPcpureq++; /* Count this one */
568 switch (holdParm1) { /* Select specific function */
569
570 case CPRQtemp: /* Get the temperature */
571 parmAddr = (unsigned int *)holdParm2; /* Get the destination address */
572 parmAddr[1] = ml_read_temp(); /* Get the core temperature */
573 eieio(); /* Force order */
574 sync(); /* Force to memory */
575 parmAddr[0] = 0; /* Show we're done */
576 return;
577
578 case CPRQtimebase:
579
580 timebaseAddr = (struct SIGtimebase *)holdParm2;
581
582 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
583 pproc->time_base_enable(pproc->cpu_id, FALSE);
584
585 timebaseAddr->abstime = 0; /* Touch to force into cache */
586 sync();
587
588 do {
589 asm volatile(" mftbu %0" : "=r" (tbu));
590 asm volatile(" mftb %0" : "=r" (tbl));
591 asm volatile(" mftbu %0" : "=r" (tbu2));
592 } while (tbu != tbu2);
593
594 timebaseAddr->abstime = ((uint64_t)tbu << 32) | tbl;
595 sync(); /* Force order */
596
597 timebaseAddr->avail = TRUE;
598
599 while (*(volatile int *)&(syncClkSpot.ready) == FALSE);
600
601 if(pproc->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
602 pproc->time_base_enable(pproc->cpu_id, TRUE);
603
604 timebaseAddr->done = TRUE;
605
606 return;
607
608 case CPRQsegload:
609 return;
610
611 case CPRQchud:
612 parmAddr = (unsigned int *)holdParm2; /* Get the destination address */
613 if(perfCpuSigHook) {
614 struct savearea *ssp = current_act()->mact.pcb;
615 if(ssp) {
616 (perfCpuSigHook)(parmAddr[1] /* request */, ssp, 0, 0);
617 }
618 }
619 parmAddr[1] = 0;
620 parmAddr[0] = 0; /* Show we're done */
621 return;
622
623 case CPRQscom:
624 if(((scomcomm *)holdParm2)->scomfunc) { /* Are we writing */
625 ((scomcomm *)holdParm2)->scomstat = ml_scom_write(((scomcomm *)holdParm2)->scomreg, ((scomcomm *)holdParm2)->scomdata); /* Write scom */
626 }
627 else { /* No, reading... */
628 ((scomcomm *)holdParm2)->scomstat = ml_scom_read(((scomcomm *)holdParm2)->scomreg, &((scomcomm *)holdParm2)->scomdata); /* Read scom */
629 }
630 return;
631
632 case CPRQsps:
633 {
634 extern void ml_set_processor_speed_slave(unsigned long speed);
635
636 ml_set_processor_speed_slave(holdParm2);
637 return;
638 }
639
640 default:
641 panic("cpu_signal_handler: unknown CPU request - %08X\n", holdParm1);
642 return;
643 }
644
645
646 case SIGPdebug: /* Enter the debugger? */
647
648 pproc->hwCtr.numSIGPdebug++; /* Count this one */
649 debugger_is_slave[cpu]++; /* Bump up the count to show we're here */
650 hw_atomic_sub(&debugger_sync, 1); /* Show we've received the 'rupt */
651 __asm__ volatile("tw 4,r3,r3"); /* Enter the debugger */
652 return; /* All done now... */
653
654 case SIGPwake: /* Wake up CPU */
655 pproc->hwCtr.numSIGPwake++; /* Count this one */
656 return; /* No need to do anything, the interrupt does it all... */
657
658 case SIGPcall: /* Call function on CPU */
659 pproc->hwCtr.numSIGPcall++; /* Count this one */
660 xfunc = holdParm1; /* Do this since I can't seem to figure C out */
661 xfunc(holdParm2); /* Call the passed function */
662 return; /* Done... */
663
664 default:
665 panic("cpu_signal_handler: unknown SIGP message order - %08X\n", holdParm0);
666 return;
667
668 }
669
670 default:
671 panic("cpu_signal_handler: unknown SIGP function - %08X\n", (holdStat & MPsigpFunc) >> 8);
672 return;
673
674 }
675 panic("cpu_signal_handler: we should never get here\n");
676 }
677
678 /*
679 * Here is where we send a message to another processor. So far we only have two:
680 * SIGPast and SIGPdebug. SIGPast is used to preempt and kick off threads (this is
681 * currently disabled). SIGPdebug is used to enter the debugger.
682 *
683 * We set up the SIGP function to indicate that this is a simple message and set the
684 * order code (MPsigpParm0) to SIGPast or SIGPdebug). After finding the per_processor
685 * block for the target, we lock the message block. Then we set the parameter(s).
686 * Next we change the lock (also called "busy") to "passing" and finally signal
687 * the other processor. Note that we only wait about 1ms to get the message lock.
688 * If we time out, we return failure to our caller. It is their responsibility to
689 * recover.
690 */
691
692 kern_return_t
693 cpu_signal(
694 int target,
695 int signal,
696 unsigned int p1,
697 unsigned int p2)
698 {
699
700 unsigned int holdStat, holdParm0, holdParm1, holdParm2, mtype;
701 struct per_proc_info *tpproc, *mpproc; /* Area for per_proc addresses */
702 int cpu;
703 int busybitset =0;
704
705 #if DEBUG
706 if(target > NCPUS) panic("cpu_signal: invalid target CPU - %08X\n", target);
707 #endif
708
709 cpu = cpu_number(); /* Get our CPU number */
710 if(target == cpu) return KERN_FAILURE; /* Don't play with ourselves */
711 if(!machine_slot[target].running) return KERN_FAILURE; /* These guys are too young */
712
713 mpproc = &per_proc_info[cpu]; /* Point to our block */
714 tpproc = &per_proc_info[target]; /* Point to the target's block */
715
716 if (!(tpproc->cpu_flags & SignalReady)) return KERN_FAILURE;
717
718 if((tpproc->MPsigpStat & MPsigpMsgp) == MPsigpMsgp) { /* Is there an unreceived message already pending? */
719
720 if(signal == SIGPwake) { /* SIGPwake can merge into all others... */
721 mpproc->hwCtr.numSIGPmwake++; /* Account for merged wakes */
722 return KERN_SUCCESS;
723 }
724
725 if((signal == SIGPast) && (tpproc->MPsigpParm0 == SIGPast)) { /* We can merge ASTs */
726 mpproc->hwCtr.numSIGPmast++; /* Account for merged ASTs */
727 return KERN_SUCCESS; /* Don't bother to send this one... */
728 }
729
730 if (tpproc->MPsigpParm0 == SIGPwake) {
731 if (hw_lock_mbits(&tpproc->MPsigpStat, (MPsigpMsgp | MPsigpAck),
732 (MPsigpBusy | MPsigpPass ), MPsigpBusy, 0)) {
733 busybitset = 1;
734 mpproc->hwCtr.numSIGPmwake++;
735 }
736 }
737 }
738
739 if((busybitset == 0) &&
740 (!hw_lock_mbits(&tpproc->MPsigpStat, MPsigpMsgp, 0, MPsigpBusy,
741 (gPEClockFrequencyInfo.timebase_frequency_hz >> 11)))) { /* Try to lock the message block with a .5ms timeout */
742 mpproc->hwCtr.numSIGPtimo++; /* Account for timeouts */
743 return KERN_FAILURE; /* Timed out, take your ball and go home... */
744 }
745
746 holdStat = MPsigpBusy | MPsigpPass | (MPsigpSigp << 8) | cpu; /* Set up the signal status word */
747 tpproc->MPsigpParm0 = signal; /* Set message order */
748 tpproc->MPsigpParm1 = p1; /* Set additional parm */
749 tpproc->MPsigpParm2 = p2; /* Set additional parm */
750
751 __asm__ volatile("sync"); /* Make sure it's all there */
752
753 tpproc->MPsigpStat = holdStat; /* Set status and pass the lock */
754 __asm__ volatile("eieio"); /* I'm a paraniod freak */
755
756 if (busybitset == 0)
757 PE_cpu_signal(mpproc->cpu_id, tpproc->cpu_id); /* Kick the other processor */
758
759 return KERN_SUCCESS; /* All is goodness and rainbows... */
760 }
761
762 void
763 cpu_doshutdown(
764 void)
765 {
766 enable_preemption();
767 processor_offline(current_processor());
768 }
769
770 void
771 cpu_sleep(
772 void)
773 {
774 struct per_proc_info *proc_info;
775 unsigned int cpu, i;
776 unsigned int wait_ncpus_sleep, ncpus_sleep;
777 facility_context *fowner;
778 extern vm_offset_t intstack;
779 extern vm_offset_t debstack;
780 extern void _restart_cpu(void);
781
782 cpu = cpu_number();
783
784 proc_info = &per_proc_info[cpu];
785
786 fowner = proc_info->FPU_owner; /* Cache this */
787 if(fowner) fpu_save(fowner); /* If anyone owns FPU, save it */
788 proc_info->FPU_owner = 0; /* Set no fpu owner now */
789
790 fowner = proc_info->VMX_owner; /* Cache this */
791 if(fowner) vec_save(fowner); /* If anyone owns vectors, save it */
792 proc_info->VMX_owner = 0; /* Set no vector owner now */
793
794 if (proc_info->cpu_number == 0) {
795 proc_info->cpu_flags &= BootDone;
796 proc_info->istackptr = (vm_offset_t)&intstack + (INTSTACK_SIZE*(cpu+1)) - FM_SIZE;
797 proc_info->intstack_top_ss = proc_info->istackptr;
798 #if MACH_KDP || MACH_KDB
799 proc_info->debstackptr = (vm_offset_t)&debstack + (KERNEL_STACK_SIZE*(cpu+1)) - FM_SIZE;
800 proc_info->debstack_top_ss = proc_info->debstackptr;
801 #endif /* MACH_KDP || MACH_KDB */
802 proc_info->interrupts_enabled = 0;
803
804 if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) {
805 extern void _start_cpu(void);
806
807 resethandler_target.type = RESET_HANDLER_START;
808 resethandler_target.call_paddr = (vm_offset_t)_start_cpu; /* Note: these routines are always V=R */
809 resethandler_target.arg__paddr = (vm_offset_t)proc_info; /* Note: these routines are always V=R */
810
811 ml_phys_write((vm_offset_t)&ResetHandler + 0,
812 resethandler_target.type);
813 ml_phys_write((vm_offset_t)&ResetHandler + 4,
814 resethandler_target.call_paddr);
815 ml_phys_write((vm_offset_t)&ResetHandler + 8,
816 resethandler_target.arg__paddr);
817
818 __asm__ volatile("sync");
819 __asm__ volatile("isync");
820 }
821
822 wait_ncpus_sleep = real_ncpus-1;
823 ncpus_sleep = 0;
824 while (wait_ncpus_sleep != ncpus_sleep) {
825 ncpus_sleep = 0;
826 for(i=1; i < real_ncpus ; i++) {
827 if ((*(volatile short *)&per_proc_info[i].cpu_flags) & SleepState)
828 ncpus_sleep++;
829 }
830 }
831 }
832
833 PE_cpu_machine_quiesce(proc_info->cpu_id);
834 }
835
836 void
837 cpu_sync_timebase(
838 void)
839 {
840 natural_t tbu, tbl;
841 boolean_t intr;
842
843 intr = ml_set_interrupts_enabled(FALSE); /* No interruptions in here */
844
845 /* Note that syncClkSpot is in a cache aligned area */
846 syncClkSpot.avail = FALSE;
847 syncClkSpot.ready = FALSE;
848 syncClkSpot.done = FALSE;
849
850 while (cpu_signal(master_cpu, SIGPcpureq, CPRQtimebase,
851 (unsigned int)&syncClkSpot) != KERN_SUCCESS)
852 continue;
853
854 while (*(volatile int *)&(syncClkSpot.avail) == FALSE)
855 continue;
856
857 isync();
858
859 /*
860 * We do the following to keep the compiler from generating extra stuff
861 * in tb set part
862 */
863 tbu = syncClkSpot.abstime >> 32;
864 tbl = (uint32_t)syncClkSpot.abstime;
865
866 mttb(0);
867 mttbu(tbu);
868 mttb(tbl);
869
870 syncClkSpot.ready = TRUE;
871
872 while (*(volatile int *)&(syncClkSpot.done) == FALSE)
873 continue;
874
875 (void)ml_set_interrupts_enabled(intr);
876 }
877
878 /*
879 * Call a function on all running processors
880 *
881 * Note that the synch paramter is used to wait until all functions are complete.
882 * It is not passed to the other processor and must be known by the called function.
883 * The called function must do a thread_wakeup on the synch if it decrements the
884 * synch count to 0.
885 */
886
887
888 int32_t cpu_broadcast(uint32_t *synch, broadcastFunc func, uint32_t parm) {
889
890 int sigproc, cpu, ocpu;
891
892 cpu = cpu_number(); /* Who are we? */
893 sigproc = 0; /* Clear called processor count */
894
895 if(real_ncpus > 1) { /* Are we just a uni? */
896
897 assert_wait((event_t)synch, THREAD_UNINT); /* If more than one processor, we may have to wait */
898
899 for(ocpu = 0; ocpu < real_ncpus; ocpu++) { /* Tell everyone to call */
900 if(ocpu == cpu) continue; /* If we talk to ourselves, people will wonder... */
901 hw_atomic_add(synch, 1); /* Tentatively bump synchronizer */
902 sigproc++; /* Tentatively bump signal sent count */
903 if(KERN_SUCCESS != cpu_signal(ocpu, SIGPcall, (uint32_t)func, parm)) { /* Call the function on the other processor */
904 hw_atomic_sub(synch, 1); /* Other guy isn't really there, ignore it */
905 sigproc--; /* and don't count it */
906 }
907 }
908
909 if(!sigproc) clear_wait(current_thread(), THREAD_AWAKENED); /* Clear wait if we never signalled */
910 else thread_block(THREAD_CONTINUE_NULL); /* Wait for everyone to get into step... */
911 }
912
913 return sigproc; /* Return the number of guys actually signalled */
914
915 }