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 
36 #if IOKITSTATS
37 
38 #define IOStatisticsInitializeCounter() \
39 do { \
40 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsFilterInterruptEventSourceCounter); \
41 } while (0)
42 
43 #define IOStatisticsInterrupt() \
44 do { \
45 	IOStatistics::countInterrupt(IOEventSource::reserved->counter); \
46 } while (0)
47 
48 #else
49 
50 #define IOStatisticsInitializeCounter()
51 #define IOStatisticsInterrupt()
52 
53 #endif /* IOKITSTATS */
54 
55 #define super IOInterruptEventSource
56 
57 OSDefineMetaClassAndStructors
58     (IOFilterInterruptEventSource, IOInterruptEventSource)
59 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 0);
60 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 1);
61 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 2);
62 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 3);
63 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 4);
64 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 5);
65 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 6);
66 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 7);
67 
68 /*
69  * Implement the call throughs for the private protection conversion
70  */
71 bool IOFilterInterruptEventSource::init(OSObject *inOwner,
72                                         Action inAction,
73                                         IOService *inProvider,
74                                         int inIntIndex)
75 {
76     return false;
77 }
78 
79 IOInterruptEventSource *
80 IOFilterInterruptEventSource::interruptEventSource(OSObject *inOwner,
81                                                    Action inAction,
82                                                    IOService *inProvider,
83                                                    int inIntIndex)
84 {
85     return 0;
86 }
87 
88 bool
89 IOFilterInterruptEventSource::init(OSObject *inOwner,
90                                    Action inAction,
91                                    Filter inFilterAction,
92                                    IOService *inProvider,
93                                    int inIntIndex)
94 {
95     if ( !super::init(inOwner, inAction, inProvider, inIntIndex) )
96         return false;
97 
98     if (!inFilterAction)
99         return false;
100 
101     filterAction = inFilterAction;
102 
103     IOStatisticsInitializeCounter();
104 
105     return true;
106 }
107 
108 IOFilterInterruptEventSource *IOFilterInterruptEventSource
109 ::filterInterruptEventSource(OSObject *inOwner,
110                              Action inAction,
111                              Filter inFilterAction,
112                              IOService *inProvider,
113                              int inIntIndex)
114 {
115     IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource;
116 
117     if (me
118     && !me->init(inOwner, inAction, inFilterAction, inProvider, inIntIndex)) {
119         me->release();
120         return 0;
121     }
122 
123     return me;
124 }
125 
126 void IOFilterInterruptEventSource::signalInterrupt()
127 {
128 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
129 
130     IOStatisticsInterrupt();
131     producerCount++;
132 
133 	if (trace)
134 	    IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
135 
136     signalWorkAvailable();
137 
138 	if (trace)
139 	    IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
140 
141 }
142 
143 
144 IOFilterInterruptEventSource::Filter
145 IOFilterInterruptEventSource::getFilterAction() const
146 {
147     return filterAction;
148 }
149 
150 
151 
152 
153 void IOFilterInterruptEventSource::normalInterruptOccurred
154     (void */*refcon*/, IOService */*prov*/, int /*source*/)
155 {
156     bool 	filterRes;
157     uint64_t	startTime = 0;
158     uint64_t	endTime = 0;
159 	bool	trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
160 
161 	if (trace)
162 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER),
163 					 VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
164 
165     if (IOInterruptEventSource::reserved->statistics) {
166         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) {
167             startTime = mach_absolute_time();
168         }
169     }
170 
171     // Call the filter.
172     filterRes = (*filterAction)(owner, this);
173 
174     if (IOInterruptEventSource::reserved->statistics) {
175         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) {
176             IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1);
177         }
178 
179         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) {
180             endTime = mach_absolute_time();
181             IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime);
182         }
183     }
184 
185 	if (trace)
186 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER),
187 				       VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
188 
189     if (filterRes)
190         signalInterrupt();
191 }
192 
193 void IOFilterInterruptEventSource::disableInterruptOccurred
194     (void */*refcon*/, IOService *prov, int source)
195 {
196     bool 	filterRes;
197     uint64_t	startTime = 0;
198     uint64_t	endTime = 0;
199 	bool	trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
200 
201 	if (trace)
202 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER),
203 					 VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
204 
205     if (IOInterruptEventSource::reserved->statistics) {
206         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) {
207             startTime = mach_absolute_time();
208         }
209     }
210 
211     // Call the filter.
212     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_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
228 
229     if (filterRes) {
230         prov->disableInterrupt(source);	/* disable the interrupt */
231         signalInterrupt();
232     }
233 }
234