]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/pmCPU.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / osfmk / i386 / pmCPU.c
CommitLineData
0c530ab8 1/*
7ddcb079 2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
0c530ab8 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0c530ab8 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0c530ab8 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
0c530ab8
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0c530ab8 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0c530ab8
A
27 */
28
29/*
30 * CPU-specific power management support.
31 *
32 * Implements the "wrappers" to the KEXT.
33 */
0c530ab8 34#include <i386/asm.h>
b0d623f7 35#include <i386/machine_cpu.h>
0c530ab8 36#include <i386/mp.h>
b0d623f7 37#include <i386/machine_routines.h>
0c530ab8 38#include <i386/proc_reg.h>
b0d623f7
A
39#include <i386/pmap.h>
40#include <i386/misc_protos.h>
41#include <kern/machine.h>
0c530ab8
A
42#include <kern/pms.h>
43#include <kern/processor.h>
39236c6e 44#include <kern/timer_queue.h>
2d21ac55 45#include <i386/cpu_threads.h>
0c530ab8
A
46#include <i386/pmCPU.h>
47#include <i386/cpuid.h>
6d2010ae 48#include <i386/rtclock_protos.h>
593a1d5f 49#include <kern/sched_prim.h>
b0d623f7 50#include <i386/lapic.h>
6d2010ae 51#include <i386/pal_routines.h>
6d2010ae 52#include <sys/kdebug.h>
39236c6e 53#include <i386/tsc.h>
593a1d5f 54
0c530ab8
A
55extern int disableConsoleOutput;
56
7ddcb079 57#define DELAY_UNSET 0xFFFFFFFFFFFFFFFFULL
0c530ab8 58
bd504ef0
A
59uint64_t cpu_itime_bins[CPU_ITIME_BINS] = {16* NSEC_PER_USEC, 32* NSEC_PER_USEC, 64* NSEC_PER_USEC, 128* NSEC_PER_USEC, 256* NSEC_PER_USEC, 512* NSEC_PER_USEC, 1024* NSEC_PER_USEC, 2048* NSEC_PER_USEC, 4096* NSEC_PER_USEC, 8192* NSEC_PER_USEC, 16384* NSEC_PER_USEC, 32768* NSEC_PER_USEC};
60uint64_t *cpu_rtime_bins = &cpu_itime_bins[0];
61
0c530ab8
A
62/*
63 * The following is set when the KEXT loads and initializes.
64 */
6d2010ae 65pmDispatch_t *pmDispatch = NULL;
0c530ab8 66
bd504ef0 67uint32_t pmInitDone = 0;
7ddcb079
A
68static boolean_t earlyTopology = FALSE;
69static uint64_t earlyMaxBusDelay = DELAY_UNSET;
70static uint64_t earlyMaxIntDelay = DELAY_UNSET;
2d21ac55 71
0c530ab8
A
72/*
73 * Initialize the Cstate change code.
74 */
75void
76power_management_init(void)
77{
0c530ab8
A
78 if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
79 (*pmDispatch->cstateInit)();
80}
81
bd504ef0
A
82static inline void machine_classify_interval(uint64_t interval, uint64_t *bins, uint64_t *binvals, uint32_t nbins) {
83 uint32_t i;
84 for (i = 0; i < nbins; i++) {
85 if (interval < binvals[i]) {
86 bins[i]++;
87 break;
88 }
89 }
90}
4b17d6b6 91
39236c6e
A
92uint64_t idle_pending_timers_processed;
93uint32_t idle_entry_timer_processing_hdeadline_threshold = 5000000;
94
0c530ab8 95/*
593a1d5f
A
96 * Called when the CPU is idle. It calls into the power management kext
97 * to determine the best way to idle the CPU.
0c530ab8 98 */
593a1d5f
A
99void
100machine_idle(void)
0c530ab8 101{
bd504ef0 102 cpu_data_t *my_cpu = current_cpu_datap();
39236c6e 103 __unused uint32_t cnum = my_cpu->cpu_number;
bd504ef0 104 uint64_t ctime, rtime, itime;
39236c6e
A
105#if CST_DEMOTION_DEBUG
106 processor_t cproc = my_cpu->cpu_processor;
107 uint64_t cwakeups = PROCESSOR_DATA(cproc, wakeups_issued_total);
108#endif /* CST_DEMOTION_DEBUG */
109 uint64_t esdeadline, ehdeadline;
110 boolean_t do_process_pending_timers = FALSE;
0c530ab8 111
4b17d6b6 112 ctime = mach_absolute_time();
39236c6e
A
113 esdeadline = my_cpu->rtclock_timer.queue.earliest_soft_deadline;
114 ehdeadline = my_cpu->rtclock_timer.deadline;
115/* Determine if pending timers exist */
116 if ((ctime >= esdeadline) && (ctime < ehdeadline) &&
117 ((ehdeadline - ctime) < idle_entry_timer_processing_hdeadline_threshold)) {
118 idle_pending_timers_processed++;
119 do_process_pending_timers = TRUE;
120 goto machine_idle_exit;
121 } else {
122 TCOAL_DEBUG(0xCCCC0000, ctime, my_cpu->rtclock_timer.queue.earliest_soft_deadline, my_cpu->rtclock_timer.deadline, idle_pending_timers_processed, 0);
123 }
124
bd504ef0
A
125 my_cpu->lcpu.state = LCPU_IDLE;
126 DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
39236c6e 127 MARK_CPU_IDLE(cnum);
0c530ab8 128
4b17d6b6
A
129 rtime = ctime - my_cpu->cpu_ixtime;
130
131 my_cpu->cpu_rtime_total += rtime;
bd504ef0 132 machine_classify_interval(rtime, &my_cpu->cpu_rtimes[0], &cpu_rtime_bins[0], CPU_RTIME_BINS);
39236c6e
A
133#if CST_DEMOTION_DEBUG
134 uint32_t cl = 0, ch = 0;
135 uint64_t c3res, c6res, c7res;
136 rdmsr_carefully(MSR_IA32_CORE_C3_RESIDENCY, &cl, &ch);
137 c3res = ((uint64_t)ch << 32) | cl;
138 rdmsr_carefully(MSR_IA32_CORE_C6_RESIDENCY, &cl, &ch);
139 c6res = ((uint64_t)ch << 32) | cl;
140 rdmsr_carefully(MSR_IA32_CORE_C7_RESIDENCY, &cl, &ch);
141 c7res = ((uint64_t)ch << 32) | cl;
142#endif
bd504ef0
A
143
144 if (pmInitDone) {
145 /*
146 * Handle case where ml_set_maxbusdelay() or ml_set_maxintdelay()
147 * were called prior to the CPU PM kext being registered. We do
148 * this here since we know at this point the values will be first
149 * used since idle is where the decisions using these values is made.
150 */
151 if (earlyMaxBusDelay != DELAY_UNSET)
152 ml_set_maxbusdelay((uint32_t)(earlyMaxBusDelay & 0xFFFFFFFF));
bd504ef0
A
153 if (earlyMaxIntDelay != DELAY_UNSET)
154 ml_set_maxintdelay(earlyMaxIntDelay);
155 }
4b17d6b6 156
bd504ef0
A
157 if (pmInitDone
158 && pmDispatch != NULL
159 && pmDispatch->MachineIdle != NULL)
160 (*pmDispatch->MachineIdle)(0x7FFFFFFFFFFFFFFFULL);
161 else {
162 /*
163 * If no power management, re-enable interrupts and halt.
164 * This will keep the CPU from spinning through the scheduler
165 * and will allow at least some minimal power savings (but it
166 * cause problems in some MP configurations w.r.t. the APIC
167 * stopping during a GV3 transition).
168 */
169 pal_hlt();
bd504ef0
A
170 /* Once woken, re-disable interrupts. */
171 pal_cli();
172 }
4b17d6b6 173
7ddcb079 174 /*
bd504ef0 175 * Mark the CPU as running again.
7ddcb079 176 */
39236c6e
A
177 MARK_CPU_ACTIVE(cnum);
178 DBGLOG(cpu_handle, cnum, MP_UNIDLE);
179 my_cpu->lcpu.state = LCPU_RUN;
4b17d6b6 180 uint64_t ixtime = my_cpu->cpu_ixtime = mach_absolute_time();
bd504ef0 181 itime = ixtime - ctime;
39236c6e
A
182 my_cpu->cpu_idle_exits++;
183 my_cpu->cpu_itime_total += itime;
184 machine_classify_interval(itime, &my_cpu->cpu_itimes[0], &cpu_itime_bins[0], CPU_ITIME_BINS);
185#if CST_DEMOTION_DEBUG
186 cl = ch = 0;
187 rdmsr_carefully(MSR_IA32_CORE_C3_RESIDENCY, &cl, &ch);
188 c3res = (((uint64_t)ch << 32) | cl) - c3res;
189 rdmsr_carefully(MSR_IA32_CORE_C6_RESIDENCY, &cl, &ch);
190 c6res = (((uint64_t)ch << 32) | cl) - c6res;
191 rdmsr_carefully(MSR_IA32_CORE_C7_RESIDENCY, &cl, &ch);
192 c7res = (((uint64_t)ch << 32) | cl) - c7res;
193
194 uint64_t ndelta = itime - tmrCvt(c3res + c6res + c7res, tscFCvtt2n);
195 KERNEL_DEBUG_CONSTANT(0xcead0000, ndelta, itime, c7res, c6res, c3res);
196 if ((itime > 1000000) && (ndelta > 250000))
197 KERNEL_DEBUG_CONSTANT(0xceae0000, ndelta, itime, c7res, c6res, c3res);
198#endif
593a1d5f 199
39236c6e 200 machine_idle_exit:
bd504ef0
A
201 /*
202 * Re-enable interrupts.
203 */
39236c6e 204
bd504ef0 205 pal_sti();
39236c6e
A
206
207 if (do_process_pending_timers) {
208 TCOAL_DEBUG(0xBBBB0000 | DBG_FUNC_START, ctime, esdeadline, ehdeadline, idle_pending_timers_processed, 0);
209
210 /* Adjust to reflect that this isn't truly a package idle exit */
211 __sync_fetch_and_sub(&my_cpu->lcpu.package->num_idle, 1);
212 lapic_timer_swi(); /* Trigger software timer interrupt */
213 __sync_fetch_and_add(&my_cpu->lcpu.package->num_idle, 1);
214
215 TCOAL_DEBUG(0xBBBB0000 | DBG_FUNC_END, ctime, esdeadline, idle_pending_timers_processed, 0, 0);
216 }
217#if CST_DEMOTION_DEBUG
218 uint64_t nwakeups = PROCESSOR_DATA(cproc, wakeups_issued_total);
219
220 if ((nwakeups == cwakeups) && (topoParms.nLThreadsPerPackage == my_cpu->lcpu.package->num_idle)) {
221 KERNEL_DEBUG_CONSTANT(0xceaa0000, cwakeups, 0, 0, 0, 0);
222 }
223#endif
2d21ac55
A
224}
225
226/*
227 * Called when the CPU is to be halted. It will choose the best C-State
228 * to be in.
229 */
230void
231pmCPUHalt(uint32_t reason)
232{
593a1d5f 233 cpu_data_t *cpup = current_cpu_datap();
2d21ac55
A
234
235 switch (reason) {
236 case PM_HALT_DEBUG:
593a1d5f 237 cpup->lcpu.state = LCPU_PAUSE;
6d2010ae 238 pal_stop_cpu(FALSE);
2d21ac55
A
239 break;
240
241 case PM_HALT_PANIC:
593a1d5f 242 cpup->lcpu.state = LCPU_PAUSE;
6d2010ae 243 pal_stop_cpu(TRUE);
2d21ac55
A
244 break;
245
246 case PM_HALT_NORMAL:
bd504ef0 247 case PM_HALT_SLEEP:
2d21ac55 248 default:
6d2010ae 249 pal_cli();
2d21ac55 250
6d2010ae 251 if (pmInitDone
2d21ac55
A
252 && pmDispatch != NULL
253 && pmDispatch->pmCPUHalt != NULL) {
593a1d5f
A
254 /*
255 * Halt the CPU (and put it in a low power state.
256 */
2d21ac55 257 (*pmDispatch->pmCPUHalt)();
2d21ac55 258
593a1d5f 259 /*
bd504ef0
A
260 * We've exited halt, so get the CPU schedulable again.
261 * - by calling the fast init routine for a slave, or
262 * - by returning if we're the master processor.
593a1d5f 263 */
bd504ef0
A
264 if (cpup->cpu_number != master_cpu) {
265 i386_init_slave_fast();
266 panic("init_slave_fast returned");
267 }
6d2010ae
A
268 } else
269 {
2d21ac55
A
270 /*
271 * If no power managment and a processor is taken off-line,
272 * then invalidate the cache and halt it (it will not be able
273 * to be brought back on-line without resetting the CPU).
274 */
275 __asm__ volatile ("wbinvd");
593a1d5f 276 cpup->lcpu.state = LCPU_HALT;
6d2010ae 277 pal_stop_cpu(FALSE);
593a1d5f
A
278
279 panic("back from Halt");
2d21ac55 280 }
6d2010ae 281
2d21ac55 282 break;
0c530ab8
A
283 }
284}
285
2d21ac55 286void
593a1d5f 287pmMarkAllCPUsOff(void)
2d21ac55 288{
593a1d5f
A
289 if (pmInitDone
290 && pmDispatch != NULL
291 && pmDispatch->markAllCPUsOff != NULL)
292 (*pmDispatch->markAllCPUsOff)();
2d21ac55
A
293}
294
295static void
296pmInitComplete(void)
297{
7ddcb079
A
298 if (earlyTopology
299 && pmDispatch != NULL
300 && pmDispatch->pmCPUStateInit != NULL) {
060df5ea 301 (*pmDispatch->pmCPUStateInit)();
7ddcb079
A
302 earlyTopology = FALSE;
303 }
2d21ac55
A
304 pmInitDone = 1;
305}
306
bd504ef0 307x86_lcpu_t *
2d21ac55 308pmGetLogicalCPU(int cpu)
0c530ab8 309{
2d21ac55
A
310 return(cpu_to_lcpu(cpu));
311}
312
bd504ef0 313x86_lcpu_t *
2d21ac55
A
314pmGetMyLogicalCPU(void)
315{
316 cpu_data_t *cpup = current_cpu_datap();
0c530ab8 317
2d21ac55
A
318 return(&cpup->lcpu);
319}
320
321static x86_core_t *
322pmGetCore(int cpu)
323{
324 return(cpu_to_core(cpu));
0c530ab8
A
325}
326
2d21ac55
A
327static x86_core_t *
328pmGetMyCore(void)
0c530ab8 329{
2d21ac55 330 cpu_data_t *cpup = current_cpu_datap();
0c530ab8 331
2d21ac55 332 return(cpup->lcpu.core);
0c530ab8
A
333}
334
593a1d5f
A
335static x86_die_t *
336pmGetDie(int cpu)
337{
338 return(cpu_to_die(cpu));
339}
340
341static x86_die_t *
342pmGetMyDie(void)
343{
344 cpu_data_t *cpup = current_cpu_datap();
345
346 return(cpup->lcpu.die);
347}
348
2d21ac55
A
349static x86_pkg_t *
350pmGetPackage(int cpu)
0c530ab8 351{
2d21ac55
A
352 return(cpu_to_package(cpu));
353}
354
355static x86_pkg_t *
356pmGetMyPackage(void)
357{
358 cpu_data_t *cpup = current_cpu_datap();
359
593a1d5f 360 return(cpup->lcpu.package);
2d21ac55
A
361}
362
363static void
364pmLockCPUTopology(int lock)
365{
366 if (lock) {
367 simple_lock(&x86_topo_lock);
368 } else {
369 simple_unlock(&x86_topo_lock);
370 }
0c530ab8
A
371}
372
373/*
2d21ac55
A
374 * Called to get the next deadline that has been set by the
375 * power management code.
6d2010ae
A
376 * Note: a return of 0 from AICPM and this routine signifies
377 * that no deadline is set.
0c530ab8 378 */
2d21ac55
A
379uint64_t
380pmCPUGetDeadline(cpu_data_t *cpu)
381{
060df5ea 382 uint64_t deadline = 0;
0c530ab8 383
7ddcb079 384 if (pmInitDone
2d21ac55
A
385 && pmDispatch != NULL
386 && pmDispatch->GetDeadline != NULL)
387 deadline = (*pmDispatch->GetDeadline)(&cpu->lcpu);
388
389 return(deadline);
0c530ab8
A
390}
391
392/*
2d21ac55
A
393 * Called to determine if the supplied deadline or the power management
394 * deadline is sooner. Returns which ever one is first.
0c530ab8 395 */
39236c6e 396
2d21ac55
A
397uint64_t
398pmCPUSetDeadline(cpu_data_t *cpu, uint64_t deadline)
0c530ab8 399{
b0d623f7 400 if (pmInitDone
2d21ac55
A
401 && pmDispatch != NULL
402 && pmDispatch->SetDeadline != NULL)
403 deadline = (*pmDispatch->SetDeadline)(&cpu->lcpu, deadline);
404
405 return(deadline);
0c530ab8
A
406}
407
0c530ab8 408/*
2d21ac55 409 * Called when a power management deadline expires.
0c530ab8
A
410 */
411void
2d21ac55 412pmCPUDeadline(cpu_data_t *cpu)
0c530ab8 413{
2d21ac55
A
414 if (pmInitDone
415 && pmDispatch != NULL
416 && pmDispatch->Deadline != NULL)
417 (*pmDispatch->Deadline)(&cpu->lcpu);
418}
419
420/*
421 * Called to get a CPU out of idle.
422 */
423boolean_t
424pmCPUExitIdle(cpu_data_t *cpu)
425{
426 boolean_t do_ipi;
427
428 if (pmInitDone
429 && pmDispatch != NULL
430 && pmDispatch->exitIdle != NULL)
431 do_ipi = (*pmDispatch->exitIdle)(&cpu->lcpu);
432 else
433 do_ipi = TRUE;
434
435 return(do_ipi);
0c530ab8
A
436}
437
593a1d5f
A
438kern_return_t
439pmCPUExitHalt(int cpu)
440{
441 kern_return_t rc = KERN_INVALID_ARGUMENT;
442
443 if (pmInitDone
444 && pmDispatch != NULL
445 && pmDispatch->exitHalt != NULL)
446 rc = pmDispatch->exitHalt(cpu_to_lcpu(cpu));
447
448 return(rc);
449}
450
e2fac8b1
A
451kern_return_t
452pmCPUExitHaltToOff(int cpu)
453{
4b17d6b6 454 kern_return_t rc = KERN_SUCCESS;
e2fac8b1
A
455
456 if (pmInitDone
457 && pmDispatch != NULL
458 && pmDispatch->exitHaltToOff != NULL)
459 rc = pmDispatch->exitHaltToOff(cpu_to_lcpu(cpu));
460
461 return(rc);
462}
463
2d21ac55 464/*
593a1d5f 465 * Called to initialize the power management structures for the CPUs.
2d21ac55 466 */
0c530ab8 467void
593a1d5f 468pmCPUStateInit(void)
0c530ab8 469{
593a1d5f
A
470 if (pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
471 (*pmDispatch->pmCPUStateInit)();
060df5ea
A
472 else
473 earlyTopology = TRUE;
0c530ab8
A
474}
475
2d21ac55 476/*
593a1d5f 477 * Called when a CPU is being restarted after being powered off (as in S3).
2d21ac55 478 */
0c530ab8 479void
593a1d5f 480pmCPUMarkRunning(cpu_data_t *cpu)
0c530ab8 481{
593a1d5f
A
482 cpu_data_t *cpup = current_cpu_datap();
483
2d21ac55
A
484 if (pmInitDone
485 && pmDispatch != NULL
593a1d5f
A
486 && pmDispatch->markCPURunning != NULL)
487 (*pmDispatch->markCPURunning)(&cpu->lcpu);
488 else
489 cpup->lcpu.state = LCPU_RUN;
2d21ac55
A
490}
491
492/*
493 * Called to get/set CPU power management state.
494 */
495int
496pmCPUControl(uint32_t cmd, void *datap)
497{
498 int rc = -1;
499
500 if (pmDispatch != NULL
501 && pmDispatch->pmCPUControl != NULL)
502 rc = (*pmDispatch->pmCPUControl)(cmd, datap);
503
504 return(rc);
0c530ab8
A
505}
506
593a1d5f
A
507/*
508 * Called to save the timer state used by power management prior
509 * to "sleeping".
510 */
511void
512pmTimerSave(void)
513{
514 if (pmDispatch != NULL
515 && pmDispatch->pmTimerStateSave != NULL)
516 (*pmDispatch->pmTimerStateSave)();
517}
518
519/*
520 * Called to restore the timer state used by power management after
521 * waking from "sleep".
522 */
523void
524pmTimerRestore(void)
525{
526 if (pmDispatch != NULL
527 && pmDispatch->pmTimerStateRestore != NULL)
528 (*pmDispatch->pmTimerStateRestore)();
529}
530
2d21ac55
A
531/*
532 * Set the worst-case time for the C4 to C2 transition.
533 * No longer does anything.
534 */
0c530ab8 535void
2d21ac55 536ml_set_maxsnoop(__unused uint32_t maxdelay)
0c530ab8 537{
0c530ab8
A
538}
539
2d21ac55
A
540
541/*
542 * Get the worst-case time for the C4 to C2 transition. Returns nanoseconds.
543 */
544unsigned
545ml_get_maxsnoop(void)
546{
547 uint64_t max_snoop = 0;
548
7ddcb079
A
549 if (pmInitDone
550 && pmDispatch != NULL
2d21ac55
A
551 && pmDispatch->getMaxSnoop != NULL)
552 max_snoop = pmDispatch->getMaxSnoop();
553
554 return((unsigned)(max_snoop & 0xffffffff));
555}
556
557
558uint32_t
559ml_get_maxbusdelay(void)
560{
561 uint64_t max_delay = 0;
562
7ddcb079
A
563 if (pmInitDone
564 && pmDispatch != NULL
2d21ac55
A
565 && pmDispatch->getMaxBusDelay != NULL)
566 max_delay = pmDispatch->getMaxBusDelay();
567
568 return((uint32_t)(max_delay & 0xffffffff));
569}
570
571/*
15129b1c 572 * Advertise a memory access latency tolerance of "mdelay" ns
2d21ac55 573 */
0c530ab8 574void
2d21ac55 575ml_set_maxbusdelay(uint32_t mdelay)
0c530ab8 576{
2d21ac55
A
577 uint64_t maxdelay = mdelay;
578
579 if (pmDispatch != NULL
7ddcb079
A
580 && pmDispatch->setMaxBusDelay != NULL) {
581 earlyMaxBusDelay = DELAY_UNSET;
2d21ac55 582 pmDispatch->setMaxBusDelay(maxdelay);
7ddcb079
A
583 } else
584 earlyMaxBusDelay = maxdelay;
593a1d5f
A
585}
586
587uint64_t
588ml_get_maxintdelay(void)
589{
590 uint64_t max_delay = 0;
591
592 if (pmDispatch != NULL
593 && pmDispatch->getMaxIntDelay != NULL)
594 max_delay = pmDispatch->getMaxIntDelay();
595
596 return(max_delay);
597}
598
599/*
600 * Set the maximum delay allowed for an interrupt.
601 */
602void
603ml_set_maxintdelay(uint64_t mdelay)
604{
605 if (pmDispatch != NULL
7ddcb079
A
606 && pmDispatch->setMaxIntDelay != NULL) {
607 earlyMaxIntDelay = DELAY_UNSET;
593a1d5f 608 pmDispatch->setMaxIntDelay(mdelay);
7ddcb079
A
609 } else
610 earlyMaxIntDelay = mdelay;
0c530ab8
A
611}
612
6d2010ae
A
613boolean_t
614ml_get_interrupt_prewake_applicable()
615{
616 boolean_t applicable = FALSE;
617
618 if (pmInitDone
619 && pmDispatch != NULL
620 && pmDispatch->pmInterruptPrewakeApplicable != NULL)
621 applicable = pmDispatch->pmInterruptPrewakeApplicable();
622
623 return applicable;
624}
625
2d21ac55
A
626/*
627 * Put a CPU into "safe" mode with respect to power.
628 *
629 * Some systems cannot operate at a continuous "normal" speed without
630 * exceeding the thermal design. This is called per-CPU to place the
631 * CPUs into a "safe" operating mode.
632 */
0c530ab8 633void
2d21ac55
A
634pmSafeMode(x86_lcpu_t *lcpu, uint32_t flags)
635{
636 if (pmDispatch != NULL
637 && pmDispatch->pmCPUSafeMode != NULL)
638 pmDispatch->pmCPUSafeMode(lcpu, flags);
639 else {
640 /*
641 * Do something reasonable if the KEXT isn't present.
642 *
643 * We only look at the PAUSE and RESUME flags. The other flag(s)
644 * will not make any sense without the KEXT, so just ignore them.
645 *
593a1d5f
A
646 * We set the CPU's state to indicate that it's halted. If this
647 * is the CPU we're currently running on, then spin until the
648 * state becomes non-halted.
2d21ac55
A
649 */
650 if (flags & PM_SAFE_FL_PAUSE) {
593a1d5f 651 lcpu->state = LCPU_PAUSE;
2d21ac55 652 if (lcpu == x86_lcpu()) {
593a1d5f 653 while (lcpu->state == LCPU_PAUSE)
2d21ac55
A
654 cpu_pause();
655 }
656 }
657
658 /*
659 * Clear the halted flag for the specified CPU, that will
660 * get it out of it's spin loop.
661 */
662 if (flags & PM_SAFE_FL_RESUME) {
593a1d5f 663 lcpu->state = LCPU_RUN;
2d21ac55
A
664 }
665 }
666}
667
c910b4d9
A
668static uint32_t saved_run_count = 0;
669
670void
671machine_run_count(uint32_t count)
672{
673 if (pmDispatch != NULL
674 && pmDispatch->pmSetRunCount != NULL)
675 pmDispatch->pmSetRunCount(count);
676 else
677 saved_run_count = count;
678}
679
b7266188
A
680processor_t
681machine_choose_processor(processor_set_t pset,
682 processor_t preferred)
683{
684 int startCPU;
685 int endCPU;
686 int preferredCPU;
687 int chosenCPU;
688
689 if (!pmInitDone)
690 return(preferred);
691
692 if (pset == NULL) {
693 startCPU = -1;
694 endCPU = -1;
695 } else {
696 startCPU = pset->cpu_set_low;
697 endCPU = pset->cpu_set_hi;
698 }
699
700 if (preferred == NULL)
701 preferredCPU = -1;
702 else
703 preferredCPU = preferred->cpu_id;
704
705 if (pmDispatch != NULL
706 && pmDispatch->pmChooseCPU != NULL) {
707 chosenCPU = pmDispatch->pmChooseCPU(startCPU, endCPU, preferredCPU);
708
709 if (chosenCPU == -1)
710 return(NULL);
711 return(cpu_datap(chosenCPU)->cpu_processor);
712 }
713
714 return(preferred);
715}
716
060df5ea 717static int
6d2010ae 718pmThreadGetUrgency(uint64_t *rt_period, uint64_t *rt_deadline)
060df5ea 719{
39236c6e
A
720 int urgency;
721 uint64_t arg1, arg2;
722
723 urgency = thread_get_urgency(current_processor()->next_thread, &arg1, &arg2);
724
725 if (urgency == THREAD_URGENCY_REAL_TIME) {
726 if (rt_period != NULL)
727 *rt_period = arg1;
728
729 if (rt_deadline != NULL)
730 *rt_deadline = arg2;
731 }
732
733 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_SCHED_GET_URGENCY), urgency, arg1, arg2, 0, 0);
060df5ea 734
39236c6e 735 return(urgency);
060df5ea
A
736}
737
6d2010ae
A
738#if DEBUG
739uint32_t urgency_stats[64][THREAD_URGENCY_MAX];
740#endif
741
742#define URGENCY_NOTIFICATION_ASSERT_NS (5 * 1000 * 1000)
743uint64_t urgency_notification_assert_abstime_threshold, urgency_notification_max_recorded;
744
060df5ea
A
745void
746thread_tell_urgency(int urgency,
6d2010ae 747 uint64_t rt_period,
39236c6e
A
748 uint64_t rt_deadline,
749 thread_t nthread)
6d2010ae
A
750{
751 uint64_t urgency_notification_time_start, delta;
752 boolean_t urgency_assert = (urgency_notification_assert_abstime_threshold != 0);
753 assert(get_preemption_level() > 0 || ml_get_interrupts_enabled() == FALSE);
754#if DEBUG
755 urgency_stats[cpu_number() % 64][urgency]++;
756#endif
757 if (!pmInitDone
758 || pmDispatch == NULL
759 || pmDispatch->pmThreadTellUrgency == NULL)
760 return;
761
39236c6e 762 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_START, urgency, rt_period, rt_deadline, 0, 0);
6d2010ae
A
763
764 if (__improbable((urgency_assert == TRUE)))
765 urgency_notification_time_start = mach_absolute_time();
766
39236c6e 767 current_cpu_datap()->cpu_nthread = nthread;
6d2010ae
A
768 pmDispatch->pmThreadTellUrgency(urgency, rt_period, rt_deadline);
769
770 if (__improbable((urgency_assert == TRUE))) {
771 delta = mach_absolute_time() - urgency_notification_time_start;
772
773 if (__improbable(delta > urgency_notification_max_recorded)) {
774 /* This is not synchronized, but it doesn't matter
775 * if we (rarely) miss an event, as it is statistically
776 * unlikely that it will never recur.
777 */
778 urgency_notification_max_recorded = delta;
779
780 if (__improbable((delta > urgency_notification_assert_abstime_threshold) && !machine_timeout_suspended()))
781 panic("Urgency notification callout %p exceeded threshold, 0x%llx abstime units", pmDispatch->pmThreadTellUrgency, delta);
782 }
783 }
060df5ea 784
39236c6e 785 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_END, urgency, rt_period, rt_deadline, 0, 0);
060df5ea
A
786}
787
788void
789active_rt_threads(boolean_t active)
790{
791 if (!pmInitDone
792 || pmDispatch == NULL
793 || pmDispatch->pmActiveRTThreads == NULL)
794 return;
795
796 pmDispatch->pmActiveRTThreads(active);
797}
798
c910b4d9
A
799static uint32_t
800pmGetSavedRunCount(void)
801{
802 return(saved_run_count);
803}
804
2d21ac55
A
805/*
806 * Returns the root of the package tree.
807 */
bd504ef0 808x86_pkg_t *
2d21ac55
A
809pmGetPkgRoot(void)
810{
811 return(x86_pkgs);
812}
813
814static boolean_t
815pmCPUGetHibernate(int cpu)
0c530ab8 816{
2d21ac55 817 return(cpu_datap(cpu)->cpu_hibernate);
0c530ab8
A
818}
819
bd504ef0 820processor_t
2d21ac55
A
821pmLCPUtoProcessor(int lcpu)
822{
823 return(cpu_datap(lcpu)->cpu_processor);
824}
825
c910b4d9
A
826static void
827pmReSyncDeadlines(int cpu)
828{
829 static boolean_t registered = FALSE;
830
831 if (!registered) {
39236c6e 832 PM_interrupt_register(&timer_resync_deadlines);
c910b4d9
A
833 registered = TRUE;
834 }
835
836 if ((uint32_t)cpu == current_cpu_datap()->lcpu.cpu_num)
39236c6e 837 timer_resync_deadlines();
c910b4d9
A
838 else
839 cpu_PM_interrupt(cpu);
840}
841
b0d623f7
A
842static void
843pmSendIPI(int cpu)
844{
845 lapic_send_ipi(cpu, LAPIC_PM_INTERRUPT);
846}
847
060df5ea
A
848static void
849pmGetNanotimeInfo(pm_rtc_nanotime_t *rtc_nanotime)
850{
851 /*
852 * Make sure that nanotime didn't change while we were reading it.
853 */
854 do {
6d2010ae
A
855 rtc_nanotime->generation = pal_rtc_nanotime_info.generation; /* must be first */
856 rtc_nanotime->tsc_base = pal_rtc_nanotime_info.tsc_base;
857 rtc_nanotime->ns_base = pal_rtc_nanotime_info.ns_base;
858 rtc_nanotime->scale = pal_rtc_nanotime_info.scale;
859 rtc_nanotime->shift = pal_rtc_nanotime_info.shift;
860 } while(pal_rtc_nanotime_info.generation != 0
861 && rtc_nanotime->generation != pal_rtc_nanotime_info.generation);
060df5ea
A
862}
863
bd504ef0 864uint32_t
6d2010ae 865pmTimerQueueMigrate(int target_cpu)
7e4a7d39 866{
6d2010ae
A
867 /* Call the etimer code to do this. */
868 return (target_cpu != cpu_number())
39236c6e 869 ? timer_queue_migrate_cpu(target_cpu)
6d2010ae 870 : 0;
7e4a7d39
A
871}
872
6d2010ae 873
2d21ac55
A
874/*
875 * Called by the power management kext to register itself and to get the
876 * callbacks it might need into other kernel functions. This interface
877 * is versioned to allow for slight mis-matches between the kext and the
878 * kernel.
879 */
0c530ab8 880void
2d21ac55 881pmKextRegister(uint32_t version, pmDispatch_t *cpuFuncs,
39236c6e
A
882 pmCallBacks_t *callbacks)
883{
884 if (callbacks != NULL && version == PM_DISPATCH_VERSION) {
885 callbacks->setRTCPop = setPop;
886 callbacks->resyncDeadlines = pmReSyncDeadlines;
887 callbacks->initComplete = pmInitComplete;
888 callbacks->GetLCPU = pmGetLogicalCPU;
889 callbacks->GetCore = pmGetCore;
890 callbacks->GetDie = pmGetDie;
891 callbacks->GetPackage = pmGetPackage;
892 callbacks->GetMyLCPU = pmGetMyLogicalCPU;
893 callbacks->GetMyCore = pmGetMyCore;
894 callbacks->GetMyDie = pmGetMyDie;
895 callbacks->GetMyPackage = pmGetMyPackage;
896 callbacks->GetPkgRoot = pmGetPkgRoot;
897 callbacks->LockCPUTopology = pmLockCPUTopology;
898 callbacks->GetHibernate = pmCPUGetHibernate;
899 callbacks->LCPUtoProcessor = pmLCPUtoProcessor;
900 callbacks->ThreadBind = thread_bind;
901 callbacks->GetSavedRunCount = pmGetSavedRunCount;
902 callbacks->GetNanotimeInfo = pmGetNanotimeInfo;
903 callbacks->ThreadGetUrgency = pmThreadGetUrgency;
904 callbacks->RTCClockAdjust = rtc_clock_adjust;
905 callbacks->timerQueueMigrate = pmTimerQueueMigrate;
906 callbacks->topoParms = &topoParms;
907 callbacks->pmSendIPI = pmSendIPI;
908 callbacks->InterruptPending = lapic_is_interrupt_pending;
909 callbacks->IsInterrupting = lapic_is_interrupting;
910 callbacks->InterruptStats = lapic_interrupt_counts;
911 callbacks->DisableApicTimer = lapic_disable_timer;
912 } else {
913 panic("Version mis-match between Kernel and CPU PM");
914 }
2d21ac55 915
39236c6e
A
916 if (cpuFuncs != NULL) {
917 if (pmDispatch) {
918 panic("Attempt to re-register power management interface--AICPM present in xcpm mode? %p->%p", pmDispatch, cpuFuncs);
919 }
bd504ef0 920
39236c6e 921 pmDispatch = cpuFuncs;
b0d623f7 922
39236c6e
A
923 if (earlyTopology
924 && pmDispatch->pmCPUStateInit != NULL) {
925 (*pmDispatch->pmCPUStateInit)();
926 earlyTopology = FALSE;
927 }
7ddcb079 928
39236c6e
A
929 if (pmDispatch->pmIPIHandler != NULL) {
930 lapic_set_pm_func((i386_intr_func_t)pmDispatch->pmIPIHandler);
931 }
b0d623f7 932 }
0c530ab8
A
933}
934
2d21ac55
A
935/*
936 * Unregisters the power management functions from the kext.
937 */
0c530ab8 938void
2d21ac55 939pmUnRegister(pmDispatch_t *cpuFuncs)
0c530ab8 940{
2d21ac55
A
941 if (cpuFuncs != NULL && pmDispatch == cpuFuncs) {
942 pmDispatch = NULL;
943 }
0c530ab8 944}
2d21ac55 945
4b17d6b6
A
946void machine_track_platform_idle(boolean_t entry) {
947 cpu_data_t *my_cpu = current_cpu_datap();
948
949 if (entry) {
950 (void)__sync_fetch_and_add(&my_cpu->lcpu.package->num_idle, 1);
951 }
bd504ef0
A
952 else {
953 uint32_t nidle = __sync_fetch_and_sub(&my_cpu->lcpu.package->num_idle, 1);
954 if (nidle == topoParms.nLThreadsPerPackage) {
955 my_cpu->lcpu.package->package_idle_exits++;
956 }
957 }
4b17d6b6 958}