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 73 IOFilterInterruptEventSource::init(OSObject *inOwner, 74 Action inAction, 75 IOService *inProvider, 76 int inIntIndex) 77 { 78 return false; 79 } 80 81 IOInterruptEventSource * 82 IOFilterInterruptEventSource::interruptEventSource(OSObject *inOwner, 83 Action inAction, 84 IOService *inProvider, 85 int inIntIndex) 86 { 87 return NULL; 88 } 89 90 bool 91 IOFilterInterruptEventSource::init(OSObject *inOwner, 92 Action inAction, 93 Filter inFilterAction, 94 IOService *inProvider, 95 int inIntIndex) 96 { 97 if (!super::init(inOwner, inAction, inProvider, inIntIndex)) { 98 return false; 99 } 100 101 if (!inFilterAction) { 102 return false; 103 } 104 105 filterAction = inFilterAction; 106 107 IOStatisticsInitializeCounter(); 108 109 return true; 110 } 111 112 IOFilterInterruptEventSource * 113 IOFilterInterruptEventSource 114 ::filterInterruptEventSource(OSObject *inOwner, 115 Action inAction, 116 Filter inFilterAction, 117 IOService *inProvider, 118 int inIntIndex) 119 { 120 IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource; 121 122 if (me 123 && !me->init(inOwner, inAction, inFilterAction, inProvider, inIntIndex)) { 124 me->release(); 125 return NULL; 126 } 127 128 return me; 129 } 130 131 132 IOFilterInterruptEventSource * 133 IOFilterInterruptEventSource 134 ::filterInterruptEventSource(OSObject *inOwner, 135 IOService *inProvider, 136 int inIntIndex, 137 ActionBlock inAction, 138 FilterBlock inFilterAction) 139 { 140 IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource; 141 142 FilterBlock filter = Block_copy(inFilterAction); 143 if (!filter) { 144 OSSafeReleaseNULL(me); 145 return NULL; 146 } 147 148 if (me 149 && !me->init(inOwner, (Action) NULL, (Filter) filter, inProvider, inIntIndex)) { 150 me->release(); 151 Block_release(filter); 152 return NULL; 153 } 154 me->flags |= kFilterBlock; 155 me->setActionBlock((IOEventSource::ActionBlock) inAction); 156 157 return me; 158 } 159 160 161 void 162 IOFilterInterruptEventSource::free( void ) 163 { 164 if ((kFilterBlock & flags) && filterActionBlock) { 165 Block_release(filterActionBlock); 166 } 167 168 super::free(); 169 } 170 171 void 172 IOFilterInterruptEventSource::signalInterrupt() 173 { 174 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 175 176 IOStatisticsInterrupt(); 177 producerCount++; 178 179 if (trace) { 180 IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner)); 181 } 182 183 signalWorkAvailable(); 184 185 if (trace) { 186 IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner)); 187 } 188 } 189 190 191 IOFilterInterruptEventSource::Filter 192 IOFilterInterruptEventSource::getFilterAction() const 193 { 194 if (kFilterBlock & flags) { 195 return NULL; 196 } 197 return filterAction; 198 } 199 200 IOFilterInterruptEventSource::FilterBlock 201 IOFilterInterruptEventSource::getFilterActionBlock() const 202 { 203 if (kFilterBlock & flags) { 204 return filterActionBlock; 205 } 206 return NULL; 207 } 208 209 void 210 IOFilterInterruptEventSource::normalInterruptOccurred 211 (void */*refcon*/, IOService */*prov*/, int /*source*/) 212 { 213 bool filterRes; 214 uint64_t startTime = 0; 215 uint64_t endTime = 0; 216 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 217 218 if (trace) { 219 IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER), 220 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 221 } 222 223 if (IOInterruptEventSource::reserved->statistics) { 224 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex) 225 || IOInterruptEventSource::reserved->statistics->enablePrimaryTimestamp) { 226 startTime = mach_absolute_time(); 227 } 228 if (IOInterruptEventSource::reserved->statistics->enablePrimaryTimestamp) { 229 IOInterruptEventSource::reserved->statistics->primaryTimestamp = startTime; 230 } 231 } 232 233 // Call the filter. 234 if (kFilterBlock & flags) { 235 filterRes = (filterActionBlock)(this); 236 } else { 237 filterRes = (*filterAction)(owner, this); 238 } 239 240 if (IOInterruptEventSource::reserved->statistics) { 241 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) { 242 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1); 243 } 244 245 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 246 endTime = mach_absolute_time(); 247 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime); 248 } 249 } 250 251 if (trace) { 252 IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER), 253 VM_KERNEL_ADDRHIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), 254 VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 255 } 256 257 if (filterRes) { 258 signalInterrupt(); 259 } 260 } 261 262 void 263 IOFilterInterruptEventSource::disableInterruptOccurred 264 (void */*refcon*/, IOService *prov, int source) 265 { 266 bool filterRes; 267 uint64_t startTime = 0; 268 uint64_t endTime = 0; 269 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false; 270 271 if (trace) { 272 IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER), 273 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 274 } 275 276 if (IOInterruptEventSource::reserved->statistics) { 277 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex) 278 || IOInterruptEventSource::reserved->statistics->enablePrimaryTimestamp) { 279 startTime = mach_absolute_time(); 280 } 281 if (IOInterruptEventSource::reserved->statistics->enablePrimaryTimestamp) { 282 IOInterruptEventSource::reserved->statistics->primaryTimestamp = startTime; 283 } 284 } 285 286 // Call the filter. 287 if (kFilterBlock & flags) { 288 filterRes = (filterActionBlock)(this); 289 } else { 290 filterRes = (*filterAction)(owner, this); 291 } 292 293 if (IOInterruptEventSource::reserved->statistics) { 294 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) { 295 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1); 296 } 297 298 if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) { 299 endTime = mach_absolute_time(); 300 IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime); 301 } 302 } 303 304 if (trace) { 305 IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER), 306 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop)); 307 } 308 309 if (filterRes) { 310 prov->disableInterrupt(source); /* disable the interrupt */ 311 signalInterrupt(); 312 } 313 } 314