2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
38 #include <machine/machine_routines.h>
39 #include <pexpert/pexpert.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOUserClient.h>
45 #include <IOKit/IOCPU.h>
48 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
50 kern_return_t
PE_cpu_start(cpu_id_t target
,
51 vm_offset_t start_paddr
, vm_offset_t arg_paddr
)
53 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
55 if (targetCPU
== 0) return KERN_FAILURE
;
56 return targetCPU
->startCPU(start_paddr
, arg_paddr
);
59 void PE_cpu_halt(cpu_id_t target
)
61 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
63 if (targetCPU
) targetCPU
->haltCPU();
66 void PE_cpu_signal(cpu_id_t source
, cpu_id_t target
)
68 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
69 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
71 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPU(targetCPU
);
74 void PE_cpu_machine_init(cpu_id_t target
, boolean_t boot
)
76 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
78 if (targetCPU
) targetCPU
->initCPU(boot
);
81 void PE_cpu_machine_quiesce(cpu_id_t target
)
83 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
85 if (targetCPU
) targetCPU
->quiesceCPU();
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 #define super IOService
92 OSDefineMetaClassAndAbstractStructors(IOCPU
, IOService
);
93 OSMetaClassDefineReservedUnused(IOCPU
, 0);
94 OSMetaClassDefineReservedUnused(IOCPU
, 1);
95 OSMetaClassDefineReservedUnused(IOCPU
, 2);
96 OSMetaClassDefineReservedUnused(IOCPU
, 3);
97 OSMetaClassDefineReservedUnused(IOCPU
, 4);
98 OSMetaClassDefineReservedUnused(IOCPU
, 5);
99 OSMetaClassDefineReservedUnused(IOCPU
, 6);
100 OSMetaClassDefineReservedUnused(IOCPU
, 7);
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
104 static OSArray
*gIOCPUs
;
105 static const OSSymbol
*gIOCPUStateKey
;
106 static OSString
*gIOCPUStateNames
[kIOCPUStateCount
];
108 void IOCPUSleepKernel(void)
113 numCPUs
= gIOCPUs
->getCount();
118 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
119 if (target
->getCPUState() == kIOCPUStateRunning
) {
124 // Wake the other CPUs.
125 for (cnt
= 1; cnt
< numCPUs
; cnt
++) {
126 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
127 if (target
->getCPUState() == kIOCPUStateStopped
) {
128 processor_start(target
->getMachProcessor());
133 void IOCPU::initCPUs(void)
136 gIOCPUs
= OSArray::withCapacity(1);
138 gIOCPUStateKey
= OSSymbol::withCStringNoCopy("IOCPUState");
140 gIOCPUStateNames
[kIOCPUStateUnregistered
] =
141 OSString::withCStringNoCopy("Unregistered");
142 gIOCPUStateNames
[kIOCPUStateUninitalized
] =
143 OSString::withCStringNoCopy("Uninitalized");
144 gIOCPUStateNames
[kIOCPUStateStopped
] =
145 OSString::withCStringNoCopy("Stopped");
146 gIOCPUStateNames
[kIOCPUStateRunning
] =
147 OSString::withCStringNoCopy("Running");
151 bool IOCPU::start(IOService
*provider
)
153 OSData
*busFrequency
, *cpuFrequency
, *timebaseFrequency
;
155 if (!super::start(provider
)) return false;
162 gIOCPUs
->setObject(this);
164 // Correct the bus, cpu and timebase frequencies in the device tree.
165 if (gPEClockFrequencyInfo
.bus_frequency_hz
< 0x100000000ULL
) {
166 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
168 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_frequency_hz
, 8);
170 provider
->setProperty("bus-frequency", busFrequency
);
171 busFrequency
->release();
173 if (gPEClockFrequencyInfo
.cpu_frequency_hz
< 0x100000000ULL
) {
174 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_clock_rate_hz
, 4);
176 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_frequency_hz
, 8);
178 provider
->setProperty("clock-frequency", cpuFrequency
);
179 cpuFrequency
->release();
181 timebaseFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.timebase_frequency_hz
, 4);
182 provider
->setProperty("timebase-frequency", timebaseFrequency
);
183 timebaseFrequency
->release();
185 super::setProperty("IOCPUID", (UInt32
)this, 32);
188 setCPUState(kIOCPUStateUnregistered
);
193 OSObject
*IOCPU::getProperty(const OSSymbol
*aKey
) const
195 if (aKey
== gIOCPUStateKey
) return gIOCPUStateNames
[_cpuState
];
197 return super::getProperty(aKey
);
200 bool IOCPU::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
204 if (aKey
== gIOCPUStateKey
) {
205 stateStr
= OSDynamicCast(OSString
, anObject
);
206 if (stateStr
== 0) return false;
208 if (_cpuNumber
== 0) return false;
210 if (stateStr
->isEqualTo("running")) {
211 if (_cpuState
== kIOCPUStateStopped
) {
212 processor_start(machProcessor
);
213 } else if (_cpuState
!= kIOCPUStateRunning
) {
216 } else if (stateStr
->isEqualTo("stopped")) {
217 if (_cpuState
== kIOCPUStateRunning
) {
219 } else if (_cpuState
!= kIOCPUStateStopped
) {
227 return super::setProperty(aKey
, anObject
);
230 bool IOCPU::serializeProperties(OSSerialize
*serialize
) const
233 OSDictionary
*dict
= dictionaryWithProperties();
234 dict
->setObject(gIOCPUStateKey
, gIOCPUStateNames
[_cpuState
]);
235 result
= dict
->serialize(serialize
);
240 IOReturn
IOCPU::setProperties(OSObject
*properties
)
242 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, properties
);
246 if (dict
== 0) return kIOReturnUnsupported
;
248 stateStr
= OSDynamicCast(OSString
, dict
->getObject(gIOCPUStateKey
));
250 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
251 if (result
!= kIOReturnSuccess
) return result
;
253 if (setProperty(gIOCPUStateKey
, stateStr
)) return kIOReturnSuccess
;
255 return kIOReturnUnsupported
;
258 return kIOReturnUnsupported
;
261 void IOCPU::signalCPU(IOCPU */
*target*/
)
265 void IOCPU::enableCPUTimeBase(bool /*enable*/)
269 UInt32
IOCPU::getCPUNumber(void)
274 void IOCPU::setCPUNumber(UInt32 cpuNumber
)
276 _cpuNumber
= cpuNumber
;
277 super::setProperty("IOCPUNumber", _cpuNumber
, 32);
280 UInt32
IOCPU::getCPUState(void)
285 void IOCPU::setCPUState(UInt32 cpuState
)
287 if (cpuState
< kIOCPUStateCount
) {
288 _cpuState
= cpuState
;
292 OSArray
*IOCPU::getCPUGroup(void)
297 UInt32
IOCPU::getCPUGroupSize(void)
299 return _cpuGroup
->getCount();
302 processor_t
IOCPU::getMachProcessor(void)
304 return machProcessor
;
308 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
311 #define super IOInterruptController
313 OSDefineMetaClassAndStructors(IOCPUInterruptController
, IOInterruptController
);
315 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 0);
316 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 1);
317 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 2);
318 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 3);
319 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 4);
320 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 5);
324 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327 IOReturn
IOCPUInterruptController::initCPUInterruptController(int sources
)
331 if (!super::init()) return kIOReturnInvalid
;
335 cpus
= (IOCPU
**)IOMalloc(numCPUs
* sizeof(IOCPU
*));
336 if (cpus
== 0) return kIOReturnNoMemory
;
337 bzero(cpus
, numCPUs
* sizeof(IOCPU
*));
339 vectors
= (IOInterruptVector
*)IOMalloc(numCPUs
* sizeof(IOInterruptVector
));
340 if (vectors
== 0) return kIOReturnNoMemory
;
341 bzero(vectors
, numCPUs
* sizeof(IOInterruptVector
));
343 // Allocate locks for the
344 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
345 vectors
[cnt
].interruptLock
= IOLockAlloc();
346 if (vectors
[cnt
].interruptLock
== NULL
) {
347 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
348 if (vectors
[cnt
].interruptLock
!= NULL
)
349 IOLockFree(vectors
[cnt
].interruptLock
);
351 return kIOReturnNoResources
;
355 ml_init_max_cpus(numCPUs
);
357 return kIOReturnSuccess
;
360 void IOCPUInterruptController::registerCPUInterruptController(void)
364 getPlatform()->registerInterruptController(gPlatformInterruptControllerName
,
368 void IOCPUInterruptController::setCPUInterruptProperties(IOService
*service
)
376 // Create the interrupt specifer array.
377 specifier
= OSArray::withCapacity(numCPUs
);
378 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
380 tmpData
= OSData::withBytes(&tmpLong
, sizeof(tmpLong
));
381 specifier
->setObject(tmpData
);
385 // Create the interrupt controller array.
386 controller
= OSArray::withCapacity(numCPUs
);
387 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
388 controller
->setObject(gPlatformInterruptControllerName
);
391 // Put the two arrays into the property table.
392 service
->setProperty(gIOInterruptControllersKey
, controller
);
393 service
->setProperty(gIOInterruptSpecifiersKey
, specifier
);
394 controller
->release();
395 specifier
->release();
398 void IOCPUInterruptController::enableCPUInterrupt(IOCPU
*cpu
)
400 IOInterruptHandler handler
= OSMemberFunctionCast(
401 IOInterruptHandler
, this, &IOCPUInterruptController::handleInterrupt
);
403 ml_install_interrupt_handler(cpu
, cpu
->getCPUNumber(), this, handler
, 0);
407 if (enabledCPUs
== numCPUs
) thread_wakeup(this);
410 IOReturn
IOCPUInterruptController::registerInterrupt(IOService
*nub
,
413 IOInterruptHandler handler
,
416 IOInterruptVector
*vector
;
418 if (source
>= numCPUs
) return kIOReturnNoResources
;
420 vector
= &vectors
[source
];
422 // Get the lock for this vector.
423 IOTakeLock(vector
->interruptLock
);
425 // Make sure the vector is not in use.
426 if (vector
->interruptRegistered
) {
427 IOUnlock(vector
->interruptLock
);
428 return kIOReturnNoResources
;
431 // Fill in vector with the client's info.
432 vector
->handler
= handler
;
434 vector
->source
= source
;
435 vector
->target
= target
;
436 vector
->refCon
= refCon
;
438 // Get the vector ready. It starts hard disabled.
439 vector
->interruptDisabledHard
= 1;
440 vector
->interruptDisabledSoft
= 1;
441 vector
->interruptRegistered
= 1;
443 IOUnlock(vector
->interruptLock
);
445 if (enabledCPUs
!= numCPUs
) {
446 assert_wait(this, THREAD_UNINT
);
447 thread_block(THREAD_CONTINUE_NULL
);
450 return kIOReturnSuccess
;
453 IOReturn
IOCPUInterruptController::getInterruptType(IOService */
*nub*/
,
457 if (interruptType
== 0) return kIOReturnBadArgument
;
459 *interruptType
= kIOInterruptTypeLevel
;
461 return kIOReturnSuccess
;
464 IOReturn
IOCPUInterruptController::enableInterrupt(IOService */
*nub*/
,
467 // ml_set_interrupts_enabled(true);
468 return kIOReturnSuccess
;
471 IOReturn
IOCPUInterruptController::disableInterrupt(IOService */
*nub*/
,
474 // ml_set_interrupts_enabled(false);
475 return kIOReturnSuccess
;
478 IOReturn
IOCPUInterruptController::causeInterrupt(IOService */
*nub*/
,
481 ml_cause_interrupt();
482 return kIOReturnSuccess
;
485 IOReturn
IOCPUInterruptController::handleInterrupt(void */
*refCon*/
,
489 IOInterruptVector
*vector
;
491 vector
= &vectors
[source
];
493 if (!vector
->interruptRegistered
) return kIOReturnInvalid
;
495 vector
->handler(vector
->target
, vector
->refCon
,
496 vector
->nub
, vector
->source
);
498 return kIOReturnSuccess
;
501 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */