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