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