#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 <kern/sched_prim.h>
#include <i386/lapic.h>
int idlehalt = 1;
extern int disableConsoleOutput;
decl_simple_lock_data(,pm_init_lock);
pmDispatch_t *pmDispatch = NULL;
static uint32_t pmInitDone = 0;
void
power_management_init(void)
{
static boolean_t initialized = FALSE;
if (!initialized) {
simple_lock_init(&pm_init_lock, 0);
initialized = TRUE;
}
if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
(*pmDispatch->cstateInit)();
}
void
machine_idle(void)
{
cpu_data_t *my_cpu = current_cpu_datap();
if (my_cpu == NULL)
goto out;
if (!idlehalt)
goto out;
my_cpu->lcpu.state = LCPU_IDLE;
DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
MARK_CPU_IDLE(cpu_number());
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->cstateMachineIdle != NULL)
(*pmDispatch->cstateMachineIdle)(0x7FFFFFFFFFFFFFFFULL);
else {
__asm__ volatile ("sti; hlt");
}
MARK_CPU_ACTIVE(cpu_number());
DBGLOG(cpu_handle, cpu_number(), MP_UNIDLE);
my_cpu->lcpu.state = LCPU_RUN;
out:
__asm__ volatile("sti");
}
void
pmCPUHalt(uint32_t reason)
{
cpu_data_t *cpup = current_cpu_datap();
switch (reason) {
case PM_HALT_DEBUG:
cpup->lcpu.state = LCPU_PAUSE;
__asm__ volatile ("wbinvd; hlt");
break;
case PM_HALT_PANIC:
cpup->lcpu.state = LCPU_PAUSE;
__asm__ volatile ("cli; wbinvd; hlt");
break;
case PM_HALT_NORMAL:
default:
__asm__ volatile ("cli");
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->pmCPUHalt != NULL) {
(*pmDispatch->pmCPUHalt)();
i386_init_slave_fast();
panic("init_slave_fast returned");
} else {
__asm__ volatile ("wbinvd");
cpup->lcpu.state = LCPU_HALT;
__asm__ volatile ( "wbinvd; hlt" );
panic("back from Halt");
}
break;
}
}
void
pmMarkAllCPUsOff(void)
{
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->markAllCPUsOff != NULL)
(*pmDispatch->markAllCPUsOff)();
}
static void
pmInitComplete(void)
{
pmInitDone = 1;
}
static x86_lcpu_t *
pmGetLogicalCPU(int cpu)
{
return(cpu_to_lcpu(cpu));
}
static x86_lcpu_t *
pmGetMyLogicalCPU(void)
{
cpu_data_t *cpup = current_cpu_datap();
return(&cpup->lcpu);
}
static x86_core_t *
pmGetCore(int cpu)
{
return(cpu_to_core(cpu));
}
static x86_core_t *
pmGetMyCore(void)
{
cpu_data_t *cpup = current_cpu_datap();
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)
{
return(cpu_to_package(cpu));
}
static x86_pkg_t *
pmGetMyPackage(void)
{
cpu_data_t *cpup = current_cpu_datap();
return(cpup->lcpu.package);
}
static void
pmLockCPUTopology(int lock)
{
if (lock) {
simple_lock(&x86_topo_lock);
} else {
simple_unlock(&x86_topo_lock);
}
}
uint64_t
pmCPUGetDeadline(cpu_data_t *cpu)
{
uint64_t deadline = EndOfAllTime;
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->GetDeadline != NULL)
deadline = (*pmDispatch->GetDeadline)(&cpu->lcpu);
return(deadline);
}
uint64_t
pmCPUSetDeadline(cpu_data_t *cpu, uint64_t deadline)
{
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->SetDeadline != NULL)
deadline = (*pmDispatch->SetDeadline)(&cpu->lcpu, deadline);
return(deadline);
}
void
pmCPUDeadline(cpu_data_t *cpu)
{
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->Deadline != NULL)
(*pmDispatch->Deadline)(&cpu->lcpu);
}
boolean_t
pmCPUExitIdle(cpu_data_t *cpu)
{
boolean_t do_ipi;
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->exitIdle != NULL)
do_ipi = (*pmDispatch->exitIdle)(&cpu->lcpu);
else
do_ipi = TRUE;
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);
}
void
pmCPUStateInit(void)
{
if (pmDispatch != NULL && pmDispatch->pmCPUStateInit != NULL)
(*pmDispatch->pmCPUStateInit)();
}
void
pmCPUMarkRunning(cpu_data_t *cpu)
{
cpu_data_t *cpup = current_cpu_datap();
if (pmInitDone
&& pmDispatch != NULL
&& pmDispatch->markCPURunning != NULL)
(*pmDispatch->markCPURunning)(&cpu->lcpu);
else
cpup->lcpu.state = LCPU_RUN;
}
int
pmCPUControl(uint32_t cmd, void *datap)
{
int rc = -1;
if (pmDispatch != NULL
&& pmDispatch->pmCPUControl != NULL)
rc = (*pmDispatch->pmCPUControl)(cmd, datap);
return(rc);
}
void
pmTimerSave(void)
{
if (pmDispatch != NULL
&& pmDispatch->pmTimerStateSave != NULL)
(*pmDispatch->pmTimerStateSave)();
}
void
pmTimerRestore(void)
{
if (pmDispatch != NULL
&& pmDispatch->pmTimerStateRestore != NULL)
(*pmDispatch->pmTimerStateRestore)();
}
void
ml_set_maxsnoop(__unused uint32_t maxdelay)
{
}
unsigned
ml_get_maxsnoop(void)
{
uint64_t max_snoop = 0;
if (pmDispatch != NULL
&& pmDispatch->getMaxSnoop != NULL)
max_snoop = pmDispatch->getMaxSnoop();
return((unsigned)(max_snoop & 0xffffffff));
}
uint32_t
ml_get_maxbusdelay(void)
{
uint64_t max_delay = 0;
if (pmDispatch != NULL
&& pmDispatch->getMaxBusDelay != NULL)
max_delay = pmDispatch->getMaxBusDelay();
return((uint32_t)(max_delay & 0xffffffff));
}
void
ml_set_maxbusdelay(uint32_t mdelay)
{
uint64_t maxdelay = mdelay;
if (pmDispatch != NULL
&& pmDispatch->setMaxBusDelay != NULL)
pmDispatch->setMaxBusDelay(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);
}
void
ml_set_maxintdelay(uint64_t mdelay)
{
if (pmDispatch != NULL
&& pmDispatch->setMaxIntDelay != NULL)
pmDispatch->setMaxIntDelay(mdelay);
}
void
pmSafeMode(x86_lcpu_t *lcpu, uint32_t flags)
{
if (pmDispatch != NULL
&& pmDispatch->pmCPUSafeMode != NULL)
pmDispatch->pmCPUSafeMode(lcpu, flags);
else {
if (flags & PM_SAFE_FL_PAUSE) {
lcpu->state = LCPU_PAUSE;
if (lcpu == x86_lcpu()) {
while (lcpu->state == LCPU_PAUSE)
cpu_pause();
}
}
if (flags & PM_SAFE_FL_RESUME) {
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_cpu_is_inactive(int cpu)
{
if (pmDispatch != NULL
&& pmDispatch->pmIsCPUUnAvailable != NULL)
return(pmDispatch->pmIsCPUUnAvailable(cpu_to_lcpu(cpu)));
else
return(FALSE);
}
static uint32_t
pmGetSavedRunCount(void)
{
return(saved_run_count);
}
static x86_pkg_t *
pmGetPkgRoot(void)
{
return(x86_pkgs);
}
static boolean_t
pmCPUGetHibernate(int cpu)
{
return(cpu_datap(cpu)->cpu_hibernate);
}
static processor_t
pmLCPUtoProcessor(int lcpu)
{
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 rtc_nanotime_t *
pmGetNanotimeInfo(void)
{
return(&rtc_nanotime_info);
}
void
pmKextRegister(uint32_t version, pmDispatch_t *cpuFuncs,
pmCallBacks_t *callbacks)
{
if (callbacks != NULL && version == PM_DISPATCH_VERSION) {
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->pmSendIPI = pmSendIPI;
callbacks->GetNanotimeInfo = pmGetNanotimeInfo;
callbacks->topoParms = &topoParms;
} else {
panic("Version mis-match between Kernel and CPU PM");
}
if (cpuFuncs != NULL) {
pmDispatch = cpuFuncs;
if (pmDispatch->pmIPIHandler != NULL) {
lapic_set_pm_func((i386_intr_func_t)pmDispatch->pmIPIHandler);
}
}
}
void
pmUnRegister(pmDispatch_t *cpuFuncs)
{
if (cpuFuncs != NULL && pmDispatch == cpuFuncs) {
pmDispatch = NULL;
}
}
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);
}