X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..bb59bff194111743b33cc36712410b5656329d3c:/iokit/Kernel/IOCPU.cpp diff --git a/iokit/Kernel/IOCPU.cpp b/iokit/Kernel/IOCPU.cpp index fd87cc975..00504e9eb 100644 --- a/iokit/Kernel/IOCPU.cpp +++ b/iokit/Kernel/IOCPU.cpp @@ -37,11 +37,250 @@ extern "C" { #include } +#include + #include #include +#include +#include #include +#include #include +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include + +typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority, + 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; +}; +typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t; + +queue_head_t * +iocpu_get_platform_quiesce_queue(void); + +queue_head_t * +iocpu_get_platform_active_queue(void); + +void +iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, queue_head_t * init_queue); + +void +iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry); + +void +iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry); + +kern_return_t +iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority, + void * param1, void * param2, void * param3); + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define kBootCPUNumber 0 + +static iocpu_platform_action_entry_t * gIOAllActionsQueue; +static queue_head_t gIOSleepActionQueue; +static queue_head_t gIOWakeActionQueue; + +static queue_head_t iocpu_quiesce_queue; +static queue_head_t iocpu_active_queue; + +static queue_head_t gIOHaltRestartActionQueue; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +void +iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, __unused queue_head_t * init_queue) +{ +#if 0 + enum { kNumQuiesceActions = 2 }; + static iocpu_platform_action_entry_t quiesce_actions[kNumQuiesceActions] = + { + { { NULL, NULL }, (iocpu_platform_action_t) &clean_mmu_dcache, 97000, 0, 0, NULL }, + { { NULL, NULL }, (iocpu_platform_action_t) &arm_sleep, 99000, 0, 0, NULL }, + }; + unsigned int idx; + + for (idx = 0; idx < kNumQuiesceActions; idx++) + iocpu_add_platform_action(quiesce_queue, &quiesce_actions[idx]); +#endif +} + +queue_head_t * iocpu_get_platform_quiesce_queue(void) +{ + if (!iocpu_quiesce_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_quiesce_queue); +} + +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); +} + +void iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry) +{ + iocpu_platform_action_entry_t * next; + + queue_iterate(queue, next, iocpu_platform_action_entry_t *, link) + { + if (next->priority > entry->priority) + { + queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link); + return; + } + } + queue_enter(queue, entry, iocpu_platform_action_entry_t *, link); // at tail +} + +void iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry) +{ + remque(&entry->link); +} + +kern_return_t +iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority, + void * param1, void * param2, void * param3) +{ + kern_return_t ret = KERN_SUCCESS; + kern_return_t result = KERN_SUCCESS; + iocpu_platform_action_entry_t * next; + + queue_iterate(queue, next, iocpu_platform_action_entry_t *, link) + { + uint32_t pri = (next->priority < 0) ? -next->priority : next->priority; + if ((pri >= first_priority) && (pri <= last_priority)) + { + //kprintf("[%p]", next->action); + ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3, next->name); + } + if (KERN_SUCCESS == result) + result = ret; + } + return (result); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +extern "C" kern_return_t +IOCPURunPlatformQuiesceActions(void) +{ + 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, 0U-1, + NULL, NULL, NULL)); +} + +static kern_return_t +IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority, + 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_name); + + ret = service->callPlatformFunction(function, false, + (void *)(uintptr_t) priority, param1, param2, param3); + + return (ret); +} + +static void +IOInstallServicePlatformAction(IOService * service, + const OSSymbol * key, queue_head_t * queue, + bool reverse) +{ + OSNumber * num; + iocpu_platform_action_entry_t * entry; + uint32_t priority; + + num = OSDynamicCast(OSNumber, service->getProperty(key)); + if (!num) + return; + + entry = IONew(iocpu_platform_action_entry_t, 1); + entry->action = &IOServicePlatformAction; + entry->name = service->getName(); + priority = num->unsigned32BitValue(); + if (reverse) + entry->priority = -priority; + else + entry->priority = priority; + entry->refcon0 = service; + entry->refcon1 = (void *) key; + + iocpu_add_platform_action(queue, entry); + entry->alloc_list = gIOAllActionsQueue; + 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); +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -69,20 +308,21 @@ void PE_cpu_signal(cpu_id_t source, cpu_id_t target) if (sourceCPU && targetCPU) sourceCPU->signalCPU(targetCPU); } -void PE_cpu_machine_init(cpu_id_t target, boolean_t boot) +void PE_cpu_machine_init(cpu_id_t target, boolean_t bootb) { IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target); - if (targetCPU) targetCPU->initCPU(boot); + if (targetCPU) targetCPU->initCPU(bootb); } void PE_cpu_machine_quiesce(cpu_id_t target) { IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target); - + if (targetCPU) targetCPU->quiesceCPU(); } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define super IOService @@ -105,27 +345,114 @@ static OSString *gIOCPUStateNames[kIOCPUStateCount]; void IOCPUSleepKernel(void) { - long cnt, numCPUs; - IOCPU *target; - - numCPUs = gIOCPUs->getCount(); - - // Sleep the CPUs. - cnt = numCPUs; - while (cnt--) { - target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt)); - if (target->getCPUState() == kIOCPUStateRunning) { - target->haltCPU(); + long cnt, numCPUs; + IOCPU *target; + IOCPU *bootCPU = NULL; + IOPMrootDomain *rootDomain = IOService::getPMRootDomain(); + + kprintf("IOCPUSleepKernel\n"); + + 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) + { + all = 0; + do + { + if (all) + all->release(); + all = iter->iterateAll(); + } + while (!iter->isValid()); + iter->release(); + + if (all) + { + 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); + } + all->release(); + } } - } - - // Wake the other CPUs. - for (cnt = 1; cnt < numCPUs; cnt++) { - target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt)); - if (target->getCPUState() == kIOCPUStateStopped) { - processor_start(target->getMachProcessor()); + + 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)); + + // 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(); + } + } + + 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; + while ((entry = gIOAllActionsQueue)) + { + gIOAllActionsQueue = entry->alloc_list; + iocpu_remove_platform_action(entry); + IODelete(entry, iocpu_platform_action_entry_t, 1); + } + + 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 = 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()); + } } - } } void IOCPU::initCPUs(void) @@ -180,7 +507,7 @@ bool IOCPU::start(IOService *provider) 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); @@ -227,9 +554,12 @@ bool IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject) bool IOCPU::serializeProperties(OSSerialize *serialize) const { - super::setProperty(gIOCPUStateKey, gIOCPUStateNames[_cpuState]); - - return super::serializeProperties(serialize); + bool result; + OSDictionary *dict = dictionaryWithProperties(); + dict->setObject(gIOCPUStateKey, gIOCPUStateNames[_cpuState]); + result = dict->serialize(serialize); + dict->release(); + return result; } IOReturn IOCPU::setProperties(OSObject *properties) @@ -368,6 +698,10 @@ void IOCPUInterruptController::setCPUInterruptProperties(IOService *service) OSData *tmpData; long tmpLong; + if ((service->getProperty(gIOInterruptControllersKey) != 0) && + (service->getProperty(gIOInterruptSpecifiersKey) != 0)) + return; + // Create the interrupt specifer array. specifier = OSArray::withCapacity(numCPUs); for (cnt = 0; cnt < numCPUs; cnt++) { @@ -392,12 +726,15 @@ void IOCPUInterruptController::setCPUInterruptProperties(IOService *service) void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu) { - ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, - (IOInterruptHandler)&IOCPUInterruptController::handleInterrupt, 0); - - enabledCPUs++; - - if (enabledCPUs == numCPUs) thread_wakeup(this); + IOInterruptHandler handler = OSMemberFunctionCast( + IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt); + + ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, 0); + + // Ensure that the increment is seen by all processors + OSIncrementAtomic(&enabledCPUs); + + if (enabledCPUs == numCPUs) thread_wakeup(this); } IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,