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 35extern "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 53typedef 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 57struct 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}; 67typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t; 68 69queue_head_t * 70iocpu_get_platform_quiesce_queue(void); 71 72queue_head_t * 73iocpu_get_platform_active_queue(void); 74 75void 76iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, queue_head_t * init_queue); 77 78void 79iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry); 80 81void 82iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry); 83 84kern_return_t 85iocpu_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 92static iocpu_platform_action_entry_t * gIOAllActionsQueue; 93static queue_head_t gIOSleepActionQueue; 94static queue_head_t gIOWakeActionQueue; 95 96static queue_head_t iocpu_quiesce_queue; 97static queue_head_t iocpu_active_queue; 98 99static queue_head_t gIOHaltRestartActionQueue; 100 101/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 102 103void 104iocpu_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 120queue_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 131queue_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 142void 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 157void iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry) 158{ 159 remque(&entry->link); 160} 161 162kern_return_t 163iocpu_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 186extern "C" kern_return_t 187IOCPURunPlatformQuiesceActions(void) 188{ 189 return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0U-1, 190 NULL, NULL, NULL)); 191} 192 193extern "C" kern_return_t 194IOCPURunPlatformActiveActions(void) 195{ 196 return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0U-1, 197 NULL, NULL, NULL)); 198} 199 200static kern_return_t 201IOServicePlatformAction(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 217static void 218IOInstallServicePlatformAction(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 246extern "C" kern_return_t 247IOCPURunPlatformHaltRestartActions(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 287kern_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 296void PE_cpu_halt(cpu_id_t target) 297{ 298 IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target); 299 300 if (targetCPU) targetCPU->haltCPU(); 301} 302 303void 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 311void 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 318void 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 330OSDefineMetaClassAndAbstractStructors(IOCPU, IOService); 331OSMetaClassDefineReservedUnused(IOCPU, 0); 332OSMetaClassDefineReservedUnused(IOCPU, 1); 333OSMetaClassDefineReservedUnused(IOCPU, 2); 334OSMetaClassDefineReservedUnused(IOCPU, 3); 335OSMetaClassDefineReservedUnused(IOCPU, 4); 336OSMetaClassDefineReservedUnused(IOCPU, 5); 337OSMetaClassDefineReservedUnused(IOCPU, 6); 338OSMetaClassDefineReservedUnused(IOCPU, 7); 339 340/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 341 342static OSArray *gIOCPUs; 343static const OSSymbol *gIOCPUStateKey; 344static OSString *gIOCPUStateNames[kIOCPUStateCount]; 345 346void 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 458void 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 476bool 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 518OSObject *IOCPU::getProperty(const OSSymbol *aKey) const 519{ 520 if (aKey == gIOCPUStateKey) return gIOCPUStateNames[_cpuState]; 521 522 return super::getProperty(aKey); 523} 524 525bool 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 555bool 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 565IOReturn 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 586void IOCPU::signalCPU(IOCPU */*target*/) 587{ 588} 589 590void IOCPU::enableCPUTimeBase(bool /*enable*/) 591{ 592} 593 594UInt32 IOCPU::getCPUNumber(void) 595{ 596 return _cpuNumber; 597} 598 599void IOCPU::setCPUNumber(UInt32 cpuNumber) 600{ 601 _cpuNumber = cpuNumber; 602 super::setProperty("IOCPUNumber", _cpuNumber, 32); 603} 604 605UInt32 IOCPU::getCPUState(void) 606{ 607 return _cpuState; 608} 609 610void IOCPU::setCPUState(UInt32 cpuState) 611{ 612 if (cpuState < kIOCPUStateCount) { 613 _cpuState = cpuState; 614 } 615} 616 617OSArray *IOCPU::getCPUGroup(void) 618{ 619 return _cpuGroup; 620} 621 622UInt32 IOCPU::getCPUGroupSize(void) 623{ 624 return _cpuGroup->getCount(); 625} 626 627processor_t IOCPU::getMachProcessor(void) 628{ 629 return machProcessor; 630} 631 632 633/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 634 635#undef super 636#define super IOInterruptController 637 638OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController); 639 640OSMetaClassDefineReservedUnused(IOCPUInterruptController, 0); 641OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1); 642OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2); 643OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3); 644OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4); 645OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5); 646 647 648 649/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 650 651 652IOReturn 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 685void IOCPUInterruptController::registerCPUInterruptController(void) 686{ 687 registerService(); 688 689 getPlatform()->registerInterruptController(gPlatformInterruptControllerName, 690 this); 691} 692 693void 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 727void 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 740IOReturn 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 783IOReturn 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 794IOReturn IOCPUInterruptController::enableInterrupt(IOService */*nub*/, 795 int /*source*/) 796{ 797// ml_set_interrupts_enabled(true); 798 return kIOReturnSuccess; 799} 800 801IOReturn IOCPUInterruptController::disableInterrupt(IOService */*nub*/, 802 int /*source*/) 803{ 804// ml_set_interrupts_enabled(false); 805 return kIOReturnSuccess; 806} 807 808IOReturn IOCPUInterruptController::causeInterrupt(IOService */*nub*/, 809 int /*source*/) 810{ 811 ml_cause_interrupt(); 812 return kIOReturnSuccess; 813} 814 815IOReturn 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/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 832