]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCPU.cpp
xnu-1504.15.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCPU.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 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.
8f6c56a5 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.
17 *
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
30 *
31 * DRI: Josh de Cesare
32 *
33 */
34
35extern "C" {
36#include <machine/machine_routines.h>
37#include <pexpert/pexpert.h>
38}
39
2d21ac55
A
40#include <machine/machine_routines.h>
41
1c79356b
A
42#include <IOKit/IOLib.h>
43#include <IOKit/IOPlatformExpert.h>
2d21ac55 44#include <IOKit/pwr_mgt/RootDomain.h>
1c79356b 45#include <IOKit/IOUserClient.h>
2d21ac55 46#include <IOKit/IOKitKeysPrivate.h>
1c79356b
A
47#include <IOKit/IOCPU.h>
48
2d21ac55
A
49/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
50#include <kern/queue.h>
51
52typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
53 void * param1, void * param2, void * param3);
54
55struct iocpu_platform_action_entry
56{
57 queue_chain_t link;
58 iocpu_platform_action_t action;
59 int32_t priority;
60 void * refcon0;
61 void * refcon1;
62 struct iocpu_platform_action_entry * alloc_list;
63};
64typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t;
65
66queue_head_t *
67iocpu_get_platform_quiesce_queue(void);
68
69queue_head_t *
70iocpu_get_platform_active_queue(void);
71
72void
73iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, queue_head_t * init_queue);
74
75void
76iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry);
77
78void
79iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry);
80
81kern_return_t
82iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
83 void * param1, void * param2, void * param3);
84
85/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86
cf7d32b8 87#define kBootCPUNumber 0
2d21ac55
A
88
89static iocpu_platform_action_entry_t * gIOAllActionsQueue;
90static queue_head_t gIOSleepActionQueue;
91static queue_head_t gIOWakeActionQueue;
92
93static queue_head_t iocpu_quiesce_queue;
94static queue_head_t iocpu_active_queue;
95
96/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
97
98void
99iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, __unused queue_head_t * init_queue)
100{
101#if 0
102 enum { kNumQuiesceActions = 2 };
103 static iocpu_platform_action_entry_t quiesce_actions[kNumQuiesceActions] =
104 {
105 { { NULL, NULL }, (iocpu_platform_action_t) &clean_mmu_dcache, 97000, 0, 0, NULL },
106 { { NULL, NULL }, (iocpu_platform_action_t) &arm_sleep, 99000, 0, 0, NULL },
107 };
108 unsigned int idx;
109
110 for (idx = 0; idx < kNumQuiesceActions; idx++)
111 iocpu_add_platform_action(quiesce_queue, &quiesce_actions[idx]);
112#endif
113}
114
115queue_head_t * iocpu_get_platform_quiesce_queue(void)
116{
117 if (!iocpu_quiesce_queue.next)
118 {
119 queue_init(&iocpu_quiesce_queue);
120 queue_init(&iocpu_active_queue);
121 iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
122 }
123 return (&iocpu_quiesce_queue);
124}
125
126queue_head_t * iocpu_get_platform_active_queue(void)
127{
d1ecb069
A
128 if (!iocpu_active_queue.next)
129 {
130 queue_init(&iocpu_quiesce_queue);
131 queue_init(&iocpu_active_queue);
132 iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
133 }
2d21ac55
A
134 return (&iocpu_active_queue);
135}
136
137void iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry)
138{
139 iocpu_platform_action_entry_t * next;
140
141 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
142 {
143 if (next->priority > entry->priority)
144 {
145 queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link);
146 return;
147 }
148 }
149 queue_enter(queue, entry, iocpu_platform_action_entry_t *, link); // at tail
150}
151
152void iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry)
153{
154 remque(&entry->link);
155}
156
157kern_return_t
158iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
159 void * param1, void * param2, void * param3)
160{
161 kern_return_t ret = KERN_SUCCESS;
162 kern_return_t result = KERN_SUCCESS;
163 iocpu_platform_action_entry_t * next;
164
165 queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
166 {
167 uint32_t pri = (next->priority < 0) ? -next->priority : next->priority;
168 if ((pri >= first_priority) && (pri <= last_priority))
169 {
170 //kprintf("[%p]", next->action);
171 ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3);
172 }
173 if (KERN_SUCCESS == result)
174 result = ret;
175 }
176 return (result);
177}
178
179/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
180
181extern "C" kern_return_t
182IOCPURunPlatformQuiesceActions(void)
183{
b0d623f7 184 return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0U-1,
2d21ac55
A
185 NULL, NULL, NULL));
186}
187
188extern "C" kern_return_t
189IOCPURunPlatformActiveActions(void)
190{
b0d623f7 191 return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0U-1,
2d21ac55
A
192 NULL, NULL, NULL));
193}
194
195static kern_return_t
196IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
197 void * param1, void * param2, void * param3)
198{
199 IOReturn ret;
200 IOService * service = (IOService *) refcon0;
201 const OSSymbol * function = (const OSSymbol *) refcon1;
202
203 kprintf("%s -> %s\n", function->getCStringNoCopy(), service->getName());
204
205 ret = service->callPlatformFunction(function, false,
206 (void *) priority, param1, param2, param3);
207
208 return (ret);
209}
210
211static void
212IOInstallServicePlatformAction(IOService * service,
213 const OSSymbol * key, queue_head_t * queue,
214 bool reverse)
215{
216 OSNumber * num;
217 iocpu_platform_action_entry_t * entry;
218 uint32_t priority;
219
220 num = OSDynamicCast(OSNumber, service->getProperty(key));
221 if (!num)
222 return;
223
224 entry = IONew(iocpu_platform_action_entry_t, 1);
225 entry->action = &IOServicePlatformAction;
226 priority = num->unsigned32BitValue();
227 if (reverse)
228 entry->priority = -priority;
229 else
230 entry->priority = priority;
231 entry->refcon0 = service;
232 entry->refcon1 = (void *) key;
233
234 iocpu_add_platform_action(queue, entry);
235 entry->alloc_list = gIOAllActionsQueue;
236 gIOAllActionsQueue = entry;
237}
1c79356b
A
238
239/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
240
241kern_return_t PE_cpu_start(cpu_id_t target,
242 vm_offset_t start_paddr, vm_offset_t arg_paddr)
243{
244 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
245
246 if (targetCPU == 0) return KERN_FAILURE;
247 return targetCPU->startCPU(start_paddr, arg_paddr);
248}
249
250void PE_cpu_halt(cpu_id_t target)
251{
252 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
253
254 if (targetCPU) targetCPU->haltCPU();
255}
256
257void PE_cpu_signal(cpu_id_t source, cpu_id_t target)
258{
259 IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
260 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
261
262 if (sourceCPU && targetCPU) sourceCPU->signalCPU(targetCPU);
263}
264
2d21ac55 265void PE_cpu_machine_init(cpu_id_t target, boolean_t bootb)
1c79356b
A
266{
267 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
268
2d21ac55 269 if (targetCPU) targetCPU->initCPU(bootb);
1c79356b
A
270}
271
272void PE_cpu_machine_quiesce(cpu_id_t target)
273{
274 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
2d21ac55 275
1c79356b
A
276 if (targetCPU) targetCPU->quiesceCPU();
277}
278
593a1d5f 279
1c79356b
A
280/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
281
282#define super IOService
283
284OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
285OSMetaClassDefineReservedUnused(IOCPU, 0);
286OSMetaClassDefineReservedUnused(IOCPU, 1);
287OSMetaClassDefineReservedUnused(IOCPU, 2);
288OSMetaClassDefineReservedUnused(IOCPU, 3);
289OSMetaClassDefineReservedUnused(IOCPU, 4);
290OSMetaClassDefineReservedUnused(IOCPU, 5);
291OSMetaClassDefineReservedUnused(IOCPU, 6);
292OSMetaClassDefineReservedUnused(IOCPU, 7);
293
294/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
295
296static OSArray *gIOCPUs;
297static const OSSymbol *gIOCPUStateKey;
298static OSString *gIOCPUStateNames[kIOCPUStateCount];
299
300void IOCPUSleepKernel(void)
301{
2d21ac55
A
302 long cnt, numCPUs;
303 IOCPU *target;
cf7d32b8 304 IOCPU *bootCPU = NULL;
2d21ac55
A
305
306 kprintf("IOCPUSleepKernel\n");
307
308 OSIterator * iter;
309 IOService * service;
310
311 queue_init(&gIOSleepActionQueue);
312 queue_init(&gIOWakeActionQueue);
313
314 iter = IORegistryIterator::iterateOver( gIOServicePlane,
315 kIORegistryIterateRecursively );
316 if( iter)
317 {
318 do
319 {
320 iter->reset();
321 while((service = (IOService *) iter->getNextObject()))
322 {
323 IOInstallServicePlatformAction(service, gIOPlatformSleepActionKey, &gIOSleepActionQueue, false);
324 IOInstallServicePlatformAction(service, gIOPlatformWakeActionKey, &gIOWakeActionQueue, true);
325 IOInstallServicePlatformAction(service, gIOPlatformQuiesceActionKey, iocpu_get_platform_quiesce_queue(), false);
326 IOInstallServicePlatformAction(service, gIOPlatformActiveActionKey, iocpu_get_platform_active_queue(), true);
327 }
328 }
329 while( !service && !iter->isValid());
330 iter->release();
1c79356b 331 }
2d21ac55 332
b0d623f7 333 iocpu_run_platform_actions(&gIOSleepActionQueue, 0, 0U-1,
2d21ac55
A
334 NULL, NULL, NULL);
335
336 numCPUs = gIOCPUs->getCount();
337 // Sleep the CPUs.
338 cnt = numCPUs;
cf7d32b8
A
339 while (cnt--)
340 {
341 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
342
343 // We make certain that the bootCPU is the last to sleep
344 // We'll skip it for now, and halt it after finishing the
345 // non-boot CPU's.
346 if (target->getCPUNumber() == kBootCPUNumber)
347 {
348 bootCPU = target;
349 } else if (target->getCPUState() == kIOCPUStateRunning)
350 {
351 target->haltCPU();
352 }
2d21ac55
A
353 }
354
cf7d32b8
A
355 // Now sleep the boot CPU.
356 if (bootCPU)
357 bootCPU->haltCPU();
358
b0d623f7 359 iocpu_run_platform_actions(&gIOWakeActionQueue, 0, 0U-1,
2d21ac55
A
360 NULL, NULL, NULL);
361
362 iocpu_platform_action_entry_t * entry;
363 while ((entry = gIOAllActionsQueue))
364 {
365 gIOAllActionsQueue = entry->alloc_list;
366 iocpu_remove_platform_action(entry);
367 IODelete(entry, iocpu_platform_action_entry_t, 1);
368 }
369
370 if (!queue_empty(&gIOSleepActionQueue))
b0d623f7 371 panic("gIOSleepActionQueue");
2d21ac55 372 if (!queue_empty(&gIOWakeActionQueue))
b0d623f7 373 panic("gIOWakeActionQueue");
2d21ac55
A
374
375 // Wake the other CPUs.
cf7d32b8
A
376 for (cnt = 0; cnt < numCPUs; cnt++)
377 {
378 target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
379
380 // Skip the already-woken boot CPU.
381 if ((target->getCPUNumber() != kBootCPUNumber)
382 && (target->getCPUState() == kIOCPUStateStopped))
383 {
384 processor_start(target->getMachProcessor());
385 }
1c79356b 386 }
1c79356b
A
387}
388
389void IOCPU::initCPUs(void)
390{
391 if (gIOCPUs == 0) {
392 gIOCPUs = OSArray::withCapacity(1);
393
394 gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
395
396 gIOCPUStateNames[kIOCPUStateUnregistered] =
397 OSString::withCStringNoCopy("Unregistered");
398 gIOCPUStateNames[kIOCPUStateUninitalized] =
399 OSString::withCStringNoCopy("Uninitalized");
400 gIOCPUStateNames[kIOCPUStateStopped] =
401 OSString::withCStringNoCopy("Stopped");
402 gIOCPUStateNames[kIOCPUStateRunning] =
403 OSString::withCStringNoCopy("Running");
404 }
405}
406
407bool IOCPU::start(IOService *provider)
408{
90556fb8 409 OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
1c79356b
A
410
411 if (!super::start(provider)) return false;
412
413 initCPUs();
414
415 _cpuGroup = gIOCPUs;
416 cpuNub = provider;
417
418 gIOCPUs->setObject(this);
419
43866e37 420 // Correct the bus, cpu and timebase frequencies in the device tree.
91447636
A
421 if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
422 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
423 } else {
424 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
425 }
1c79356b 426 provider->setProperty("bus-frequency", busFrequency);
de355530 427 busFrequency->release();
43866e37 428
91447636
A
429 if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
430 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
431 } else {
432 cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
433 }
43866e37 434 provider->setProperty("clock-frequency", cpuFrequency);
1c79356b 435 cpuFrequency->release();
43866e37
A
436
437 timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
438 provider->setProperty("timebase-frequency", timebaseFrequency);
90556fb8 439 timebaseFrequency->release();
1c79356b 440
b0d623f7 441 super::setProperty("IOCPUID", (uintptr_t)this, sizeof(uintptr_t)*8);
1c79356b
A
442
443 setCPUNumber(0);
444 setCPUState(kIOCPUStateUnregistered);
445
446 return true;
447}
448
91447636 449OSObject *IOCPU::getProperty(const OSSymbol *aKey) const
1c79356b 450{
91447636 451 if (aKey == gIOCPUStateKey) return gIOCPUStateNames[_cpuState];
1c79356b 452
91447636
A
453 return super::getProperty(aKey);
454}
455
456bool IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
457{
458 OSString *stateStr;
1c79356b 459
91447636
A
460 if (aKey == gIOCPUStateKey) {
461 stateStr = OSDynamicCast(OSString, anObject);
462 if (stateStr == 0) return false;
1c79356b 463
91447636 464 if (_cpuNumber == 0) return false;
1c79356b
A
465
466 if (stateStr->isEqualTo("running")) {
467 if (_cpuState == kIOCPUStateStopped) {
468 processor_start(machProcessor);
469 } else if (_cpuState != kIOCPUStateRunning) {
91447636 470 return false;
1c79356b
A
471 }
472 } else if (stateStr->isEqualTo("stopped")) {
473 if (_cpuState == kIOCPUStateRunning) {
474 haltCPU();
475 } else if (_cpuState != kIOCPUStateStopped) {
91447636 476 return false;
1c79356b 477 }
91447636
A
478 } else return false;
479
480 return true;
481 }
482
483 return super::setProperty(aKey, anObject);
484}
485
486bool IOCPU::serializeProperties(OSSerialize *serialize) const
487{
0c530ab8
A
488 bool result;
489 OSDictionary *dict = dictionaryWithProperties();
490 dict->setObject(gIOCPUStateKey, gIOCPUStateNames[_cpuState]);
491 result = dict->serialize(serialize);
492 dict->release();
493 return result;
91447636
A
494}
495
496IOReturn IOCPU::setProperties(OSObject *properties)
497{
498 OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
499 OSString *stateStr;
500 IOReturn result;
501
502 if (dict == 0) return kIOReturnUnsupported;
503
504 stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
505 if (stateStr != 0) {
506 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
507 if (result != kIOReturnSuccess) return result;
508
509 if (setProperty(gIOCPUStateKey, stateStr)) return kIOReturnSuccess;
1c79356b 510
91447636 511 return kIOReturnUnsupported;
1c79356b
A
512 }
513
514 return kIOReturnUnsupported;
515}
516
517void IOCPU::signalCPU(IOCPU */*target*/)
518{
519}
520
521void IOCPU::enableCPUTimeBase(bool /*enable*/)
522{
523}
524
525UInt32 IOCPU::getCPUNumber(void)
526{
527 return _cpuNumber;
528}
529
530void IOCPU::setCPUNumber(UInt32 cpuNumber)
531{
532 _cpuNumber = cpuNumber;
91447636 533 super::setProperty("IOCPUNumber", _cpuNumber, 32);
1c79356b
A
534}
535
536UInt32 IOCPU::getCPUState(void)
537{
538 return _cpuState;
539}
540
541void IOCPU::setCPUState(UInt32 cpuState)
542{
91447636 543 if (cpuState < kIOCPUStateCount) {
1c79356b 544 _cpuState = cpuState;
1c79356b
A
545 }
546}
547
548OSArray *IOCPU::getCPUGroup(void)
549{
550 return _cpuGroup;
551}
552
553UInt32 IOCPU::getCPUGroupSize(void)
554{
555 return _cpuGroup->getCount();
556}
557
558processor_t IOCPU::getMachProcessor(void)
559{
560 return machProcessor;
561}
562
563
564/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
565
566#undef super
567#define super IOInterruptController
568
569OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
570
571OSMetaClassDefineReservedUnused(IOCPUInterruptController, 0);
572OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
573OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
574OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
575OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
576OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
577
578
579
580/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
581
582
583IOReturn IOCPUInterruptController::initCPUInterruptController(int sources)
584{
585 int cnt;
586
587 if (!super::init()) return kIOReturnInvalid;
588
589 numCPUs = sources;
590
591 cpus = (IOCPU **)IOMalloc(numCPUs * sizeof(IOCPU *));
592 if (cpus == 0) return kIOReturnNoMemory;
593 bzero(cpus, numCPUs * sizeof(IOCPU *));
594
595 vectors = (IOInterruptVector *)IOMalloc(numCPUs * sizeof(IOInterruptVector));
596 if (vectors == 0) return kIOReturnNoMemory;
597 bzero(vectors, numCPUs * sizeof(IOInterruptVector));
598
599 // Allocate locks for the
600 for (cnt = 0; cnt < numCPUs; cnt++) {
601 vectors[cnt].interruptLock = IOLockAlloc();
602 if (vectors[cnt].interruptLock == NULL) {
603 for (cnt = 0; cnt < numCPUs; cnt++) {
604 if (vectors[cnt].interruptLock != NULL)
605 IOLockFree(vectors[cnt].interruptLock);
606 }
607 return kIOReturnNoResources;
608 }
609 }
610
43866e37
A
611 ml_init_max_cpus(numCPUs);
612
1c79356b
A
613 return kIOReturnSuccess;
614}
615
616void IOCPUInterruptController::registerCPUInterruptController(void)
617{
618 registerService();
619
620 getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
621 this);
622}
623
624void IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
625{
626 int cnt;
627 OSArray *controller;
628 OSArray *specifier;
629 OSData *tmpData;
630 long tmpLong;
631
2d21ac55
A
632 if ((service->getProperty(gIOInterruptControllersKey) != 0) &&
633 (service->getProperty(gIOInterruptSpecifiersKey) != 0))
634 return;
635
1c79356b
A
636 // Create the interrupt specifer array.
637 specifier = OSArray::withCapacity(numCPUs);
638 for (cnt = 0; cnt < numCPUs; cnt++) {
639 tmpLong = cnt;
640 tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
641 specifier->setObject(tmpData);
642 tmpData->release();
643 };
644
645 // Create the interrupt controller array.
646 controller = OSArray::withCapacity(numCPUs);
647 for (cnt = 0; cnt < numCPUs; cnt++) {
648 controller->setObject(gPlatformInterruptControllerName);
649 }
650
651 // Put the two arrays into the property table.
652 service->setProperty(gIOInterruptControllersKey, controller);
653 service->setProperty(gIOInterruptSpecifiersKey, specifier);
654 controller->release();
655 specifier->release();
656}
657
658void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
659{
0c530ab8
A
660 IOInterruptHandler handler = OSMemberFunctionCast(
661 IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
662
663 ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, 0);
1c79356b 664
2d21ac55 665 enabledCPUs++;
1c79356b
A
666
667 if (enabledCPUs == numCPUs) thread_wakeup(this);
668}
669
670IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,
671 int source,
672 void *target,
673 IOInterruptHandler handler,
674 void *refCon)
675{
676 IOInterruptVector *vector;
677
678 if (source >= numCPUs) return kIOReturnNoResources;
679
680 vector = &vectors[source];
681
682 // Get the lock for this vector.
683 IOTakeLock(vector->interruptLock);
684
685 // Make sure the vector is not in use.
686 if (vector->interruptRegistered) {
687 IOUnlock(vector->interruptLock);
688 return kIOReturnNoResources;
689 }
690
691 // Fill in vector with the client's info.
692 vector->handler = handler;
693 vector->nub = nub;
694 vector->source = source;
695 vector->target = target;
696 vector->refCon = refCon;
697
698 // Get the vector ready. It starts hard disabled.
699 vector->interruptDisabledHard = 1;
700 vector->interruptDisabledSoft = 1;
701 vector->interruptRegistered = 1;
702
703 IOUnlock(vector->interruptLock);
704
705 if (enabledCPUs != numCPUs) {
706 assert_wait(this, THREAD_UNINT);
9bccf70c 707 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
708 }
709
710 return kIOReturnSuccess;
711}
712
713IOReturn IOCPUInterruptController::getInterruptType(IOService */*nub*/,
714 int /*source*/,
715 int *interruptType)
716{
717 if (interruptType == 0) return kIOReturnBadArgument;
718
719 *interruptType = kIOInterruptTypeLevel;
720
721 return kIOReturnSuccess;
722}
723
724IOReturn IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
725 int /*source*/)
726{
727// ml_set_interrupts_enabled(true);
728 return kIOReturnSuccess;
729}
730
731IOReturn IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
732 int /*source*/)
733{
734// ml_set_interrupts_enabled(false);
735 return kIOReturnSuccess;
736}
737
738IOReturn IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
739 int /*source*/)
740{
741 ml_cause_interrupt();
742 return kIOReturnSuccess;
743}
744
745IOReturn IOCPUInterruptController::handleInterrupt(void */*refCon*/,
746 IOService */*nub*/,
747 int source)
748{
749 IOInterruptVector *vector;
750
751 vector = &vectors[source];
752
753 if (!vector->interruptRegistered) return kIOReturnInvalid;
754
755 vector->handler(vector->target, vector->refCon,
756 vector->nub, vector->source);
757
758 return kIOReturnSuccess;
759}
760
761/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */