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() \
40do { \
41 IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsFilterInterruptEventSourceCounter); \
42} while (0)
43
44#define IOStatisticsInterrupt() \
45do { \
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
58OSDefineMetaClassAndStructors
59 (IOFilterInterruptEventSource, IOInterruptEventSource)
60OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 0);
61OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 1);
62OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 2);
63OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 3);
64OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 4);
65OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 5);
66OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 6);
67OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 7);
68
69/*
70 * Implement the call throughs for the private protection conversion
71 */
72bool IOFilterInterruptEventSource::init(OSObject *inOwner,
73 Action inAction,
74 IOService *inProvider,
75 int inIntIndex)
76{
77 return false;
78}
79
80IOInterruptEventSource *
81IOFilterInterruptEventSource::interruptEventSource(OSObject *inOwner,
82 Action inAction,
83 IOService *inProvider,
84 int inIntIndex)
85{
86 return 0;
87}
88
89bool
90IOFilterInterruptEventSource::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
109IOFilterInterruptEventSource *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
128IOFilterInterruptEventSource *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
153void IOFilterInterruptEventSource::free( void )
154{
155 if ((kFilterBlock & flags) && filterActionBlock) Block_release(filterActionBlock);
156
157 super::free();
158}
159
160void 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
178IOFilterInterruptEventSource::Filter
179IOFilterInterruptEventSource::getFilterAction() const
180{
181 if (kFilterBlock & flags) return NULL;
182 return filterAction;
183}
184
185IOFilterInterruptEventSource::FilterBlock
186IOFilterInterruptEventSource::getFilterActionBlock() const
187{
188 if (kFilterBlock & flags) return filterActionBlock;
189 return (NULL);
190}
191
192void 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
234void 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