2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
33 #include <machine/machine_routines.h>
34 #include <pexpert/pexpert.h>
37 #include <IOKit/IOLib.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IOUserClient.h>
40 #include <IOKit/IOCPU.h>
43 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
45 kern_return_t
PE_cpu_start(cpu_id_t target
,
46 vm_offset_t start_paddr
, vm_offset_t arg_paddr
)
48 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
50 if (targetCPU
== 0) return KERN_FAILURE
;
51 return targetCPU
->startCPU(start_paddr
, arg_paddr
);
54 void PE_cpu_halt(cpu_id_t target
)
56 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
58 if (targetCPU
) targetCPU
->haltCPU();
61 void PE_cpu_signal(cpu_id_t source
, cpu_id_t target
)
63 IOCPU
*sourceCPU
= OSDynamicCast(IOCPU
, (OSObject
*)source
);
64 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
66 if (sourceCPU
&& targetCPU
) sourceCPU
->signalCPU(targetCPU
);
69 void PE_cpu_machine_init(cpu_id_t target
, boolean_t boot
)
71 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
73 if (targetCPU
) targetCPU
->initCPU(boot
);
76 void PE_cpu_machine_quiesce(cpu_id_t target
)
78 IOCPU
*targetCPU
= OSDynamicCast(IOCPU
, (OSObject
*)target
);
80 if (targetCPU
) targetCPU
->quiesceCPU();
83 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
85 #define super IOService
87 OSDefineMetaClassAndAbstractStructors(IOCPU
, IOService
);
88 OSMetaClassDefineReservedUnused(IOCPU
, 0);
89 OSMetaClassDefineReservedUnused(IOCPU
, 1);
90 OSMetaClassDefineReservedUnused(IOCPU
, 2);
91 OSMetaClassDefineReservedUnused(IOCPU
, 3);
92 OSMetaClassDefineReservedUnused(IOCPU
, 4);
93 OSMetaClassDefineReservedUnused(IOCPU
, 5);
94 OSMetaClassDefineReservedUnused(IOCPU
, 6);
95 OSMetaClassDefineReservedUnused(IOCPU
, 7);
97 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
99 static OSArray
*gIOCPUs
;
100 static const OSSymbol
*gIOCPUStateKey
;
101 static OSString
*gIOCPUStateNames
[kIOCPUStateCount
];
103 void IOCPUSleepKernel(void)
108 numCPUs
= gIOCPUs
->getCount();
113 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
114 if (target
->getCPUState() == kIOCPUStateRunning
) {
119 // Wake the other CPUs.
120 for (cnt
= 1; cnt
< numCPUs
; cnt
++) {
121 target
= OSDynamicCast(IOCPU
, gIOCPUs
->getObject(cnt
));
122 if (target
->getCPUState() == kIOCPUStateStopped
) {
123 processor_start(target
->getMachProcessor());
128 void IOCPU::initCPUs(void)
131 gIOCPUs
= OSArray::withCapacity(1);
133 gIOCPUStateKey
= OSSymbol::withCStringNoCopy("IOCPUState");
135 gIOCPUStateNames
[kIOCPUStateUnregistered
] =
136 OSString::withCStringNoCopy("Unregistered");
137 gIOCPUStateNames
[kIOCPUStateUninitalized
] =
138 OSString::withCStringNoCopy("Uninitalized");
139 gIOCPUStateNames
[kIOCPUStateStopped
] =
140 OSString::withCStringNoCopy("Stopped");
141 gIOCPUStateNames
[kIOCPUStateRunning
] =
142 OSString::withCStringNoCopy("Running");
146 bool IOCPU::start(IOService
*provider
)
148 OSData
*busFrequency
, *cpuFrequency
, *timebaseFrequency
;
150 if (!super::start(provider
)) return false;
157 gIOCPUs
->setObject(this);
159 // Correct the bus, cpu and timebase frequencies in the device tree.
160 if (gPEClockFrequencyInfo
.bus_frequency_hz
< 0x100000000ULL
)
161 busFrequency
= OSData::withBytesNoCopy((void *)((char *)&gPEClockFrequencyInfo
.bus_frequency_hz
+ 4), 4);
163 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 8);
164 provider
->setProperty("bus-frequency", busFrequency
);
165 busFrequency
->release();
167 if (gPEClockFrequencyInfo
.cpu_frequency_hz
< 0x100000000ULL
)
168 cpuFrequency
= OSData::withBytesNoCopy((void *)((char *)&gPEClockFrequencyInfo
.cpu_frequency_hz
+ 4), 4);
170 cpuFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.cpu_clock_rate_hz
, 8);
171 provider
->setProperty("clock-frequency", cpuFrequency
);
172 cpuFrequency
->release();
174 timebaseFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.timebase_frequency_hz
, 4);
175 provider
->setProperty("timebase-frequency", timebaseFrequency
);
176 timebaseFrequency
->release();
178 setProperty("IOCPUID", (UInt32
)this, 32);
181 setCPUState(kIOCPUStateUnregistered
);
186 IOReturn
IOCPU::setProperties(OSObject
*properties
)
188 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, properties
);
192 if (dict
== 0) return kIOReturnUnsupported
;
194 stateStr
= OSDynamicCast(OSString
, dict
->getObject(gIOCPUStateKey
));
196 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
197 if (result
!= kIOReturnSuccess
) return result
;
199 if (_cpuNumber
== 0) return kIOReturnUnsupported
;
201 if (stateStr
->isEqualTo("running")) {
202 if (_cpuState
== kIOCPUStateStopped
) {
203 processor_start(machProcessor
);
204 } else if (_cpuState
!= kIOCPUStateRunning
) {
205 return kIOReturnUnsupported
;
207 } else if (stateStr
->isEqualTo("stopped")) {
208 if (_cpuState
== kIOCPUStateRunning
) {
210 } else if (_cpuState
!= kIOCPUStateStopped
) {
211 return kIOReturnUnsupported
;
213 } else return kIOReturnUnsupported
;
215 return kIOReturnSuccess
;
218 return kIOReturnUnsupported
;
221 void IOCPU::signalCPU(IOCPU */
*target*/
)
225 void IOCPU::enableCPUTimeBase(bool /*enable*/)
229 UInt32
IOCPU::getCPUNumber(void)
234 void IOCPU::setCPUNumber(UInt32 cpuNumber
)
236 _cpuNumber
= cpuNumber
;
237 setProperty("IOCPUNumber", _cpuNumber
, 32);
240 UInt32
IOCPU::getCPUState(void)
245 void IOCPU::setCPUState(UInt32 cpuState
)
247 if ((cpuState
>= 0) && (cpuState
< kIOCPUStateCount
)) {
248 _cpuState
= cpuState
;
249 setProperty(gIOCPUStateKey
, gIOCPUStateNames
[cpuState
]);
253 OSArray
*IOCPU::getCPUGroup(void)
258 UInt32
IOCPU::getCPUGroupSize(void)
260 return _cpuGroup
->getCount();
263 processor_t
IOCPU::getMachProcessor(void)
265 return machProcessor
;
269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
272 #define super IOInterruptController
274 OSDefineMetaClassAndStructors(IOCPUInterruptController
, IOInterruptController
);
276 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 0);
277 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 1);
278 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 2);
279 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 3);
280 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 4);
281 OSMetaClassDefineReservedUnused(IOCPUInterruptController
, 5);
285 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
288 IOReturn
IOCPUInterruptController::initCPUInterruptController(int sources
)
292 if (!super::init()) return kIOReturnInvalid
;
296 cpus
= (IOCPU
**)IOMalloc(numCPUs
* sizeof(IOCPU
*));
297 if (cpus
== 0) return kIOReturnNoMemory
;
298 bzero(cpus
, numCPUs
* sizeof(IOCPU
*));
300 vectors
= (IOInterruptVector
*)IOMalloc(numCPUs
* sizeof(IOInterruptVector
));
301 if (vectors
== 0) return kIOReturnNoMemory
;
302 bzero(vectors
, numCPUs
* sizeof(IOInterruptVector
));
304 // Allocate locks for the
305 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
306 vectors
[cnt
].interruptLock
= IOLockAlloc();
307 if (vectors
[cnt
].interruptLock
== NULL
) {
308 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
309 if (vectors
[cnt
].interruptLock
!= NULL
)
310 IOLockFree(vectors
[cnt
].interruptLock
);
312 return kIOReturnNoResources
;
316 ml_init_max_cpus(numCPUs
);
318 return kIOReturnSuccess
;
321 void IOCPUInterruptController::registerCPUInterruptController(void)
325 getPlatform()->registerInterruptController(gPlatformInterruptControllerName
,
329 void IOCPUInterruptController::setCPUInterruptProperties(IOService
*service
)
337 // Create the interrupt specifer array.
338 specifier
= OSArray::withCapacity(numCPUs
);
339 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
341 tmpData
= OSData::withBytes(&tmpLong
, sizeof(tmpLong
));
342 specifier
->setObject(tmpData
);
346 // Create the interrupt controller array.
347 controller
= OSArray::withCapacity(numCPUs
);
348 for (cnt
= 0; cnt
< numCPUs
; cnt
++) {
349 controller
->setObject(gPlatformInterruptControllerName
);
352 // Put the two arrays into the property table.
353 service
->setProperty(gIOInterruptControllersKey
, controller
);
354 service
->setProperty(gIOInterruptSpecifiersKey
, specifier
);
355 controller
->release();
356 specifier
->release();
359 void IOCPUInterruptController::enableCPUInterrupt(IOCPU
*cpu
)
361 ml_install_interrupt_handler(cpu
, cpu
->getCPUNumber(), this,
362 (IOInterruptHandler
)&IOCPUInterruptController::handleInterrupt
, 0);
366 if (enabledCPUs
== numCPUs
) thread_wakeup(this);
369 IOReturn
IOCPUInterruptController::registerInterrupt(IOService
*nub
,
372 IOInterruptHandler handler
,
375 IOInterruptVector
*vector
;
377 if (source
>= numCPUs
) return kIOReturnNoResources
;
379 vector
= &vectors
[source
];
381 // Get the lock for this vector.
382 IOTakeLock(vector
->interruptLock
);
384 // Make sure the vector is not in use.
385 if (vector
->interruptRegistered
) {
386 IOUnlock(vector
->interruptLock
);
387 return kIOReturnNoResources
;
390 // Fill in vector with the client's info.
391 vector
->handler
= handler
;
393 vector
->source
= source
;
394 vector
->target
= target
;
395 vector
->refCon
= refCon
;
397 // Get the vector ready. It starts hard disabled.
398 vector
->interruptDisabledHard
= 1;
399 vector
->interruptDisabledSoft
= 1;
400 vector
->interruptRegistered
= 1;
402 IOUnlock(vector
->interruptLock
);
404 if (enabledCPUs
!= numCPUs
) {
405 assert_wait(this, THREAD_UNINT
);
406 thread_block(THREAD_CONTINUE_NULL
);
409 return kIOReturnSuccess
;
412 IOReturn
IOCPUInterruptController::getInterruptType(IOService */
*nub*/
,
416 if (interruptType
== 0) return kIOReturnBadArgument
;
418 *interruptType
= kIOInterruptTypeLevel
;
420 return kIOReturnSuccess
;
423 IOReturn
IOCPUInterruptController::enableInterrupt(IOService */
*nub*/
,
426 // ml_set_interrupts_enabled(true);
427 return kIOReturnSuccess
;
430 IOReturn
IOCPUInterruptController::disableInterrupt(IOService */
*nub*/
,
433 // ml_set_interrupts_enabled(false);
434 return kIOReturnSuccess
;
437 IOReturn
IOCPUInterruptController::causeInterrupt(IOService */
*nub*/
,
440 ml_cause_interrupt();
441 return kIOReturnSuccess
;
444 IOReturn
IOCPUInterruptController::handleInterrupt(void */
*refCon*/
,
448 IOInterruptVector
*vector
;
450 vector
= &vectors
[source
];
452 if (!vector
->interruptRegistered
) return kIOReturnInvalid
;
454 vector
->handler(vector
->target
, vector
->refCon
,
455 vector
->nub
, vector
->source
);
457 return kIOReturnSuccess
;
460 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */