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