1c1dac77fSApple OSS Distributions /*
2a3bb9fccSApple OSS Distributions  * Copyright (c) 1998-2014 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 
29*bb611c8fSApple OSS Distributions #define IOKIT_ENABLE_SHARED_PTR
30*bb611c8fSApple OSS Distributions 
31*bb611c8fSApple OSS Distributions #include <ptrauth.h>
32c1dac77fSApple OSS Distributions #include <IOKit/IOInterruptEventSource.h>
33855239e5SApple OSS Distributions #include <IOKit/IOKitDebug.h>
34c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h>
35c1dac77fSApple OSS Distributions #include <IOKit/IOService.h>
36c1dac77fSApple OSS Distributions #include <IOKit/IOInterrupts.h>
37c1dac77fSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
38c1dac77fSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
39a3bb9fccSApple OSS Distributions #include <IOKit/IOInterruptAccountingPrivate.h>
40*bb611c8fSApple OSS Distributions #include <libkern/Block_private.h>
41c1dac77fSApple OSS Distributions 
42855239e5SApple OSS Distributions #if IOKITSTATS
43c1dac77fSApple OSS Distributions 
44855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter() \
45c1dac77fSApple OSS Distributions do { \
46855239e5SApple OSS Distributions 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsInterruptEventSourceCounter); \
47c1dac77fSApple OSS Distributions } while (0)
48c1dac77fSApple OSS Distributions 
49855239e5SApple OSS Distributions #define IOStatisticsCheckForWork() \
50c1dac77fSApple OSS Distributions do { \
51855239e5SApple OSS Distributions 	IOStatistics::countInterruptCheckForWork(IOEventSource::reserved->counter); \
52c1dac77fSApple OSS Distributions } while (0)
53c1dac77fSApple OSS Distributions 
54855239e5SApple OSS Distributions #define IOStatisticsInterrupt() \
55c1dac77fSApple OSS Distributions do { \
56855239e5SApple OSS Distributions 	IOStatistics::countInterrupt(IOEventSource::reserved->counter); \
57c1dac77fSApple OSS Distributions } while (0)
58c1dac77fSApple OSS Distributions 
59855239e5SApple OSS Distributions #else
60855239e5SApple OSS Distributions 
61855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter()
62855239e5SApple OSS Distributions #define IOStatisticsCheckForWork()
63855239e5SApple OSS Distributions #define IOStatisticsInterrupt()
64855239e5SApple OSS Distributions 
65855239e5SApple OSS Distributions #endif // IOKITSTATS
66c1dac77fSApple OSS Distributions 
67c1dac77fSApple OSS Distributions #define super IOEventSource
68c1dac77fSApple OSS Distributions 
69c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource)
70c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0);
71c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1);
72c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2);
73c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3);
74c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4);
75c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5);
76c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6);
77c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7);
78c1dac77fSApple OSS Distributions 
79a5e72196SApple OSS Distributions bool
80a5e72196SApple OSS Distributions IOInterruptEventSource::init(OSObject *inOwner,
81368ad365SApple OSS Distributions     Action inAction,
82368ad365SApple OSS Distributions     IOService *inProvider,
83368ad365SApple OSS Distributions     int inIntIndex)
84c1dac77fSApple OSS Distributions {
85c1dac77fSApple OSS Distributions 	bool res = true;
86c1dac77fSApple OSS Distributions 
87a5e72196SApple OSS Distributions 	if (!super::init(inOwner, (IOEventSourceAction) inAction)) {
88c1dac77fSApple OSS Distributions 		return false;
89a5e72196SApple OSS Distributions 	}
90c1dac77fSApple OSS Distributions 
91a3bb9fccSApple OSS Distributions 	reserved = IONew(ExpansionData, 1);
92a3bb9fccSApple OSS Distributions 
93a3bb9fccSApple OSS Distributions 	if (!reserved) {
94a3bb9fccSApple OSS Distributions 		return false;
95a3bb9fccSApple OSS Distributions 	}
96a3bb9fccSApple OSS Distributions 
97a3bb9fccSApple OSS Distributions 	bzero(reserved, sizeof(ExpansionData));
98a3bb9fccSApple OSS Distributions 
99c1dac77fSApple OSS Distributions 	provider = inProvider;
100c1dac77fSApple OSS Distributions 	producerCount = consumerCount = 0;
101c1dac77fSApple OSS Distributions 	autoDisable = explicitDisable = false;
102855239e5SApple OSS Distributions 	intIndex = ~inIntIndex;
103c1dac77fSApple OSS Distributions 
104c1dac77fSApple OSS Distributions 	// Assumes inOwner holds a reference(retain) on the provider
105c1dac77fSApple OSS Distributions 	if (inProvider) {
106a3bb9fccSApple OSS Distributions 		if (IA_ANY_STATISTICS_ENABLED) {
107a3bb9fccSApple OSS Distributions 			/*
108a3bb9fccSApple OSS Distributions 			 * We only treat this as an "interrupt" if it has a provider; if it does,
109a3bb9fccSApple OSS Distributions 			 * set up the objects necessary to track interrupt statistics.  Interrupt
110a3bb9fccSApple OSS Distributions 			 * event sources without providers are most likely being used as simple
111a3bb9fccSApple OSS Distributions 			 * event source in order to poke at workloops and kick off work.
112a3bb9fccSApple OSS Distributions 			 *
113a3bb9fccSApple OSS Distributions 			 * We also avoid try to avoid interrupt accounting overhead if none of
114a3bb9fccSApple OSS Distributions 			 * the statistics are enabled.
115a3bb9fccSApple OSS Distributions 			 */
116a3bb9fccSApple OSS Distributions 			reserved->statistics = IONew(IOInterruptAccountingData, 1);
117a3bb9fccSApple OSS Distributions 
118a3bb9fccSApple OSS Distributions 			if (!reserved->statistics) {
119a3bb9fccSApple OSS Distributions 				/*
120a3bb9fccSApple OSS Distributions 				 * We rely on the free() routine to clean up after us if init fails
121a3bb9fccSApple OSS Distributions 				 * midway.
122a3bb9fccSApple OSS Distributions 				 */
123a3bb9fccSApple OSS Distributions 				return false;
124a3bb9fccSApple OSS Distributions 			}
125a3bb9fccSApple OSS Distributions 
126a3bb9fccSApple OSS Distributions 			bzero(reserved->statistics, sizeof(IOInterruptAccountingData));
127a3bb9fccSApple OSS Distributions 
128a3bb9fccSApple OSS Distributions 			reserved->statistics->owner = this;
129a3bb9fccSApple OSS Distributions 		}
130a3bb9fccSApple OSS Distributions 
131855239e5SApple OSS Distributions 		res = (kIOReturnSuccess == registerInterruptHandler(inProvider, inIntIndex));
132a3bb9fccSApple OSS Distributions 
133a3bb9fccSApple OSS Distributions 		if (res) {
134855239e5SApple OSS Distributions 			intIndex = inIntIndex;
135855239e5SApple OSS Distributions 		}
136a3bb9fccSApple OSS Distributions 	}
137c1dac77fSApple OSS Distributions 
138855239e5SApple OSS Distributions 	IOStatisticsInitializeCounter();
139855239e5SApple OSS Distributions 
140855239e5SApple OSS Distributions 	return res;
141855239e5SApple OSS Distributions }
142855239e5SApple OSS Distributions 
143a5e72196SApple OSS Distributions IOReturn
144a5e72196SApple OSS Distributions IOInterruptEventSource::registerInterruptHandler(IOService *inProvider,
145855239e5SApple OSS Distributions     int inIntIndex)
146855239e5SApple OSS Distributions {
147855239e5SApple OSS Distributions 	IOReturn ret;
148855239e5SApple OSS Distributions 	int intType;
149c1dac77fSApple OSS Distributions 	IOInterruptAction intHandler;
150c1dac77fSApple OSS Distributions 
151855239e5SApple OSS Distributions 	ret = inProvider->getInterruptType(inIntIndex, &intType);
152a5e72196SApple OSS Distributions 	if (kIOReturnSuccess != ret) {
153a5e72196SApple OSS Distributions 		return ret;
154a5e72196SApple OSS Distributions 	}
155855239e5SApple OSS Distributions 
156c1dac77fSApple OSS Distributions 	autoDisable = (intType == kIOInterruptTypeLevel);
157c1dac77fSApple OSS Distributions 	if (autoDisable) {
15814e3d835SApple OSS Distributions 		intHandler = OSMemberFunctionCast(IOInterruptAction,
15914e3d835SApple OSS Distributions 		    this, &IOInterruptEventSource::disableInterruptOccurred);
160a5e72196SApple OSS Distributions 	} else {
16114e3d835SApple OSS Distributions 		intHandler = OSMemberFunctionCast(IOInterruptAction,
16214e3d835SApple OSS Distributions 		    this, &IOInterruptEventSource::normalInterruptOccurred);
163a5e72196SApple OSS Distributions 	}
164c1dac77fSApple OSS Distributions 
165855239e5SApple OSS Distributions 	ret = provider->registerInterrupt(inIntIndex, this, intHandler);
166c1dac77fSApple OSS Distributions 
167a3bb9fccSApple OSS Distributions 	/*
168a3bb9fccSApple OSS Distributions 	 * Add statistics to the provider.  The setWorkLoop convention should ensure
169a3bb9fccSApple OSS Distributions 	 * that we always go down the unregister path before we register (outside of
170a3bb9fccSApple OSS Distributions 	 * init()), so we don't have to worry that we will invoke addInterruptStatistics
171a3bb9fccSApple OSS Distributions 	 * erroneously.
172a3bb9fccSApple OSS Distributions 	 */
173a3bb9fccSApple OSS Distributions 	if ((ret == kIOReturnSuccess) && (reserved->statistics)) {
174a3bb9fccSApple OSS Distributions 		/*
175a3bb9fccSApple OSS Distributions 		 * Stash the normal index value, for the sake of debugging.
176a3bb9fccSApple OSS Distributions 		 */
177a3bb9fccSApple OSS Distributions 		reserved->statistics->interruptIndex = inIntIndex;
178a3bb9fccSApple OSS Distributions 
179a3bb9fccSApple OSS Distributions 		/*
180a3bb9fccSApple OSS Distributions 		 * We need to hook the interrupt information up to the provider so that it
181a3bb9fccSApple OSS Distributions 		 * can find the statistics for this interrupt when desired.  The provider is
182a3bb9fccSApple OSS Distributions 		 * responsible for maintaining the reporter for a particular interrupt, and
183a3bb9fccSApple OSS Distributions 		 * needs a handle on the statistics so that it can request that the reporter
184a3bb9fccSApple OSS Distributions 		 * be updated as needed.  Errors are considered "soft" for the moment (it
185a3bb9fccSApple OSS Distributions 		 * will either panic, or fail in a way such that we can still service the
186a3bb9fccSApple OSS Distributions 		 * interrupt).
187a3bb9fccSApple OSS Distributions 		 */
188a3bb9fccSApple OSS Distributions 		provider->addInterruptStatistics(reserved->statistics, inIntIndex);
189a3bb9fccSApple OSS Distributions 
190a3bb9fccSApple OSS Distributions 		/*
191a3bb9fccSApple OSS Distributions 		 * Add the statistics object to the global list of statistics objects; this
192a3bb9fccSApple OSS Distributions 		 * is an aid to debugging (we can trivially find statistics for all eligible
193a3bb9fccSApple OSS Distributions 		 * interrupts, and dump them; potentially helpful if the system is wedged
194a3bb9fccSApple OSS Distributions 		 * due to interrupt activity).
195a3bb9fccSApple OSS Distributions 		 */
196a3bb9fccSApple OSS Distributions 		interruptAccountingDataAddToList(reserved->statistics);
197a3bb9fccSApple OSS Distributions 	}
198a3bb9fccSApple OSS Distributions 
199a5e72196SApple OSS Distributions 	return ret;
200c1dac77fSApple OSS Distributions }
201c1dac77fSApple OSS Distributions 
202a3bb9fccSApple OSS Distributions void
203a3bb9fccSApple OSS Distributions IOInterruptEventSource::unregisterInterruptHandler(IOService *inProvider,
204a3bb9fccSApple OSS Distributions     int inIntIndex)
205a3bb9fccSApple OSS Distributions {
206a3bb9fccSApple OSS Distributions 	if (reserved->statistics) {
207a3bb9fccSApple OSS Distributions 		interruptAccountingDataRemoveFromList(reserved->statistics);
208a3bb9fccSApple OSS Distributions 		provider->removeInterruptStatistics(reserved->statistics->interruptIndex);
209a3bb9fccSApple OSS Distributions 	}
210a3bb9fccSApple OSS Distributions 
211a3bb9fccSApple OSS Distributions 	provider->unregisterInterrupt(inIntIndex);
212a3bb9fccSApple OSS Distributions }
213a3bb9fccSApple OSS Distributions 
214a3bb9fccSApple OSS Distributions 
215*bb611c8fSApple OSS Distributions OSSharedPtr<IOInterruptEventSource>
216c1dac77fSApple OSS Distributions IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
217c1dac77fSApple OSS Distributions     Action inAction,
218c1dac77fSApple OSS Distributions     IOService *inProvider,
219c1dac77fSApple OSS Distributions     int inIntIndex)
220c1dac77fSApple OSS Distributions {
221*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOInterruptEventSource> me = OSMakeShared<IOInterruptEventSource>();
222c1dac77fSApple OSS Distributions 
223c1dac77fSApple OSS Distributions 	if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) {
224*bb611c8fSApple OSS Distributions 		return nullptr;
225c1dac77fSApple OSS Distributions 	}
226c1dac77fSApple OSS Distributions 
227c1dac77fSApple OSS Distributions 	return me;
228c1dac77fSApple OSS Distributions }
229c1dac77fSApple OSS Distributions 
230*bb611c8fSApple OSS Distributions OSSharedPtr<IOInterruptEventSource>
231cc9a6355SApple OSS Distributions IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
232cc9a6355SApple OSS Distributions     IOService *inProvider,
233cc9a6355SApple OSS Distributions     int inIntIndex,
234cc9a6355SApple OSS Distributions     ActionBlock inAction)
235cc9a6355SApple OSS Distributions {
236*bb611c8fSApple OSS Distributions 	OSSharedPtr<IOInterruptEventSource> ies;
237cc9a6355SApple OSS Distributions 	ies = IOInterruptEventSource::interruptEventSource(inOwner, (Action) NULL, inProvider, inIntIndex);
238a5e72196SApple OSS Distributions 	if (ies) {
239a5e72196SApple OSS Distributions 		ies->setActionBlock((IOEventSource::ActionBlock) inAction);
240a5e72196SApple OSS Distributions 	}
241cc9a6355SApple OSS Distributions 
242cc9a6355SApple OSS Distributions 	return ies;
243cc9a6355SApple OSS Distributions }
244cc9a6355SApple OSS Distributions 
245a5e72196SApple OSS Distributions void
246a5e72196SApple OSS Distributions IOInterruptEventSource::free()
247c1dac77fSApple OSS Distributions {
248a5e72196SApple OSS Distributions 	if (provider && intIndex >= 0) {
249a3bb9fccSApple OSS Distributions 		unregisterInterruptHandler(provider, intIndex);
250a5e72196SApple OSS Distributions 	}
251a3bb9fccSApple OSS Distributions 
252a3bb9fccSApple OSS Distributions 	if (reserved) {
253a3bb9fccSApple OSS Distributions 		if (reserved->statistics) {
254a3bb9fccSApple OSS Distributions 			IODelete(reserved->statistics, IOInterruptAccountingData, 1);
255a3bb9fccSApple OSS Distributions 		}
256a3bb9fccSApple OSS Distributions 
257a3bb9fccSApple OSS Distributions 		IODelete(reserved, ExpansionData, 1);
258a3bb9fccSApple OSS Distributions 	}
259c1dac77fSApple OSS Distributions 
260c1dac77fSApple OSS Distributions 	super::free();
261c1dac77fSApple OSS Distributions }
262c1dac77fSApple OSS Distributions 
263a5e72196SApple OSS Distributions void
264a5e72196SApple OSS Distributions IOInterruptEventSource::enable()
265c1dac77fSApple OSS Distributions {
266855239e5SApple OSS Distributions 	if (provider && intIndex >= 0) {
267c1dac77fSApple OSS Distributions 		provider->enableInterrupt(intIndex);
268c1dac77fSApple OSS Distributions 		explicitDisable = false;
269e13b1fa5SApple OSS Distributions 		enabled = true;
270c1dac77fSApple OSS Distributions 	}
271c1dac77fSApple OSS Distributions }
272c1dac77fSApple OSS Distributions 
273a5e72196SApple OSS Distributions void
274a5e72196SApple OSS Distributions IOInterruptEventSource::disable()
275c1dac77fSApple OSS Distributions {
276855239e5SApple OSS Distributions 	if (provider && intIndex >= 0) {
277c1dac77fSApple OSS Distributions 		provider->disableInterrupt(intIndex);
278c1dac77fSApple OSS Distributions 		explicitDisable = true;
279e13b1fa5SApple OSS Distributions 		enabled = false;
280c1dac77fSApple OSS Distributions 	}
281c1dac77fSApple OSS Distributions }
282c1dac77fSApple OSS Distributions 
283a5e72196SApple OSS Distributions void
284a5e72196SApple OSS Distributions IOInterruptEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
285855239e5SApple OSS Distributions {
286a5e72196SApple OSS Distributions 	if (inWorkLoop) {
287a5e72196SApple OSS Distributions 		super::setWorkLoop(inWorkLoop);
288a5e72196SApple OSS Distributions 	}
289855239e5SApple OSS Distributions 
290186b8fceSApple OSS Distributions 	if (provider) {
291855239e5SApple OSS Distributions 		if (!inWorkLoop) {
292855239e5SApple OSS Distributions 			if (intIndex >= 0) {
293a3bb9fccSApple OSS Distributions 				/*
294a3bb9fccSApple OSS Distributions 				 * It isn't necessarily safe to wait until free() to unregister the interrupt;
295a3bb9fccSApple OSS Distributions 				 * our provider may disappear.
296a3bb9fccSApple OSS Distributions 				 */
297a3bb9fccSApple OSS Distributions 				unregisterInterruptHandler(provider, intIndex);
298855239e5SApple OSS Distributions 				intIndex = ~intIndex;
299855239e5SApple OSS Distributions 			}
300855239e5SApple OSS Distributions 		} else if ((intIndex < 0) && (kIOReturnSuccess == registerInterruptHandler(provider, ~intIndex))) {
301855239e5SApple OSS Distributions 			intIndex = ~intIndex;
302855239e5SApple OSS Distributions 		}
303855239e5SApple OSS Distributions 	}
304855239e5SApple OSS Distributions 
305a5e72196SApple OSS Distributions 	if (!inWorkLoop) {
306a5e72196SApple OSS Distributions 		super::setWorkLoop(inWorkLoop);
307a5e72196SApple OSS Distributions 	}
308186b8fceSApple OSS Distributions }
309186b8fceSApple OSS Distributions 
310a5e72196SApple OSS Distributions const IOService *
311a5e72196SApple OSS Distributions IOInterruptEventSource::getProvider() const
312c1dac77fSApple OSS Distributions {
313c1dac77fSApple OSS Distributions 	return provider;
314c1dac77fSApple OSS Distributions }
315c1dac77fSApple OSS Distributions 
316a5e72196SApple OSS Distributions int
317a5e72196SApple OSS Distributions IOInterruptEventSource::getIntIndex() const
318c1dac77fSApple OSS Distributions {
319c1dac77fSApple OSS Distributions 	return intIndex;
320c1dac77fSApple OSS Distributions }
321c1dac77fSApple OSS Distributions 
322a5e72196SApple OSS Distributions bool
323a5e72196SApple OSS Distributions IOInterruptEventSource::getAutoDisable() const
324c1dac77fSApple OSS Distributions {
325c1dac77fSApple OSS Distributions 	return autoDisable;
326c1dac77fSApple OSS Distributions }
327c1dac77fSApple OSS Distributions 
328a5e72196SApple OSS Distributions bool
329a5e72196SApple OSS Distributions IOInterruptEventSource::checkForWork()
330c1dac77fSApple OSS Distributions {
331a3bb9fccSApple OSS Distributions 	uint64_t startSystemTime = 0;
332a3bb9fccSApple OSS Distributions 	uint64_t endSystemTime = 0;
333a3bb9fccSApple OSS Distributions 	uint64_t startCPUTime = 0;
334a3bb9fccSApple OSS Distributions 	uint64_t endCPUTime = 0;
335c1dac77fSApple OSS Distributions 	unsigned int cacheProdCount = producerCount;
336c1dac77fSApple OSS Distributions 	int numInts = cacheProdCount - consumerCount;
337*bb611c8fSApple OSS Distributions 	IOEventSource::Action intAction = action;
338cc9a6355SApple OSS Distributions 	ActionBlock intActionBlock = (ActionBlock) actionBlock;
339*bb611c8fSApple OSS Distributions 	void *address;
340855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
341c1dac77fSApple OSS Distributions 
342*bb611c8fSApple OSS Distributions 	if (kActionBlock & flags) {
343*bb611c8fSApple OSS Distributions 		address = ptrauth_nop_cast(void *, _Block_get_invoke_fn((struct Block_layout *)intActionBlock));
344*bb611c8fSApple OSS Distributions 	} else {
345*bb611c8fSApple OSS Distributions 		address = ptrauth_nop_cast(void *, intAction);
346*bb611c8fSApple OSS Distributions 	}
347*bb611c8fSApple OSS Distributions 
348855239e5SApple OSS Distributions 	IOStatisticsCheckForWork();
349c1dac77fSApple OSS Distributions 
350a5e72196SApple OSS Distributions 	if (numInts > 0) {
351a5e72196SApple OSS Distributions 		if (trace) {
352855239e5SApple OSS Distributions 			IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
353*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(address),
354*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(owner),
35576e12aa3SApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
356a5e72196SApple OSS Distributions 		}
357855239e5SApple OSS Distributions 
358a3bb9fccSApple OSS Distributions 		if (reserved->statistics) {
359a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelSystemTimeIndex)) {
360a3bb9fccSApple OSS Distributions 				startSystemTime = mach_absolute_time();
361a3bb9fccSApple OSS Distributions 			}
362a3bb9fccSApple OSS Distributions 
363a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCPUTimeIndex)) {
364a3bb9fccSApple OSS Distributions 				startCPUTime = thread_get_runtime_self();
365a3bb9fccSApple OSS Distributions 			}
366a3bb9fccSApple OSS Distributions 		}
367a3bb9fccSApple OSS Distributions 
368855239e5SApple OSS Distributions 		// Call the handler
369a5e72196SApple OSS Distributions 		if (kActionBlock & flags) {
370a5e72196SApple OSS Distributions 			(intActionBlock)(this, numInts);
371a5e72196SApple OSS Distributions 		} else {
372*bb611c8fSApple OSS Distributions 			((IOInterruptEventAction)intAction)(owner, this, numInts);
373a5e72196SApple OSS Distributions 		}
374855239e5SApple OSS Distributions 
375a3bb9fccSApple OSS Distributions 		if (reserved->statistics) {
376a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCountIndex)) {
377a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelCountIndex], 1);
378a3bb9fccSApple OSS Distributions 			}
379a3bb9fccSApple OSS Distributions 
380a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCPUTimeIndex)) {
381a3bb9fccSApple OSS Distributions 				endCPUTime = thread_get_runtime_self();
382a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelCPUTimeIndex], endCPUTime - startCPUTime);
383a3bb9fccSApple OSS Distributions 			}
384a3bb9fccSApple OSS Distributions 
385a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelSystemTimeIndex)) {
386a3bb9fccSApple OSS Distributions 				endSystemTime = mach_absolute_time();
387a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelSystemTimeIndex], endSystemTime - startSystemTime);
388a3bb9fccSApple OSS Distributions 			}
389a3bb9fccSApple OSS Distributions 		}
390a3bb9fccSApple OSS Distributions 
391a5e72196SApple OSS Distributions 		if (trace) {
392855239e5SApple OSS Distributions 			IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
393*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(address),
394*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(owner),
39576e12aa3SApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
396c1dac77fSApple OSS Distributions 		}
397855239e5SApple OSS Distributions 
398a5e72196SApple OSS Distributions 		consumerCount = cacheProdCount;
399a5e72196SApple OSS Distributions 		if (autoDisable && !explicitDisable) {
400a5e72196SApple OSS Distributions 			enable();
401a5e72196SApple OSS Distributions 		}
402a5e72196SApple OSS Distributions 	} else if (numInts < 0) {
403a5e72196SApple OSS Distributions 		if (trace) {
404855239e5SApple OSS Distributions 			IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
405*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(address),
406*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(owner),
40776e12aa3SApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
408a5e72196SApple OSS Distributions 		}
409855239e5SApple OSS Distributions 
410a3bb9fccSApple OSS Distributions 		if (reserved->statistics) {
411a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelSystemTimeIndex)) {
412a3bb9fccSApple OSS Distributions 				startSystemTime = mach_absolute_time();
413a3bb9fccSApple OSS Distributions 			}
414a3bb9fccSApple OSS Distributions 
415a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCPUTimeIndex)) {
416a3bb9fccSApple OSS Distributions 				startCPUTime = thread_get_runtime_self();
417a3bb9fccSApple OSS Distributions 			}
418a3bb9fccSApple OSS Distributions 		}
419a3bb9fccSApple OSS Distributions 
420855239e5SApple OSS Distributions 		// Call the handler
421a5e72196SApple OSS Distributions 		if (kActionBlock & flags) {
422a5e72196SApple OSS Distributions 			(intActionBlock)(this, numInts);
423a5e72196SApple OSS Distributions 		} else {
424*bb611c8fSApple OSS Distributions 			((IOInterruptEventAction)intAction)(owner, this, numInts);
425a5e72196SApple OSS Distributions 		}
426855239e5SApple OSS Distributions 
427a3bb9fccSApple OSS Distributions 		if (reserved->statistics) {
428a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCountIndex)) {
429a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelCountIndex], 1);
430a3bb9fccSApple OSS Distributions 			}
431a3bb9fccSApple OSS Distributions 
432a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelCPUTimeIndex)) {
433a3bb9fccSApple OSS Distributions 				endCPUTime = thread_get_runtime_self();
434a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelCPUTimeIndex], endCPUTime - startCPUTime);
435a3bb9fccSApple OSS Distributions 			}
436a3bb9fccSApple OSS Distributions 
437a3bb9fccSApple OSS Distributions 			if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingSecondLevelSystemTimeIndex)) {
438a3bb9fccSApple OSS Distributions 				endSystemTime = mach_absolute_time();
439a3bb9fccSApple OSS Distributions 				IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingSecondLevelSystemTimeIndex], endSystemTime - startSystemTime);
440a3bb9fccSApple OSS Distributions 			}
441a3bb9fccSApple OSS Distributions 		}
442a3bb9fccSApple OSS Distributions 
443a5e72196SApple OSS Distributions 		if (trace) {
444855239e5SApple OSS Distributions 			IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
445*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(address),
446*bb611c8fSApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(owner),
44776e12aa3SApple OSS Distributions 			    VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(workLoop));
448a5e72196SApple OSS Distributions 		}
449c1dac77fSApple OSS Distributions 
450c1dac77fSApple OSS Distributions 		consumerCount = cacheProdCount;
451a5e72196SApple OSS Distributions 		if (autoDisable && !explicitDisable) {
452c1dac77fSApple OSS Distributions 			enable();
453c1dac77fSApple OSS Distributions 		}
454a5e72196SApple OSS Distributions 	}
455c1dac77fSApple OSS Distributions 
456c1dac77fSApple OSS Distributions 	return false;
457c1dac77fSApple OSS Distributions }
458c1dac77fSApple OSS Distributions 
459a5e72196SApple OSS Distributions void
460a5e72196SApple OSS Distributions IOInterruptEventSource::normalInterruptOccurred
461c1dac77fSApple OSS Distributions (void */*refcon*/, IOService */*prov*/, int /*source*/)
462c1dac77fSApple OSS Distributions {
463855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
464c1dac77fSApple OSS Distributions 
465855239e5SApple OSS Distributions 	IOStatisticsInterrupt();
466c1dac77fSApple OSS Distributions 	producerCount++;
467c1dac77fSApple OSS Distributions 
468a5e72196SApple OSS Distributions 	if (trace) {
46976e12aa3SApple OSS Distributions 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner));
470a5e72196SApple OSS Distributions 	}
471c1dac77fSApple OSS Distributions 
472a3bb9fccSApple OSS Distributions 	if (reserved->statistics) {
473a5e72196SApple OSS Distributions 		if (reserved->statistics->enablePrimaryTimestamp) {
474a5e72196SApple OSS Distributions 			reserved->statistics->primaryTimestamp = mach_absolute_time();
475a5e72196SApple OSS Distributions 		}
476a3bb9fccSApple OSS Distributions 		if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) {
477a3bb9fccSApple OSS Distributions 			IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1);
478a3bb9fccSApple OSS Distributions 		}
479a3bb9fccSApple OSS Distributions 	}
480a3bb9fccSApple OSS Distributions 
481855239e5SApple OSS Distributions 	signalWorkAvailable();
482855239e5SApple OSS Distributions 
483a5e72196SApple OSS Distributions 	if (trace) {
48476e12aa3SApple OSS Distributions 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner));
485c1dac77fSApple OSS Distributions 	}
486a5e72196SApple OSS Distributions }
487c1dac77fSApple OSS Distributions 
488a5e72196SApple OSS Distributions void
489a5e72196SApple OSS Distributions IOInterruptEventSource::disableInterruptOccurred
490c1dac77fSApple OSS Distributions (void */*refcon*/, IOService *prov, int source)
491c1dac77fSApple OSS Distributions {
492855239e5SApple OSS Distributions 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
493c1dac77fSApple OSS Distributions 
494c1dac77fSApple OSS Distributions 	prov->disableInterrupt(source); /* disable the interrupt */
495c1dac77fSApple OSS Distributions 
496855239e5SApple OSS Distributions 	IOStatisticsInterrupt();
497c1dac77fSApple OSS Distributions 	producerCount++;
498c1dac77fSApple OSS Distributions 
499a5e72196SApple OSS Distributions 	if (trace) {
50076e12aa3SApple OSS Distributions 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner));
501a5e72196SApple OSS Distributions 	}
502c1dac77fSApple OSS Distributions 
503a3bb9fccSApple OSS Distributions 	if (reserved->statistics) {
504a5e72196SApple OSS Distributions 		if (reserved->statistics->enablePrimaryTimestamp) {
505a5e72196SApple OSS Distributions 			reserved->statistics->primaryTimestamp = mach_absolute_time();
506a5e72196SApple OSS Distributions 		}
507a3bb9fccSApple OSS Distributions 		if (IA_GET_STATISTIC_ENABLED(kInterruptAccountingFirstLevelCountIndex)) {
508a3bb9fccSApple OSS Distributions 			IA_ADD_VALUE(&reserved->statistics->interruptStatistics[kInterruptAccountingFirstLevelCountIndex], 1);
509a3bb9fccSApple OSS Distributions 		}
510a3bb9fccSApple OSS Distributions 	}
511a3bb9fccSApple OSS Distributions 
512855239e5SApple OSS Distributions 	signalWorkAvailable();
513855239e5SApple OSS Distributions 
514a5e72196SApple OSS Distributions 	if (trace) {
51576e12aa3SApple OSS Distributions 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(owner));
516c1dac77fSApple OSS Distributions 	}
517c1dac77fSApple OSS Distributions }
518855239e5SApple OSS Distributions 
519a5e72196SApple OSS Distributions void
520a5e72196SApple OSS Distributions IOInterruptEventSource::interruptOccurred
521a5e72196SApple OSS Distributions (void *_refcon, IOService *prov, int source)
522a5e72196SApple OSS Distributions {
523a5e72196SApple OSS Distributions 	if (autoDisable && prov) {
524a5e72196SApple OSS Distributions 		disableInterruptOccurred(_refcon, prov, source);
525a5e72196SApple OSS Distributions 	} else {
526a5e72196SApple OSS Distributions 		normalInterruptOccurred(_refcon, prov, source);
527a5e72196SApple OSS Distributions 	}
528a5e72196SApple OSS Distributions }
529a5e72196SApple OSS Distributions 
530a5e72196SApple OSS Distributions IOReturn
531a5e72196SApple OSS Distributions IOInterruptEventSource::warmCPU
532855239e5SApple OSS Distributions (uint64_t abstime)
533855239e5SApple OSS Distributions {
534855239e5SApple OSS Distributions 	return ml_interrupt_prewarm(abstime);
535855239e5SApple OSS Distributions }
536a5e72196SApple OSS Distributions 
537a5e72196SApple OSS Distributions void
538a5e72196SApple OSS Distributions IOInterruptEventSource::enablePrimaryInterruptTimestamp(bool enable)
539a5e72196SApple OSS Distributions {
540a5e72196SApple OSS Distributions 	if (reserved->statistics) {
541a5e72196SApple OSS Distributions 		reserved->statistics->enablePrimaryTimestamp = enable;
542a5e72196SApple OSS Distributions 	}
543a5e72196SApple OSS Distributions }
544a5e72196SApple OSS Distributions 
545a5e72196SApple OSS Distributions uint64_t
546*bb611c8fSApple OSS Distributions IOInterruptEventSource::getPrimaryInterruptTimestamp()
547a5e72196SApple OSS Distributions {
548a5e72196SApple OSS Distributions 	if (reserved->statistics && reserved->statistics->enablePrimaryTimestamp) {
549a5e72196SApple OSS Distributions 		return reserved->statistics->primaryTimestamp;
550a5e72196SApple OSS Distributions 	}
551a5e72196SApple OSS Distributions 	return -1ULL;
552a5e72196SApple OSS Distributions }
553