2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
36 #include <machine/machine_routines.h>
37 #include <pexpert/pexpert.h>
40 #include <machine/machine_routines.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/pwr_mgt/RootDomain.h>
45 #include <IOKit/pwr_mgt/IOPMPrivate.h>
46 #include <IOKit/IOUserClient.h>
47 #include <IOKit/IOKitKeysPrivate.h>
48 #include <IOKit/IOCPU.h>
50 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
51 #include <kern/queue.h>
53 typedef kern_return_t (*iocpu_platform_action_t
)(void * refcon0
, void * refcon1
, uint32_t priority
,
54 void * param1
, void * param2
, void * param3
,
57 struct iocpu_platform_action_entry
60 iocpu_platform_action_t action
;
65 struct iocpu_platform_action_entry
* alloc_list
;
67 typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t
;
69 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71 #define kBootCPUNumber 0
79 kQueueHaltRestart
= 4,
84 const OSSymbol
* gIOPlatformSleepActionKey
;
85 const OSSymbol
* gIOPlatformWakeActionKey
;
86 const OSSymbol
* gIOPlatformQuiesceActionKey
;
87 const OSSymbol
* gIOPlatformActiveActionKey
;
88 const OSSymbol
* gIOPlatformHaltRestartActionKey
;
89 const OSSymbol
* gIOPlatformPanicActionKey
;
91 static queue_head_t gActionQueues
[kQueueCount
];
92 static const OSSymbol
* gActionSymbols
[kQueueCount
];
94 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
97 iocpu_add_platform_action(queue_head_t
* queue
, iocpu_platform_action_entry_t
* entry
)
99 iocpu_platform_action_entry_t
* next
;
101 queue_iterate(queue
, next
, iocpu_platform_action_entry_t
*, link
)
103 if (next
->priority
> entry
->priority
)
105 queue_insert_before(queue
, entry
, next
, iocpu_platform_action_entry_t
*, link
);
109 queue_enter(queue
, entry
, iocpu_platform_action_entry_t
*, link
); // at tail
113 iocpu_remove_platform_action(iocpu_platform_action_entry_t
* entry
)
115 remque(&entry
->link
);
119 iocpu_run_platform_actions(queue_head_t
* queue
, uint32_t first_priority
, uint32_t last_priority
,
120 void * param1
, void * param2
, void * param3
)
122 kern_return_t ret
= KERN_SUCCESS
;
123 kern_return_t result
= KERN_SUCCESS
;
124 iocpu_platform_action_entry_t
* next
;
126 queue_iterate(queue
, next
, iocpu_platform_action_entry_t
*, link
)
128 uint32_t pri
= (next
->priority
< 0) ? -next
->priority
: next
->priority
;
129 if ((pri
>= first_priority
) && (pri
<= last_priority
))
131 //kprintf("[%p]", next->action);
132 ret
= (*next
->action
)(next
->refcon0
, next
->refcon1
, pri
, param1
, param2
, param3
, next
->name
);
134 if (KERN_SUCCESS
== result
)
140 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
142 extern "C" kern_return_t
143 IOCPURunPlatformQuiesceActions(void)
145 return (iocpu_run_platform_actions(&gActionQueues
[kQueueQuiesce
], 0, 0U-1,
149 extern "C" kern_return_t
150 IOCPURunPlatformActiveActions(void)
152 return (iocpu_run_platform_actions(&gActionQueues
[kQueueActive
], 0, 0U-1,
156 extern "C" kern_return_t
157 IOCPURunPlatformHaltRestartActions(uint32_t message
)
159 return (iocpu_run_platform_actions(&gActionQueues
[kQueueHaltRestart
], 0, 0U-1,
160 (void *)(uintptr_t) message
, NULL
, NULL
));
163 extern "C" kern_return_t
164 IOCPURunPlatformPanicActions(uint32_t message
)
166 return (iocpu_run_platform_actions(&gActionQueues
[kQueuePanic
], 0, 0U-1,
167 (void *)(uintptr_t) message
, NULL
, NULL
));
170 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
173 IOServicePlatformAction(void * refcon0
, void * refcon1
, uint32_t priority
,
174 void * param1
, void * param2
, void * param3
,
175 const char * service_name
)
178 IOService
* service
= (IOService
*) refcon0
;
179 const OSSymbol
* function
= (const OSSymbol
*) refcon1
;
181 kprintf("%s -> %s\n", function
->getCStringNoCopy(), service_name
);
183 ret
= service
->callPlatformFunction(function
, false,
184 (void *)(uintptr_t) priority
, param1
, param2
, param3
);
190 IOInstallServicePlatformAction(IOService
* service
, uint32_t qidx
)
192 iocpu_platform_action_entry_t
* entry
;
195 const OSSymbol
* key
= gActionSymbols
[qidx
];
196 queue_head_t
* queue
= &gActionQueues
[qidx
];
200 num
= OSDynamicCast(OSNumber
, service
->getProperty(key
));
211 case kQueueHaltRestart
:
218 queue_iterate(queue
, entry
, iocpu_platform_action_entry_t
*, link
)
220 if (service
== entry
->refcon0
) return;
224 entry
= IONew(iocpu_platform_action_entry_t
, 1);
225 entry
->action
= &IOServicePlatformAction
;
226 entry
->name
= service
->getName();
227 priority
= num
->unsigned32BitValue();
229 entry
->priority
= -priority
;
231 entry
->priority
= priority
;
232 entry
->refcon0
= service
;
233 entry
->refcon1
= (void *) key
;
235 iocpu_add_platform_action(queue
, entry
);
238 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
241 IOCPUInitialize(void)
243 for (uint32_t qidx
= kQueueSleep
; qidx
< kQueueCount
; qidx
++)
245 queue_init(&gActionQueues
[qidx
]);
248 gIOPlatformSleepActionKey
= gActionSymbols
[kQueueSleep
]
249 = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
250 gIOPlatformWakeActionKey
= gActionSymbols
[kQueueWake
]
251 = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
252 gIOPlatformQuiesceActionKey
= gActionSymbols
[kQueueQuiesce
]
253 = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
254 gIOPlatformActiveActionKey
= gActionSymbols
[kQueueActive
]
255 = OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
256 gIOPlatformHaltRestartActionKey
= gActionSymbols
[kQueueHaltRestart
]
257 = OSSymbol::withCStringNoCopy(kIOPlatformHaltRestartActionKey
);
258 gIOPlatformPanicActionKey
= gActionSymbols
[kQueuePanic
]
259 = OSSymbol::withCStringNoCopy(kIOPlatformPanicActionKey
);
263 IOInstallServicePlatformActions(IOService
* service
)
265 IOInstallServicePlatformAction(service
, kQueueHaltRestart
);
266 IOInstallServicePlatformAction(service
, kQueuePanic
);
268 return (kIOReturnSuccess
);
272 IORemoveServicePlatformActions(IOService
* service
)
274 iocpu_platform_action_entry_t
* entry
;
275 iocpu_platform_action_entry_t
* next
;
277 for (uint32_t qidx
= kQueueSleep
; qidx
< kQueueCount
; qidx
++)
279 next
= (typeof(entry
)) queue_first(&gActionQueues
[qidx
]);
280 while (!queue_end(&gActionQueues
[qidx
], &next
->link
))
283 next
= (typeof(entry
)) queue_next(&entry
->link
);
284 if (service
== entry
->refcon0
)
286 iocpu_remove_platform_action(entry
);
287 IODelete(entry
, iocpu_platform_action_entry_t
, 1);
292 return (kIOReturnSuccess
);
296 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
298 kern_return_t
PE_cpu_start(cpu_id_t target
,
299 vm_offset_t start_paddr
, vm_offset_t arg_paddr
)
301 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
303 if (targetCPU
== 0) return KERN_FAILURE
;
304 return targetCPU
->startCPU(start_paddr
, arg_paddr
);
307 void PE_cpu_halt(cpu_id_t target
)
309 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
311 if (targetCPU
) targetCPU
->haltCPU();
314 void PE_cpu_signal(cpu_id_t source
, cpu_id_t target
)
316 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
317 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
319 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPU(targetCPU
);
322 void PE_cpu_signal_deferred(cpu_id_t source
, cpu_id_t target
)
324 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
325 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
327 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPUDeferred(targetCPU
);
330 void PE_cpu_signal_cancel(cpu_id_t source
, cpu_id_t target
)
332 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
333 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
335 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPUCancel(targetCPU
);
338 void PE_cpu_machine_init(cpu_id_t target
, boolean_t bootb
)
340 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
342 if (targetCPU
) targetCPU
->initCPU(bootb
);
345 void PE_cpu_machine_quiesce(cpu_id_t target
)
347 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
349 if (targetCPU
) targetCPU
->quiesceCPU();
353 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
355 #define super IOService
357 OSDefineMetaClassAndAbstractStructors(IOCPU
, IOService
);
358 OSMetaClassDefineReservedUnused(IOCPU
, 0);
359 OSMetaClassDefineReservedUnused(IOCPU
, 1);
360 OSMetaClassDefineReservedUnused(IOCPU
, 2);
361 OSMetaClassDefineReservedUnused(IOCPU
, 3);
362 OSMetaClassDefineReservedUnused(IOCPU
, 4);
363 OSMetaClassDefineReservedUnused(IOCPU
, 5);
364 OSMetaClassDefineReservedUnused(IOCPU
, 6);
365 OSMetaClassDefineReservedUnused(IOCPU
, 7);
367 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
369 static OSArray
*gIOCPUs
;
370 static const OSSymbol
*gIOCPUStateKey
;
371 static OSString
*gIOCPUStateNames
[kIOCPUStateCount
];
373 void IOCPUSleepKernel(void)
377 IOCPU
*bootCPU
= NULL
;
378 IOPMrootDomain
*rootDomain
= IOService::getPMRootDomain();
380 kprintf("IOCPUSleepKernel\n");
382 IORegistryIterator
* iter
;
386 rootDomain
->tracePoint( kIOPMTracePointSleepPlatformActions
);
388 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
389 kIORegistryIterateRecursively
);
397 all
= iter
->iterateAll();
399 while (!iter
->isValid());
404 while((service
= (IOService
*) all
->getFirstObject()))
406 for (uint32_t qidx
= kQueueSleep
; qidx
<= kQueueActive
; qidx
++)
408 IOInstallServicePlatformAction(service
, qidx
);
410 all
->removeObject(service
);
416 iocpu_run_platform_actions(&gActionQueues
[kQueueSleep
], 0, 0U-1,
419 rootDomain
->tracePoint( kIOPMTracePointSleepCPUs
);
421 numCPUs
= gIOCPUs
->getCount();
426 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
428 // We make certain that the bootCPU is the last to sleep
429 // We'll skip it for now, and halt it after finishing the
431 if (target
->getCPUNumber() == kBootCPUNumber
)
434 } else if (target
->getCPUState() == kIOCPUStateRunning
)
440 rootDomain
->tracePoint( kIOPMTracePointSleepPlatformDriver
);
442 // Now sleep the boot CPU.
446 rootDomain
->tracePoint( kIOPMTracePointWakePlatformActions
);
448 iocpu_run_platform_actions(&gActionQueues
[kQueueWake
], 0, 0U-1,
451 iocpu_platform_action_entry_t
* entry
;
452 for (uint32_t qidx
= kQueueSleep
; qidx
<= kQueueActive
; qidx
++)
454 while (!(queue_empty(&gActionQueues
[qidx
])))
456 entry
= (typeof(entry
)) queue_first(&gActionQueues
[qidx
]);
457 iocpu_remove_platform_action(entry
);
458 IODelete(entry
, iocpu_platform_action_entry_t
, 1);
462 rootDomain
->tracePoint( kIOPMTracePointWakeCPUs
);
464 // Wake the other CPUs.
465 for (cnt
= 0; cnt
< numCPUs
; cnt
++)
467 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
469 // Skip the already-woken boot CPU.
470 if ((target
->getCPUNumber() != kBootCPUNumber
)
471 && (target
->getCPUState() == kIOCPUStateStopped
))
473 processor_start(target
->getMachProcessor());
478 void IOCPU::initCPUs(void)
481 gIOCPUs
= OSArray::withCapacity(1);
483 gIOCPUStateKey
= OSSymbol::withCStringNoCopy("IOCPUState");
485 gIOCPUStateNames
[kIOCPUStateUnregistered
] =
486 OSString::withCStringNoCopy("Unregistered");
487 gIOCPUStateNames
[kIOCPUStateUninitalized
] =
488 OSString::withCStringNoCopy("Uninitalized");
489 gIOCPUStateNames
[kIOCPUStateStopped
] =
490 OSString::withCStringNoCopy("Stopped");
491 gIOCPUStateNames
[kIOCPUStateRunning
] =
492 OSString::withCStringNoCopy("Running");
496 bool IOCPU::start(IOService
*provider
)
498 OSData
*busFrequency
, *cpuFrequency
, *timebaseFrequency
;
500 if (!super::start(provider
)) return false;
507 gIOCPUs
->setObject(this);
509 // Correct the bus, cpu and timebase frequencies in the device tree.
510 if (gPEClockFrequencyInfo
.bus_frequency_hz
< 0x100000000ULL
) {
511 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
513 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_frequency_hz
, 8);
515 provider
->setProperty("bus-frequency", busFrequency
);
516 busFrequency
->release();
518 if (gPEClockFrequencyInfo
.cpu_frequency_hz
< 0x100000000ULL
) {
519 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_clock_rate_hz
, 4);
521 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_frequency_hz
, 8);
523 provider
->setProperty("clock-frequency", cpuFrequency
);
524 cpuFrequency
->release();
526 timebaseFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.timebase_frequency_hz
, 4);
527 provider
->setProperty("timebase-frequency", timebaseFrequency
);
528 timebaseFrequency
->release();
530 super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t)*8);
533 setCPUState(kIOCPUStateUnregistered
);
538 OSObject
*IOCPU::getProperty(const OSSymbol
*aKey
) const
540 if (aKey
== gIOCPUStateKey
) return gIOCPUStateNames
[_cpuState
];
542 return super::getProperty(aKey
);
545 bool IOCPU::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
549 if (aKey
== gIOCPUStateKey
) {
550 stateStr
= OSDynamicCast(OSString
, anObject
);
551 if (stateStr
== 0) return false;
553 if (_cpuNumber
== 0) return false;
555 if (stateStr
->isEqualTo("running")) {
556 if (_cpuState
== kIOCPUStateStopped
) {
557 processor_start(machProcessor
);
558 } else if (_cpuState
!= kIOCPUStateRunning
) {
561 } else if (stateStr
->isEqualTo("stopped")) {
562 if (_cpuState
== kIOCPUStateRunning
) {
564 } else if (_cpuState
!= kIOCPUStateStopped
) {
572 return super::setProperty(aKey
, anObject
);
575 bool IOCPU::serializeProperties(OSSerialize
*serialize
) const
578 OSDictionary
*dict
= dictionaryWithProperties();
579 if (!dict
) return false;
580 dict
->setObject(gIOCPUStateKey
, gIOCPUStateNames
[_cpuState
]);
581 result
= dict
->serialize(serialize
);
586 IOReturn
IOCPU::setProperties(OSObject
*properties
)
588 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, properties
);
592 if (dict
== 0) return kIOReturnUnsupported
;
594 stateStr
= OSDynamicCast(OSString
, dict
->getObject(gIOCPUStateKey
));
596 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
597 if (result
!= kIOReturnSuccess
) return result
;
599 if (setProperty(gIOCPUStateKey
, stateStr
)) return kIOReturnSuccess
;
601 return kIOReturnUnsupported
;
604 return kIOReturnUnsupported
;
607 void IOCPU::signalCPU(IOCPU */
*target*/
)
611 void IOCPU::signalCPUDeferred(IOCPU
*target
)
613 // Our CPU may not support deferred IPIs,
614 // so send a regular IPI by default
618 void IOCPU::signalCPUCancel(IOCPU */
*target*/
)
620 // Meant to cancel signals sent by
621 // signalCPUDeferred; unsupported
625 void IOCPU::enableCPUTimeBase(bool /*enable*/)
629 UInt32
IOCPU::getCPUNumber(void)
634 void IOCPU::setCPUNumber(UInt32 cpuNumber
)
636 _cpuNumber
= cpuNumber
;
637 super::setProperty("IOCPUNumber", _cpuNumber
, 32);
640 UInt32
IOCPU::getCPUState(void)
645 void IOCPU::setCPUState(UInt32 cpuState
)
647 if (cpuState
< kIOCPUStateCount
) {
648 _cpuState
= cpuState
;
652 OSArray
*IOCPU::getCPUGroup(void)
657 UInt32
IOCPU::getCPUGroupSize(void)
659 return _cpuGroup
->getCount();
662 processor_t
IOCPU::getMachProcessor(void)
664 return machProcessor
;
668 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
671 #define super IOInterruptController
673 OSDefineMetaClassAndStructors(IOCPUInterruptController
, IOInterruptController
);
675 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 0);
676 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 1);
677 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 2);
678 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 3);
679 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 4);
680 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 5);
684 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
687 IOReturn
IOCPUInterruptController::initCPUInterruptController(int sources
)
691 if (!super::init()) return kIOReturnInvalid
;
695 cpus
= (IOCPU
**)IOMalloc(numCPUs
* sizeof(IOCPU
*));
696 if (cpus
== 0) return kIOReturnNoMemory
;
697 bzero(cpus
, numCPUs
* sizeof(IOCPU
*));
699 vectors
= (IOInterruptVector
*)IOMalloc(numCPUs
* sizeof(IOInterruptVector
));
700 if (vectors
== 0) return kIOReturnNoMemory
;
701 bzero(vectors
, numCPUs
* sizeof(IOInterruptVector
));
703 // Allocate locks for the
704 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
705 vectors
[cnt
].interruptLock
= IOLockAlloc();
706 if (vectors
[cnt
].interruptLock
== NULL
) {
707 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
708 if (vectors
[cnt
].interruptLock
!= NULL
)
709 IOLockFree(vectors
[cnt
].interruptLock
);
711 return kIOReturnNoResources
;
715 ml_init_max_cpus(numCPUs
);
717 return kIOReturnSuccess
;
720 void IOCPUInterruptController::registerCPUInterruptController(void)
724 getPlatform()->registerInterruptController(gPlatformInterruptControllerName
,
728 void IOCPUInterruptController::setCPUInterruptProperties(IOService
*service
)
736 if ((service
->getProperty(gIOInterruptControllersKey
) != 0) &&
737 (service
->getProperty(gIOInterruptSpecifiersKey
) != 0))
740 // Create the interrupt specifer array.
741 specifier
= OSArray::withCapacity(numCPUs
);
742 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
744 tmpData
= OSData::withBytes(&tmpLong
, sizeof(tmpLong
));
745 specifier
->setObject(tmpData
);
749 // Create the interrupt controller array.
750 controller
= OSArray::withCapacity(numCPUs
);
751 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
752 controller
->setObject(gPlatformInterruptControllerName
);
755 // Put the two arrays into the property table.
756 service
->setProperty(gIOInterruptControllersKey
, controller
);
757 service
->setProperty(gIOInterruptSpecifiersKey
, specifier
);
758 controller
->release();
759 specifier
->release();
762 void IOCPUInterruptController::enableCPUInterrupt(IOCPU
*cpu
)
764 IOInterruptHandler handler
= OSMemberFunctionCast(
765 IOInterruptHandler
, this, &IOCPUInterruptController::handleInterrupt
);
767 ml_install_interrupt_handler(cpu
, cpu
->getCPUNumber(), this, handler
, 0);
769 // Ensure that the increment is seen by all processors
770 OSIncrementAtomic(&enabledCPUs
);
772 if (enabledCPUs
== numCPUs
) {
773 IOService::cpusRunning();
778 IOReturn
IOCPUInterruptController::registerInterrupt(IOService
*nub
,
781 IOInterruptHandler handler
,
784 IOInterruptVector
*vector
;
786 if (source
>= numCPUs
) return kIOReturnNoResources
;
788 vector
= &vectors
[source
];
790 // Get the lock for this vector.
791 IOTakeLock(vector
->interruptLock
);
793 // Make sure the vector is not in use.
794 if (vector
->interruptRegistered
) {
795 IOUnlock(vector
->interruptLock
);
796 return kIOReturnNoResources
;
799 // Fill in vector with the client's info.
800 vector
->handler
= handler
;
802 vector
->source
= source
;
803 vector
->target
= target
;
804 vector
->refCon
= refCon
;
806 // Get the vector ready. It starts hard disabled.
807 vector
->interruptDisabledHard
= 1;
808 vector
->interruptDisabledSoft
= 1;
809 vector
->interruptRegistered
= 1;
811 IOUnlock(vector
->interruptLock
);
813 if (enabledCPUs
!= numCPUs
) {
814 assert_wait(this, THREAD_UNINT
);
815 thread_block(THREAD_CONTINUE_NULL
);
818 return kIOReturnSuccess
;
821 IOReturn
IOCPUInterruptController::getInterruptType(IOService */
*nub*/
,
825 if (interruptType
== 0) return kIOReturnBadArgument
;
827 *interruptType
= kIOInterruptTypeLevel
;
829 return kIOReturnSuccess
;
832 IOReturn
IOCPUInterruptController::enableInterrupt(IOService */
*nub*/
,
835 // ml_set_interrupts_enabled(true);
836 return kIOReturnSuccess
;
839 IOReturn
IOCPUInterruptController::disableInterrupt(IOService */
*nub*/
,
842 // ml_set_interrupts_enabled(false);
843 return kIOReturnSuccess
;
846 IOReturn
IOCPUInterruptController::causeInterrupt(IOService */
*nub*/
,
849 ml_cause_interrupt();
850 return kIOReturnSuccess
;
853 IOReturn
IOCPUInterruptController::handleInterrupt(void */
*refCon*/
,
857 IOInterruptVector
*vector
;
859 vector
= &vectors
[source
];
861 if (!vector
->interruptRegistered
) return kIOReturnInvalid
;
863 vector
->handler(vector
->target
, vector
->refCon
,
864 vector
->nub
, vector
->source
);
866 return kIOReturnSuccess
;
869 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */