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