1 /* 2 * Copyright (c) 1998-2010 Apple 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 #include <IOKit/IOFilterInterruptEventSource.h> 30 #include <IOKit/IOService.h> 31 #include <IOKit/IOKitDebug.h> 32 #include <IOKit/IOTimeStamp.h> 33 #include <IOKit/IOWorkLoop.h> 34 #include <IOKit/IOInterruptAccountingPrivate.h> 35 #include <libkern/Block.h> 36 37 #if IOKITSTATS 38 39 #define IOStatisticsInitializeCounter() \ 40 do { \ 41 IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsFilterInterruptEventSourceCounter); \ 42 } while (0) 43 44 #define IOStatisticsInterrupt() \ 45 do { \ 46 IOStatistics::countInterrupt(IOEventSource::reserved->counter); \ 47 } while (0) 48 49 #else 50 51 #define IOStatisticsInitializeCounter() 52 #define IOStatisticsInterrupt() 53 54 #endif /* IOKITSTATS */ 55 56 #define super IOInterruptEventSource 57 58 OSDefineMetaClassAndStructors 59 (IOFilterInterruptEventSource, IOInterruptEventSource) 60 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 0); 61 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 1); 62 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 2); 63 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 3); 64 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 4); 65 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 5); 66 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 6); 67 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 7); 68 69 /* 70 * Implement the call throughs for the private protection conversion 71 */ 72 bool IOFilterInterruptEventSource::init(OSObject *inOwner, 73 Action inAction, 74 IOService *inProvider, 75 int inIntIndex) 76 { 77 return false; 78 } 79 80 IOInterruptEventSource * 81 IOFilterInterruptEventSource::interruptEventSource(OSObject *inOwner, 82 Action inAction, 83 IOService *inProvider, 84 int inIntIndex) 85 { 86 return 0; 87 } 88 89 bool 90 IOFilterInterruptEventSource::init(OSObject *inOwner, 91 Action inAction, 92 Filter inFilterAction, 93 IOService *inProvider, 94 int inIntIndex) 95 { 96 if ( !super::init(inOwner, inAction, inProvider, inIntIndex) ) 97 return false; 98 99 if (!inFilterAction) 100 return false; 101 102 filterAction = inFilterAction; 103 104 IOStatisticsInitializeCounter(); 105 106 return true; 107 } 108 109 IOFilterInterruptEventSource *IOFilterInterruptEventSource 110 ::filterInterruptEventSource(OSObject *inOwner, 111 Action inAction, 112 Filter inFilterAction, 113 IOService *inProvider, 114 int inIntIndex) 115 { 116 IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource; 117 118 if (me 119 && !me->init(inOwner, inAction, inFilterAction, inProvider, inIntIndex)) { 120 me->release(); 121 return 0; 122 } 123 124 return me; 125 } 126 127 128 IOFilterInterruptEventSource *IOFilterInterruptEventSource 129 ::filterInterruptEventSource(OSObject *inOwner, 130 IOService *inProvider, 131 int inIntIndex, 132 ActionBlock inAction, 133 FilterBlock inFilterAction) 134 { 135 IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource; 136 137 FilterBlock filter = Block_copy(inFilterAction); 138 if (!filter) return 0; 139 140 if (me 141 && !me->init(inOwner, (Action) NULL, (Filter) filter, inProvider, inIntIndex)) { 142 me->release(); 143 Block_release(filter); 144 return 0; 145 } 146 me->flags |= kFilterBlock; 147 me->setActionBlock((IOEventSource::ActionBlock) inAction); 148 149 return me; 150 } 151 152 153 void IOFilterInterruptEventSource::free( void ) 154 { 155 if ((kFilterBlock & flags) && filterActionBlock) Block_release(filterActionBlock); 156 157 super::free(); 158 } 159 160 void IOFilterInterruptEventSource::signalInterrupt() 161 { 162 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 163 164 IOStatisticsInterrupt(); 165 producerCount++; 166 167 if (trace) 168 IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner)); 169 170 signalWorkAvailable(); 171 172 if (trace) 173 IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner)); 174 175 } 176 177 178 IOFilterInterruptEventSource::Filter 179 IOFilterInterruptEventSource::getFilterAction() const 180 { 181 if (kFilterBlock & flags) return NULL; 182 return filterAction; 183 } 184 185 IOFilterInterruptEventSource::FilterBlock 186 IOFilterInterruptEventSource::getFilterActionBlock() const 187 { 188 if (kFilterBlock & flags) return filterActionBlock; 189 return (NULL); 190 } 191 192 void IOFilterInterruptEventSource::normalInterruptOccurred 193 (void */*refcon*/, IOService */*prov*/, int /*source*/) 194 { 195 bool filterRes; 196 uint64_t startTime = 0; 197 uint64_t endTime = 0; 198 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 199 200 if (trace) 201 IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER), 202 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 203 204 if (IOInterruptEventSource::reserved->statistics) { 205 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 206 startTime = mach_absolute_time(); 207 } 208 } 209 210 // Call the filter. 211 if (kFilterBlock & flags) filterRes = (filterActionBlock)(this); 212 else filterRes = (*filterAction)(owner, this); 213 214 if (IOInterruptEventSource::reserved->statistics) { 215 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) { 216 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1); 217 } 218 219 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 220 endTime = mach_absolute_time(); 221 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime); 222 } 223 } 224 225 if (trace) 226 IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER), 227 VM_KERNEL_ADDRHIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), 228 VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 229 230 if (filterRes) 231 signalInterrupt(); 232 } 233 234 void IOFilterInterruptEventSource::disableInterruptOccurred 235 (void */*refcon*/, IOService *prov, int source) 236 { 237 bool filterRes; 238 uint64_t startTime = 0; 239 uint64_t endTime = 0; 240 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 241 242 if (trace) 243 IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER), 244 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 245 246 if (IOInterruptEventSource::reserved->statistics) { 247 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 248 startTime = mach_absolute_time(); 249 } 250 } 251 252 // Call the filter. 253 if (kFilterBlock & flags) filterRes = (filterActionBlock)(this); 254 else filterRes = (*filterAction)(owner, this); 255 256 if (IOInterruptEventSource::reserved->statistics) { 257 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) { 258 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1); 259 } 260 261 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 262 endTime = mach_absolute_time(); 263 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime); 264 } 265 } 266 267 if (trace) 268 IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER), 269 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 270 271 if (filterRes) { 272 prov->disableInterrupt(source); /* disable the interrupt */ 273 signalInterrupt(); 274 } 275 } 276