]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/pmCPU.c
22eafd1b8df26dee214e90833f7a10a0eec22f91
[apple/xnu.git] / osfmk / i386 / pmCPU.c
1 /*
2 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * CPU-specific power management support.
31 *
32 * Implements the "wrappers" to the KEXT.
33 */
34 #include <i386/asm.h>
35 #include <i386/machine_cpu.h>
36 #include <i386/mp.h>
37 #include <i386/machine_routines.h>
38 #include <i386/proc_reg.h>
39 #include <i386/pmap.h>
40 #include <i386/misc_protos.h>
41 #include <kern/machine.h>
42 #include <kern/pms.h>
43 #include <kern/processor.h>
44 #include <kern/etimer.h>
45 #include <i386/cpu_threads.h>
46 #include <i386/pmCPU.h>
47 #include <i386/cpuid.h>
48 #include <i386/rtclock_protos.h>
49 #include <kern/sched_prim.h>
50 #include <i386/lapic.h>
51 #include <i386/pal_routines.h>
52
53 #include <sys/kdebug.h>
54
55 extern int disableConsoleOutput;
56
57 decl_simple_lock_data(,pm_init_lock);
58
59 /*
60 * The following is set when the KEXT loads and initializes.
61 */
62 pmDispatch_t *pmDispatch = NULL;
63
64 static uint32_t pmInitDone = 0;
65 static boolean_t earlyTopology = FALSE;
66
67
68 /*
69 * Initialize the Cstate change code.
70 */
71 void
72 power_management_init(void)
73 {
74 static boolean_t initialized = FALSE;
75
76 /*
77 * Initialize the lock for the KEXT initialization.
78 */
79 if (!initialized) {
80 simple_lock_init(&pm_init_lock, 0);
81 initialized = TRUE;
82 }
83
84 if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
85 (*pmDispatch->cstateInit)();
86 }
87
88 /*
89 * Called when the CPU is idle. It calls into the power management kext
90 * to determine the best way to idle the CPU.
91 */
92 void
93 machine_idle(void)
94 {
95 cpu_data_t *my_cpu = current_cpu_datap();
96
97 if (my_cpu == NULL)
98 goto out;
99
100 my_cpu->lcpu.state = LCPU_IDLE;
101 DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
102 MARK_CPU_IDLE(cpu_number());
103
104 if (pmInitDone
105 && pmDispatch != NULL
106 && pmDispatch->MachineIdle != NULL)
107 (*pmDispatch->MachineIdle)(0x7FFFFFFFFFFFFFFFULL);
108 else {
109 /*
110 * If no power management, re-enable interrupts and halt.
111 * This will keep the CPU from spinning through the scheduler
112 * and will allow at least some minimal power savings (but it
113 * cause problems in some MP configurations w.r.t. the APIC
114 * stopping during a GV3 transition).
115 */
116 pal_hlt();
117
118 /* Once woken, re-disable interrupts. */
119 pal_cli();
120 }
121
122 /*
123 * Mark the CPU as running again.
124 */
125 MARK_CPU_ACTIVE(cpu_number());
126 DBGLOG(cpu_handle, cpu_number(), MP_UNIDLE);
127 my_cpu->lcpu.state = LCPU_RUN;
128
129 /*
130 * Re-enable interrupts.
131 */
132 out:
133 pal_sti();
134 }
135
136 /*
137 * Called when the CPU is to be halted. It will choose the best C-State
138 * to be in.
139 */
140 void
141 pmCPUHalt(uint32_t reason)
142 {
143 cpu_data_t *cpup = current_cpu_datap();
144
145 switch (reason) {
146 case PM_HALT_DEBUG:
147 cpup->lcpu.state = LCPU_PAUSE;
148 pal_stop_cpu(FALSE);
149 break;
150
151 case PM_HALT_PANIC:
152 cpup->lcpu.state = LCPU_PAUSE;
153 pal_stop_cpu(TRUE);
154 break;
155
156 case PM_HALT_NORMAL:
157 default:
158 pal_cli();
159
160 if (pmInitDone
161 && pmDispatch != NULL
162 && pmDispatch->pmCPUHalt != NULL) {
163 /*
164 * Halt the CPU (and put it in a low power state.
165 */
166 (*pmDispatch->pmCPUHalt)();
167
168 /*
169 * We've exited halt, so get the the CPU schedulable again.
170 */
171 i386_init_slave_fast();
172
173 panic("init_slave_fast returned");
174 } else
175 {
176 /*
177 * If no power managment and a processor is taken off-line,
178 * then invalidate the cache and halt it (it will not be able
179 * to be brought back on-line without resetting the CPU).
180 */
181 __asm__ volatile ("wbinvd");
182 cpup->lcpu.state = LCPU_HALT;
183 pal_stop_cpu(FALSE);
184
185 panic("back from Halt");
186 }
187
188 break;
189 }
190 }
191
192 void
193 pmMarkAllCPUsOff(void)
194 {
195 if (pmInitDone
196 && pmDispatch != NULL
197 && pmDispatch->markAllCPUsOff != NULL)
198 (*pmDispatch->markAllCPUsOff)();
199 }
200
201 static void
202 pmInitComplete(void)
203 {
204 if (earlyTopology && pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
205 (*pmDispatch->pmCPUStateInit)();
206
207 pmInitDone = 1;
208 }
209
210 static x86_lcpu_t *
211 pmGetLogicalCPU(int cpu)
212 {
213 return(cpu_to_lcpu(cpu));
214 }
215
216 static x86_lcpu_t *
217 pmGetMyLogicalCPU(void)
218 {
219 cpu_data_t *cpup = current_cpu_datap();
220
221 return(&cpup->lcpu);
222 }
223
224 static x86_core_t *
225 pmGetCore(int cpu)
226 {
227 return(cpu_to_core(cpu));
228 }
229
230 static x86_core_t *
231 pmGetMyCore(void)
232 {
233 cpu_data_t *cpup = current_cpu_datap();
234
235 return(cpup->lcpu.core);
236 }
237
238 static x86_die_t *
239 pmGetDie(int cpu)
240 {
241 return(cpu_to_die(cpu));
242 }
243
244 static x86_die_t *
245 pmGetMyDie(void)
246 {
247 cpu_data_t *cpup = current_cpu_datap();
248
249 return(cpup->lcpu.die);
250 }
251
252 static x86_pkg_t *
253 pmGetPackage(int cpu)
254 {
255 return(cpu_to_package(cpu));
256 }
257
258 static x86_pkg_t *
259 pmGetMyPackage(void)
260 {
261 cpu_data_t *cpup = current_cpu_datap();
262
263 return(cpup->lcpu.package);
264 }
265
266 static void
267 pmLockCPUTopology(int lock)
268 {
269 if (lock) {
270 simple_lock(&x86_topo_lock);
271 } else {
272 simple_unlock(&x86_topo_lock);
273 }
274 }
275
276 /*
277 * Called to get the next deadline that has been set by the
278 * power management code.
279 * Note: a return of 0 from AICPM and this routine signifies
280 * that no deadline is set.
281 */
282 uint64_t
283 pmCPUGetDeadline(cpu_data_t *cpu)
284 {
285 uint64_t deadline = 0;
286
287 if (pmInitDone
288 && pmDispatch != NULL
289 && pmDispatch->GetDeadline != NULL)
290 deadline = (*pmDispatch->GetDeadline)(&cpu->lcpu);
291
292 return(deadline);
293 }
294
295 /*
296 * Called to determine if the supplied deadline or the power management
297 * deadline is sooner. Returns which ever one is first.
298 */
299 uint64_t
300 pmCPUSetDeadline(cpu_data_t *cpu, uint64_t deadline)
301 {
302 if (pmInitDone
303 && pmDispatch != NULL
304 && pmDispatch->SetDeadline != NULL)
305 deadline = (*pmDispatch->SetDeadline)(&cpu->lcpu, deadline);
306
307 return(deadline);
308 }
309
310 /*
311 * Called when a power management deadline expires.
312 */
313 void
314 pmCPUDeadline(cpu_data_t *cpu)
315 {
316 if (pmInitDone
317 && pmDispatch != NULL
318 && pmDispatch->Deadline != NULL)
319 (*pmDispatch->Deadline)(&cpu->lcpu);
320 }
321
322 /*
323 * Called to get a CPU out of idle.
324 */
325 boolean_t
326 pmCPUExitIdle(cpu_data_t *cpu)
327 {
328 boolean_t do_ipi;
329
330 if (pmInitDone
331 && pmDispatch != NULL
332 && pmDispatch->exitIdle != NULL)
333 do_ipi = (*pmDispatch->exitIdle)(&cpu->lcpu);
334 else
335 do_ipi = TRUE;
336
337 return(do_ipi);
338 }
339
340 kern_return_t
341 pmCPUExitHalt(int cpu)
342 {
343 kern_return_t rc = KERN_INVALID_ARGUMENT;
344
345 if (pmInitDone
346 && pmDispatch != NULL
347 && pmDispatch->exitHalt != NULL)
348 rc = pmDispatch->exitHalt(cpu_to_lcpu(cpu));
349
350 return(rc);
351 }
352
353 kern_return_t
354 pmCPUExitHaltToOff(int cpu)
355 {
356 kern_return_t rc = KERN_INVALID_ARGUMENT;
357
358 if (pmInitDone
359 && pmDispatch != NULL
360 && pmDispatch->exitHaltToOff != NULL)
361 rc = pmDispatch->exitHaltToOff(cpu_to_lcpu(cpu));
362
363 return(rc);
364 }
365
366 /*
367 * Called to initialize the power management structures for the CPUs.
368 */
369 void
370 pmCPUStateInit(void)
371 {
372 if (pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
373 (*pmDispatch->pmCPUStateInit)();
374 else
375 earlyTopology = TRUE;
376 }
377
378 /*
379 * Called when a CPU is being restarted after being powered off (as in S3).
380 */
381 void
382 pmCPUMarkRunning(cpu_data_t *cpu)
383 {
384 cpu_data_t *cpup = current_cpu_datap();
385
386 if (pmInitDone
387 && pmDispatch != NULL
388 && pmDispatch->markCPURunning != NULL)
389 (*pmDispatch->markCPURunning)(&cpu->lcpu);
390 else
391 cpup->lcpu.state = LCPU_RUN;
392 }
393
394 /*
395 * Called to get/set CPU power management state.
396 */
397 int
398 pmCPUControl(uint32_t cmd, void *datap)
399 {
400 int rc = -1;
401
402 if (pmDispatch != NULL
403 && pmDispatch->pmCPUControl != NULL)
404 rc = (*pmDispatch->pmCPUControl)(cmd, datap);
405
406 return(rc);
407 }
408
409 /*
410 * Called to save the timer state used by power management prior
411 * to "sleeping".
412 */
413 void
414 pmTimerSave(void)
415 {
416 if (pmDispatch != NULL
417 && pmDispatch->pmTimerStateSave != NULL)
418 (*pmDispatch->pmTimerStateSave)();
419 }
420
421 /*
422 * Called to restore the timer state used by power management after
423 * waking from "sleep".
424 */
425 void
426 pmTimerRestore(void)
427 {
428 if (pmDispatch != NULL
429 && pmDispatch->pmTimerStateRestore != NULL)
430 (*pmDispatch->pmTimerStateRestore)();
431 }
432
433 /*
434 * Set the worst-case time for the C4 to C2 transition.
435 * No longer does anything.
436 */
437 void
438 ml_set_maxsnoop(__unused uint32_t maxdelay)
439 {
440 }
441
442
443 /*
444 * Get the worst-case time for the C4 to C2 transition. Returns nanoseconds.
445 */
446 unsigned
447 ml_get_maxsnoop(void)
448 {
449 uint64_t max_snoop = 0;
450
451 if (pmDispatch != NULL
452 && pmDispatch->getMaxSnoop != NULL)
453 max_snoop = pmDispatch->getMaxSnoop();
454
455 return((unsigned)(max_snoop & 0xffffffff));
456 }
457
458
459 uint32_t
460 ml_get_maxbusdelay(void)
461 {
462 uint64_t max_delay = 0;
463
464 if (pmDispatch != NULL
465 && pmDispatch->getMaxBusDelay != NULL)
466 max_delay = pmDispatch->getMaxBusDelay();
467
468 return((uint32_t)(max_delay & 0xffffffff));
469 }
470
471 /*
472 * Set the maximum delay time allowed for snoop on the bus.
473 *
474 * Note that this value will be compared to the amount of time that it takes
475 * to transition from a non-snooping power state (C4) to a snooping state (C2).
476 * If maxBusDelay is less than C4C2SnoopDelay,
477 * we will not enter the lowest power state.
478 */
479 void
480 ml_set_maxbusdelay(uint32_t mdelay)
481 {
482 uint64_t maxdelay = mdelay;
483
484 if (pmDispatch != NULL
485 && pmDispatch->setMaxBusDelay != NULL)
486 pmDispatch->setMaxBusDelay(maxdelay);
487 }
488
489 uint64_t
490 ml_get_maxintdelay(void)
491 {
492 uint64_t max_delay = 0;
493
494 if (pmDispatch != NULL
495 && pmDispatch->getMaxIntDelay != NULL)
496 max_delay = pmDispatch->getMaxIntDelay();
497
498 return(max_delay);
499 }
500
501 /*
502 * Set the maximum delay allowed for an interrupt.
503 */
504 void
505 ml_set_maxintdelay(uint64_t mdelay)
506 {
507 if (pmDispatch != NULL
508 && pmDispatch->setMaxIntDelay != NULL)
509 pmDispatch->setMaxIntDelay(mdelay);
510 }
511
512 boolean_t
513 ml_get_interrupt_prewake_applicable()
514 {
515 boolean_t applicable = FALSE;
516
517 if (pmInitDone
518 && pmDispatch != NULL
519 && pmDispatch->pmInterruptPrewakeApplicable != NULL)
520 applicable = pmDispatch->pmInterruptPrewakeApplicable();
521
522 return applicable;
523 }
524
525 /*
526 * Put a CPU into "safe" mode with respect to power.
527 *
528 * Some systems cannot operate at a continuous "normal" speed without
529 * exceeding the thermal design. This is called per-CPU to place the
530 * CPUs into a "safe" operating mode.
531 */
532 void
533 pmSafeMode(x86_lcpu_t *lcpu, uint32_t flags)
534 {
535 if (pmDispatch != NULL
536 && pmDispatch->pmCPUSafeMode != NULL)
537 pmDispatch->pmCPUSafeMode(lcpu, flags);
538 else {
539 /*
540 * Do something reasonable if the KEXT isn't present.
541 *
542 * We only look at the PAUSE and RESUME flags. The other flag(s)
543 * will not make any sense without the KEXT, so just ignore them.
544 *
545 * We set the CPU's state to indicate that it's halted. If this
546 * is the CPU we're currently running on, then spin until the
547 * state becomes non-halted.
548 */
549 if (flags & PM_SAFE_FL_PAUSE) {
550 lcpu->state = LCPU_PAUSE;
551 if (lcpu == x86_lcpu()) {
552 while (lcpu->state == LCPU_PAUSE)
553 cpu_pause();
554 }
555 }
556
557 /*
558 * Clear the halted flag for the specified CPU, that will
559 * get it out of it's spin loop.
560 */
561 if (flags & PM_SAFE_FL_RESUME) {
562 lcpu->state = LCPU_RUN;
563 }
564 }
565 }
566
567 static uint32_t saved_run_count = 0;
568
569 void
570 machine_run_count(uint32_t count)
571 {
572 if (pmDispatch != NULL
573 && pmDispatch->pmSetRunCount != NULL)
574 pmDispatch->pmSetRunCount(count);
575 else
576 saved_run_count = count;
577 }
578
579 boolean_t
580 machine_processor_is_inactive(processor_t processor)
581 {
582 int cpu = processor->cpu_id;
583
584 if (pmDispatch != NULL
585 && pmDispatch->pmIsCPUUnAvailable != NULL)
586 return(pmDispatch->pmIsCPUUnAvailable(cpu_to_lcpu(cpu)));
587 else
588 return(FALSE);
589 }
590
591 processor_t
592 machine_choose_processor(processor_set_t pset,
593 processor_t preferred)
594 {
595 int startCPU;
596 int endCPU;
597 int preferredCPU;
598 int chosenCPU;
599
600 if (!pmInitDone)
601 return(preferred);
602
603 if (pset == NULL) {
604 startCPU = -1;
605 endCPU = -1;
606 } else {
607 startCPU = pset->cpu_set_low;
608 endCPU = pset->cpu_set_hi;
609 }
610
611 if (preferred == NULL)
612 preferredCPU = -1;
613 else
614 preferredCPU = preferred->cpu_id;
615
616 if (pmDispatch != NULL
617 && pmDispatch->pmChooseCPU != NULL) {
618 chosenCPU = pmDispatch->pmChooseCPU(startCPU, endCPU, preferredCPU);
619
620 if (chosenCPU == -1)
621 return(NULL);
622 return(cpu_datap(chosenCPU)->cpu_processor);
623 }
624
625 return(preferred);
626 }
627
628 static int
629 pmThreadGetUrgency(uint64_t *rt_period, uint64_t *rt_deadline)
630 {
631
632 return(thread_get_urgency(rt_period, rt_deadline));
633 }
634
635 #if DEBUG
636 uint32_t urgency_stats[64][THREAD_URGENCY_MAX];
637 #endif
638
639 #define URGENCY_NOTIFICATION_ASSERT_NS (5 * 1000 * 1000)
640 uint64_t urgency_notification_assert_abstime_threshold, urgency_notification_max_recorded;
641
642 void
643 thread_tell_urgency(int urgency,
644 uint64_t rt_period,
645 uint64_t rt_deadline)
646 {
647 uint64_t urgency_notification_time_start, delta;
648 boolean_t urgency_assert = (urgency_notification_assert_abstime_threshold != 0);
649 assert(get_preemption_level() > 0 || ml_get_interrupts_enabled() == FALSE);
650 #if DEBUG
651 urgency_stats[cpu_number() % 64][urgency]++;
652 #endif
653 if (!pmInitDone
654 || pmDispatch == NULL
655 || pmDispatch->pmThreadTellUrgency == NULL)
656 return;
657
658 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_START, urgency, rt_period, (rt_deadline >> 32), rt_deadline, 0);
659
660 if (__improbable((urgency_assert == TRUE)))
661 urgency_notification_time_start = mach_absolute_time();
662
663 pmDispatch->pmThreadTellUrgency(urgency, rt_period, rt_deadline);
664
665 if (__improbable((urgency_assert == TRUE))) {
666 delta = mach_absolute_time() - urgency_notification_time_start;
667
668 if (__improbable(delta > urgency_notification_max_recorded)) {
669 /* This is not synchronized, but it doesn't matter
670 * if we (rarely) miss an event, as it is statistically
671 * unlikely that it will never recur.
672 */
673 urgency_notification_max_recorded = delta;
674
675 if (__improbable((delta > urgency_notification_assert_abstime_threshold) && !machine_timeout_suspended()))
676 panic("Urgency notification callout %p exceeded threshold, 0x%llx abstime units", pmDispatch->pmThreadTellUrgency, delta);
677 }
678 }
679
680 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_END, urgency, rt_period, (rt_deadline >> 32), rt_deadline, 0);
681 }
682
683 void
684 active_rt_threads(boolean_t active)
685 {
686 if (!pmInitDone
687 || pmDispatch == NULL
688 || pmDispatch->pmActiveRTThreads == NULL)
689 return;
690
691 pmDispatch->pmActiveRTThreads(active);
692 }
693
694 static uint32_t
695 pmGetSavedRunCount(void)
696 {
697 return(saved_run_count);
698 }
699
700 /*
701 * Returns the root of the package tree.
702 */
703 static x86_pkg_t *
704 pmGetPkgRoot(void)
705 {
706 return(x86_pkgs);
707 }
708
709 static boolean_t
710 pmCPUGetHibernate(int cpu)
711 {
712 return(cpu_datap(cpu)->cpu_hibernate);
713 }
714
715 static processor_t
716 pmLCPUtoProcessor(int lcpu)
717 {
718 return(cpu_datap(lcpu)->cpu_processor);
719 }
720
721 static void
722 pmReSyncDeadlines(int cpu)
723 {
724 static boolean_t registered = FALSE;
725
726 if (!registered) {
727 PM_interrupt_register(&etimer_resync_deadlines);
728 registered = TRUE;
729 }
730
731 if ((uint32_t)cpu == current_cpu_datap()->lcpu.cpu_num)
732 etimer_resync_deadlines();
733 else
734 cpu_PM_interrupt(cpu);
735 }
736
737 static void
738 pmSendIPI(int cpu)
739 {
740 lapic_send_ipi(cpu, LAPIC_PM_INTERRUPT);
741 }
742
743 static void
744 pmGetNanotimeInfo(pm_rtc_nanotime_t *rtc_nanotime)
745 {
746 /*
747 * Make sure that nanotime didn't change while we were reading it.
748 */
749 do {
750 rtc_nanotime->generation = pal_rtc_nanotime_info.generation; /* must be first */
751 rtc_nanotime->tsc_base = pal_rtc_nanotime_info.tsc_base;
752 rtc_nanotime->ns_base = pal_rtc_nanotime_info.ns_base;
753 rtc_nanotime->scale = pal_rtc_nanotime_info.scale;
754 rtc_nanotime->shift = pal_rtc_nanotime_info.shift;
755 } while(pal_rtc_nanotime_info.generation != 0
756 && rtc_nanotime->generation != pal_rtc_nanotime_info.generation);
757 }
758
759 static uint32_t
760 pmTimerQueueMigrate(int target_cpu)
761 {
762 /* Call the etimer code to do this. */
763 return (target_cpu != cpu_number())
764 ? etimer_queue_migrate(target_cpu)
765 : 0;
766 }
767
768
769 /*
770 * Called by the power management kext to register itself and to get the
771 * callbacks it might need into other kernel functions. This interface
772 * is versioned to allow for slight mis-matches between the kext and the
773 * kernel.
774 */
775 void
776 pmKextRegister(uint32_t version, pmDispatch_t *cpuFuncs,
777 pmCallBacks_t *callbacks)
778 {
779 if (callbacks != NULL && version == PM_DISPATCH_VERSION) {
780 callbacks->setRTCPop = setPop;
781 callbacks->resyncDeadlines = pmReSyncDeadlines;
782 callbacks->initComplete = pmInitComplete;
783 callbacks->GetLCPU = pmGetLogicalCPU;
784 callbacks->GetCore = pmGetCore;
785 callbacks->GetDie = pmGetDie;
786 callbacks->GetPackage = pmGetPackage;
787 callbacks->GetMyLCPU = pmGetMyLogicalCPU;
788 callbacks->GetMyCore = pmGetMyCore;
789 callbacks->GetMyDie = pmGetMyDie;
790 callbacks->GetMyPackage = pmGetMyPackage;
791 callbacks->GetPkgRoot = pmGetPkgRoot;
792 callbacks->LockCPUTopology = pmLockCPUTopology;
793 callbacks->GetHibernate = pmCPUGetHibernate;
794 callbacks->LCPUtoProcessor = pmLCPUtoProcessor;
795 callbacks->ThreadBind = thread_bind;
796 callbacks->GetSavedRunCount = pmGetSavedRunCount;
797 callbacks->GetNanotimeInfo = pmGetNanotimeInfo;
798 callbacks->ThreadGetUrgency = pmThreadGetUrgency;
799 callbacks->RTCClockAdjust = rtc_clock_adjust;
800 callbacks->timerQueueMigrate = pmTimerQueueMigrate;
801 callbacks->topoParms = &topoParms;
802 callbacks->pmSendIPI = pmSendIPI;
803 callbacks->InterruptPending = lapic_is_interrupt_pending;
804 callbacks->IsInterrupting = lapic_is_interrupting;
805 callbacks->InterruptStats = lapic_interrupt_counts;
806 callbacks->DisableApicTimer = lapic_disable_timer;
807 } else {
808 panic("Version mis-match between Kernel and CPU PM");
809 }
810
811 if (cpuFuncs != NULL) {
812 pmDispatch = cpuFuncs;
813
814 if (pmDispatch->pmIPIHandler != NULL) {
815 lapic_set_pm_func((i386_intr_func_t)pmDispatch->pmIPIHandler);
816 }
817 }
818 }
819
820 /*
821 * Unregisters the power management functions from the kext.
822 */
823 void
824 pmUnRegister(pmDispatch_t *cpuFuncs)
825 {
826 if (cpuFuncs != NULL && pmDispatch == cpuFuncs) {
827 pmDispatch = NULL;
828 }
829 }
830
831 /******************************************************************************
832 *
833 * All of the following are deprecated interfaces and no longer used.
834 *
835 ******************************************************************************/
836 kern_return_t
837 pmsControl(__unused uint32_t request, __unused user_addr_t reqaddr,
838 __unused uint32_t reqsize)
839 {
840 return(KERN_SUCCESS);
841 }
842
843 void
844 pmsInit(void)
845 {
846 }
847
848 void
849 pmsStart(void)
850 {
851 }
852
853 void
854 pmsPark(void)
855 {
856 }
857
858 void
859 pmsRun(__unused uint32_t nstep)
860 {
861 }
862
863 kern_return_t
864 pmsBuild(__unused pmsDef *pd, __unused uint32_t pdsize,
865 __unused pmsSetFunc_t *functab,
866 __unused uint32_t platformData, __unused pmsQueryFunc_t queryFunc)
867 {
868 return(KERN_SUCCESS);
869 }