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