]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCPU.cpp
xnu-2782.20.48.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
index d0e8b868d6582ecf8ce222fa0c39448c8af25d9e..00504e9ebaf1da9f9ed2e964c5ffdf509a083e93 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
 #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>
@@ -50,13 +51,15 @@ extern "C" {
 #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;
@@ -93,6 +96,8 @@ 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 
@@ -125,6 +130,12 @@ queue_head_t * iocpu_get_platform_quiesce_queue(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);
 }
 
@@ -162,7 +173,7 @@ iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32
        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;
@@ -188,16 +199,17 @@ IOCPURunPlatformActiveActions(void)
 
 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);
 }
@@ -217,6 +229,7 @@ IOInstallServicePlatformAction(IOService * service,
 
     entry = IONew(iocpu_platform_action_entry_t, 1);
     entry->action = &IOServicePlatformAction;
+    entry->name = service->getName();
     priority = num->unsigned32BitValue();
     if (reverse)
        entry->priority = -priority;
@@ -230,6 +243,45 @@ IOInstallServicePlatformAction(IOService * service,
     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,
@@ -296,37 +348,54 @@ void IOCPUSleepKernel(void)
     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 
        {
-           iter->reset();
-           while((service = (IOService *) iter->getNextObject()))
+           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);
            }
-       }
-       while( !service && !iter->isValid());
-       iter->release();
+           all->release();
+       }       
     }
 
     iocpu_run_platform_actions(&gIOSleepActionQueue, 0, 0U-1,
                                NULL, NULL, NULL);
 
+    rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
+
     numCPUs = gIOCPUs->getCount();
     // Sleep the CPUs.
     cnt = numCPUs;
@@ -346,10 +415,14 @@ void IOCPUSleepKernel(void)
         }
     }
 
+    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);
 
@@ -361,11 +434,13 @@ void IOCPUSleepKernel(void)
        IODelete(entry, iocpu_platform_action_entry_t, 1);
     }
 
-    if (!queue_empty(&gIOSleepActionQueue))
-       panic("gIOSleepActionQueue");
-    if (!queue_empty(&gIOWakeActionQueue))
-       panic("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 = 0; cnt < numCPUs; cnt++) 
     {
@@ -432,7 +507,7 @@ bool IOCPU::start(IOService *provider)
   provider->setProperty("timebase-frequency", timebaseFrequency);
   timebaseFrequency->release();
   
-  super::setProperty("IOCPUID", (uintptr_t)this, sizeof(uintptr_t)*8);
+  super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t)*8);
   
   setCPUNumber(0);
   setCPUState(kIOCPUStateUnregistered);
@@ -655,10 +730,11 @@ void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
                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,