/*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*
* Implements the "wrappers" to the KEXT.
*/
-#include <i386/machine_routines.h>
-#include <i386/machine_cpu.h>
-#include <i386/misc_protos.h>
-#include <i386/pmap.h>
#include <i386/asm.h>
+#include <i386/machine_cpu.h>
#include <i386/mp.h>
+#include <i386/machine_routines.h>
#include <i386/proc_reg.h>
+#include <i386/pmap.h>
+#include <i386/misc_protos.h>
+#include <kern/machine.h>
#include <kern/pms.h>
#include <kern/processor.h>
+#include <kern/etimer.h>
#include <i386/cpu_threads.h>
#include <i386/pmCPU.h>
#include <i386/cpuid.h>
-#include <i386/rtclock.h>
+#include <i386/rtclock_protos.h>
+#include <kern/sched_prim.h>
+#include <i386/lapic.h>
+#include <i386/pal_routines.h>
+
+#include <sys/kdebug.h>
extern int disableConsoleOutput;
-decl_simple_lock_data(,pm_init_lock);
+#define DELAY_UNSET 0xFFFFFFFFFFFFFFFFULL
/*
* The following is set when the KEXT loads and initializes.
*/
pmDispatch_t *pmDispatch = NULL;
-/*
- * Current power management states (for use until KEXT is loaded).
- */
-static pmInitState_t pmInitState;
-
-static uint32_t pmInitDone = 0;
+static uint32_t pmInitDone = 0;
+static boolean_t earlyTopology = FALSE;
+static uint64_t earlyMaxBusDelay = DELAY_UNSET;
+static uint64_t earlyMaxIntDelay = DELAY_UNSET;
-/*
- * Nap control variables:
- */
-uint32_t forcenap = 0; /* Force nap (fn) boot-arg controls */
/*
- * Do any initialization needed
- */
-void
-pmsInit(void)
-{
- static int initialized = 0;
-
- /*
- * Initialize some of the initial state to "uninitialized" until
- * it gets set with something more useful. This allows the KEXT
- * to determine if the initial value was actually set to something.
- */
- if (!initialized) {
- pmInitState.PState = -1;
- pmInitState.PLimit = -1;
- pmInitState.maxBusDelay = -1;
- initialized = 1;
- }
-
- if (pmDispatch != NULL && pmDispatch->pmsInit != NULL)
- (*pmDispatch->pmsInit)();
-}
-
-/*
- * Start the power management stepper on all processors
- *
- * All processors must be parked. This should be called when the hardware
- * is ready to step. Probably only at boot and after wake from sleep.
- *
- */
-void
-pmsStart(void)
-{
- if (pmDispatch != NULL && pmDispatch->pmsStart != NULL)
- (*pmDispatch->pmsStart)();
-}
-
-/*
- * Park the stepper execution. This will force the stepper on this
- * processor to abandon its current step and stop. No changes to the
- * hardware state is made and any previous step is lost.
- *
- * This is used as the initial state at startup and when the step table
- * is being changed.
- *
+ * Initialize the Cstate change code.
*/
void
-pmsPark(void)
-{
- if (pmDispatch != NULL && pmDispatch->pmsPark != NULL)
- (*pmDispatch->pmsPark)();
-}
-
-/*
- * Control the Power Management Stepper.
- * Called from user state by the superuser.
- * Interrupts disabled.
- *
- * This interface is deprecated and is now a no-op.
- */
-kern_return_t
-pmsControl(__unused uint32_t request, __unused user_addr_t reqaddr,
- __unused uint32_t reqsize)
+power_management_init(void)
{
- return(KERN_SUCCESS);
+ if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
+ (*pmDispatch->cstateInit)();
}
/*
- * Broadcast a change to all processors including ourselves.
- *
- * Interrupts disabled.
+ * Called when the CPU is idle. It calls into the power management kext
+ * to determine the best way to idle the CPU.
*/
void
-pmsRun(uint32_t nstep)
+machine_idle(void)
{
- if (pmDispatch != NULL && pmDispatch->pmsRun != NULL)
- (*pmDispatch->pmsRun)(nstep);
-}
+ cpu_data_t *my_cpu = current_cpu_datap();
-/*
- * Build the tables needed for the stepper. This includes both the step
- * definitions and the step control table.
- *
- * We most absolutely need to be parked before this happens because we're
- * going to change the table. We also have to be complte about checking
- * for errors. A copy is always made because we don't want to be crippled
- * by not being able to change the table or description formats.
- *
- * We pass in a table of external functions and the new stepper def uses
- * the corresponding indexes rather than actual function addresses. This
- * is done so that a proper table can be built with the control syscall.
- * It can't supply addresses, so the index has to do. We internalize the
- * table so our caller does not need to keep it. Note that passing in a 0
- * will use the current function table. Also note that entry 0 is reserved
- * and must be 0, we will check and fail the build.
- *
- * The platformData parameter is a 32-bit word of data that is passed unaltered
- * to the set function.
- *
- * The queryFunc parameter is the address of a function that will return the
- * current state of the platform. The format of the data returned is the same
- * as the platform specific portions of pmsSetCmd, i.e., pmsXClk, pmsVoltage,
- * and any part of pmsPowerID that is maintained by the platform hardware
- * (an example would be the values of the gpios that correspond to pmsPowerID).
- * The value should be constructed by querying hardware rather than returning
- * a value cached by software. One of the intents of this function is to help
- * recover lost or determine initial power states.
- *
- */
-kern_return_t
-pmsBuild(pmsDef *pd, uint32_t pdsize, pmsSetFunc_t *functab,
- uint32_t platformData, pmsQueryFunc_t queryFunc)
-{
- kern_return_t rc = 0;
+ if (my_cpu == NULL)
+ goto out;
- if (pmDispatch != NULL && pmDispatch->pmsBuild != NULL)
- rc = (*pmDispatch->pmsBuild)(pd, pdsize, functab,
- platformData, queryFunc);
+ my_cpu->lcpu.state = LCPU_IDLE;
+ DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
+ MARK_CPU_IDLE(cpu_number());
- return(rc);
-}
+ if (pmInitDone) {
+ /*
+ * Handle case where ml_set_maxbusdelay() or ml_set_maxintdelay()
+ * were called prior to the CPU PM kext being registered. We do
+ * this here since we know at this point since it'll be at idle
+ * where the decision using these values will be used.
+ */
+ if (earlyMaxBusDelay != DELAY_UNSET)
+ ml_set_maxbusdelay((uint32_t)(earlyMaxBusDelay & 0xFFFFFFFF));
+ if (earlyMaxIntDelay != DELAY_UNSET)
+ ml_set_maxintdelay(earlyMaxIntDelay);
+ }
-/*
- * Load a new ratio/VID table.
- *
- * Note that this interface is specific to the Intel SpeedStep implementation.
- * It is expected that this will only be called once to override the default
- * ratio/VID table when the platform starts.
- *
- * Normally, the table will need to be replaced at the same time that the
- * stepper program proper is replaced, as the PState indices from an old
- * program may no longer be valid. When replacing the default program this
- * should not be a problem as any new table will have at least two PState
- * entries and the default program only references P0 and P1.
- */
-kern_return_t
-pmsCPULoadVIDTable(uint16_t *tablep, int nstates)
-{
- if (pmDispatch != NULL && pmDispatch->pmsCPULoadVIDTable != NULL)
- return((*pmDispatch->pmsCPULoadVIDTable)(tablep, nstates));
+ if (pmInitDone
+ && pmDispatch != NULL
+ && pmDispatch->MachineIdle != NULL)
+ (*pmDispatch->MachineIdle)(0x7FFFFFFFFFFFFFFFULL);
else {
- int i;
-
- if (nstates > MAX_PSTATES)
- return(KERN_FAILURE);
+ /*
+ * If no power management, re-enable interrupts and halt.
+ * This will keep the CPU from spinning through the scheduler
+ * and will allow at least some minimal power savings (but it
+ * cause problems in some MP configurations w.r.t. the APIC
+ * stopping during a GV3 transition).
+ */
+ pal_hlt();
- for (i = 0; i < nstates; i += 1)
- pmInitState.VIDTable[i] = tablep[i];
+ /* Once woken, re-disable interrupts. */
+ pal_cli();
}
- return(KERN_SUCCESS);
-}
-
-/*
- * Set the (global) PState limit. CPUs will not be permitted to run at
- * a lower (more performant) PState than this.
- */
-kern_return_t
-pmsCPUSetPStateLimit(uint32_t limit)
-{
- if (pmDispatch != NULL && pmDispatch->pmsCPUSetPStateLimit != NULL)
- return((*pmDispatch->pmsCPUSetPStateLimit)(limit));
-
- pmInitState.PLimit = limit;
- return(KERN_SUCCESS);
-}
-
-/*
- * Initialize the Cstate change code.
- */
-void
-power_management_init(void)
-{
- static boolean_t initialized = FALSE;
/*
- * Initialize the lock for the KEXT initialization.
+ * Mark the CPU as running again.
*/
- if (!initialized) {
- simple_lock_init(&pm_init_lock, 0);
- initialized = TRUE;
- }
-
- if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
- (*pmDispatch->cstateInit)();
-}
+ MARK_CPU_ACTIVE(cpu_number());
+ DBGLOG(cpu_handle, cpu_number(), MP_UNIDLE);
+ my_cpu->lcpu.state = LCPU_RUN;
-/*
- * ACPI calls the following routine to set/update mwait hints. A table
- * (possibly null) specifies the available Cstates and their hints, all
- * other states are assumed to be invalid. ACPI may update available
- * states to change the nap policy (for example, while AC power is
- * available).
- */
-kern_return_t
-Cstate_table_set(Cstate_hint_t *tablep, unsigned int nstates)
-{
- if (forcenap)
- return(KERN_SUCCESS);
-
- if (pmDispatch != NULL && pmDispatch->cstateTableSet != NULL)
- return((*pmDispatch->cstateTableSet)(tablep, nstates));
- else {
- unsigned int i;
-
- for (i = 0; i < nstates; i += 1) {
- pmInitState.CStates[i].number = tablep[i].number;
- pmInitState.CStates[i].hint = tablep[i].hint;
- }
-
- pmInitState.CStatesCount = nstates;
- }
- return(KERN_SUCCESS);
-}
-
-/*
- * Called when the CPU is idle. It will choose the best C state to
- * be in.
- */
-void
-machine_idle_cstate(boolean_t halted)
-{
- if (pmInitDone
- && pmDispatch != NULL
- && pmDispatch->cstateMachineIdle != NULL)
- (*pmDispatch->cstateMachineIdle)(!halted ?
- 0x7FFFFFFFFFFFFFFFULL : 0ULL);
- else if (halted) {
- /*
- * If no power managment and a processor is taken off-line,
- * then invalidate the cache and halt it (it will not be able
- * to be brought back on-line without resetting the CPU).
- */
- __asm__ volatile ( "wbinvd; hlt" );
- } else {
- /*
- * If no power management, re-enable interrupts and halt.
- * This will keep the CPU from spinning through the scheduler
- * and will allow at least some minimal power savings (but it
- * may cause problems in some MP configurations w.r.t to the
- * APIC stopping during a P-State transition).
- */
- __asm__ volatile ( "sti; hlt" );
- }
+ /*
+ * Re-enable interrupts.
+ */
+ out:
+ pal_sti();
}
/*
void
pmCPUHalt(uint32_t reason)
{
+ cpu_data_t *cpup = current_cpu_datap();
switch (reason) {
case PM_HALT_DEBUG:
- __asm__ volatile ("wbinvd; hlt");
+ cpup->lcpu.state = LCPU_PAUSE;
+ pal_stop_cpu(FALSE);
break;
case PM_HALT_PANIC:
- __asm__ volatile ("cli; wbinvd; hlt");
+ cpup->lcpu.state = LCPU_PAUSE;
+ pal_stop_cpu(TRUE);
break;
case PM_HALT_NORMAL:
default:
- __asm__ volatile ("cli");
+ pal_cli();
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->pmCPUHalt != NULL) {
+ /*
+ * Halt the CPU (and put it in a low power state.
+ */
(*pmDispatch->pmCPUHalt)();
- } else {
- cpu_data_t *cpup = current_cpu_datap();
+ /*
+ * We've exited halt, so get the the CPU schedulable again.
+ */
+ i386_init_slave_fast();
+
+ panic("init_slave_fast returned");
+ } else
+ {
/*
* If no power managment and a processor is taken off-line,
* then invalidate the cache and halt it (it will not be able
* to be brought back on-line without resetting the CPU).
*/
__asm__ volatile ("wbinvd");
- cpup->lcpu.halted = TRUE;
- __asm__ volatile ( "wbinvd; hlt" );
+ cpup->lcpu.state = LCPU_HALT;
+ pal_stop_cpu(FALSE);
+
+ panic("back from Halt");
}
+
break;
}
}
-/*
- * Called to initialize the power management structures for the CPUs.
- */
void
-pmCPUStateInit(void)
+pmMarkAllCPUsOff(void)
{
- if (pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
- (*pmDispatch->pmCPUStateInit)();
+ if (pmInitDone
+ && pmDispatch != NULL
+ && pmDispatch->markAllCPUsOff != NULL)
+ (*pmDispatch->markAllCPUsOff)();
}
static void
pmInitComplete(void)
{
+ if (earlyTopology
+ && pmDispatch != NULL
+ && pmDispatch->pmCPUStateInit != NULL) {
+ (*pmDispatch->pmCPUStateInit)();
+ earlyTopology = FALSE;
+ }
+
pmInitDone = 1;
}
return(cpup->lcpu.core);
}
+static x86_die_t *
+pmGetDie(int cpu)
+{
+ return(cpu_to_die(cpu));
+}
+
+static x86_die_t *
+pmGetMyDie(void)
+{
+ cpu_data_t *cpup = current_cpu_datap();
+
+ return(cpup->lcpu.die);
+}
+
static x86_pkg_t *
pmGetPackage(int cpu)
{
{
cpu_data_t *cpup = current_cpu_datap();
- return(cpup->lcpu.core->package);
+ return(cpup->lcpu.package);
}
static void
/*
* Called to get the next deadline that has been set by the
* power management code.
+ * Note: a return of 0 from AICPM and this routine signifies
+ * that no deadline is set.
*/
uint64_t
pmCPUGetDeadline(cpu_data_t *cpu)
{
- uint64_t deadline = EndOfAllTime;
+ uint64_t deadline = 0;
if (pmInitDone
&& pmDispatch != NULL
uint64_t
pmCPUSetDeadline(cpu_data_t *cpu, uint64_t deadline)
{
- if (pmInitDone
+ if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->SetDeadline != NULL)
deadline = (*pmDispatch->SetDeadline)(&cpu->lcpu, deadline);
return(do_ipi);
}
+kern_return_t
+pmCPUExitHalt(int cpu)
+{
+ kern_return_t rc = KERN_INVALID_ARGUMENT;
+
+ if (pmInitDone
+ && pmDispatch != NULL
+ && pmDispatch->exitHalt != NULL)
+ rc = pmDispatch->exitHalt(cpu_to_lcpu(cpu));
+
+ return(rc);
+}
+
+kern_return_t
+pmCPUExitHaltToOff(int cpu)
+{
+ kern_return_t rc = KERN_INVALID_ARGUMENT;
+
+ if (pmInitDone
+ && pmDispatch != NULL
+ && pmDispatch->exitHaltToOff != NULL)
+ rc = pmDispatch->exitHaltToOff(cpu_to_lcpu(cpu));
+
+ return(rc);
+}
+
/*
- * Called when a CPU is being restarted after being powered off (as in S3).
+ * Called to initialize the power management structures for the CPUs.
*/
void
-pmCPUMarkRunning(cpu_data_t *cpu)
+pmCPUStateInit(void)
{
- if (pmInitDone
- && pmDispatch != NULL
- && pmDispatch->markCPURunning != NULL)
- (*pmDispatch->markCPURunning)(&cpu->lcpu);
+ if (pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
+ (*pmDispatch->pmCPUStateInit)();
+ else
+ earlyTopology = TRUE;
}
/*
- * Called from the HPET interrupt handler to perform the
- * necessary power management work.
+ * Called when a CPU is being restarted after being powered off (as in S3).
*/
void
-pmHPETInterrupt(void)
+pmCPUMarkRunning(cpu_data_t *cpu)
{
+ cpu_data_t *cpup = current_cpu_datap();
+
if (pmInitDone
&& pmDispatch != NULL
- && pmDispatch->HPETInterrupt != NULL)
- (*pmDispatch->HPETInterrupt)();
+ && pmDispatch->markCPURunning != NULL)
+ (*pmDispatch->markCPURunning)(&cpu->lcpu);
+ else
+ cpup->lcpu.state = LCPU_RUN;
}
/*
return(rc);
}
+/*
+ * Called to save the timer state used by power management prior
+ * to "sleeping".
+ */
+void
+pmTimerSave(void)
+{
+ if (pmDispatch != NULL
+ && pmDispatch->pmTimerStateSave != NULL)
+ (*pmDispatch->pmTimerStateSave)();
+}
+
+/*
+ * Called to restore the timer state used by power management after
+ * waking from "sleep".
+ */
+void
+pmTimerRestore(void)
+{
+ if (pmDispatch != NULL
+ && pmDispatch->pmTimerStateRestore != NULL)
+ (*pmDispatch->pmTimerStateRestore)();
+}
+
/*
* Set the worst-case time for the C4 to C2 transition.
* No longer does anything.
{
uint64_t max_snoop = 0;
- if (pmDispatch != NULL
+ if (pmInitDone
+ && pmDispatch != NULL
&& pmDispatch->getMaxSnoop != NULL)
max_snoop = pmDispatch->getMaxSnoop();
{
uint64_t max_delay = 0;
- if (pmDispatch != NULL
+ if (pmInitDone
+ && pmDispatch != NULL
&& pmDispatch->getMaxBusDelay != NULL)
max_delay = pmDispatch->getMaxBusDelay();
uint64_t maxdelay = mdelay;
if (pmDispatch != NULL
- && pmDispatch->setMaxBusDelay != NULL)
+ && pmDispatch->setMaxBusDelay != NULL) {
+ earlyMaxBusDelay = DELAY_UNSET;
pmDispatch->setMaxBusDelay(maxdelay);
- else
- pmInitState.maxBusDelay = maxdelay;
+ } else
+ earlyMaxBusDelay = maxdelay;
+}
+
+uint64_t
+ml_get_maxintdelay(void)
+{
+ uint64_t max_delay = 0;
+
+ if (pmDispatch != NULL
+ && pmDispatch->getMaxIntDelay != NULL)
+ max_delay = pmDispatch->getMaxIntDelay();
+
+ return(max_delay);
+}
+
+/*
+ * Set the maximum delay allowed for an interrupt.
+ */
+void
+ml_set_maxintdelay(uint64_t mdelay)
+{
+ if (pmDispatch != NULL
+ && pmDispatch->setMaxIntDelay != NULL) {
+ earlyMaxIntDelay = DELAY_UNSET;
+ pmDispatch->setMaxIntDelay(mdelay);
+ } else
+ earlyMaxIntDelay = mdelay;
+}
+
+boolean_t
+ml_get_interrupt_prewake_applicable()
+{
+ boolean_t applicable = FALSE;
+
+ if (pmInitDone
+ && pmDispatch != NULL
+ && pmDispatch->pmInterruptPrewakeApplicable != NULL)
+ applicable = pmDispatch->pmInterruptPrewakeApplicable();
+
+ return applicable;
}
/*
* We only look at the PAUSE and RESUME flags. The other flag(s)
* will not make any sense without the KEXT, so just ignore them.
*
- * We set the halted flag in the LCPU structure to indicate
- * that this CPU isn't to do anything. If it's the CPU we're
- * currently running on, then spin until the halted flag is
- * reset.
+ * We set the CPU's state to indicate that it's halted. If this
+ * is the CPU we're currently running on, then spin until the
+ * state becomes non-halted.
*/
if (flags & PM_SAFE_FL_PAUSE) {
- lcpu->halted = TRUE;
+ lcpu->state = LCPU_PAUSE;
if (lcpu == x86_lcpu()) {
- while (lcpu->halted)
+ while (lcpu->state == LCPU_PAUSE)
cpu_pause();
}
}
* get it out of it's spin loop.
*/
if (flags & PM_SAFE_FL_RESUME) {
- lcpu->halted = FALSE;
+ lcpu->state = LCPU_RUN;
}
}
}
+static uint32_t saved_run_count = 0;
+
+void
+machine_run_count(uint32_t count)
+{
+ if (pmDispatch != NULL
+ && pmDispatch->pmSetRunCount != NULL)
+ pmDispatch->pmSetRunCount(count);
+ else
+ saved_run_count = count;
+}
+
+boolean_t
+machine_processor_is_inactive(processor_t processor)
+{
+ int cpu = processor->cpu_id;
+
+ if (pmDispatch != NULL
+ && pmDispatch->pmIsCPUUnAvailable != NULL)
+ return(pmDispatch->pmIsCPUUnAvailable(cpu_to_lcpu(cpu)));
+ else
+ return(FALSE);
+}
+
+processor_t
+machine_choose_processor(processor_set_t pset,
+ processor_t preferred)
+{
+ int startCPU;
+ int endCPU;
+ int preferredCPU;
+ int chosenCPU;
+
+ if (!pmInitDone)
+ return(preferred);
+
+ if (pset == NULL) {
+ startCPU = -1;
+ endCPU = -1;
+ } else {
+ startCPU = pset->cpu_set_low;
+ endCPU = pset->cpu_set_hi;
+ }
+
+ if (preferred == NULL)
+ preferredCPU = -1;
+ else
+ preferredCPU = preferred->cpu_id;
+
+ if (pmDispatch != NULL
+ && pmDispatch->pmChooseCPU != NULL) {
+ chosenCPU = pmDispatch->pmChooseCPU(startCPU, endCPU, preferredCPU);
+
+ if (chosenCPU == -1)
+ return(NULL);
+ return(cpu_datap(chosenCPU)->cpu_processor);
+ }
+
+ return(preferred);
+}
+
+static int
+pmThreadGetUrgency(uint64_t *rt_period, uint64_t *rt_deadline)
+{
+
+ return(thread_get_urgency(rt_period, rt_deadline));
+}
+
+#if DEBUG
+uint32_t urgency_stats[64][THREAD_URGENCY_MAX];
+#endif
+
+#define URGENCY_NOTIFICATION_ASSERT_NS (5 * 1000 * 1000)
+uint64_t urgency_notification_assert_abstime_threshold, urgency_notification_max_recorded;
+
+void
+thread_tell_urgency(int urgency,
+ uint64_t rt_period,
+ uint64_t rt_deadline)
+{
+ uint64_t urgency_notification_time_start, delta;
+ boolean_t urgency_assert = (urgency_notification_assert_abstime_threshold != 0);
+ assert(get_preemption_level() > 0 || ml_get_interrupts_enabled() == FALSE);
+#if DEBUG
+ urgency_stats[cpu_number() % 64][urgency]++;
+#endif
+ if (!pmInitDone
+ || pmDispatch == NULL
+ || pmDispatch->pmThreadTellUrgency == NULL)
+ return;
+
+ KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_START, urgency, rt_period, (rt_deadline >> 32), rt_deadline, 0);
+
+ if (__improbable((urgency_assert == TRUE)))
+ urgency_notification_time_start = mach_absolute_time();
+
+ pmDispatch->pmThreadTellUrgency(urgency, rt_period, rt_deadline);
+
+ if (__improbable((urgency_assert == TRUE))) {
+ delta = mach_absolute_time() - urgency_notification_time_start;
+
+ if (__improbable(delta > urgency_notification_max_recorded)) {
+ /* This is not synchronized, but it doesn't matter
+ * if we (rarely) miss an event, as it is statistically
+ * unlikely that it will never recur.
+ */
+ urgency_notification_max_recorded = delta;
+
+ if (__improbable((delta > urgency_notification_assert_abstime_threshold) && !machine_timeout_suspended()))
+ panic("Urgency notification callout %p exceeded threshold, 0x%llx abstime units", pmDispatch->pmThreadTellUrgency, delta);
+ }
+ }
+
+ KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_URGENCY) | DBG_FUNC_END, urgency, rt_period, (rt_deadline >> 32), rt_deadline, 0);
+}
+
+void
+active_rt_threads(boolean_t active)
+{
+ if (!pmInitDone
+ || pmDispatch == NULL
+ || pmDispatch->pmActiveRTThreads == NULL)
+ return;
+
+ pmDispatch->pmActiveRTThreads(active);
+}
+
+static uint32_t
+pmGetSavedRunCount(void)
+{
+ return(saved_run_count);
+}
+
/*
* Returns the root of the package tree.
*/
return(cpu_datap(lcpu)->cpu_processor);
}
+static void
+pmReSyncDeadlines(int cpu)
+{
+ static boolean_t registered = FALSE;
+
+ if (!registered) {
+ PM_interrupt_register(&etimer_resync_deadlines);
+ registered = TRUE;
+ }
+
+ if ((uint32_t)cpu == current_cpu_datap()->lcpu.cpu_num)
+ etimer_resync_deadlines();
+ else
+ cpu_PM_interrupt(cpu);
+}
+
+static void
+pmSendIPI(int cpu)
+{
+ lapic_send_ipi(cpu, LAPIC_PM_INTERRUPT);
+}
+
+static void
+pmGetNanotimeInfo(pm_rtc_nanotime_t *rtc_nanotime)
+{
+ /*
+ * Make sure that nanotime didn't change while we were reading it.
+ */
+ do {
+ rtc_nanotime->generation = pal_rtc_nanotime_info.generation; /* must be first */
+ rtc_nanotime->tsc_base = pal_rtc_nanotime_info.tsc_base;
+ rtc_nanotime->ns_base = pal_rtc_nanotime_info.ns_base;
+ rtc_nanotime->scale = pal_rtc_nanotime_info.scale;
+ rtc_nanotime->shift = pal_rtc_nanotime_info.shift;
+ } while(pal_rtc_nanotime_info.generation != 0
+ && rtc_nanotime->generation != pal_rtc_nanotime_info.generation);
+}
+
+static uint32_t
+pmTimerQueueMigrate(int target_cpu)
+{
+ /* Call the etimer code to do this. */
+ return (target_cpu != cpu_number())
+ ? etimer_queue_migrate(target_cpu)
+ : 0;
+}
+
+
/*
* Called by the power management kext to register itself and to get the
* callbacks it might need into other kernel functions. This interface
pmCallBacks_t *callbacks)
{
if (callbacks != NULL && version == PM_DISPATCH_VERSION) {
- callbacks->InitState = &pmInitState;
- callbacks->setRTCPop = setPop;
- callbacks->resyncDeadlines = etimer_resync_deadlines;
- callbacks->initComplete= pmInitComplete;
- callbacks->GetLCPU = pmGetLogicalCPU;
- callbacks->GetCore = pmGetCore;
- callbacks->GetPackage = pmGetPackage;
- callbacks->GetMyLCPU = pmGetMyLogicalCPU;
- callbacks->GetMyCore = pmGetMyCore;
- callbacks->GetMyPackage= pmGetMyPackage;
- callbacks->CoresPerPkg = cpuid_info()->cpuid_cores_per_package;
- callbacks->GetPkgRoot = pmGetPkgRoot;
- callbacks->LockCPUTopology = pmLockCPUTopology;
- callbacks->GetHibernate = pmCPUGetHibernate;
- callbacks->LCPUtoProcessor = pmLCPUtoProcessor;
+ callbacks->setRTCPop = setPop;
+ callbacks->resyncDeadlines = pmReSyncDeadlines;
+ callbacks->initComplete = pmInitComplete;
+ callbacks->GetLCPU = pmGetLogicalCPU;
+ callbacks->GetCore = pmGetCore;
+ callbacks->GetDie = pmGetDie;
+ callbacks->GetPackage = pmGetPackage;
+ callbacks->GetMyLCPU = pmGetMyLogicalCPU;
+ callbacks->GetMyCore = pmGetMyCore;
+ callbacks->GetMyDie = pmGetMyDie;
+ callbacks->GetMyPackage = pmGetMyPackage;
+ callbacks->GetPkgRoot = pmGetPkgRoot;
+ callbacks->LockCPUTopology = pmLockCPUTopology;
+ callbacks->GetHibernate = pmCPUGetHibernate;
+ callbacks->LCPUtoProcessor = pmLCPUtoProcessor;
+ callbacks->ThreadBind = thread_bind;
+ callbacks->GetSavedRunCount = pmGetSavedRunCount;
+ callbacks->GetNanotimeInfo = pmGetNanotimeInfo;
+ callbacks->ThreadGetUrgency = pmThreadGetUrgency;
+ callbacks->RTCClockAdjust = rtc_clock_adjust;
+ callbacks->timerQueueMigrate = pmTimerQueueMigrate;
+ callbacks->topoParms = &topoParms;
+ callbacks->pmSendIPI = pmSendIPI;
+ callbacks->InterruptPending = lapic_is_interrupt_pending;
+ callbacks->IsInterrupting = lapic_is_interrupting;
+ callbacks->InterruptStats = lapic_interrupt_counts;
+ callbacks->DisableApicTimer = lapic_disable_timer;
+ } else {
+ panic("Version mis-match between Kernel and CPU PM");
}
if (cpuFuncs != NULL) {
pmDispatch = cpuFuncs;
+
+ if (earlyTopology
+ && pmDispatch->pmCPUStateInit != NULL) {
+ (*pmDispatch->pmCPUStateInit)();
+ earlyTopology = FALSE;
+ }
+
+ if (pmDispatch->pmIPIHandler != NULL) {
+ lapic_set_pm_func((i386_intr_func_t)pmDispatch->pmIPIHandler);
+ }
}
}
}
}
+/******************************************************************************
+ *
+ * All of the following are deprecated interfaces and no longer used.
+ *
+ ******************************************************************************/
+kern_return_t
+pmsControl(__unused uint32_t request, __unused user_addr_t reqaddr,
+ __unused uint32_t reqsize)
+{
+ return(KERN_SUCCESS);
+}
+
+void
+pmsInit(void)
+{
+}
+
+void
+pmsStart(void)
+{
+}
+
+void
+pmsPark(void)
+{
+}
+
+void
+pmsRun(__unused uint32_t nstep)
+{
+}
+
+kern_return_t
+pmsBuild(__unused pmsDef *pd, __unused uint32_t pdsize,
+ __unused pmsSetFunc_t *functab,
+ __unused uint32_t platformData, __unused pmsQueryFunc_t queryFunc)
+{
+ return(KERN_SUCCESS);
+}