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), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner));
135 
136     signalWorkAvailable();
137 
138 	if (trace)
139 	    IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(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), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(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_ADDRHIDE(filterAction), VM_KERNEL_ADDRHIDE(owner),
188 				VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
189 
190     if (filterRes)
191         signalInterrupt();
192 }
193 
194 void IOFilterInterruptEventSource::disableInterruptOccurred
195     (void */*refcon*/, IOService *prov, int source)
196 {
197     bool 	filterRes;
198     uint64_t	startTime = 0;
199     uint64_t	endTime = 0;
200 	bool	trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
201 
202 	if (trace)
203 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER),
204 					 VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
205 
206     if (IOInterruptEventSource::reserved->statistics) {
207         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) {
208             startTime = mach_absolute_time();
209         }
210     }
211 
212     // Call the filter.
213     filterRes = (*filterAction)(owner, this);
214 
215     if (IOInterruptEventSource::reserved->statistics) {
216         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) {
217             IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1);
218         }
219 
220         if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelTimeIndex)) {
221             endTime = mach_absolute_time();
222             IA_ADD_VALUE(&IOInterruptEventSource::reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelTimeIndex], endTime - startTime);
223         }
224     }
225 
226 	if (trace)
227 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER),
228 				       VM_KERNEL_UNSLIDE(filterAction), VM_KERNEL_ADDRHIDE(owner), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
229 
230     if (filterRes) {
231         prov->disableInterrupt(source);	/* disable the interrupt */
232         signalInterrupt();
233     }
234 }
235