]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCPU.cpp
xnu-6153.41.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
28
29extern "C" {
30#include <machine/machine_routines.h>
31#include <pexpert/pexpert.h>
490019cf 32#include <kern/cpu_number.h>
5ba3f43e 33extern void kperf_kernel_configure(char *);
1c79356b
A
34}
35
36#include <IOKit/IOLib.h>
37#include <IOKit/IOPlatformExpert.h>
2d21ac55 38#include <IOKit/pwr_mgt/RootDomain.h>
316670eb 39#include <IOKit/pwr_mgt/IOPMPrivate.h>
1c79356b 40#include <IOKit/IOUserClient.h>
2d21ac55 41#include <IOKit/IOKitKeysPrivate.h>
1c79356b 42#include <IOKit/IOCPU.h>
39037602 43#include "IOKitKernelInternal.h"
1c79356b 44
2d21ac55
A
45/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
46#include <kern/queue.h>
cb323159 47#include <kern/sched_prim.h>
2d21ac55 48
39037602
A
49extern "C" void console_suspend();
50extern "C" void console_resume();
d9a64523
A
51extern "C" void sched_override_recommended_cores_for_sleep(void);
52extern "C" void sched_restore_recommended_cores_after_sleep(void);
39037602 53
2d21ac55 54typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
0a7de745
A
55 void * param1, void * param2, void * param3,
56 const char * name);
57
58struct iocpu_platform_action_entry {
59 queue_chain_t link;
60 iocpu_platform_action_t action;
61 int32_t priority;
62 const char * name;
63 void * refcon0;
64 void * refcon1;
65 boolean_t callout_in_progress;
66 struct iocpu_platform_action_entry * alloc_list;
2d21ac55
A
67};
68typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t;
69
2d21ac55
A
70/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71
5ba3f43e
A
72static IOLock *gIOCPUsLock;
73static OSArray *gIOCPUs;
74static const OSSymbol *gIOCPUStateKey;
75static OSString *gIOCPUStateNames[kIOCPUStateCount];
2d21ac55 76
0a7de745
A
77enum{
78 kQueueSleep = 0,
79 kQueueWake = 1,
80 kQueueQuiesce = 2,
81 kQueueActive = 3,
82 kQueueHaltRestart = 4,
83 kQueuePanic = 5,
84 kQueueCount = 6
3e170ce0 85};
2d21ac55 86
0a7de745
A
87const OSSymbol * gIOPlatformSleepActionKey;
88const OSSymbol * gIOPlatformWakeActionKey;
89const OSSymbol * gIOPlatformQuiesceActionKey;
90const OSSymbol * gIOPlatformActiveActionKey;
91const OSSymbol * gIOPlatformHaltRestartActionKey;
92const OSSymbol * gIOPlatformPanicActionKey;
2d21ac55 93
0a7de745
A
94static queue_head_t gActionQueues[kQueueCount];
95static const OSSymbol * gActionSymbols[kQueueCount];
2d21ac55 96
3e170ce0 97/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2d21ac55 98
3e170ce0
A
99static void
100iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry)
2d21ac55 101{
0a7de745 102 iocpu_platform_action_entry_t * next;
2d21ac55 103
0a7de745 104 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
2d21ac55 105 {
0a7de745
A
106 if (next->priority > entry->priority) {
107 queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link);
108 return;
109 }
2d21ac55 110 }
0a7de745 111 queue_enter(queue, entry, iocpu_platform_action_entry_t *, link); // at tail
2d21ac55
A
112}
113
3e170ce0
A
114static void
115iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry)
2d21ac55 116{
0a7de745 117 remque(&entry->link);
2d21ac55
A
118}
119
3e170ce0 120static kern_return_t
2d21ac55 121iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
0a7de745 122 void * param1, void * param2, void * param3, boolean_t allow_nested_callouts)
2d21ac55 123{
0a7de745
A
124 kern_return_t ret = KERN_SUCCESS;
125 kern_return_t result = KERN_SUCCESS;
126 iocpu_platform_action_entry_t * next;
2d21ac55 127
0a7de745 128 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
2d21ac55 129 {
0a7de745
A
130 uint32_t pri = (next->priority < 0) ? -next->priority : next->priority;
131 if ((pri >= first_priority) && (pri <= last_priority)) {
132 //kprintf("[%p]", next->action);
133 if (!allow_nested_callouts && !next->callout_in_progress) {
134 next->callout_in_progress = TRUE;
135 ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3, next->name);
136 next->callout_in_progress = FALSE;
137 } else if (allow_nested_callouts) {
138 ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3, next->name);
139 }
140 }
141 if (KERN_SUCCESS == result) {
142 result = ret;
143 }
144 }
145 return result;
2d21ac55
A
146}
147
148/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
149
0a7de745 150extern "C" kern_return_t
2d21ac55
A
151IOCPURunPlatformQuiesceActions(void)
152{
cb323159 153 assert(preemption_enabled() == false);
0a7de745
A
154 return iocpu_run_platform_actions(&gActionQueues[kQueueQuiesce], 0, 0U - 1,
155 NULL, NULL, NULL, TRUE);
2d21ac55
A
156}
157
0a7de745 158extern "C" kern_return_t
2d21ac55
A
159IOCPURunPlatformActiveActions(void)
160{
cb323159 161 assert(preemption_enabled() == false);
0a7de745
A
162 return iocpu_run_platform_actions(&gActionQueues[kQueueActive], 0, 0U - 1,
163 NULL, NULL, NULL, TRUE);
2d21ac55
A
164}
165
0a7de745 166extern "C" kern_return_t
3e170ce0
A
167IOCPURunPlatformHaltRestartActions(uint32_t message)
168{
0a7de745
A
169 if (!gActionQueues[kQueueHaltRestart].next) {
170 return kIOReturnNotReady;
171 }
172 return iocpu_run_platform_actions(&gActionQueues[kQueueHaltRestart], 0, 0U - 1,
173 (void *)(uintptr_t) message, NULL, NULL, TRUE);
3e170ce0
A
174}
175
0a7de745 176extern "C" kern_return_t
3e170ce0
A
177IOCPURunPlatformPanicActions(uint32_t message)
178{
0a7de745
A
179 // Don't allow nested calls of panic actions
180 if (!gActionQueues[kQueuePanic].next) {
181 return kIOReturnNotReady;
182 }
183 return iocpu_run_platform_actions(&gActionQueues[kQueuePanic], 0, 0U - 1,
184 (void *)(uintptr_t) message, NULL, NULL, FALSE);
5ba3f43e
A
185}
186
187
188extern "C" kern_return_t
5c9f4661 189IOCPURunPlatformPanicSyncAction(void *addr, uint32_t offset, uint32_t len)
5ba3f43e 190{
0a7de745
A
191 PE_panic_save_context_t context = {
192 .psc_buffer = addr,
193 .psc_offset = offset,
194 .psc_length = len
195 };
5ba3f43e 196
0a7de745
A
197 // Don't allow nested calls of panic actions
198 if (!gActionQueues[kQueuePanic].next) {
199 return kIOReturnNotReady;
200 }
201 return iocpu_run_platform_actions(&gActionQueues[kQueuePanic], 0, 0U - 1,
202 (void *)(uintptr_t)(kPEPanicSync), &context, NULL, FALSE);
3e170ce0
A
203}
204
205/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206
0a7de745 207static kern_return_t
2d21ac55 208IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
0a7de745
A
209 void * param1, void * param2, void * param3,
210 const char * service_name)
2d21ac55 211{
0a7de745
A
212 IOReturn ret;
213 IOService * service = (IOService *) refcon0;
214 const OSSymbol * function = (const OSSymbol *) refcon1;
2d21ac55 215
0a7de745 216 kprintf("%s -> %s\n", function->getCStringNoCopy(), service_name);
2d21ac55 217
0a7de745
A
218 ret = service->callPlatformFunction(function, false,
219 (void *)(uintptr_t) priority, param1, param2, param3);
2d21ac55 220
0a7de745 221 return ret;
2d21ac55
A
222}
223
224static void
3e170ce0 225IOInstallServicePlatformAction(IOService * service, uint32_t qidx)
2d21ac55 226{
0a7de745
A
227 iocpu_platform_action_entry_t * entry;
228 OSNumber * num;
229 uint32_t priority;
230 const OSSymbol * key = gActionSymbols[qidx];
231 queue_head_t * queue = &gActionQueues[qidx];
232 bool reverse;
233 bool uniq;
234
235 num = OSDynamicCast(OSNumber, service->getProperty(key));
236 if (!num) {
237 return;
238 }
239
240 reverse = false;
241 uniq = false;
242 switch (qidx) {
3e170ce0
A
243 case kQueueWake:
244 case kQueueActive:
0a7de745
A
245 reverse = true;
246 break;
3e170ce0
A
247 case kQueueHaltRestart:
248 case kQueuePanic:
0a7de745
A
249 uniq = true;
250 break;
251 }
252 if (uniq) {
253 queue_iterate(queue, entry, iocpu_platform_action_entry_t *, link)
254 {
255 if (service == entry->refcon0) {
256 return;
257 }
258 }
3e170ce0 259 }
2d21ac55 260
0a7de745
A
261 entry = IONew(iocpu_platform_action_entry_t, 1);
262 entry->action = &IOServicePlatformAction;
263 entry->name = service->getName();
264 priority = num->unsigned32BitValue();
265 if (reverse) {
266 entry->priority = -priority;
267 } else {
268 entry->priority = priority;
269 }
270 entry->refcon0 = service;
271 entry->refcon1 = (void *) key;
272 entry->callout_in_progress = FALSE;
2d21ac55 273
0a7de745 274 iocpu_add_platform_action(queue, entry);
2d21ac55 275}
1c79356b 276
3e170ce0
A
277/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
278
279void
280IOCPUInitialize(void)
fe8ab488 281{
0a7de745
A
282 gIOCPUsLock = IOLockAlloc();
283 gIOCPUs = OSArray::withCapacity(1);
284
285 for (uint32_t qidx = kQueueSleep; qidx < kQueueCount; qidx++) {
286 queue_init(&gActionQueues[qidx]);
287 }
288
289 gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
290
291 gIOCPUStateNames[kIOCPUStateUnregistered] =
292 OSString::withCStringNoCopy("Unregistered");
293 gIOCPUStateNames[kIOCPUStateUninitalized] =
294 OSString::withCStringNoCopy("Uninitalized");
295 gIOCPUStateNames[kIOCPUStateStopped] =
296 OSString::withCStringNoCopy("Stopped");
297 gIOCPUStateNames[kIOCPUStateRunning] =
298 OSString::withCStringNoCopy("Running");
299
300 gIOPlatformSleepActionKey = gActionSymbols[kQueueSleep]
301 = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey);
302 gIOPlatformWakeActionKey = gActionSymbols[kQueueWake]
303 = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey);
304 gIOPlatformQuiesceActionKey = gActionSymbols[kQueueQuiesce]
305 = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey);
306 gIOPlatformActiveActionKey = gActionSymbols[kQueueActive]
307 = OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey);
308 gIOPlatformHaltRestartActionKey = gActionSymbols[kQueueHaltRestart]
309 = OSSymbol::withCStringNoCopy(kIOPlatformHaltRestartActionKey);
310 gIOPlatformPanicActionKey = gActionSymbols[kQueuePanic]
311 = OSSymbol::withCStringNoCopy(kIOPlatformPanicActionKey);
3e170ce0
A
312}
313
314IOReturn
315IOInstallServicePlatformActions(IOService * service)
316{
0a7de745 317 IOLockLock(gIOCPUsLock);
5ba3f43e 318
0a7de745
A
319 IOInstallServicePlatformAction(service, kQueueHaltRestart);
320 IOInstallServicePlatformAction(service, kQueuePanic);
3e170ce0 321
0a7de745 322 IOLockUnlock(gIOCPUsLock);
5ba3f43e 323
0a7de745 324 return kIOReturnSuccess;
3e170ce0 325}
fe8ab488 326
3e170ce0
A
327IOReturn
328IORemoveServicePlatformActions(IOService * service)
329{
0a7de745
A
330 iocpu_platform_action_entry_t * entry;
331 iocpu_platform_action_entry_t * next;
3e170ce0 332
0a7de745 333 IOLockLock(gIOCPUsLock);
5ba3f43e 334
0a7de745
A
335 for (uint32_t qidx = kQueueSleep; qidx < kQueueCount; qidx++) {
336 next = (typeof(entry))queue_first(&gActionQueues[qidx]);
337 while (!queue_end(&gActionQueues[qidx], &next->link)) {
338 entry = next;
339 next = (typeof(entry))queue_next(&entry->link);
340 if (service == entry->refcon0) {
341 iocpu_remove_platform_action(entry);
342 IODelete(entry, iocpu_platform_action_entry_t, 1);
343 }
344 }
fe8ab488 345 }
3e170ce0 346
0a7de745 347 IOLockUnlock(gIOCPUsLock);
5ba3f43e 348
0a7de745 349 return kIOReturnSuccess;
fe8ab488
A
350}
351
3e170ce0 352
1c79356b
A
353/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
354
0a7de745
A
355kern_return_t
356PE_cpu_start(cpu_id_t target,
357 vm_offset_t start_paddr, vm_offset_t arg_paddr)
1c79356b 358{
0a7de745
A
359 IOCPU *targetCPU = (IOCPU *)target;
360
361 if (targetCPU == NULL) {
362 return KERN_FAILURE;
363 }
364 return targetCPU->startCPU(start_paddr, arg_paddr);
1c79356b
A
365}
366
0a7de745
A
367void
368PE_cpu_halt(cpu_id_t target)
1c79356b 369{
0a7de745
A
370 IOCPU *targetCPU = (IOCPU *)target;
371
372 targetCPU->haltCPU();
1c79356b
A
373}
374
0a7de745
A
375void
376PE_cpu_signal(cpu_id_t source, cpu_id_t target)
1c79356b 377{
0a7de745
A
378 IOCPU *sourceCPU = (IOCPU *)source;
379 IOCPU *targetCPU = (IOCPU *)target;
380
381 sourceCPU->signalCPU(targetCPU);
1c79356b
A
382}
383
0a7de745
A
384void
385PE_cpu_signal_deferred(cpu_id_t source, cpu_id_t target)
3e170ce0 386{
0a7de745
A
387 IOCPU *sourceCPU = (IOCPU *)source;
388 IOCPU *targetCPU = (IOCPU *)target;
3e170ce0 389
0a7de745 390 sourceCPU->signalCPUDeferred(targetCPU);
3e170ce0
A
391}
392
0a7de745
A
393void
394PE_cpu_signal_cancel(cpu_id_t source, cpu_id_t target)
3e170ce0 395{
0a7de745
A
396 IOCPU *sourceCPU = (IOCPU *)source;
397 IOCPU *targetCPU = (IOCPU *)target;
3e170ce0 398
0a7de745 399 sourceCPU->signalCPUCancel(targetCPU);
3e170ce0
A
400}
401
0a7de745
A
402void
403PE_cpu_machine_init(cpu_id_t target, boolean_t bootb)
1c79356b 404{
0a7de745 405 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
d9a64523 406
0a7de745
A
407 if (targetCPU == NULL) {
408 panic("%s: invalid target CPU %p", __func__, target);
409 }
d9a64523 410
0a7de745 411 targetCPU->initCPU(bootb);
5ba3f43e 412#if defined(__arm__) || defined(__arm64__)
0a7de745
A
413 if (!bootb && (targetCPU->getCPUNumber() == (UInt32)master_cpu)) {
414 ml_set_is_quiescing(false);
415 }
5ba3f43e 416#endif /* defined(__arm__) || defined(__arm64__) */
1c79356b
A
417}
418
0a7de745
A
419void
420PE_cpu_machine_quiesce(cpu_id_t target)
1c79356b 421{
0a7de745 422 IOCPU *targetCPU = (IOCPU*)target;
5ba3f43e 423#if defined(__arm__) || defined(__arm64__)
0a7de745
A
424 if (targetCPU->getCPUNumber() == (UInt32)master_cpu) {
425 ml_set_is_quiescing(true);
426 }
5ba3f43e 427#endif /* defined(__arm__) || defined(__arm64__) */
0a7de745 428 targetCPU->quiesceCPU();
5ba3f43e
A
429}
430
431#if defined(__arm__) || defined(__arm64__)
cb323159 432static perfmon_interrupt_handler_func pmi_handler = NULL;
2d21ac55 433
0a7de745
A
434kern_return_t
435PE_cpu_perfmon_interrupt_install_handler(perfmon_interrupt_handler_func handler)
5ba3f43e 436{
0a7de745 437 pmi_handler = handler;
5ba3f43e 438
0a7de745 439 return KERN_SUCCESS;
1c79356b
A
440}
441
0a7de745
A
442void
443PE_cpu_perfmon_interrupt_enable(cpu_id_t target, boolean_t enable)
5ba3f43e 444{
0a7de745 445 IOCPU *targetCPU = (IOCPU*)target;
5ba3f43e 446
0a7de745
A
447 if (targetCPU == nullptr) {
448 return;
449 }
d9a64523 450
0a7de745 451 if (enable) {
cb323159 452 targetCPU->getProvider()->registerInterrupt(1, targetCPU, (IOInterruptAction)pmi_handler, NULL);
0a7de745
A
453 targetCPU->getProvider()->enableInterrupt(1);
454 } else {
455 targetCPU->getProvider()->disableInterrupt(1);
456 }
5ba3f43e
A
457}
458#endif
593a1d5f 459
1c79356b
A
460/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
461
462#define super IOService
463
464OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
465OSMetaClassDefineReservedUnused(IOCPU, 0);
466OSMetaClassDefineReservedUnused(IOCPU, 1);
467OSMetaClassDefineReservedUnused(IOCPU, 2);
468OSMetaClassDefineReservedUnused(IOCPU, 3);
469OSMetaClassDefineReservedUnused(IOCPU, 4);
470OSMetaClassDefineReservedUnused(IOCPU, 5);
471OSMetaClassDefineReservedUnused(IOCPU, 6);
472OSMetaClassDefineReservedUnused(IOCPU, 7);
473
474/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
475
0a7de745
A
476void
477IOCPUSleepKernel(void)
1c79356b 478{
0a7de745
A
479#if defined(__x86_64__)
480 extern IOCPU *currentShutdownTarget;
481#endif
482 long cnt, numCPUs;
483 IOCPU *target;
484 IOCPU *bootCPU = NULL;
485 IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
6d2010ae 486
0a7de745 487 kprintf("IOCPUSleepKernel\n");
d9a64523 488#if defined(__arm64__)
0a7de745 489 sched_override_recommended_cores_for_sleep();
d9a64523 490#endif
2d21ac55 491
0a7de745
A
492 IORegistryIterator * iter;
493 OSOrderedSet * all;
494 IOService * service;
495
496 rootDomain->tracePoint( kIOPMTracePointSleepPlatformActions );
497
498 iter = IORegistryIterator::iterateOver( gIOServicePlane,
499 kIORegistryIterateRecursively );
500 if (iter) {
cb323159 501 all = NULL;
0a7de745
A
502 do{
503 if (all) {
504 all->release();
505 }
506 all = iter->iterateAll();
507 }while (!iter->isValid());
508 iter->release();
509
510 if (all) {
511 while ((service = (IOService *) all->getFirstObject())) {
512 for (uint32_t qidx = kQueueSleep; qidx <= kQueueActive; qidx++) {
513 IOInstallServicePlatformAction(service, qidx);
514 }
515 all->removeObject(service);
516 }
517 all->release();
518 }
519 }
520
521 iocpu_run_platform_actions(&gActionQueues[kQueueSleep], 0, 0U - 1,
522 NULL, NULL, NULL, TRUE);
2d21ac55 523
0a7de745 524 rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
6d2010ae 525
0a7de745
A
526 numCPUs = gIOCPUs->getCount();
527#if defined(__x86_64__)
528 currentShutdownTarget = NULL;
529#endif
530
cb323159
A
531 integer_t old_pri;
532 thread_t self = current_thread();
533
534 /*
535 * We need to boost this thread's priority to the maximum kernel priority to
536 * ensure we can urgently preempt ANY thread currently executing on the
537 * target CPU. Note that realtime threads have their own mechanism to eventually
538 * demote their priority below MAXPRI_KERNEL if they hog the CPU for too long.
539 */
540 old_pri = thread_kern_get_pri(self);
541 thread_kern_set_pri(self, thread_kern_get_kernel_maxpri());
542
0a7de745
A
543 // Sleep the CPUs.
544 cnt = numCPUs;
545 while (cnt--) {
546 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
547
548 // We make certain that the bootCPU is the last to sleep
549 // We'll skip it for now, and halt it after finishing the
550 // non-boot CPU's.
551 if (target->getCPUNumber() == (UInt32)master_cpu) {
552 bootCPU = target;
553 } else if (target->getCPUState() == kIOCPUStateRunning) {
554#if defined(__x86_64__)
555 currentShutdownTarget = target;
556#endif
557 target->haltCPU();
558 }
316670eb 559 }
316670eb 560
0a7de745
A
561 assert(bootCPU != NULL);
562 assert(cpu_number() == master_cpu);
563
564 console_suspend();
565
566 rootDomain->tracePoint( kIOPMTracePointSleepPlatformDriver );
567 rootDomain->stop_watchdog_timer();
568
cb323159
A
569 /*
570 * Now sleep the boot CPU, including calling the kQueueQuiesce actions.
571 * The system sleeps here.
572 */
573
0a7de745
A
574 bootCPU->haltCPU();
575
cb323159
A
576 /*
577 * The system is now coming back from sleep on the boot CPU.
578 * The kQueueActive actions have already been called.
579 */
580
0a7de745
A
581 rootDomain->start_watchdog_timer();
582 rootDomain->tracePoint( kIOPMTracePointWakePlatformActions );
583
584 console_resume();
585
586 iocpu_run_platform_actions(&gActionQueues[kQueueWake], 0, 0U - 1,
587 NULL, NULL, NULL, TRUE);
588
589 iocpu_platform_action_entry_t * entry;
590 for (uint32_t qidx = kQueueSleep; qidx <= kQueueActive; qidx++) {
591 while (!(queue_empty(&gActionQueues[qidx]))) {
592 entry = (typeof(entry))queue_first(&gActionQueues[qidx]);
593 iocpu_remove_platform_action(entry);
594 IODelete(entry, iocpu_platform_action_entry_t, 1);
3e170ce0 595 }
3e170ce0 596 }
2d21ac55 597
0a7de745 598 rootDomain->tracePoint( kIOPMTracePointWakeCPUs );
6d2010ae 599
0a7de745
A
600 // Wake the other CPUs.
601 for (cnt = 0; cnt < numCPUs; cnt++) {
602 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
5ba3f43e 603
0a7de745
A
604 // Skip the already-woken boot CPU.
605 if (target->getCPUNumber() != (UInt32)master_cpu) {
606 if (target->getCPUState() == kIOCPUStateRunning) {
607 panic("Spurious wakeup of cpu %u", (unsigned int)(target->getCPUNumber()));
608 }
609
610 if (target->getCPUState() == kIOCPUStateStopped) {
611 processor_start(target->getMachProcessor());
612 }
613 }
614 }
d9a64523
A
615
616#if defined(__arm64__)
0a7de745 617 sched_restore_recommended_cores_after_sleep();
d9a64523 618#endif
cb323159
A
619
620 thread_kern_set_pri(self, old_pri);
1c79356b
A
621}
622
0a7de745
A
623bool
624IOCPU::start(IOService *provider)
625{
626 OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
627
628 if (!super::start(provider)) {
629 return false;
630 }
631
632 _cpuGroup = gIOCPUs;
633 cpuNub = provider;
634
635 IOLockLock(gIOCPUsLock);
636 gIOCPUs->setObject(this);
637 IOLockUnlock(gIOCPUsLock);
638
639 // Correct the bus, cpu and timebase frequencies in the device tree.
640 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
641 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
642 } else {
643 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
644 }
645 provider->setProperty("bus-frequency", busFrequency);
646 busFrequency->release();
647
648 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
649 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
650 } else {
651 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
652 }
653 provider->setProperty("clock-frequency", cpuFrequency);
654 cpuFrequency->release();
655
656 timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
657 provider->setProperty("timebase-frequency", timebaseFrequency);
658 timebaseFrequency->release();
659
660 super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t) * 8);
661
662 setCPUNumber(0);
663 setCPUState(kIOCPUStateUnregistered);
664
665 return true;
666}
667
cb323159
A
668void
669IOCPU::detach(IOService *provider)
670{
671 super::detach(provider);
672 IOLockLock(gIOCPUsLock);
673 unsigned int index = gIOCPUs->getNextIndexOfObject(this, 0);
674 if (index != (unsigned int)-1) {
675 gIOCPUs->removeObject(index);
676 }
677 IOLockUnlock(gIOCPUsLock);
678}
679
0a7de745
A
680OSObject *
681IOCPU::getProperty(const OSSymbol *aKey) const
682{
683 if (aKey == gIOCPUStateKey) {
684 return gIOCPUStateNames[_cpuState];
685 }
686
687 return super::getProperty(aKey);
688}
689
690bool
691IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
692{
693 if (aKey == gIOCPUStateKey) {
694 return false;
695 }
696
697 return super::setProperty(aKey, anObject);
698}
699
700bool
701IOCPU::serializeProperties(OSSerialize *serialize) const
91447636 702{
0c530ab8
A
703 bool result;
704 OSDictionary *dict = dictionaryWithProperties();
0a7de745
A
705 if (!dict) {
706 return false;
707 }
0c530ab8
A
708 dict->setObject(gIOCPUStateKey, gIOCPUStateNames[_cpuState]);
709 result = dict->serialize(serialize);
0a7de745 710 dict->release();
0c530ab8 711 return result;
91447636
A
712}
713
0a7de745
A
714IOReturn
715IOCPU::setProperties(OSObject *properties)
91447636 716{
0a7de745
A
717 OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
718 OSString *stateStr;
719 IOReturn result;
720
cb323159 721 if (dict == NULL) {
0a7de745
A
722 return kIOReturnUnsupported;
723 }
724
725 stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
cb323159 726 if (stateStr != NULL) {
0a7de745
A
727 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
728 if (result != kIOReturnSuccess) {
729 return result;
730 }
731
732 if (setProperty(gIOCPUStateKey, stateStr)) {
733 return kIOReturnSuccess;
734 }
735
736 return kIOReturnUnsupported;
737 }
738
739 return kIOReturnUnsupported;
1c79356b
A
740}
741
0a7de745
A
742void
743IOCPU::signalCPU(IOCPU */*target*/)
1c79356b
A
744{
745}
746
0a7de745
A
747void
748IOCPU::signalCPUDeferred(IOCPU *target)
3e170ce0 749{
0a7de745
A
750 // Our CPU may not support deferred IPIs,
751 // so send a regular IPI by default
752 signalCPU(target);
3e170ce0
A
753}
754
0a7de745
A
755void
756IOCPU::signalCPUCancel(IOCPU */*target*/)
3e170ce0 757{
0a7de745
A
758 // Meant to cancel signals sent by
759 // signalCPUDeferred; unsupported
760 // by default
3e170ce0
A
761}
762
0a7de745
A
763void
764IOCPU::enableCPUTimeBase(bool /*enable*/)
1c79356b
A
765{
766}
767
0a7de745
A
768UInt32
769IOCPU::getCPUNumber(void)
1c79356b 770{
0a7de745 771 return _cpuNumber;
1c79356b
A
772}
773
0a7de745
A
774void
775IOCPU::setCPUNumber(UInt32 cpuNumber)
1c79356b 776{
0a7de745
A
777 _cpuNumber = cpuNumber;
778 super::setProperty("IOCPUNumber", _cpuNumber, 32);
1c79356b
A
779}
780
0a7de745
A
781UInt32
782IOCPU::getCPUState(void)
1c79356b 783{
0a7de745 784 return _cpuState;
1c79356b
A
785}
786
0a7de745
A
787void
788IOCPU::setCPUState(UInt32 cpuState)
1c79356b 789{
0a7de745
A
790 if (cpuState < kIOCPUStateCount) {
791 _cpuState = cpuState;
792 }
1c79356b
A
793}
794
0a7de745
A
795OSArray *
796IOCPU::getCPUGroup(void)
1c79356b 797{
0a7de745 798 return _cpuGroup;
1c79356b
A
799}
800
0a7de745
A
801UInt32
802IOCPU::getCPUGroupSize(void)
1c79356b 803{
0a7de745 804 return _cpuGroup->getCount();
1c79356b
A
805}
806
0a7de745
A
807processor_t
808IOCPU::getMachProcessor(void)
1c79356b 809{
0a7de745 810 return machProcessor;
1c79356b
A
811}
812
813
814/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
815
816#undef super
817#define super IOInterruptController
818
819OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
820
1c79356b
A
821OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
822OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
823OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
824OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
825OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
826
827
828
829/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
830
0a7de745
A
831IOReturn
832IOCPUInterruptController::initCPUInterruptController(int sources)
5ba3f43e
A
833{
834 return initCPUInterruptController(sources, sources);
835}
836
0a7de745
A
837IOReturn
838IOCPUInterruptController::initCPUInterruptController(int sources, int cpus)
1c79356b 839{
0a7de745
A
840 int cnt;
841
842 if (!super::init()) {
843 return kIOReturnInvalid;
844 }
5ba3f43e 845
0a7de745
A
846 numSources = sources;
847 numCPUs = cpus;
5ba3f43e 848
0a7de745 849 vectors = (IOInterruptVector *)IOMalloc(numSources * sizeof(IOInterruptVector));
cb323159 850 if (vectors == NULL) {
0a7de745
A
851 return kIOReturnNoMemory;
852 }
853 bzero(vectors, numSources * sizeof(IOInterruptVector));
854
855 // Allocate a lock for each vector
856 for (cnt = 0; cnt < numSources; cnt++) {
857 vectors[cnt].interruptLock = IOLockAlloc();
858 if (vectors[cnt].interruptLock == NULL) {
859 for (cnt = 0; cnt < numSources; cnt++) {
860 if (vectors[cnt].interruptLock != NULL) {
861 IOLockFree(vectors[cnt].interruptLock);
862 }
863 }
864 return kIOReturnNoResources;
865 }
866 }
5ba3f43e 867
0a7de745 868 ml_init_max_cpus(numSources);
5ba3f43e
A
869
870#if KPERF
0a7de745
A
871 /*
872 * kperf allocates based on the number of CPUs and requires them to all be
873 * accounted for.
874 */
875 boolean_t found_kperf = FALSE;
876 char kperf_config_str[64];
877 found_kperf = PE_parse_boot_arg_str("kperf", kperf_config_str, sizeof(kperf_config_str));
878 if (found_kperf && kperf_config_str[0] != '\0') {
879 kperf_kernel_configure(kperf_config_str);
880 }
881#endif /* KPERF */
882
883 return kIOReturnSuccess;
884}
885
886void
887IOCPUInterruptController::registerCPUInterruptController(void)
888{
889 registerService();
890
891 getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
892 this);
893}
894
895void
896IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
897{
898 int cnt;
899 OSArray *controller;
900 OSArray *specifier;
901 OSData *tmpData;
902 long tmpLong;
903
cb323159
A
904 if ((service->getProperty(gIOInterruptControllersKey) != NULL) &&
905 (service->getProperty(gIOInterruptSpecifiersKey) != NULL)) {
0a7de745
A
906 return;
907 }
908
909 // Create the interrupt specifer array.
910 specifier = OSArray::withCapacity(numSources);
911 for (cnt = 0; cnt < numSources; cnt++) {
912 tmpLong = cnt;
913 tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
914 specifier->setObject(tmpData);
915 tmpData->release();
916 }
917 ;
918
919 // Create the interrupt controller array.
920 controller = OSArray::withCapacity(numSources);
921 for (cnt = 0; cnt < numSources; cnt++) {
922 controller->setObject(gPlatformInterruptControllerName);
923 }
924
925 // Put the two arrays into the property table.
926 service->setProperty(gIOInterruptControllersKey, controller);
927 service->setProperty(gIOInterruptSpecifiersKey, specifier);
928 controller->release();
929 specifier->release();
930}
931
932void
933IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
1c79356b 934{
0c530ab8
A
935 IOInterruptHandler handler = OSMemberFunctionCast(
936 IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
937
5ba3f43e
A
938 assert(numCPUs > 0);
939
cb323159 940 ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, NULL);
39236c6e 941
5ba3f43e
A
942 IOTakeLock(vectors[0].interruptLock);
943 ++enabledCPUs;
39236c6e 944
3e170ce0 945 if (enabledCPUs == numCPUs) {
5ba3f43e
A
946 IOService::cpusRunning();
947 thread_wakeup(this);
0a7de745 948 }
5ba3f43e 949 IOUnlock(vectors[0].interruptLock);
1c79356b
A
950}
951
0a7de745
A
952IOReturn
953IOCPUInterruptController::registerInterrupt(IOService *nub,
954 int source,
955 void *target,
956 IOInterruptHandler handler,
957 void *refCon)
1c79356b 958{
0a7de745 959 IOInterruptVector *vector;
5ba3f43e 960
cb323159
A
961 // Interrupts must be enabled, as this can allocate memory.
962 assert(ml_get_interrupts_enabled() == TRUE);
963
0a7de745
A
964 if (source >= numSources) {
965 return kIOReturnNoResources;
966 }
5ba3f43e 967
0a7de745 968 vector = &vectors[source];
5ba3f43e 969
0a7de745
A
970 // Get the lock for this vector.
971 IOTakeLock(vector->interruptLock);
5ba3f43e 972
0a7de745
A
973 // Make sure the vector is not in use.
974 if (vector->interruptRegistered) {
975 IOUnlock(vector->interruptLock);
976 return kIOReturnNoResources;
977 }
5ba3f43e 978
0a7de745
A
979 // Fill in vector with the client's info.
980 vector->handler = handler;
981 vector->nub = nub;
982 vector->source = source;
983 vector->target = target;
984 vector->refCon = refCon;
5ba3f43e 985
0a7de745
A
986 // Get the vector ready. It starts hard disabled.
987 vector->interruptDisabledHard = 1;
988 vector->interruptDisabledSoft = 1;
989 vector->interruptRegistered = 1;
5ba3f43e 990
0a7de745 991 IOUnlock(vector->interruptLock);
5ba3f43e 992
0a7de745
A
993 IOTakeLock(vectors[0].interruptLock);
994 if (enabledCPUs != numCPUs) {
995 assert_wait(this, THREAD_UNINT);
996 IOUnlock(vectors[0].interruptLock);
997 thread_block(THREAD_CONTINUE_NULL);
998 } else {
999 IOUnlock(vectors[0].interruptLock);
1000 }
5ba3f43e 1001
0a7de745 1002 return kIOReturnSuccess;
1c79356b
A
1003}
1004
0a7de745
A
1005IOReturn
1006IOCPUInterruptController::getInterruptType(IOService */*nub*/,
1007 int /*source*/,
1008 int *interruptType)
1c79356b 1009{
cb323159 1010 if (interruptType == NULL) {
0a7de745
A
1011 return kIOReturnBadArgument;
1012 }
1013
1014 *interruptType = kIOInterruptTypeLevel;
1015
1016 return kIOReturnSuccess;
1c79356b
A
1017}
1018
0a7de745
A
1019IOReturn
1020IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
1021 int /*source*/)
1c79356b
A
1022{
1023// ml_set_interrupts_enabled(true);
0a7de745 1024 return kIOReturnSuccess;
1c79356b
A
1025}
1026
0a7de745
A
1027IOReturn
1028IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
1029 int /*source*/)
1c79356b
A
1030{
1031// ml_set_interrupts_enabled(false);
0a7de745 1032 return kIOReturnSuccess;
1c79356b
A
1033}
1034
0a7de745
A
1035IOReturn
1036IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
1037 int /*source*/)
1c79356b 1038{
0a7de745
A
1039 ml_cause_interrupt();
1040 return kIOReturnSuccess;
1c79356b
A
1041}
1042
0a7de745
A
1043IOReturn
1044IOCPUInterruptController::handleInterrupt(void */*refCon*/,
1045 IOService */*nub*/,
1046 int source)
1c79356b 1047{
0a7de745
A
1048 IOInterruptVector *vector;
1049
1050 vector = &vectors[source];
1051
1052 if (!vector->interruptRegistered) {
1053 return kIOReturnInvalid;
1054 }
1055
1056 vector->handler(vector->target, vector->refCon,
1057 vector->nub, vector->source);
1058
1059 return kIOReturnSuccess;
1c79356b
A
1060}
1061
1062/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */