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