#include <IOKit/IOLib.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/pwr_mgt/RootDomain.h>
+#include <IOKit/pwr_mgt/IOPMPrivate.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOKitKeysPrivate.h>
#include <IOKit/IOCPU.h>
#include <kern/queue.h>
typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
- void * param1, void * param2, void * param3);
+ void * param1, void * param2, void * param3,
+ const char * name);
struct iocpu_platform_action_entry
{
queue_chain_t link;
iocpu_platform_action_t action;
int32_t priority;
+ const char * name;
void * refcon0;
void * refcon1;
struct iocpu_platform_action_entry * alloc_list;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#define kBootCPUNumber 0
static iocpu_platform_action_entry_t * gIOAllActionsQueue;
static queue_head_t gIOSleepActionQueue;
static queue_head_t iocpu_quiesce_queue;
static queue_head_t iocpu_active_queue;
+static queue_head_t gIOHaltRestartActionQueue;
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void
queue_head_t * iocpu_get_platform_active_queue(void)
{
+ if (!iocpu_active_queue.next)
+ {
+ queue_init(&iocpu_quiesce_queue);
+ queue_init(&iocpu_active_queue);
+ iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
+ }
return (&iocpu_active_queue);
}
if ((pri >= first_priority) && (pri <= last_priority))
{
//kprintf("[%p]", next->action);
- ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3);
+ ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3, next->name);
}
if (KERN_SUCCESS == result)
result = ret;
extern "C" kern_return_t
IOCPURunPlatformQuiesceActions(void)
{
- return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0UL-1,
+ return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0U-1,
NULL, NULL, NULL));
}
extern "C" kern_return_t
IOCPURunPlatformActiveActions(void)
{
- return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0UL-1,
+ return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0U-1,
NULL, NULL, NULL));
}
static kern_return_t
IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
- void * param1, void * param2, void * param3)
+ void * param1, void * param2, void * param3,
+ const char * service_name)
{
IOReturn ret;
IOService * service = (IOService *) refcon0;
const OSSymbol * function = (const OSSymbol *) refcon1;
- kprintf("%s -> %s\n", function->getCStringNoCopy(), service->getName());
+ kprintf("%s -> %s\n", function->getCStringNoCopy(), service_name);
ret = service->callPlatformFunction(function, false,
- (void *) priority, param1, param2, param3);
+ (void *)(uintptr_t) priority, param1, param2, param3);
return (ret);
}
entry = IONew(iocpu_platform_action_entry_t, 1);
entry->action = &IOServicePlatformAction;
+ entry->name = service->getName();
priority = num->unsigned32BitValue();
if (reverse)
entry->priority = -priority;
gIOAllActionsQueue = entry;
}
+extern "C" kern_return_t
+IOCPURunPlatformHaltRestartActions(uint32_t message)
+{
+ kern_return_t ret;
+ IORegistryIterator * iter;
+ OSOrderedSet * all;
+ IOService * service;
+
+ if (!gIOHaltRestartActionQueue.next)
+ {
+ queue_init(&gIOHaltRestartActionQueue);
+ iter = IORegistryIterator::iterateOver(gIOServicePlane,
+ kIORegistryIterateRecursively);
+ if (iter)
+ {
+ all = 0;
+ do
+ {
+ if (all) all->release();
+ all = iter->iterateAll();
+ }
+ while (!iter->isValid());
+ iter->release();
+ if (all)
+ {
+ while((service = (IOService *) all->getFirstObject()))
+ {
+ IOInstallServicePlatformAction(service, gIOPlatformHaltRestartActionKey, &gIOHaltRestartActionQueue, false);
+ all->removeObject(service);
+ }
+ all->release();
+ }
+ }
+ }
+ ret = iocpu_run_platform_actions(&gIOHaltRestartActionQueue, 0, 0U-1,
+ (void *)(uintptr_t) message, NULL, NULL);
+ return (ret);
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
kern_return_t PE_cpu_start(cpu_id_t target,
if (targetCPU) targetCPU->quiesceCPU();
}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define super IOService
{
long cnt, numCPUs;
IOCPU *target;
-
+ IOCPU *bootCPU = NULL;
+ IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
+
kprintf("IOCPUSleepKernel\n");
- OSIterator * iter;
- IOService * service;
+ IORegistryIterator * iter;
+ OSOrderedSet * all;
+ IOService * service;
+
+ rootDomain->tracePoint( kIOPMTracePointSleepPlatformActions );
queue_init(&gIOSleepActionQueue);
queue_init(&gIOWakeActionQueue);
+ queue_init(&gIOHaltRestartActionQueue);
iter = IORegistryIterator::iterateOver( gIOServicePlane,
kIORegistryIterateRecursively );
if( iter)
{
- do
+ all = 0;
+ do
+ {
+ if (all)
+ all->release();
+ all = iter->iterateAll();
+ }
+ while (!iter->isValid());
+ iter->release();
+
+ if (all)
{
- iter->reset();
- while((service = (IOService *) iter->getNextObject()))
+ while((service = (IOService *) all->getFirstObject()))
{
IOInstallServicePlatformAction(service, gIOPlatformSleepActionKey, &gIOSleepActionQueue, false);
IOInstallServicePlatformAction(service, gIOPlatformWakeActionKey, &gIOWakeActionQueue, true);
IOInstallServicePlatformAction(service, gIOPlatformQuiesceActionKey, iocpu_get_platform_quiesce_queue(), false);
IOInstallServicePlatformAction(service, gIOPlatformActiveActionKey, iocpu_get_platform_active_queue(), true);
+ IOInstallServicePlatformAction(service, gIOPlatformHaltRestartActionKey, &gIOHaltRestartActionQueue, false);
+ all->removeObject(service);
}
- }
- while( !service && !iter->isValid());
- iter->release();
+ all->release();
+ }
}
- iocpu_run_platform_actions(&gIOSleepActionQueue, 0, 0UL-1,
+ iocpu_run_platform_actions(&gIOSleepActionQueue, 0, 0U-1,
NULL, NULL, NULL);
+ rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
+
numCPUs = gIOCPUs->getCount();
// Sleep the CPUs.
cnt = numCPUs;
- while (cnt--) {
- target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
- if (target->getCPUState() == kIOCPUStateRunning) {
- target->haltCPU();
- }
+ while (cnt--)
+ {
+ target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
+
+ // We make certain that the bootCPU is the last to sleep
+ // We'll skip it for now, and halt it after finishing the
+ // non-boot CPU's.
+ if (target->getCPUNumber() == kBootCPUNumber)
+ {
+ bootCPU = target;
+ } else if (target->getCPUState() == kIOCPUStateRunning)
+ {
+ target->haltCPU();
+ }
}
- iocpu_run_platform_actions(&gIOWakeActionQueue, 0, 0UL-1,
+ rootDomain->tracePoint( kIOPMTracePointSleepPlatformDriver );
+
+ // Now sleep the boot CPU.
+ if (bootCPU)
+ bootCPU->haltCPU();
+
+ rootDomain->tracePoint( kIOPMTracePointWakePlatformActions );
+
+ iocpu_run_platform_actions(&gIOWakeActionQueue, 0, 0U-1,
NULL, NULL, NULL);
iocpu_platform_action_entry_t * entry;
IODelete(entry, iocpu_platform_action_entry_t, 1);
}
- if (!queue_empty(&gIOSleepActionQueue))
- IOPanic("gIOSleepActionQueue");
- if (!queue_empty(&gIOWakeActionQueue))
- IOPanic("gIOWakeActionQueue");
+ if (!queue_empty(&gIOSleepActionQueue)) panic("gIOSleepActionQueue");
+ if (!queue_empty(&gIOWakeActionQueue)) panic("gIOWakeActionQueue");
+ if (!queue_empty(&gIOHaltRestartActionQueue)) panic("gIOHaltRestartActionQueue");
+ gIOHaltRestartActionQueue.next = 0;
+ rootDomain->tracePoint( kIOPMTracePointWakeCPUs );
+
// Wake the other CPUs.
- for (cnt = 1; cnt < numCPUs; cnt++) {
- target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
- if (target->getCPUState() == kIOCPUStateStopped) {
- processor_start(target->getMachProcessor());
- }
+ for (cnt = 0; cnt < numCPUs; cnt++)
+ {
+ target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
+
+ // Skip the already-woken boot CPU.
+ if ((target->getCPUNumber() != kBootCPUNumber)
+ && (target->getCPUState() == kIOCPUStateStopped))
+ {
+ processor_start(target->getMachProcessor());
+ }
}
}
provider->setProperty("timebase-frequency", timebaseFrequency);
timebaseFrequency->release();
- super::setProperty("IOCPUID", (UInt32)this, 32);
+ super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t)*8);
setCPUNumber(0);
setCPUState(kIOCPUStateUnregistered);
IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, 0);
-
- enabledCPUs++;
-
- if (enabledCPUs == numCPUs) thread_wakeup(this);
+
+ // Ensure that the increment is seen by all processors
+ OSIncrementAtomic(&enabledCPUs);
+
+ if (enabledCPUs == numCPUs) thread_wakeup(this);
}
IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,