1c1dac77fSApple OSS Distributions /*
2855239e5SApple OSS Distributions  * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
3c1dac77fSApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5c1dac77fSApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14c1dac77fSApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20c1dac77fSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21c1dac77fSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25c1dac77fSApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27c1dac77fSApple OSS Distributions  */
28c1dac77fSApple OSS Distributions 
29c1dac77fSApple OSS Distributions #include <IOKit/IOInterruptEventSource.h>
30855239e5SApple OSS Distributions #include <IOKit/IOKitDebug.h>
31c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h>
32c1dac77fSApple OSS Distributions #include <IOKit/IOService.h>
33c1dac77fSApple OSS Distributions #include <IOKit/IOInterrupts.h>
34c1dac77fSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
35c1dac77fSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
36c1dac77fSApple OSS Distributions 
37855239e5SApple OSS Distributions #if IOKITSTATS
38c1dac77fSApple OSS Distributions 
39855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter() \
40c1dac77fSApple OSS Distributions do { \
41855239e5SApple OSS Distributions 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsInterruptEventSourceCounter); \
42c1dac77fSApple OSS Distributions } while (0)
43c1dac77fSApple OSS Distributions 
44855239e5SApple OSS Distributions #define IOStatisticsCheckForWork() \
45c1dac77fSApple OSS Distributions do { \
46855239e5SApple OSS Distributions 	IOStatistics::countInterruptCheckForWork(IOEventSource::reserved->counter); \
47c1dac77fSApple OSS Distributions } while (0)
48c1dac77fSApple OSS Distributions 
49855239e5SApple OSS Distributions #define IOStatisticsInterrupt() \
50c1dac77fSApple OSS Distributions do { \
51855239e5SApple OSS Distributions 	IOStatistics::countInterrupt(IOEventSource::reserved->counter); \
52c1dac77fSApple OSS Distributions } while (0)
53c1dac77fSApple OSS Distributions 
54855239e5SApple OSS Distributions #else
55855239e5SApple OSS Distributions 
56855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter()
57855239e5SApple OSS Distributions #define IOStatisticsCheckForWork()
58855239e5SApple OSS Distributions #define IOStatisticsInterrupt()
59855239e5SApple OSS Distributions 
60855239e5SApple OSS Distributions #endif // IOKITSTATS
61c1dac77fSApple OSS Distributions 
62c1dac77fSApple OSS Distributions #define super IOEventSource
63c1dac77fSApple OSS Distributions 
64c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource)
65c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0);
66c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1);
67c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2);
68c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3);
69c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4);
70c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5);
71c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6);
72c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7);
73c1dac77fSApple OSS Distributions 
74c1dac77fSApple OSS Distributions bool IOInterruptEventSource::init(OSObject *inOwner,
75368ad365SApple OSS Distributions 				  Action inAction,
76368ad365SApple OSS Distributions 				  IOService *inProvider,
77368ad365SApple OSS Distributions 				  int inIntIndex)
78c1dac77fSApple OSS Distributions {
79c1dac77fSApple OSS Distributions     bool res = true;
80c1dac77fSApple OSS Distributions 
81c1dac77fSApple OSS Distributions     if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
82c1dac77fSApple OSS Distributions         return false;
83c1dac77fSApple OSS Distributions 
84c1dac77fSApple OSS Distributions     provider = inProvider;
85c1dac77fSApple OSS Distributions     producerCount = consumerCount = 0;
86c1dac77fSApple OSS Distributions     autoDisable = explicitDisable = false;
87855239e5SApple OSS Distributions     intIndex = ~inIntIndex;
88c1dac77fSApple OSS Distributions 
89c1dac77fSApple OSS Distributions     // Assumes inOwner holds a reference(retain) on the provider
90c1dac77fSApple OSS Distributions     if (inProvider) {
91855239e5SApple OSS Distributions         res = (kIOReturnSuccess == registerInterruptHandler(inProvider, inIntIndex));
92855239e5SApple OSS Distributions 	if (res)
93855239e5SApple OSS Distributions 	    intIndex = inIntIndex;
94855239e5SApple OSS Distributions     }
95c1dac77fSApple OSS Distributions 
96855239e5SApple OSS Distributions     IOStatisticsInitializeCounter();
97855239e5SApple OSS Distributions 
98855239e5SApple OSS Distributions     return res;
99855239e5SApple OSS Distributions }
100855239e5SApple OSS Distributions 
101855239e5SApple OSS Distributions IOReturn IOInterruptEventSource::registerInterruptHandler(IOService *inProvider,
102855239e5SApple OSS Distributions 				  int inIntIndex)
103855239e5SApple OSS Distributions {
104855239e5SApple OSS Distributions     IOReturn ret;
105855239e5SApple OSS Distributions     int intType;
106c1dac77fSApple OSS Distributions     IOInterruptAction intHandler;
107c1dac77fSApple OSS Distributions 
108855239e5SApple OSS Distributions     ret = inProvider->getInterruptType(inIntIndex, &intType);
109855239e5SApple OSS Distributions     if (kIOReturnSuccess != ret)
110855239e5SApple OSS Distributions 	return (ret);
111855239e5SApple OSS Distributions 
112c1dac77fSApple OSS Distributions     autoDisable = (intType == kIOInterruptTypeLevel);
113c1dac77fSApple OSS Distributions     if (autoDisable) {
11414e3d835SApple OSS Distributions 	intHandler = OSMemberFunctionCast(IOInterruptAction,
11514e3d835SApple OSS Distributions 	    this, &IOInterruptEventSource::disableInterruptOccurred);
116c1dac77fSApple OSS Distributions     }
117c1dac77fSApple OSS Distributions     else
11814e3d835SApple OSS Distributions 	intHandler = OSMemberFunctionCast(IOInterruptAction,
11914e3d835SApple OSS Distributions 	    this, &IOInterruptEventSource::normalInterruptOccurred);
120c1dac77fSApple OSS Distributions 
121855239e5SApple OSS Distributions     ret = provider->registerInterrupt(inIntIndex, this, intHandler);
122c1dac77fSApple OSS Distributions 
123855239e5SApple OSS Distributions     return (ret);
124c1dac77fSApple OSS Distributions }
125c1dac77fSApple OSS Distributions 
126c1dac77fSApple OSS Distributions IOInterruptEventSource *
127c1dac77fSApple OSS Distributions IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
128c1dac77fSApple OSS Distributions 					     Action inAction,
129c1dac77fSApple OSS Distributions 					     IOService *inProvider,
130c1dac77fSApple OSS Distributions 					     int inIntIndex)
131c1dac77fSApple OSS Distributions {
132c1dac77fSApple OSS Distributions     IOInterruptEventSource *me = new IOInterruptEventSource;
133c1dac77fSApple OSS Distributions 
134c1dac77fSApple OSS Distributions     if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) {
135368ad365SApple OSS Distributions         me->release();
136c1dac77fSApple OSS Distributions         return 0;
137c1dac77fSApple OSS Distributions     }
138c1dac77fSApple OSS Distributions 
139c1dac77fSApple OSS Distributions     return me;
140c1dac77fSApple OSS Distributions }
141c1dac77fSApple OSS Distributions 
142c1dac77fSApple OSS Distributions void IOInterruptEventSource::free()
143c1dac77fSApple OSS Distributions {
144855239e5SApple OSS Distributions     if (provider && intIndex >= 0)
145c1dac77fSApple OSS Distributions         provider->unregisterInterrupt(intIndex);
146c1dac77fSApple OSS Distributions 
147c1dac77fSApple OSS Distributions     super::free();
148c1dac77fSApple OSS Distributions }
149c1dac77fSApple OSS Distributions 
150c1dac77fSApple OSS Distributions void IOInterruptEventSource::enable()
151c1dac77fSApple OSS Distributions {
152855239e5SApple OSS Distributions     if (provider && intIndex >= 0) {
153c1dac77fSApple OSS Distributions         provider->enableInterrupt(intIndex);
154c1dac77fSApple OSS Distributions         explicitDisable = false;
155e13b1fa5SApple OSS Distributions         enabled = true;
156c1dac77fSApple OSS Distributions     }
157c1dac77fSApple OSS Distributions }
158c1dac77fSApple OSS Distributions 
159c1dac77fSApple OSS Distributions void IOInterruptEventSource::disable()
160c1dac77fSApple OSS Distributions {
161855239e5SApple OSS Distributions     if (provider && intIndex >= 0) {
162c1dac77fSApple OSS Distributions         provider->disableInterrupt(intIndex);
163c1dac77fSApple OSS Distributions         explicitDisable = true;
164e13b1fa5SApple OSS Distributions         enabled = false;
165c1dac77fSApple OSS Distributions     }
166c1dac77fSApple OSS Distributions }
167c1dac77fSApple OSS Distributions 
168855239e5SApple OSS Distributions void IOInterruptEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
169855239e5SApple OSS Distributions {
170855239e5SApple OSS Distributions     super::setWorkLoop(inWorkLoop);
171855239e5SApple OSS Distributions 
172855239e5SApple OSS Distributions     if (!provider)
173855239e5SApple OSS Distributions     	return;
174855239e5SApple OSS Distributions 
175855239e5SApple OSS Distributions     if ( !inWorkLoop ) {
176855239e5SApple OSS Distributions 	if (intIndex >= 0) {
177855239e5SApple OSS Distributions 	    provider->unregisterInterrupt(intIndex);
178855239e5SApple OSS Distributions 	    intIndex = ~intIndex;
179855239e5SApple OSS Distributions 	}
180855239e5SApple OSS Distributions     } else if ((intIndex < 0) && (kIOReturnSuccess == registerInterruptHandler(provider, ~intIndex))) {
181855239e5SApple OSS Distributions 	intIndex = ~intIndex;
182855239e5SApple OSS Distributions     }
183855239e5SApple OSS Distributions }
184855239e5SApple OSS Distributions 
185c1dac77fSApple OSS Distributions const IOService *IOInterruptEventSource::getProvider() const
186c1dac77fSApple OSS Distributions {
187c1dac77fSApple OSS Distributions     return provider;
188c1dac77fSApple OSS Distributions }
189c1dac77fSApple OSS Distributions 
190c1dac77fSApple OSS Distributions int IOInterruptEventSource::getIntIndex() const
191c1dac77fSApple OSS Distributions {
192c1dac77fSApple OSS Distributions     return intIndex;
193c1dac77fSApple OSS Distributions }
194c1dac77fSApple OSS Distributions 
195c1dac77fSApple OSS Distributions bool IOInterruptEventSource::getAutoDisable() const
196c1dac77fSApple OSS Distributions {
197c1dac77fSApple OSS Distributions     return autoDisable;
198c1dac77fSApple OSS Distributions }
199c1dac77fSApple OSS Distributions 
200c1dac77fSApple OSS Distributions bool IOInterruptEventSource::checkForWork()
201c1dac77fSApple OSS Distributions {
202c1dac77fSApple OSS Distributions     unsigned int cacheProdCount = producerCount;
203c1dac77fSApple OSS Distributions     int numInts = cacheProdCount - consumerCount;
204c1dac77fSApple OSS Distributions     IOInterruptEventAction intAction = (IOInterruptEventAction) action;
205855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
206c1dac77fSApple OSS Distributions 
207855239e5SApple OSS Distributions     IOStatisticsCheckForWork();
208c1dac77fSApple OSS Distributions 
209855239e5SApple OSS Distributions 	if ( numInts > 0 )
210855239e5SApple OSS Distributions 	{
211855239e5SApple OSS Distributions 		if (trace)
212855239e5SApple OSS Distributions 			IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
213*d0c1fef6SApple OSS Distributions 						 VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
214855239e5SApple OSS Distributions 
215855239e5SApple OSS Distributions 		// Call the handler
216c1dac77fSApple OSS Distributions 		(*intAction)(owner, this, numInts);
217855239e5SApple OSS Distributions 
218855239e5SApple OSS Distributions 		if (trace)
219855239e5SApple OSS Distributions 			IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
220*d0c1fef6SApple OSS Distributions 					       VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
221c1dac77fSApple OSS Distributions 
222c1dac77fSApple OSS Distributions 		consumerCount = cacheProdCount;
223c1dac77fSApple OSS Distributions 		if (autoDisable && !explicitDisable)
224c1dac77fSApple OSS Distributions 			enable();
225c1dac77fSApple OSS Distributions 	}
226855239e5SApple OSS Distributions 
227855239e5SApple OSS Distributions 	else if ( numInts < 0 )
228855239e5SApple OSS Distributions 	{
229855239e5SApple OSS Distributions 		if (trace)
230855239e5SApple OSS Distributions 			IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
231*d0c1fef6SApple OSS Distributions 						 VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
232855239e5SApple OSS Distributions 
233855239e5SApple OSS Distributions 		// Call the handler
234c1dac77fSApple OSS Distributions 		(*intAction)(owner, this, -numInts);
235855239e5SApple OSS Distributions 
236855239e5SApple OSS Distributions 		if (trace)
237855239e5SApple OSS Distributions 			IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
238*d0c1fef6SApple OSS Distributions 					       VM_KERNEL_UNSLIDE(intAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
239c1dac77fSApple OSS Distributions 
240c1dac77fSApple OSS Distributions 		consumerCount = cacheProdCount;
241c1dac77fSApple OSS Distributions 		if (autoDisable && !explicitDisable)
242c1dac77fSApple OSS Distributions 			enable();
243c1dac77fSApple OSS Distributions 	}
244c1dac77fSApple OSS Distributions 
245c1dac77fSApple OSS Distributions     return false;
246c1dac77fSApple OSS Distributions }
247c1dac77fSApple OSS Distributions 
248c1dac77fSApple OSS Distributions void IOInterruptEventSource::normalInterruptOccurred
249c1dac77fSApple OSS Distributions     (void */*refcon*/, IOService */*prov*/, int /*source*/)
250c1dac77fSApple OSS Distributions {
251855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
252c1dac77fSApple OSS Distributions 
253855239e5SApple OSS Distributions     IOStatisticsInterrupt();
254c1dac77fSApple OSS Distributions     producerCount++;
255c1dac77fSApple OSS Distributions 
256855239e5SApple OSS Distributions 	if (trace)
257855239e5SApple OSS Distributions 	    IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
258c1dac77fSApple OSS Distributions 
259855239e5SApple OSS Distributions     signalWorkAvailable();
260855239e5SApple OSS Distributions 
261855239e5SApple OSS Distributions 	if (trace)
262855239e5SApple OSS Distributions 	    IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
263c1dac77fSApple OSS Distributions }
264c1dac77fSApple OSS Distributions 
265c1dac77fSApple OSS Distributions void IOInterruptEventSource::disableInterruptOccurred
266c1dac77fSApple OSS Distributions     (void */*refcon*/, IOService *prov, int source)
267c1dac77fSApple OSS Distributions {
268855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
269c1dac77fSApple OSS Distributions 
270c1dac77fSApple OSS Distributions     prov->disableInterrupt(source);	/* disable the interrupt */
271c1dac77fSApple OSS Distributions 
272855239e5SApple OSS Distributions     IOStatisticsInterrupt();
273c1dac77fSApple OSS Distributions     producerCount++;
274c1dac77fSApple OSS Distributions 
275855239e5SApple OSS Distributions 	if (trace)
276855239e5SApple OSS Distributions 	    IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
277c1dac77fSApple OSS Distributions 
278855239e5SApple OSS Distributions     signalWorkAvailable();
279855239e5SApple OSS Distributions 
280855239e5SApple OSS Distributions 	if (trace)
281855239e5SApple OSS Distributions 	    IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
282c1dac77fSApple OSS Distributions }
283c1dac77fSApple OSS Distributions 
284c1dac77fSApple OSS Distributions void IOInterruptEventSource::interruptOccurred
285c1dac77fSApple OSS Distributions     (void *refcon, IOService *prov, int source)
286c1dac77fSApple OSS Distributions {
287c1dac77fSApple OSS Distributions     if (autoDisable && prov)
288c1dac77fSApple OSS Distributions         disableInterruptOccurred(refcon, prov, source);
289c1dac77fSApple OSS Distributions     else
290c1dac77fSApple OSS Distributions         normalInterruptOccurred(refcon, prov, source);
291c1dac77fSApple OSS Distributions }
292855239e5SApple OSS Distributions 
293855239e5SApple OSS Distributions IOReturn IOInterruptEventSource::warmCPU
294855239e5SApple OSS Distributions     (uint64_t abstime)
295855239e5SApple OSS Distributions {
296855239e5SApple OSS Distributions 
297855239e5SApple OSS Distributions 	return ml_interrupt_prewarm(abstime);
298855239e5SApple OSS Distributions }
299