2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
30 #include <machine/machine_routines.h>
31 #include <pexpert/pexpert.h>
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IOUserClient.h>
37 #include <IOKit/IOCPU.h>
40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
42 kern_return_t
PE_cpu_start(cpu_id_t target
,
43 vm_offset_t start_paddr
, vm_offset_t arg_paddr
)
45 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
47 if (targetCPU
== 0) return KERN_FAILURE
;
48 return targetCPU
->startCPU(start_paddr
, arg_paddr
);
51 void PE_cpu_halt(cpu_id_t target
)
53 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
55 if (targetCPU
) targetCPU
->haltCPU();
58 void PE_cpu_signal(cpu_id_t source
, cpu_id_t target
)
60 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
61 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
63 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPU(targetCPU
);
66 void PE_cpu_machine_init(cpu_id_t target
, boolean_t boot
)
68 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
70 if (targetCPU
) targetCPU
->initCPU(boot
);
73 void PE_cpu_machine_quiesce(cpu_id_t target
)
75 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
77 if (targetCPU
) targetCPU
->quiesceCPU();
80 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
82 #define super IOService
84 OSDefineMetaClassAndAbstractStructors(IOCPU
, IOService
);
85 OSMetaClassDefineReservedUnused(IOCPU
, 0);
86 OSMetaClassDefineReservedUnused(IOCPU
, 1);
87 OSMetaClassDefineReservedUnused(IOCPU
, 2);
88 OSMetaClassDefineReservedUnused(IOCPU
, 3);
89 OSMetaClassDefineReservedUnused(IOCPU
, 4);
90 OSMetaClassDefineReservedUnused(IOCPU
, 5);
91 OSMetaClassDefineReservedUnused(IOCPU
, 6);
92 OSMetaClassDefineReservedUnused(IOCPU
, 7);
94 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
96 static OSArray
*gIOCPUs
;
97 static const OSSymbol
*gIOCPUStateKey
;
98 static OSString
*gIOCPUStateNames
[kIOCPUStateCount
];
100 void IOCPUSleepKernel(void)
105 numCPUs
= gIOCPUs
->getCount();
110 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
111 if (target
->getCPUState() == kIOCPUStateRunning
) {
116 // Wake the other CPUs.
117 for (cnt
= 1; cnt
< numCPUs
; cnt
++) {
118 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
119 if (target
->getCPUState() == kIOCPUStateStopped
) {
120 processor_start(target
->getMachProcessor());
125 void IOCPU::initCPUs(void)
128 gIOCPUs
= OSArray::withCapacity(1);
130 gIOCPUStateKey
= OSSymbol::withCStringNoCopy("IOCPUState");
132 gIOCPUStateNames
[kIOCPUStateUnregistered
] =
133 OSString::withCStringNoCopy("Unregistered");
134 gIOCPUStateNames
[kIOCPUStateUninitalized
] =
135 OSString::withCStringNoCopy("Uninitalized");
136 gIOCPUStateNames
[kIOCPUStateStopped
] =
137 OSString::withCStringNoCopy("Stopped");
138 gIOCPUStateNames
[kIOCPUStateRunning
] =
139 OSString::withCStringNoCopy("Running");
143 bool IOCPU::start(IOService
*provider
)
145 OSData
*busFrequency
, *cpuFrequency
, *timebaseFrequency
;
147 if (!super::start(provider
)) return false;
154 gIOCPUs
->setObject(this);
156 // Correct the bus, cpu and timebase frequencies in the device tree.
157 if (gPEClockFrequencyInfo
.bus_frequency_hz
< 0x100000000ULL
) {
158 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
160 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_frequency_hz
, 8);
162 provider
->setProperty("bus-frequency", busFrequency
);
163 busFrequency
->release();
165 if (gPEClockFrequencyInfo
.cpu_frequency_hz
< 0x100000000ULL
) {
166 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_clock_rate_hz
, 4);
168 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_frequency_hz
, 8);
170 provider
->setProperty("clock-frequency", cpuFrequency
);
171 cpuFrequency
->release();
173 timebaseFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.timebase_frequency_hz
, 4);
174 provider
->setProperty("timebase-frequency", timebaseFrequency
);
175 timebaseFrequency
->release();
177 super::setProperty("IOCPUID", (UInt32
)this, 32);
180 setCPUState(kIOCPUStateUnregistered
);
185 OSObject
*IOCPU::getProperty(const OSSymbol
*aKey
) const
187 if (aKey
== gIOCPUStateKey
) return gIOCPUStateNames
[_cpuState
];
189 return super::getProperty(aKey
);
192 bool IOCPU::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
196 if (aKey
== gIOCPUStateKey
) {
197 stateStr
= OSDynamicCast(OSString
, anObject
);
198 if (stateStr
== 0) return false;
200 if (_cpuNumber
== 0) return false;
202 if (stateStr
->isEqualTo("running")) {
203 if (_cpuState
== kIOCPUStateStopped
) {
204 processor_start(machProcessor
);
205 } else if (_cpuState
!= kIOCPUStateRunning
) {
208 } else if (stateStr
->isEqualTo("stopped")) {
209 if (_cpuState
== kIOCPUStateRunning
) {
211 } else if (_cpuState
!= kIOCPUStateStopped
) {
219 return super::setProperty(aKey
, anObject
);
222 bool IOCPU::serializeProperties(OSSerialize
*serialize
) const
225 OSDictionary
*dict
= dictionaryWithProperties();
226 dict
->setObject(gIOCPUStateKey
, gIOCPUStateNames
[_cpuState
]);
227 result
= dict
->serialize(serialize
);
232 IOReturn
IOCPU::setProperties(OSObject
*properties
)
234 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, properties
);
238 if (dict
== 0) return kIOReturnUnsupported
;
240 stateStr
= OSDynamicCast(OSString
, dict
->getObject(gIOCPUStateKey
));
242 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
243 if (result
!= kIOReturnSuccess
) return result
;
245 if (setProperty(gIOCPUStateKey
, stateStr
)) return kIOReturnSuccess
;
247 return kIOReturnUnsupported
;
250 return kIOReturnUnsupported
;
253 void IOCPU::signalCPU(IOCPU */
*target*/
)
257 void IOCPU::enableCPUTimeBase(bool /*enable*/)
261 UInt32
IOCPU::getCPUNumber(void)
266 void IOCPU::setCPUNumber(UInt32 cpuNumber
)
268 _cpuNumber
= cpuNumber
;
269 super::setProperty("IOCPUNumber", _cpuNumber
, 32);
272 UInt32
IOCPU::getCPUState(void)
277 void IOCPU::setCPUState(UInt32 cpuState
)
279 if (cpuState
< kIOCPUStateCount
) {
280 _cpuState
= cpuState
;
284 OSArray
*IOCPU::getCPUGroup(void)
289 UInt32
IOCPU::getCPUGroupSize(void)
291 return _cpuGroup
->getCount();
294 processor_t
IOCPU::getMachProcessor(void)
296 return machProcessor
;
300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
303 #define super IOInterruptController
305 OSDefineMetaClassAndStructors(IOCPUInterruptController
, IOInterruptController
);
307 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 0);
308 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 1);
309 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 2);
310 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 3);
311 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 4);
312 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 5);
316 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
319 IOReturn
IOCPUInterruptController::initCPUInterruptController(int sources
)
323 if (!super::init()) return kIOReturnInvalid
;
327 cpus
= (IOCPU
**)IOMalloc(numCPUs
* sizeof(IOCPU
*));
328 if (cpus
== 0) return kIOReturnNoMemory
;
329 bzero(cpus
, numCPUs
* sizeof(IOCPU
*));
331 vectors
= (IOInterruptVector
*)IOMalloc(numCPUs
* sizeof(IOInterruptVector
));
332 if (vectors
== 0) return kIOReturnNoMemory
;
333 bzero(vectors
, numCPUs
* sizeof(IOInterruptVector
));
335 // Allocate locks for the
336 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
337 vectors
[cnt
].interruptLock
= IOLockAlloc();
338 if (vectors
[cnt
].interruptLock
== NULL
) {
339 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
340 if (vectors
[cnt
].interruptLock
!= NULL
)
341 IOLockFree(vectors
[cnt
].interruptLock
);
343 return kIOReturnNoResources
;
347 ml_init_max_cpus(numCPUs
);
349 return kIOReturnSuccess
;
352 void IOCPUInterruptController::registerCPUInterruptController(void)
356 getPlatform()->registerInterruptController(gPlatformInterruptControllerName
,
360 void IOCPUInterruptController::setCPUInterruptProperties(IOService
*service
)
368 // Create the interrupt specifer array.
369 specifier
= OSArray::withCapacity(numCPUs
);
370 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
372 tmpData
= OSData::withBytes(&tmpLong
, sizeof(tmpLong
));
373 specifier
->setObject(tmpData
);
377 // Create the interrupt controller array.
378 controller
= OSArray::withCapacity(numCPUs
);
379 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
380 controller
->setObject(gPlatformInterruptControllerName
);
383 // Put the two arrays into the property table.
384 service
->setProperty(gIOInterruptControllersKey
, controller
);
385 service
->setProperty(gIOInterruptSpecifiersKey
, specifier
);
386 controller
->release();
387 specifier
->release();
390 void IOCPUInterruptController::enableCPUInterrupt(IOCPU
*cpu
)
392 IOInterruptHandler handler
= OSMemberFunctionCast(
393 IOInterruptHandler
, this, &IOCPUInterruptController::handleInterrupt
);
395 ml_install_interrupt_handler(cpu
, cpu
->getCPUNumber(), this, handler
, 0);
399 if (enabledCPUs
== numCPUs
) thread_wakeup(this);
402 IOReturn
IOCPUInterruptController::registerInterrupt(IOService
*nub
,
405 IOInterruptHandler handler
,
408 IOInterruptVector
*vector
;
410 if (source
>= numCPUs
) return kIOReturnNoResources
;
412 vector
= &vectors
[source
];
414 // Get the lock for this vector.
415 IOTakeLock(vector
->interruptLock
);
417 // Make sure the vector is not in use.
418 if (vector
->interruptRegistered
) {
419 IOUnlock(vector
->interruptLock
);
420 return kIOReturnNoResources
;
423 // Fill in vector with the client's info.
424 vector
->handler
= handler
;
426 vector
->source
= source
;
427 vector
->target
= target
;
428 vector
->refCon
= refCon
;
430 // Get the vector ready. It starts hard disabled.
431 vector
->interruptDisabledHard
= 1;
432 vector
->interruptDisabledSoft
= 1;
433 vector
->interruptRegistered
= 1;
435 IOUnlock(vector
->interruptLock
);
437 if (enabledCPUs
!= numCPUs
) {
438 assert_wait(this, THREAD_UNINT
);
439 thread_block(THREAD_CONTINUE_NULL
);
442 return kIOReturnSuccess
;
445 IOReturn
IOCPUInterruptController::getInterruptType(IOService */
*nub*/
,
449 if (interruptType
== 0) return kIOReturnBadArgument
;
451 *interruptType
= kIOInterruptTypeLevel
;
453 return kIOReturnSuccess
;
456 IOReturn
IOCPUInterruptController::enableInterrupt(IOService */
*nub*/
,
459 // ml_set_interrupts_enabled(true);
460 return kIOReturnSuccess
;
463 IOReturn
IOCPUInterruptController::disableInterrupt(IOService */
*nub*/
,
466 // ml_set_interrupts_enabled(false);
467 return kIOReturnSuccess
;
470 IOReturn
IOCPUInterruptController::causeInterrupt(IOService */
*nub*/
,
473 ml_cause_interrupt();
474 return kIOReturnSuccess
;
477 IOReturn
IOCPUInterruptController::handleInterrupt(void */
*refCon*/
,
481 IOInterruptVector
*vector
;
483 vector
= &vectors
[source
];
485 if (!vector
->interruptRegistered
) return kIOReturnInvalid
;
487 vector
->handler(vector
->target
, vector
->refCon
,
488 vector
->nub
, vector
->source
);
490 return kIOReturnSuccess
;
493 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */