]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCPU.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
f427ee49
A
29#define IOKIT_ENABLE_SHARED_PTR
30
1c79356b
A
31extern "C" {
32#include <machine/machine_routines.h>
33#include <pexpert/pexpert.h>
490019cf 34#include <kern/cpu_number.h>
5ba3f43e 35extern void kperf_kernel_configure(char *);
1c79356b
A
36}
37
38#include <IOKit/IOLib.h>
39#include <IOKit/IOPlatformExpert.h>
2d21ac55 40#include <IOKit/pwr_mgt/RootDomain.h>
316670eb 41#include <IOKit/pwr_mgt/IOPMPrivate.h>
f427ee49 42#include <libkern/c++/OSSharedPtr.h>
1c79356b 43#include <IOKit/IOUserClient.h>
2d21ac55 44#include <IOKit/IOKitKeysPrivate.h>
1c79356b 45#include <IOKit/IOCPU.h>
39037602 46#include "IOKitKernelInternal.h"
1c79356b 47
2d21ac55 48/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
f427ee49 49
2d21ac55 50#include <kern/queue.h>
cb323159 51#include <kern/sched_prim.h>
2d21ac55 52
39037602
A
53extern "C" void console_suspend();
54extern "C" void console_resume();
d9a64523
A
55extern "C" void sched_override_recommended_cores_for_sleep(void);
56extern "C" void sched_restore_recommended_cores_after_sleep(void);
39037602 57
2d21ac55
A
58/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
59
5ba3f43e 60static IOLock *gIOCPUsLock;
f427ee49
A
61static OSSharedPtr<OSArray> gIOCPUs;
62static OSSharedPtr<const OSSymbol> gIOCPUStateKey;
63static OSSharedPtr<OSString> gIOCPUStateNames[kIOCPUStateCount];
2d21ac55
A
64
65/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
66
f427ee49 67#if !USE_APPLEARMSMP
3e170ce0
A
68
69void
70IOCPUInitialize(void)
fe8ab488 71{
0a7de745
A
72 gIOCPUsLock = IOLockAlloc();
73 gIOCPUs = OSArray::withCapacity(1);
74
0a7de745
A
75 gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
76
77 gIOCPUStateNames[kIOCPUStateUnregistered] =
78 OSString::withCStringNoCopy("Unregistered");
79 gIOCPUStateNames[kIOCPUStateUninitalized] =
80 OSString::withCStringNoCopy("Uninitalized");
81 gIOCPUStateNames[kIOCPUStateStopped] =
82 OSString::withCStringNoCopy("Stopped");
83 gIOCPUStateNames[kIOCPUStateRunning] =
84 OSString::withCStringNoCopy("Running");
fe8ab488
A
85}
86
1c79356b
A
87/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88
0a7de745
A
89kern_return_t
90PE_cpu_start(cpu_id_t target,
91 vm_offset_t start_paddr, vm_offset_t arg_paddr)
1c79356b 92{
0a7de745
A
93 IOCPU *targetCPU = (IOCPU *)target;
94
95 if (targetCPU == NULL) {
96 return KERN_FAILURE;
97 }
98 return targetCPU->startCPU(start_paddr, arg_paddr);
1c79356b
A
99}
100
0a7de745
A
101void
102PE_cpu_halt(cpu_id_t target)
1c79356b 103{
0a7de745
A
104 IOCPU *targetCPU = (IOCPU *)target;
105
106 targetCPU->haltCPU();
1c79356b
A
107}
108
0a7de745
A
109void
110PE_cpu_signal(cpu_id_t source, cpu_id_t target)
1c79356b 111{
0a7de745
A
112 IOCPU *sourceCPU = (IOCPU *)source;
113 IOCPU *targetCPU = (IOCPU *)target;
114
115 sourceCPU->signalCPU(targetCPU);
1c79356b
A
116}
117
0a7de745
A
118void
119PE_cpu_signal_deferred(cpu_id_t source, cpu_id_t target)
3e170ce0 120{
0a7de745
A
121 IOCPU *sourceCPU = (IOCPU *)source;
122 IOCPU *targetCPU = (IOCPU *)target;
3e170ce0 123
0a7de745 124 sourceCPU->signalCPUDeferred(targetCPU);
3e170ce0
A
125}
126
0a7de745
A
127void
128PE_cpu_signal_cancel(cpu_id_t source, cpu_id_t target)
3e170ce0 129{
0a7de745
A
130 IOCPU *sourceCPU = (IOCPU *)source;
131 IOCPU *targetCPU = (IOCPU *)target;
3e170ce0 132
0a7de745 133 sourceCPU->signalCPUCancel(targetCPU);
3e170ce0
A
134}
135
0a7de745
A
136void
137PE_cpu_machine_init(cpu_id_t target, boolean_t bootb)
1c79356b 138{
0a7de745 139 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
d9a64523 140
0a7de745
A
141 if (targetCPU == NULL) {
142 panic("%s: invalid target CPU %p", __func__, target);
143 }
d9a64523 144
0a7de745 145 targetCPU->initCPU(bootb);
5ba3f43e 146#if defined(__arm__) || defined(__arm64__)
0a7de745
A
147 if (!bootb && (targetCPU->getCPUNumber() == (UInt32)master_cpu)) {
148 ml_set_is_quiescing(false);
149 }
5ba3f43e 150#endif /* defined(__arm__) || defined(__arm64__) */
1c79356b
A
151}
152
0a7de745
A
153void
154PE_cpu_machine_quiesce(cpu_id_t target)
1c79356b 155{
0a7de745 156 IOCPU *targetCPU = (IOCPU*)target;
5ba3f43e 157#if defined(__arm__) || defined(__arm64__)
0a7de745
A
158 if (targetCPU->getCPUNumber() == (UInt32)master_cpu) {
159 ml_set_is_quiescing(true);
160 }
5ba3f43e 161#endif /* defined(__arm__) || defined(__arm64__) */
0a7de745 162 targetCPU->quiesceCPU();
5ba3f43e
A
163}
164
165#if defined(__arm__) || defined(__arm64__)
cb323159 166static perfmon_interrupt_handler_func pmi_handler = NULL;
2d21ac55 167
0a7de745
A
168kern_return_t
169PE_cpu_perfmon_interrupt_install_handler(perfmon_interrupt_handler_func handler)
5ba3f43e 170{
0a7de745 171 pmi_handler = handler;
5ba3f43e 172
0a7de745 173 return KERN_SUCCESS;
1c79356b
A
174}
175
0a7de745
A
176void
177PE_cpu_perfmon_interrupt_enable(cpu_id_t target, boolean_t enable)
5ba3f43e 178{
0a7de745 179 IOCPU *targetCPU = (IOCPU*)target;
5ba3f43e 180
0a7de745
A
181 if (targetCPU == nullptr) {
182 return;
183 }
d9a64523 184
0a7de745 185 if (enable) {
cb323159 186 targetCPU->getProvider()->registerInterrupt(1, targetCPU, (IOInterruptAction)pmi_handler, NULL);
0a7de745
A
187 targetCPU->getProvider()->enableInterrupt(1);
188 } else {
189 targetCPU->getProvider()->disableInterrupt(1);
190 }
5ba3f43e
A
191}
192#endif
593a1d5f 193
f427ee49
A
194#endif /* !USE_APPLEARMSMP */
195
1c79356b
A
196/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
197
198#define super IOService
199
200OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
201OSMetaClassDefineReservedUnused(IOCPU, 0);
202OSMetaClassDefineReservedUnused(IOCPU, 1);
203OSMetaClassDefineReservedUnused(IOCPU, 2);
204OSMetaClassDefineReservedUnused(IOCPU, 3);
205OSMetaClassDefineReservedUnused(IOCPU, 4);
206OSMetaClassDefineReservedUnused(IOCPU, 5);
207OSMetaClassDefineReservedUnused(IOCPU, 6);
208OSMetaClassDefineReservedUnused(IOCPU, 7);
209
210/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211
f427ee49 212#if !USE_APPLEARMSMP
0a7de745
A
213void
214IOCPUSleepKernel(void)
1c79356b 215{
0a7de745
A
216#if defined(__x86_64__)
217 extern IOCPU *currentShutdownTarget;
218#endif
f427ee49 219 unsigned int cnt, numCPUs;
0a7de745
A
220 IOCPU *target;
221 IOCPU *bootCPU = NULL;
222 IOPMrootDomain *rootDomain = IOService::getPMRootDomain();
6d2010ae 223
f427ee49 224 printf("IOCPUSleepKernel enter\n");
d9a64523 225#if defined(__arm64__)
0a7de745 226 sched_override_recommended_cores_for_sleep();
d9a64523 227#endif
2d21ac55 228
0a7de745 229 rootDomain->tracePoint( kIOPMTracePointSleepPlatformActions );
f427ee49 230 IOPlatformActionsPreSleep();
0a7de745 231 rootDomain->tracePoint( kIOPMTracePointSleepCPUs );
6d2010ae 232
0a7de745
A
233 numCPUs = gIOCPUs->getCount();
234#if defined(__x86_64__)
235 currentShutdownTarget = NULL;
236#endif
237
cb323159
A
238 integer_t old_pri;
239 thread_t self = current_thread();
240
241 /*
242 * We need to boost this thread's priority to the maximum kernel priority to
243 * ensure we can urgently preempt ANY thread currently executing on the
244 * target CPU. Note that realtime threads have their own mechanism to eventually
245 * demote their priority below MAXPRI_KERNEL if they hog the CPU for too long.
246 */
247 old_pri = thread_kern_get_pri(self);
248 thread_kern_set_pri(self, thread_kern_get_kernel_maxpri());
249
0a7de745 250 // Sleep the CPUs.
f427ee49 251 ml_set_is_quiescing(true);
0a7de745
A
252 cnt = numCPUs;
253 while (cnt--) {
254 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
255
256 // We make certain that the bootCPU is the last to sleep
257 // We'll skip it for now, and halt it after finishing the
258 // non-boot CPU's.
259 if (target->getCPUNumber() == (UInt32)master_cpu) {
260 bootCPU = target;
261 } else if (target->getCPUState() == kIOCPUStateRunning) {
262#if defined(__x86_64__)
263 currentShutdownTarget = target;
264#endif
265 target->haltCPU();
266 }
316670eb 267 }
316670eb 268
0a7de745
A
269 assert(bootCPU != NULL);
270 assert(cpu_number() == master_cpu);
271
272 console_suspend();
273
274 rootDomain->tracePoint( kIOPMTracePointSleepPlatformDriver );
275 rootDomain->stop_watchdog_timer();
276
cb323159
A
277 /*
278 * Now sleep the boot CPU, including calling the kQueueQuiesce actions.
279 * The system sleeps here.
280 */
281
0a7de745 282 bootCPU->haltCPU();
f427ee49 283 ml_set_is_quiescing(false);
0a7de745 284
cb323159
A
285 /*
286 * The system is now coming back from sleep on the boot CPU.
287 * The kQueueActive actions have already been called.
288 */
289
0a7de745
A
290 rootDomain->start_watchdog_timer();
291 rootDomain->tracePoint( kIOPMTracePointWakePlatformActions );
292
293 console_resume();
294
f427ee49 295 IOPlatformActionsPostResume();
0a7de745 296 rootDomain->tracePoint( kIOPMTracePointWakeCPUs );
6d2010ae 297
0a7de745
A
298 // Wake the other CPUs.
299 for (cnt = 0; cnt < numCPUs; cnt++) {
300 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
5ba3f43e 301
0a7de745
A
302 // Skip the already-woken boot CPU.
303 if (target->getCPUNumber() != (UInt32)master_cpu) {
304 if (target->getCPUState() == kIOCPUStateRunning) {
305 panic("Spurious wakeup of cpu %u", (unsigned int)(target->getCPUNumber()));
306 }
307
308 if (target->getCPUState() == kIOCPUStateStopped) {
309 processor_start(target->getMachProcessor());
310 }
311 }
312 }
d9a64523
A
313
314#if defined(__arm64__)
0a7de745 315 sched_restore_recommended_cores_after_sleep();
d9a64523 316#endif
cb323159
A
317
318 thread_kern_set_pri(self, old_pri);
f427ee49 319 printf("IOCPUSleepKernel exit\n");
1c79356b
A
320}
321
f427ee49
A
322static bool
323is_IOCPU_disabled(void)
324{
325 return false;
326}
327#else /* !USE_APPLEARMSMP */
328static bool
329is_IOCPU_disabled(void)
330{
331 return true;
332}
333#endif /* !USE_APPLEARMSMP */
334
0a7de745
A
335bool
336IOCPU::start(IOService *provider)
337{
f427ee49
A
338 if (is_IOCPU_disabled()) {
339 return false;
340 }
0a7de745
A
341
342 if (!super::start(provider)) {
343 return false;
344 }
345
346 _cpuGroup = gIOCPUs;
347 cpuNub = provider;
348
349 IOLockLock(gIOCPUsLock);
350 gIOCPUs->setObject(this);
351 IOLockUnlock(gIOCPUsLock);
352
353 // Correct the bus, cpu and timebase frequencies in the device tree.
354 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
f427ee49
A
355 OSSharedPtr<OSData> busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
356 provider->setProperty("bus-frequency", busFrequency.get());
0a7de745 357 } else {
f427ee49
A
358 OSSharedPtr<OSData> busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
359 provider->setProperty("bus-frequency", busFrequency.get());
0a7de745 360 }
0a7de745
A
361
362 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
f427ee49
A
363 OSSharedPtr<OSData> cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
364 provider->setProperty("clock-frequency", cpuFrequency.get());
0a7de745 365 } else {
f427ee49
A
366 OSSharedPtr<OSData> cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
367 provider->setProperty("clock-frequency", cpuFrequency.get());
0a7de745 368 }
0a7de745 369
f427ee49
A
370 OSSharedPtr<OSData> timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
371 provider->setProperty("timebase-frequency", timebaseFrequency.get());
0a7de745
A
372
373 super::setProperty("IOCPUID", getRegistryEntryID(), sizeof(uint64_t) * 8);
374
375 setCPUNumber(0);
376 setCPUState(kIOCPUStateUnregistered);
377
378 return true;
379}
380
cb323159
A
381void
382IOCPU::detach(IOService *provider)
383{
f427ee49
A
384 if (is_IOCPU_disabled()) {
385 return;
386 }
387
cb323159
A
388 super::detach(provider);
389 IOLockLock(gIOCPUsLock);
390 unsigned int index = gIOCPUs->getNextIndexOfObject(this, 0);
391 if (index != (unsigned int)-1) {
392 gIOCPUs->removeObject(index);
393 }
394 IOLockUnlock(gIOCPUsLock);
395}
396
0a7de745
A
397OSObject *
398IOCPU::getProperty(const OSSymbol *aKey) const
399{
400 if (aKey == gIOCPUStateKey) {
f427ee49 401 return gIOCPUStateNames[_cpuState].get();
0a7de745 402 }
f427ee49
A
403#pragma clang diagnostic push
404#pragma clang diagnostic ignored "-Wdeprecated-declarations"
0a7de745 405 return super::getProperty(aKey);
f427ee49 406#pragma clang diagnostic pop
0a7de745
A
407}
408
409bool
410IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
411{
412 if (aKey == gIOCPUStateKey) {
413 return false;
414 }
415
416 return super::setProperty(aKey, anObject);
417}
418
419bool
420IOCPU::serializeProperties(OSSerialize *serialize) const
91447636 421{
0c530ab8 422 bool result;
f427ee49 423 OSSharedPtr<OSDictionary> dict = dictionaryWithProperties();
0a7de745
A
424 if (!dict) {
425 return false;
426 }
f427ee49 427 dict->setObject(gIOCPUStateKey.get(), gIOCPUStateNames[_cpuState].get());
0c530ab8 428 result = dict->serialize(serialize);
0c530ab8 429 return result;
91447636
A
430}
431
0a7de745
A
432IOReturn
433IOCPU::setProperties(OSObject *properties)
91447636 434{
0a7de745
A
435 OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
436 OSString *stateStr;
437 IOReturn result;
438
cb323159 439 if (dict == NULL) {
0a7de745
A
440 return kIOReturnUnsupported;
441 }
442
f427ee49 443 stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey.get()));
cb323159 444 if (stateStr != NULL) {
0a7de745
A
445 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
446 if (result != kIOReturnSuccess) {
447 return result;
448 }
449
f427ee49 450 if (setProperty(gIOCPUStateKey.get(), stateStr)) {
0a7de745
A
451 return kIOReturnSuccess;
452 }
453
454 return kIOReturnUnsupported;
455 }
456
457 return kIOReturnUnsupported;
1c79356b
A
458}
459
0a7de745
A
460void
461IOCPU::signalCPU(IOCPU */*target*/)
1c79356b
A
462{
463}
464
0a7de745
A
465void
466IOCPU::signalCPUDeferred(IOCPU *target)
3e170ce0 467{
0a7de745
A
468 // Our CPU may not support deferred IPIs,
469 // so send a regular IPI by default
470 signalCPU(target);
3e170ce0
A
471}
472
0a7de745
A
473void
474IOCPU::signalCPUCancel(IOCPU */*target*/)
3e170ce0 475{
0a7de745
A
476 // Meant to cancel signals sent by
477 // signalCPUDeferred; unsupported
478 // by default
3e170ce0
A
479}
480
0a7de745
A
481void
482IOCPU::enableCPUTimeBase(bool /*enable*/)
1c79356b
A
483{
484}
485
0a7de745
A
486UInt32
487IOCPU::getCPUNumber(void)
1c79356b 488{
0a7de745 489 return _cpuNumber;
1c79356b
A
490}
491
0a7de745
A
492void
493IOCPU::setCPUNumber(UInt32 cpuNumber)
1c79356b 494{
0a7de745
A
495 _cpuNumber = cpuNumber;
496 super::setProperty("IOCPUNumber", _cpuNumber, 32);
1c79356b
A
497}
498
0a7de745
A
499UInt32
500IOCPU::getCPUState(void)
1c79356b 501{
0a7de745 502 return _cpuState;
1c79356b
A
503}
504
0a7de745
A
505void
506IOCPU::setCPUState(UInt32 cpuState)
1c79356b 507{
0a7de745
A
508 if (cpuState < kIOCPUStateCount) {
509 _cpuState = cpuState;
510 }
1c79356b
A
511}
512
0a7de745
A
513OSArray *
514IOCPU::getCPUGroup(void)
1c79356b 515{
f427ee49 516 return _cpuGroup.get();
1c79356b
A
517}
518
0a7de745
A
519UInt32
520IOCPU::getCPUGroupSize(void)
1c79356b 521{
0a7de745 522 return _cpuGroup->getCount();
1c79356b
A
523}
524
0a7de745
A
525processor_t
526IOCPU::getMachProcessor(void)
1c79356b 527{
0a7de745 528 return machProcessor;
1c79356b
A
529}
530
531
532/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
533
534#undef super
535#define super IOInterruptController
536
537OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
538
1c79356b
A
539OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
540OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
541OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
542OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
543OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
544
545
546
547/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
548
0a7de745
A
549IOReturn
550IOCPUInterruptController::initCPUInterruptController(int sources)
5ba3f43e
A
551{
552 return initCPUInterruptController(sources, sources);
553}
554
0a7de745
A
555IOReturn
556IOCPUInterruptController::initCPUInterruptController(int sources, int cpus)
1c79356b 557{
0a7de745
A
558 int cnt;
559
560 if (!super::init()) {
561 return kIOReturnInvalid;
562 }
5ba3f43e 563
0a7de745
A
564 numSources = sources;
565 numCPUs = cpus;
5ba3f43e 566
0a7de745 567 vectors = (IOInterruptVector *)IOMalloc(numSources * sizeof(IOInterruptVector));
cb323159 568 if (vectors == NULL) {
0a7de745
A
569 return kIOReturnNoMemory;
570 }
571 bzero(vectors, numSources * sizeof(IOInterruptVector));
572
573 // Allocate a lock for each vector
574 for (cnt = 0; cnt < numSources; cnt++) {
575 vectors[cnt].interruptLock = IOLockAlloc();
576 if (vectors[cnt].interruptLock == NULL) {
577 for (cnt = 0; cnt < numSources; cnt++) {
578 if (vectors[cnt].interruptLock != NULL) {
579 IOLockFree(vectors[cnt].interruptLock);
580 }
581 }
582 return kIOReturnNoResources;
583 }
584 }
5ba3f43e 585
f427ee49 586 ml_set_max_cpus(numSources);
0a7de745
A
587 return kIOReturnSuccess;
588}
589
590void
591IOCPUInterruptController::registerCPUInterruptController(void)
592{
f427ee49 593 setProperty(gPlatformInterruptControllerName, kOSBooleanTrue);
0a7de745
A
594 registerService();
595
596 getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
597 this);
598}
599
600void
601IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
602{
603 int cnt;
f427ee49
A
604 OSSharedPtr<OSArray> specifier;
605 OSSharedPtr<OSArray> controller;
0a7de745
A
606 long tmpLong;
607
f427ee49
A
608 if ((service->propertyExists(gIOInterruptControllersKey)) &&
609 (service->propertyExists(gIOInterruptSpecifiersKey))) {
0a7de745
A
610 return;
611 }
612
613 // Create the interrupt specifer array.
614 specifier = OSArray::withCapacity(numSources);
615 for (cnt = 0; cnt < numSources; cnt++) {
616 tmpLong = cnt;
f427ee49
A
617 OSSharedPtr<OSData> tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
618 specifier->setObject(tmpData.get());
0a7de745 619 }
0a7de745
A
620
621 // Create the interrupt controller array.
622 controller = OSArray::withCapacity(numSources);
623 for (cnt = 0; cnt < numSources; cnt++) {
624 controller->setObject(gPlatformInterruptControllerName);
625 }
626
627 // Put the two arrays into the property table.
f427ee49
A
628 service->setProperty(gIOInterruptControllersKey, controller.get());
629 service->setProperty(gIOInterruptSpecifiersKey, specifier.get());
0a7de745
A
630}
631
632void
633IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
1c79356b 634{
0c530ab8
A
635 IOInterruptHandler handler = OSMemberFunctionCast(
636 IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
637
5ba3f43e
A
638 assert(numCPUs > 0);
639
cb323159 640 ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, NULL);
39236c6e 641
5ba3f43e
A
642 IOTakeLock(vectors[0].interruptLock);
643 ++enabledCPUs;
39236c6e 644
3e170ce0 645 if (enabledCPUs == numCPUs) {
5ba3f43e
A
646 IOService::cpusRunning();
647 thread_wakeup(this);
0a7de745 648 }
5ba3f43e 649 IOUnlock(vectors[0].interruptLock);
1c79356b
A
650}
651
0a7de745
A
652IOReturn
653IOCPUInterruptController::registerInterrupt(IOService *nub,
654 int source,
655 void *target,
656 IOInterruptHandler handler,
657 void *refCon)
1c79356b 658{
0a7de745 659 IOInterruptVector *vector;
5ba3f43e 660
cb323159
A
661 // Interrupts must be enabled, as this can allocate memory.
662 assert(ml_get_interrupts_enabled() == TRUE);
663
0a7de745
A
664 if (source >= numSources) {
665 return kIOReturnNoResources;
666 }
5ba3f43e 667
0a7de745 668 vector = &vectors[source];
5ba3f43e 669
0a7de745
A
670 // Get the lock for this vector.
671 IOTakeLock(vector->interruptLock);
5ba3f43e 672
0a7de745
A
673 // Make sure the vector is not in use.
674 if (vector->interruptRegistered) {
675 IOUnlock(vector->interruptLock);
676 return kIOReturnNoResources;
677 }
5ba3f43e 678
0a7de745
A
679 // Fill in vector with the client's info.
680 vector->handler = handler;
681 vector->nub = nub;
682 vector->source = source;
683 vector->target = target;
684 vector->refCon = refCon;
5ba3f43e 685
0a7de745
A
686 // Get the vector ready. It starts hard disabled.
687 vector->interruptDisabledHard = 1;
688 vector->interruptDisabledSoft = 1;
689 vector->interruptRegistered = 1;
5ba3f43e 690
0a7de745 691 IOUnlock(vector->interruptLock);
5ba3f43e 692
0a7de745
A
693 IOTakeLock(vectors[0].interruptLock);
694 if (enabledCPUs != numCPUs) {
695 assert_wait(this, THREAD_UNINT);
696 IOUnlock(vectors[0].interruptLock);
697 thread_block(THREAD_CONTINUE_NULL);
698 } else {
699 IOUnlock(vectors[0].interruptLock);
700 }
5ba3f43e 701
0a7de745 702 return kIOReturnSuccess;
1c79356b
A
703}
704
0a7de745
A
705IOReturn
706IOCPUInterruptController::getInterruptType(IOService */*nub*/,
707 int /*source*/,
708 int *interruptType)
1c79356b 709{
cb323159 710 if (interruptType == NULL) {
0a7de745
A
711 return kIOReturnBadArgument;
712 }
713
714 *interruptType = kIOInterruptTypeLevel;
715
716 return kIOReturnSuccess;
1c79356b
A
717}
718
0a7de745
A
719IOReturn
720IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
721 int /*source*/)
1c79356b
A
722{
723// ml_set_interrupts_enabled(true);
0a7de745 724 return kIOReturnSuccess;
1c79356b
A
725}
726
0a7de745
A
727IOReturn
728IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
729 int /*source*/)
1c79356b
A
730{
731// ml_set_interrupts_enabled(false);
0a7de745 732 return kIOReturnSuccess;
1c79356b
A
733}
734
0a7de745
A
735IOReturn
736IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
737 int /*source*/)
1c79356b 738{
0a7de745
A
739 ml_cause_interrupt();
740 return kIOReturnSuccess;
1c79356b
A
741}
742
0a7de745
A
743IOReturn
744IOCPUInterruptController::handleInterrupt(void */*refCon*/,
745 IOService */*nub*/,
746 int source)
1c79356b 747{
0a7de745
A
748 IOInterruptVector *vector;
749
750 vector = &vectors[source];
751
752 if (!vector->interruptRegistered) {
753 return kIOReturnInvalid;
754 }
755
756 vector->handler(vector->target, vector->refCon,
757 vector->nub, vector->source);
758
759 return kIOReturnSuccess;
1c79356b
A
760}
761
762/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */