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