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