]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCPU.cpp
xnu-3248.30.4.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 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.
8f6c56a5 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.
17 *
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
30 *
31 * DRI: Josh de Cesare
32 *
33 */
34
35extern "C" {
36#include <machine/machine_routines.h>
37#include <pexpert/pexpert.h>
38}
39
2d21ac55
A
40#include <machine/machine_routines.h>
41
1c79356b
A
42#include <IOKit/IOLib.h>
43#include <IOKit/IOPlatformExpert.h>
2d21ac55 44#include <IOKit/pwr_mgt/RootDomain.h>
316670eb 45#include <IOKit/pwr_mgt/IOPMPrivate.h>
1c79356b 46#include <IOKit/IOUserClient.h>
2d21ac55 47#include <IOKit/IOKitKeysPrivate.h>
1c79356b
A
48#include <IOKit/IOCPU.h>
49
2d21ac55
A
50/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
51#include <kern/queue.h>
52
53typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
316670eb
A
54 void * param1, void * param2, void * param3,
55 const char * name);
2d21ac55
A
56
57struct iocpu_platform_action_entry
58{
59 queue_chain_t link;
60 iocpu_platform_action_t action;
61 int32_t priority;
316670eb 62 const char * name;
2d21ac55
A
63 void * refcon0;
64 void * refcon1;
65 struct iocpu_platform_action_entry * alloc_list;
66};
67typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t;
68
2d21ac55
A
69/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
70
cf7d32b8 71#define kBootCPUNumber 0
2d21ac55 72
3e170ce0 73enum
2d21ac55 74{
3e170ce0
A
75 kQueueSleep = 0,
76 kQueueWake = 1,
77 kQueueQuiesce = 2,
78 kQueueActive = 3,
79 kQueueHaltRestart = 4,
80 kQueuePanic = 5,
81 kQueueCount = 6
82};
2d21ac55 83
3e170ce0
A
84const OSSymbol * gIOPlatformSleepActionKey;
85const OSSymbol * gIOPlatformWakeActionKey;
86const OSSymbol * gIOPlatformQuiesceActionKey;
87const OSSymbol * gIOPlatformActiveActionKey;
88const OSSymbol * gIOPlatformHaltRestartActionKey;
89const OSSymbol * gIOPlatformPanicActionKey;
2d21ac55 90
3e170ce0
A
91static queue_head_t gActionQueues[kQueueCount];
92static const OSSymbol * gActionSymbols[kQueueCount];
2d21ac55 93
3e170ce0 94/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2d21ac55 95
3e170ce0
A
96static void
97iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry)
2d21ac55
A
98{
99 iocpu_platform_action_entry_t * next;
100
101 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
102 {
103 if (next->priority > entry->priority)
104 {
105 queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link);
106 return;
107 }
108 }
109 queue_enter(queue, entry, iocpu_platform_action_entry_t *, link); // at tail
110}
111
3e170ce0
A
112static void
113iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry)
2d21ac55
A
114{
115 remque(&entry->link);
116}
117
3e170ce0 118static kern_return_t
2d21ac55
A
119iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
120 void * param1, void * param2, void * param3)
121{
122 kern_return_t ret = KERN_SUCCESS;
123 kern_return_t result = KERN_SUCCESS;
124 iocpu_platform_action_entry_t * next;
125
126 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
127 {
128 uint32_t pri = (next->priority < 0) ? -next->priority : next->priority;
129 if ((pri >= first_priority) && (pri <= last_priority))
130 {
131 //kprintf("[%p]", next->action);
316670eb 132 ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3, next->name);
2d21ac55
A
133 }
134 if (KERN_SUCCESS == result)
135 result = ret;
136 }
137 return (result);
138}
139
140/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
141
142extern "C" kern_return_t
143IOCPURunPlatformQuiesceActions(void)
144{
3e170ce0 145 return (iocpu_run_platform_actions(&gActionQueues[kQueueQuiesce], 0, 0U-1,
2d21ac55
A
146 NULL, NULL, NULL));
147}
148
149extern "C" kern_return_t
150IOCPURunPlatformActiveActions(void)
151{
3e170ce0 152 return (iocpu_run_platform_actions(&gActionQueues[kQueueActive], 0, 0U-1,
2d21ac55
A
153 NULL, NULL, NULL));
154}
155
3e170ce0
A
156extern "C" kern_return_t
157IOCPURunPlatformHaltRestartActions(uint32_t message)
158{
159 return (iocpu_run_platform_actions(&gActionQueues[kQueueHaltRestart], 0, 0U-1,
160 (void *)(uintptr_t) message, NULL, NULL));
161}
162
163extern "C" kern_return_t
164IOCPURunPlatformPanicActions(uint32_t message)
165{
166 return (iocpu_run_platform_actions(&gActionQueues[kQueuePanic], 0, 0U-1,
167 (void *)(uintptr_t) message, NULL, NULL));
168}
169
170/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
171
2d21ac55
A
172static kern_return_t
173IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
316670eb
A
174 void * param1, void * param2, void * param3,
175 const char * service_name)
2d21ac55
A
176{
177 IOReturn ret;
178 IOService * service = (IOService *) refcon0;
179 const OSSymbol * function = (const OSSymbol *) refcon1;
180
316670eb 181 kprintf("%s -> %s\n", function->getCStringNoCopy(), service_name);
2d21ac55
A
182
183 ret = service->callPlatformFunction(function, false,
39236c6e 184 (void *)(uintptr_t) priority, param1, param2, param3);
2d21ac55
A
185
186 return (ret);
187}
188
189static void
3e170ce0 190IOInstallServicePlatformAction(IOService * service, uint32_t qidx)
2d21ac55 191{
2d21ac55 192 iocpu_platform_action_entry_t * entry;
3e170ce0
A
193 OSNumber * num;
194 uint32_t priority;
195 const OSSymbol * key = gActionSymbols[qidx];
196 queue_head_t * queue = &gActionQueues[qidx];
197 bool reverse;
198 bool uniq;
2d21ac55
A
199
200 num = OSDynamicCast(OSNumber, service->getProperty(key));
3e170ce0
A
201 if (!num) return;
202
203 reverse = false;
204 uniq = false;
205 switch (qidx)
206 {
207 case kQueueWake:
208 case kQueueActive:
209 reverse = true;
210 break;
211 case kQueueHaltRestart:
212 case kQueuePanic:
213 uniq = true;
214 break;
215 }
216 if (uniq)
217 {
218 queue_iterate(queue, entry, iocpu_platform_action_entry_t *, link)
219 {
220 if (service == entry->refcon0) return;
221 }
222 }
2d21ac55
A
223
224 entry = IONew(iocpu_platform_action_entry_t, 1);
225 entry->action = &IOServicePlatformAction;
316670eb 226 entry->name = service->getName();
2d21ac55
A
227 priority = num->unsigned32BitValue();
228 if (reverse)
229 entry->priority = -priority;
230 else
231 entry->priority = priority;
232 entry->refcon0 = service;
233 entry->refcon1 = (void *) key;
234
235 iocpu_add_platform_action(queue, entry);
2d21ac55 236}
1c79356b 237
3e170ce0
A
238/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
239
240void
241IOCPUInitialize(void)
fe8ab488 242{
3e170ce0
A
243 for (uint32_t qidx = kQueueSleep; qidx < kQueueCount; qidx++)
244 {
245 queue_init(&gActionQueues[qidx]);
246 }
247
248 gIOPlatformSleepActionKey = gActionSymbols[kQueueSleep]
249 = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey);
250 gIOPlatformWakeActionKey = gActionSymbols[kQueueWake]
251 = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey);
252 gIOPlatformQuiesceActionKey = gActionSymbols[kQueueQuiesce]
253 = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey);
254 gIOPlatformActiveActionKey = gActionSymbols[kQueueActive]
255 = OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey);
256 gIOPlatformHaltRestartActionKey = gActionSymbols[kQueueHaltRestart]
257 = OSSymbol::withCStringNoCopy(kIOPlatformHaltRestartActionKey);
258 gIOPlatformPanicActionKey = gActionSymbols[kQueuePanic]
259 = OSSymbol::withCStringNoCopy(kIOPlatformPanicActionKey);
260}
261
262IOReturn
263IOInstallServicePlatformActions(IOService * service)
264{
265 IOInstallServicePlatformAction(service, kQueueHaltRestart);
266 IOInstallServicePlatformAction(service, kQueuePanic);
267
268 return (kIOReturnSuccess);
269}
fe8ab488 270
3e170ce0
A
271IOReturn
272IORemoveServicePlatformActions(IOService * service)
273{
274 iocpu_platform_action_entry_t * entry;
275 iocpu_platform_action_entry_t * next;
276
277 for (uint32_t qidx = kQueueSleep; qidx < kQueueCount; qidx++)
fe8ab488 278 {
3e170ce0
A
279 next = (typeof(entry)) queue_first(&gActionQueues[qidx]);
280 while (!queue_end(&gActionQueues[qidx], &next->link))
fe8ab488 281 {
3e170ce0
A
282 entry = next;
283 next = (typeof(entry)) queue_next(&entry->link);
284 if (service == entry->refcon0)
fe8ab488 285 {
3e170ce0
A
286 iocpu_remove_platform_action(entry);
287 IODelete(entry, iocpu_platform_action_entry_t, 1);
fe8ab488 288 }
fe8ab488
A
289 }
290 }
3e170ce0
A
291
292 return (kIOReturnSuccess);
fe8ab488
A
293}
294
3e170ce0 295
1c79356b
A
296/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
297
298kern_return_t PE_cpu_start(cpu_id_t target,
299 vm_offset_t start_paddr, vm_offset_t arg_paddr)
300{
301 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
302
303 if (targetCPU == 0) return KERN_FAILURE;
304 return targetCPU->startCPU(start_paddr, arg_paddr);
305}
306
307void PE_cpu_halt(cpu_id_t target)
308{
309 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
310
311 if (targetCPU) targetCPU->haltCPU();
312}
313
314void PE_cpu_signal(cpu_id_t source, cpu_id_t target)
315{
316 IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
317 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
318
319 if (sourceCPU && targetCPU) sourceCPU->signalCPU(targetCPU);
320}
321
3e170ce0
A
322void PE_cpu_signal_deferred(cpu_id_t source, cpu_id_t target)
323{
324 IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
325 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
326
327 if (sourceCPU && targetCPU) sourceCPU->signalCPUDeferred(targetCPU);
328}
329
330void PE_cpu_signal_cancel(cpu_id_t source, cpu_id_t target)
331{
332 IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
333 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
334
335 if (sourceCPU && targetCPU) sourceCPU->signalCPUCancel(targetCPU);
336}
337
2d21ac55 338void PE_cpu_machine_init(cpu_id_t target, boolean_t bootb)
1c79356b
A
339{
340 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
341
2d21ac55 342 if (targetCPU) targetCPU->initCPU(bootb);
1c79356b
A
343}
344
345void PE_cpu_machine_quiesce(cpu_id_t target)
346{
347 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
2d21ac55 348
1c79356b
A
349 if (targetCPU) targetCPU->quiesceCPU();
350}
351
593a1d5f 352
1c79356b
A
353/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
354
355#define super IOService
356
357OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
358OSMetaClassDefineReservedUnused(IOCPU, 0);
359OSMetaClassDefineReservedUnused(IOCPU, 1);
360OSMetaClassDefineReservedUnused(IOCPU, 2);
361OSMetaClassDefineReservedUnused(IOCPU, 3);
362OSMetaClassDefineReservedUnused(IOCPU, 4);
363OSMetaClassDefineReservedUnused(IOCPU, 5);
364OSMetaClassDefineReservedUnused(IOCPU, 6);
365OSMetaClassDefineReservedUnused(IOCPU, 7);
366
367/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
368
369static OSArray *gIOCPUs;
370static const OSSymbol *gIOCPUStateKey;
371static OSString *gIOCPUStateNames[kIOCPUStateCount];
372
373void IOCPUSleepKernel(void)
374{
2d21ac55
A
375 long cnt, numCPUs;
376 IOCPU *target;
cf7d32b8 377 IOCPU *bootCPU = NULL;
6d2010ae
A
378 IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
379
2d21ac55
A
380 kprintf("IOCPUSleepKernel\n");
381
316670eb
A
382 IORegistryIterator * iter;
383 OSOrderedSet * all;
384 IOService * service;
2d21ac55 385
6d2010ae
A
386 rootDomain->tracePoint( kIOPMTracePointSleepPlatformActions );
387
2d21ac55
A
388 iter = IORegistryIterator::iterateOver( gIOServicePlane,
389 kIORegistryIterateRecursively );
390 if( iter)
391 {
316670eb
A
392 all = 0;
393 do
2d21ac55 394 {
316670eb
A
395 if (all)
396 all->release();
397 all = iter->iterateAll();
398 }
399 while (!iter->isValid());
400 iter->release();
401
402 if (all)
403 {
404 while((service = (IOService *) all->getFirstObject()))
2d21ac55 405 {
3e170ce0
A
406 for (uint32_t qidx = kQueueSleep; qidx <= kQueueActive; qidx++)
407 {
408 IOInstallServicePlatformAction(service, qidx);
409 }
316670eb 410 all->removeObject(service);
2d21ac55 411 }
316670eb
A
412 all->release();
413 }
1c79356b 414 }
2d21ac55 415
3e170ce0 416 iocpu_run_platform_actions(&gActionQueues[kQueueSleep], 0, 0U-1,
2d21ac55
A
417 NULL, NULL, NULL);
418
6d2010ae
A
419 rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
420
2d21ac55
A
421 numCPUs = gIOCPUs->getCount();
422 // Sleep the CPUs.
423 cnt = numCPUs;
cf7d32b8
A
424 while (cnt--)
425 {
426 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
427
428 // We make certain that the bootCPU is the last to sleep
429 // We'll skip it for now, and halt it after finishing the
430 // non-boot CPU's.
431 if (target->getCPUNumber() == kBootCPUNumber)
432 {
433 bootCPU = target;
434 } else if (target->getCPUState() == kIOCPUStateRunning)
435 {
436 target->haltCPU();
437 }
2d21ac55
A
438 }
439
6d2010ae
A
440 rootDomain->tracePoint( kIOPMTracePointSleepPlatformDriver );
441
cf7d32b8
A
442 // Now sleep the boot CPU.
443 if (bootCPU)
444 bootCPU->haltCPU();
445
6d2010ae
A
446 rootDomain->tracePoint( kIOPMTracePointWakePlatformActions );
447
3e170ce0 448 iocpu_run_platform_actions(&gActionQueues[kQueueWake], 0, 0U-1,
2d21ac55
A
449 NULL, NULL, NULL);
450
451 iocpu_platform_action_entry_t * entry;
3e170ce0 452 for (uint32_t qidx = kQueueSleep; qidx <= kQueueActive; qidx++)
2d21ac55 453 {
3e170ce0
A
454 while (!(queue_empty(&gActionQueues[qidx])))
455 {
456 entry = (typeof(entry)) queue_first(&gActionQueues[qidx]);
457 iocpu_remove_platform_action(entry);
458 IODelete(entry, iocpu_platform_action_entry_t, 1);
459 }
2d21ac55
A
460 }
461
6d2010ae
A
462 rootDomain->tracePoint( kIOPMTracePointWakeCPUs );
463
2d21ac55 464 // Wake the other CPUs.
cf7d32b8
A
465 for (cnt = 0; cnt < numCPUs; cnt++)
466 {
467 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
468
469 // Skip the already-woken boot CPU.
470 if ((target->getCPUNumber() != kBootCPUNumber)
471 && (target->getCPUState() == kIOCPUStateStopped))
472 {
473 processor_start(target->getMachProcessor());
474 }
1c79356b 475 }
1c79356b
A
476}
477
478void IOCPU::initCPUs(void)
479{
480 if (gIOCPUs == 0) {
481 gIOCPUs = OSArray::withCapacity(1);
482
483 gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
484
485 gIOCPUStateNames[kIOCPUStateUnregistered] =
486 OSString::withCStringNoCopy("Unregistered");
487 gIOCPUStateNames[kIOCPUStateUninitalized] =
488 OSString::withCStringNoCopy("Uninitalized");
489 gIOCPUStateNames[kIOCPUStateStopped] =
490 OSString::withCStringNoCopy("Stopped");
491 gIOCPUStateNames[kIOCPUStateRunning] =
492 OSString::withCStringNoCopy("Running");
493 }
494}
495
496bool IOCPU::start(IOService *provider)
497{
90556fb8 498 OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
1c79356b
A
499
500 if (!super::start(provider)) return false;
501
502 initCPUs();
503
504 _cpuGroup = gIOCPUs;
505 cpuNub = provider;
506
507 gIOCPUs->setObject(this);
508
43866e37 509 // Correct the bus, cpu and timebase frequencies in the device tree.
91447636
A
510 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
511 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
512 } else {
513 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
514 }
1c79356b 515 provider->setProperty("bus-frequency", busFrequency);
de355530 516 busFrequency->release();
43866e37 517
91447636
A
518 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
519 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
520 } else {
521 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
522 }
43866e37 523 provider->setProperty("clock-frequency", cpuFrequency);
1c79356b 524 cpuFrequency->release();
43866e37
A
525
526 timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
527 provider->setProperty("timebase-frequency", timebaseFrequency);
90556fb8 528 timebaseFrequency->release();
1c79356b 529
fe8ab488 530 super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t)*8);
1c79356b
A
531
532 setCPUNumber(0);
533 setCPUState(kIOCPUStateUnregistered);
534
535 return true;
536}
537
91447636 538OSObject *IOCPU::getProperty(const OSSymbol *aKey) const
1c79356b 539{
91447636 540 if (aKey == gIOCPUStateKey) return gIOCPUStateNames[_cpuState];
1c79356b 541
91447636
A
542 return super::getProperty(aKey);
543}
544
545bool IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
546{
547 OSString *stateStr;
1c79356b 548
91447636
A
549 if (aKey == gIOCPUStateKey) {
550 stateStr = OSDynamicCast(OSString, anObject);
551 if (stateStr == 0) return false;
1c79356b 552
91447636 553 if (_cpuNumber == 0) return false;
1c79356b
A
554
555 if (stateStr->isEqualTo("running")) {
556 if (_cpuState == kIOCPUStateStopped) {
557 processor_start(machProcessor);
558 } else if (_cpuState != kIOCPUStateRunning) {
91447636 559 return false;
1c79356b
A
560 }
561 } else if (stateStr->isEqualTo("stopped")) {
562 if (_cpuState == kIOCPUStateRunning) {
563 haltCPU();
564 } else if (_cpuState != kIOCPUStateStopped) {
91447636 565 return false;
1c79356b 566 }
91447636
A
567 } else return false;
568
569 return true;
570 }
571
572 return super::setProperty(aKey, anObject);
573}
574
575bool IOCPU::serializeProperties(OSSerialize *serialize) const
576{
0c530ab8
A
577 bool result;
578 OSDictionary *dict = dictionaryWithProperties();
3e170ce0 579 if (!dict) return false;
0c530ab8
A
580 dict->setObject(gIOCPUStateKey, gIOCPUStateNames[_cpuState]);
581 result = dict->serialize(serialize);
582 dict->release();
583 return result;
91447636
A
584}
585
586IOReturn IOCPU::setProperties(OSObject *properties)
587{
588 OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
589 OSString *stateStr;
590 IOReturn result;
591
592 if (dict == 0) return kIOReturnUnsupported;
593
594 stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
595 if (stateStr != 0) {
596 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
597 if (result != kIOReturnSuccess) return result;
598
599 if (setProperty(gIOCPUStateKey, stateStr)) return kIOReturnSuccess;
1c79356b 600
91447636 601 return kIOReturnUnsupported;
1c79356b
A
602 }
603
604 return kIOReturnUnsupported;
605}
606
607void IOCPU::signalCPU(IOCPU */*target*/)
608{
609}
610
3e170ce0
A
611void IOCPU::signalCPUDeferred(IOCPU *target)
612{
613 // Our CPU may not support deferred IPIs,
614 // so send a regular IPI by default
615 signalCPU(target);
616}
617
618void IOCPU::signalCPUCancel(IOCPU */*target*/)
619{
620 // Meant to cancel signals sent by
621 // signalCPUDeferred; unsupported
622 // by default
623}
624
1c79356b
A
625void IOCPU::enableCPUTimeBase(bool /*enable*/)
626{
627}
628
629UInt32 IOCPU::getCPUNumber(void)
630{
631 return _cpuNumber;
632}
633
634void IOCPU::setCPUNumber(UInt32 cpuNumber)
635{
636 _cpuNumber = cpuNumber;
91447636 637 super::setProperty("IOCPUNumber", _cpuNumber, 32);
1c79356b
A
638}
639
640UInt32 IOCPU::getCPUState(void)
641{
642 return _cpuState;
643}
644
645void IOCPU::setCPUState(UInt32 cpuState)
646{
91447636 647 if (cpuState < kIOCPUStateCount) {
1c79356b 648 _cpuState = cpuState;
1c79356b
A
649 }
650}
651
652OSArray *IOCPU::getCPUGroup(void)
653{
654 return _cpuGroup;
655}
656
657UInt32 IOCPU::getCPUGroupSize(void)
658{
659 return _cpuGroup->getCount();
660}
661
662processor_t IOCPU::getMachProcessor(void)
663{
664 return machProcessor;
665}
666
667
668/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
669
670#undef super
671#define super IOInterruptController
672
673OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
674
675OSMetaClassDefineReservedUnused(IOCPUInterruptController, 0);
676OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
677OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
678OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
679OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
680OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
681
682
683
684/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
685
686
687IOReturn IOCPUInterruptController::initCPUInterruptController(int sources)
688{
689 int cnt;
690
691 if (!super::init()) return kIOReturnInvalid;
692
693 numCPUs = sources;
694
695 cpus = (IOCPU **)IOMalloc(numCPUs * sizeof(IOCPU *));
696 if (cpus == 0) return kIOReturnNoMemory;
697 bzero(cpus, numCPUs * sizeof(IOCPU *));
698
699 vectors = (IOInterruptVector *)IOMalloc(numCPUs * sizeof(IOInterruptVector));
700 if (vectors == 0) return kIOReturnNoMemory;
701 bzero(vectors, numCPUs * sizeof(IOInterruptVector));
702
703 // Allocate locks for the
704 for (cnt = 0; cnt < numCPUs; cnt++) {
705 vectors[cnt].interruptLock = IOLockAlloc();
706 if (vectors[cnt].interruptLock == NULL) {
707 for (cnt = 0; cnt < numCPUs; cnt++) {
708 if (vectors[cnt].interruptLock != NULL)
709 IOLockFree(vectors[cnt].interruptLock);
710 }
711 return kIOReturnNoResources;
712 }
713 }
714
43866e37
A
715 ml_init_max_cpus(numCPUs);
716
1c79356b
A
717 return kIOReturnSuccess;
718}
719
720void IOCPUInterruptController::registerCPUInterruptController(void)
721{
722 registerService();
723
724 getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
725 this);
726}
727
728void IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
729{
730 int cnt;
731 OSArray *controller;
732 OSArray *specifier;
733 OSData *tmpData;
734 long tmpLong;
735
2d21ac55
A
736 if ((service->getProperty(gIOInterruptControllersKey) != 0) &&
737 (service->getProperty(gIOInterruptSpecifiersKey) != 0))
738 return;
739
1c79356b
A
740 // Create the interrupt specifer array.
741 specifier = OSArray::withCapacity(numCPUs);
742 for (cnt = 0; cnt < numCPUs; cnt++) {
743 tmpLong = cnt;
744 tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
745 specifier->setObject(tmpData);
746 tmpData->release();
747 };
748
749 // Create the interrupt controller array.
750 controller = OSArray::withCapacity(numCPUs);
751 for (cnt = 0; cnt < numCPUs; cnt++) {
752 controller->setObject(gPlatformInterruptControllerName);
753 }
754
755 // Put the two arrays into the property table.
756 service->setProperty(gIOInterruptControllersKey, controller);
757 service->setProperty(gIOInterruptSpecifiersKey, specifier);
758 controller->release();
759 specifier->release();
760}
761
762void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
763{
0c530ab8
A
764 IOInterruptHandler handler = OSMemberFunctionCast(
765 IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
766
767 ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, 0);
39236c6e
A
768
769 // Ensure that the increment is seen by all processors
770 OSIncrementAtomic(&enabledCPUs);
771
3e170ce0
A
772 if (enabledCPUs == numCPUs) {
773 IOService::cpusRunning();
774 thread_wakeup(this);
775 }
1c79356b
A
776}
777
778IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,
779 int source,
780 void *target,
781 IOInterruptHandler handler,
782 void *refCon)
783{
784 IOInterruptVector *vector;
785
786 if (source >= numCPUs) return kIOReturnNoResources;
787
788 vector = &vectors[source];
789
790 // Get the lock for this vector.
791 IOTakeLock(vector->interruptLock);
792
793 // Make sure the vector is not in use.
794 if (vector->interruptRegistered) {
795 IOUnlock(vector->interruptLock);
796 return kIOReturnNoResources;
797 }
798
799 // Fill in vector with the client's info.
800 vector->handler = handler;
801 vector->nub = nub;
802 vector->source = source;
803 vector->target = target;
804 vector->refCon = refCon;
805
806 // Get the vector ready. It starts hard disabled.
807 vector->interruptDisabledHard = 1;
808 vector->interruptDisabledSoft = 1;
809 vector->interruptRegistered = 1;
810
811 IOUnlock(vector->interruptLock);
812
813 if (enabledCPUs != numCPUs) {
814 assert_wait(this, THREAD_UNINT);
9bccf70c 815 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
816 }
817
818 return kIOReturnSuccess;
819}
820
821IOReturn IOCPUInterruptController::getInterruptType(IOService */*nub*/,
822 int /*source*/,
823 int *interruptType)
824{
825 if (interruptType == 0) return kIOReturnBadArgument;
826
827 *interruptType = kIOInterruptTypeLevel;
828
829 return kIOReturnSuccess;
830}
831
832IOReturn IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
833 int /*source*/)
834{
835// ml_set_interrupts_enabled(true);
836 return kIOReturnSuccess;
837}
838
839IOReturn IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
840 int /*source*/)
841{
842// ml_set_interrupts_enabled(false);
843 return kIOReturnSuccess;
844}
845
846IOReturn IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
847 int /*source*/)
848{
849 ml_cause_interrupt();
850 return kIOReturnSuccess;
851}
852
853IOReturn IOCPUInterruptController::handleInterrupt(void */*refCon*/,
854 IOService */*nub*/,
855 int source)
856{
857 IOInterruptVector *vector;
858
859 vector = &vectors[source];
860
861 if (!vector->interruptRegistered) return kIOReturnInvalid;
862
863 vector->handler(vector->target, vector->refCon,
864 vector->nub, vector->source);
865
866 return kIOReturnSuccess;
867}
868
869/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */