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