1c1dac77fSApple OSS Distributions /* 2855239e5SApple OSS Distributions * Copyright (c) 1998-2010 Apple Inc. All rights reserved. 3c1dac77fSApple OSS Distributions * 4e13b1fa5SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5c1dac77fSApple OSS Distributions * 6e13b1fa5SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code 7e13b1fa5SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License 8e13b1fa5SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in 9e13b1fa5SApple OSS Distributions * compliance with the License. The rights granted to you under the License 10e13b1fa5SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of, 11e13b1fa5SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to 12e13b1fa5SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any 13e13b1fa5SApple OSS Distributions * terms of an Apple operating system software license agreement. 14c1dac77fSApple OSS Distributions * 15e13b1fa5SApple OSS Distributions * Please obtain a copy of the License at 16e13b1fa5SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file. 17e13b1fa5SApple OSS Distributions * 18e13b1fa5SApple OSS Distributions * The Original Code and all software distributed under the License are 19e13b1fa5SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20c1dac77fSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21c1dac77fSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22e13b1fa5SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23e13b1fa5SApple OSS Distributions * Please see the License for the specific language governing rights and 24e13b1fa5SApple OSS Distributions * limitations under the License. 25c1dac77fSApple OSS Distributions * 26e13b1fa5SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27c1dac77fSApple OSS Distributions */ 28c1dac77fSApple OSS Distributions 29c1dac77fSApple OSS Distributions #include <IOKit/IOInterruptEventSource.h> 30855239e5SApple OSS Distributions #include <IOKit/IOKitDebug.h> 31c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h> 32c1dac77fSApple OSS Distributions #include <IOKit/IOService.h> 33c1dac77fSApple OSS Distributions #include <IOKit/IOInterrupts.h> 34c1dac77fSApple OSS Distributions #include <IOKit/IOTimeStamp.h> 35c1dac77fSApple OSS Distributions #include <IOKit/IOWorkLoop.h> 36c1dac77fSApple OSS Distributions 37855239e5SApple OSS Distributions #if IOKITSTATS 38c1dac77fSApple OSS Distributions 39855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter() \ 40c1dac77fSApple OSS Distributions do { \ 41855239e5SApple OSS Distributions IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsInterruptEventSourceCounter); \ 42c1dac77fSApple OSS Distributions } while (0) 43c1dac77fSApple OSS Distributions 44855239e5SApple OSS Distributions #define IOStatisticsCheckForWork() \ 45c1dac77fSApple OSS Distributions do { \ 46855239e5SApple OSS Distributions IOStatistics::countInterruptCheckForWork(IOEventSource::reserved->counter); \ 47c1dac77fSApple OSS Distributions } while (0) 48c1dac77fSApple OSS Distributions 49855239e5SApple OSS Distributions #define IOStatisticsInterrupt() \ 50c1dac77fSApple OSS Distributions do { \ 51855239e5SApple OSS Distributions IOStatistics::countInterrupt(IOEventSource::reserved->counter); \ 52c1dac77fSApple OSS Distributions } while (0) 53c1dac77fSApple OSS Distributions 54855239e5SApple OSS Distributions #else 55855239e5SApple OSS Distributions 56855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter() 57855239e5SApple OSS Distributions #define IOStatisticsCheckForWork() 58855239e5SApple OSS Distributions #define IOStatisticsInterrupt() 59855239e5SApple OSS Distributions 60855239e5SApple OSS Distributions #endif // IOKITSTATS 61c1dac77fSApple OSS Distributions 62c1dac77fSApple OSS Distributions #define super IOEventSource 63c1dac77fSApple OSS Distributions 64c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource) 65c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0); 66c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1); 67c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2); 68c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3); 69c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4); 70c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5); 71c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6); 72c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7); 73c1dac77fSApple OSS Distributions 74c1dac77fSApple OSS Distributions bool IOInterruptEventSource::init(OSObject *inOwner, 75368ad365SApple OSS Distributions Action inAction, 76368ad365SApple OSS Distributions IOService *inProvider, 77368ad365SApple OSS Distributions int inIntIndex) 78c1dac77fSApple OSS Distributions { 79c1dac77fSApple OSS Distributions bool res = true; 80c1dac77fSApple OSS Distributions 81c1dac77fSApple OSS Distributions if ( !super::init(inOwner, (IOEventSourceAction) inAction) ) 82c1dac77fSApple OSS Distributions return false; 83c1dac77fSApple OSS Distributions 84c1dac77fSApple OSS Distributions provider = inProvider; 85c1dac77fSApple OSS Distributions producerCount = consumerCount = 0; 86c1dac77fSApple OSS Distributions autoDisable = explicitDisable = false; 87855239e5SApple OSS Distributions intIndex = ~inIntIndex; 88c1dac77fSApple OSS Distributions 89c1dac77fSApple OSS Distributions // Assumes inOwner holds a reference(retain) on the provider 90c1dac77fSApple OSS Distributions if (inProvider) { 91855239e5SApple OSS Distributions res = (kIOReturnSuccess == registerInterruptHandler(inProvider, inIntIndex)); 92855239e5SApple OSS Distributions if (res) 93855239e5SApple OSS Distributions intIndex = inIntIndex; 94855239e5SApple OSS Distributions } 95c1dac77fSApple OSS Distributions 96855239e5SApple OSS Distributions IOStatisticsInitializeCounter(); 97855239e5SApple OSS Distributions 98855239e5SApple OSS Distributions return res; 99855239e5SApple OSS Distributions } 100855239e5SApple OSS Distributions 101855239e5SApple OSS Distributions IOReturn IOInterruptEventSource::registerInterruptHandler(IOService *inProvider, 102855239e5SApple OSS Distributions int inIntIndex) 103855239e5SApple OSS Distributions { 104855239e5SApple OSS Distributions IOReturn ret; 105855239e5SApple OSS Distributions int intType; 106c1dac77fSApple OSS Distributions IOInterruptAction intHandler; 107c1dac77fSApple OSS Distributions 108855239e5SApple OSS Distributions ret = inProvider->getInterruptType(inIntIndex, &intType); 109855239e5SApple OSS Distributions if (kIOReturnSuccess != ret) 110855239e5SApple OSS Distributions return (ret); 111855239e5SApple OSS Distributions 112c1dac77fSApple OSS Distributions autoDisable = (intType == kIOInterruptTypeLevel); 113c1dac77fSApple OSS Distributions if (autoDisable) { 11414e3d835SApple OSS Distributions intHandler = OSMemberFunctionCast(IOInterruptAction, 11514e3d835SApple OSS Distributions this, &IOInterruptEventSource::disableInterruptOccurred); 116c1dac77fSApple OSS Distributions } 117c1dac77fSApple OSS Distributions else 11814e3d835SApple OSS Distributions intHandler = OSMemberFunctionCast(IOInterruptAction, 11914e3d835SApple OSS Distributions this, &IOInterruptEventSource::normalInterruptOccurred); 120c1dac77fSApple OSS Distributions 121855239e5SApple OSS Distributions ret = provider->registerInterrupt(inIntIndex, this, intHandler); 122c1dac77fSApple OSS Distributions 123855239e5SApple OSS Distributions return (ret); 124c1dac77fSApple OSS Distributions } 125c1dac77fSApple OSS Distributions 126c1dac77fSApple OSS Distributions IOInterruptEventSource * 127c1dac77fSApple OSS Distributions IOInterruptEventSource::interruptEventSource(OSObject *inOwner, 128c1dac77fSApple OSS Distributions Action inAction, 129c1dac77fSApple OSS Distributions IOService *inProvider, 130c1dac77fSApple OSS Distributions int inIntIndex) 131c1dac77fSApple OSS Distributions { 132c1dac77fSApple OSS Distributions IOInterruptEventSource *me = new IOInterruptEventSource; 133c1dac77fSApple OSS Distributions 134c1dac77fSApple OSS Distributions if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) { 135368ad365SApple OSS Distributions me->release(); 136c1dac77fSApple OSS Distributions return 0; 137c1dac77fSApple OSS Distributions } 138c1dac77fSApple OSS Distributions 139c1dac77fSApple OSS Distributions return me; 140c1dac77fSApple OSS Distributions } 141c1dac77fSApple OSS Distributions 142c1dac77fSApple OSS Distributions void IOInterruptEventSource::free() 143c1dac77fSApple OSS Distributions { 144855239e5SApple OSS Distributions if (provider && intIndex >= 0) 145c1dac77fSApple OSS Distributions provider->unregisterInterrupt(intIndex); 146c1dac77fSApple OSS Distributions 147c1dac77fSApple OSS Distributions super::free(); 148c1dac77fSApple OSS Distributions } 149c1dac77fSApple OSS Distributions 150c1dac77fSApple OSS Distributions void IOInterruptEventSource::enable() 151c1dac77fSApple OSS Distributions { 152855239e5SApple OSS Distributions if (provider && intIndex >= 0) { 153c1dac77fSApple OSS Distributions provider->enableInterrupt(intIndex); 154c1dac77fSApple OSS Distributions explicitDisable = false; 155e13b1fa5SApple OSS Distributions enabled = true; 156c1dac77fSApple OSS Distributions } 157c1dac77fSApple OSS Distributions } 158c1dac77fSApple OSS Distributions 159c1dac77fSApple OSS Distributions void IOInterruptEventSource::disable() 160c1dac77fSApple OSS Distributions { 161855239e5SApple OSS Distributions if (provider && intIndex >= 0) { 162c1dac77fSApple OSS Distributions provider->disableInterrupt(intIndex); 163c1dac77fSApple OSS Distributions explicitDisable = true; 164e13b1fa5SApple OSS Distributions enabled = false; 165c1dac77fSApple OSS Distributions } 166c1dac77fSApple OSS Distributions } 167c1dac77fSApple OSS Distributions 168855239e5SApple OSS Distributions void IOInterruptEventSource::setWorkLoop(IOWorkLoop *inWorkLoop) 169855239e5SApple OSS Distributions { 170855239e5SApple OSS Distributions super::setWorkLoop(inWorkLoop); 171855239e5SApple OSS Distributions 172855239e5SApple OSS Distributions if (!provider) 173855239e5SApple OSS Distributions return; 174855239e5SApple OSS Distributions 175855239e5SApple OSS Distributions if ( !inWorkLoop ) { 176855239e5SApple OSS Distributions if (intIndex >= 0) { 177855239e5SApple OSS Distributions provider->unregisterInterrupt(intIndex); 178855239e5SApple OSS Distributions intIndex = ~intIndex; 179855239e5SApple OSS Distributions } 180855239e5SApple OSS Distributions } else if ((intIndex < 0) && (kIOReturnSuccess == registerInterruptHandler(provider, ~intIndex))) { 181855239e5SApple OSS Distributions intIndex = ~intIndex; 182855239e5SApple OSS Distributions } 183855239e5SApple OSS Distributions } 184855239e5SApple OSS Distributions 185c1dac77fSApple OSS Distributions const IOService *IOInterruptEventSource::getProvider() const 186c1dac77fSApple OSS Distributions { 187c1dac77fSApple OSS Distributions return provider; 188c1dac77fSApple OSS Distributions } 189c1dac77fSApple OSS Distributions 190c1dac77fSApple OSS Distributions int IOInterruptEventSource::getIntIndex() const 191c1dac77fSApple OSS Distributions { 192c1dac77fSApple OSS Distributions return intIndex; 193c1dac77fSApple OSS Distributions } 194c1dac77fSApple OSS Distributions 195c1dac77fSApple OSS Distributions bool IOInterruptEventSource::getAutoDisable() const 196c1dac77fSApple OSS Distributions { 197c1dac77fSApple OSS Distributions return autoDisable; 198c1dac77fSApple OSS Distributions } 199c1dac77fSApple OSS Distributions 200c1dac77fSApple OSS Distributions bool IOInterruptEventSource::checkForWork() 201c1dac77fSApple OSS Distributions { 202c1dac77fSApple OSS Distributions unsigned int cacheProdCount = producerCount; 203c1dac77fSApple OSS Distributions int numInts = cacheProdCount - consumerCount; 204c1dac77fSApple OSS Distributions IOInterruptEventAction intAction = (IOInterruptEventAction) action; 205855239e5SApple OSS Distributions bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 206c1dac77fSApple OSS Distributions 207855239e5SApple OSS Distributions IOStatisticsCheckForWork(); 208c1dac77fSApple OSS Distributions 209855239e5SApple OSS Distributions if ( numInts > 0 ) 210855239e5SApple OSS Distributions { 211855239e5SApple OSS Distributions if (trace) 212855239e5SApple OSS Distributions IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION), 213*d0c1fef6SApple OSS Distributions VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop); 214855239e5SApple OSS Distributions 215855239e5SApple OSS Distributions // Call the handler 216c1dac77fSApple OSS Distributions (*intAction)(owner, this, numInts); 217855239e5SApple OSS Distributions 218855239e5SApple OSS Distributions if (trace) 219855239e5SApple OSS Distributions IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION), 220*d0c1fef6SApple OSS Distributions VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop); 221c1dac77fSApple OSS Distributions 222c1dac77fSApple OSS Distributions consumerCount = cacheProdCount; 223c1dac77fSApple OSS Distributions if (autoDisable && !explicitDisable) 224c1dac77fSApple OSS Distributions enable(); 225c1dac77fSApple OSS Distributions } 226855239e5SApple OSS Distributions 227855239e5SApple OSS Distributions else if ( numInts < 0 ) 228855239e5SApple OSS Distributions { 229855239e5SApple OSS Distributions if (trace) 230855239e5SApple OSS Distributions IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION), 231*d0c1fef6SApple OSS Distributions VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop); 232855239e5SApple OSS Distributions 233855239e5SApple OSS Distributions // Call the handler 234c1dac77fSApple OSS Distributions (*intAction)(owner, this, -numInts); 235855239e5SApple OSS Distributions 236855239e5SApple OSS Distributions if (trace) 237855239e5SApple OSS Distributions IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION), 238*d0c1fef6SApple OSS Distributions VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop); 239c1dac77fSApple OSS Distributions 240c1dac77fSApple OSS Distributions consumerCount = cacheProdCount; 241c1dac77fSApple OSS Distributions if (autoDisable && !explicitDisable) 242c1dac77fSApple OSS Distributions enable(); 243c1dac77fSApple OSS Distributions } 244c1dac77fSApple OSS Distributions 245c1dac77fSApple OSS Distributions return false; 246c1dac77fSApple OSS Distributions } 247c1dac77fSApple OSS Distributions 248c1dac77fSApple OSS Distributions void IOInterruptEventSource::normalInterruptOccurred 249c1dac77fSApple OSS Distributions (void */*refcon*/, IOService */*prov*/, int /*source*/) 250c1dac77fSApple OSS Distributions { 251855239e5SApple OSS Distributions bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 252c1dac77fSApple OSS Distributions 253855239e5SApple OSS Distributions IOStatisticsInterrupt(); 254c1dac77fSApple OSS Distributions producerCount++; 255c1dac77fSApple OSS Distributions 256855239e5SApple OSS Distributions if (trace) 257855239e5SApple OSS Distributions IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner); 258c1dac77fSApple OSS Distributions 259855239e5SApple OSS Distributions signalWorkAvailable(); 260855239e5SApple OSS Distributions 261855239e5SApple OSS Distributions if (trace) 262855239e5SApple OSS Distributions IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner); 263c1dac77fSApple OSS Distributions } 264c1dac77fSApple OSS Distributions 265c1dac77fSApple OSS Distributions void IOInterruptEventSource::disableInterruptOccurred 266c1dac77fSApple OSS Distributions (void */*refcon*/, IOService *prov, int source) 267c1dac77fSApple OSS Distributions { 268855239e5SApple OSS Distributions bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 269c1dac77fSApple OSS Distributions 270c1dac77fSApple OSS Distributions prov->disableInterrupt(source); /* disable the interrupt */ 271c1dac77fSApple OSS Distributions 272855239e5SApple OSS Distributions IOStatisticsInterrupt(); 273c1dac77fSApple OSS Distributions producerCount++; 274c1dac77fSApple OSS Distributions 275855239e5SApple OSS Distributions if (trace) 276855239e5SApple OSS Distributions IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner); 277c1dac77fSApple OSS Distributions 278855239e5SApple OSS Distributions signalWorkAvailable(); 279855239e5SApple OSS Distributions 280855239e5SApple OSS Distributions if (trace) 281855239e5SApple OSS Distributions IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner); 282c1dac77fSApple OSS Distributions } 283c1dac77fSApple OSS Distributions 284c1dac77fSApple OSS Distributions void IOInterruptEventSource::interruptOccurred 285c1dac77fSApple OSS Distributions (void *refcon, IOService *prov, int source) 286c1dac77fSApple OSS Distributions { 287c1dac77fSApple OSS Distributions if (autoDisable && prov) 288c1dac77fSApple OSS Distributions disableInterruptOccurred(refcon, prov, source); 289c1dac77fSApple OSS Distributions else 290c1dac77fSApple OSS Distributions normalInterruptOccurred(refcon, prov, source); 291c1dac77fSApple OSS Distributions } 292855239e5SApple OSS Distributions 293855239e5SApple OSS Distributions IOReturn IOInterruptEventSource::warmCPU 294855239e5SApple OSS Distributions (uint64_t abstime) 295855239e5SApple OSS Distributions { 296855239e5SApple OSS Distributions 297855239e5SApple OSS Distributions return ml_interrupt_prewarm(abstime); 298855239e5SApple OSS Distributions } 299