xref: /xnu-12377.61.12/iokit/IOKit/IOInterruptAccountingPrivate.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2014 Apple Computer, 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 #ifndef __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H
30 #define __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H
31 
32 /*
33  * Header containing interrupt accounting related prototypes/defines that should be kept private to
34  * xnu itself (no userspace, no kexts, no nothing!).
35  */
36 
37 #include <stdint.h>
38 #include <IOKit/IOInterruptAccounting.h>
39 #include <kern/queue.h>
40 
41 class OSObject;
42 class IOSimpleReporter;
43 
44 /*
45  * A brief overview.  Interrupt accounting (as implemented in IOKit) pertains to infrastructure for
46  * gathering information (currently, statistics only) on interrupts, and allowing them to be reported
47  * (either to userspace through IOReporting, or through lldb; lldb macros have yet to be implemented).
48  *
49  * Currently, interrupt accounting consists of of a relationship between an IOService (a nub, which
50  * will contain interrupt specifiers), an IOInterruptEventSource (if we add other interrupt target
51  * abstractions, support could be added for them as well), and objects necessary to support them.  An
52  * interrupt is "named" by a tuple of {provider, interrupt index}; no nub should ever have more than
53  * one interrupt registered for a given index, so this tuple should be unique.
54  *
55  * The "additional objects" mentioned above consist of an IOReporter object (lazily allocated and
56  * tied to the nub; once allocated it will live until the nub is freed), and a statistics object
57  * (effectively part of the IOIES in terms of lifecycle).  The statistics object is used by the
58  * interrupt codepath itself, and by the nub when it needs to update the reporter; the reporter is
59  * used to report values to userspace.
60  *
61  * As a consequence of the above relationship, we do not track statistics for directly registered
62  * interrupt handlers.  We have no guarantees what the handler or the target may be; if you don't
63  * follow the generic IOKit interrupt model, you will not be tracked by interrupt accounting.  For
64  * now, this means you must use an IOIES to be eligible for interrupt accounting.  We also do not
65  * track IOIES' that do not have providers (this is indicative that it is only being used to drive
66  * workloop activity, and is not actually handling interrupts).
67  */
68 
69 /*
70  * This is meant to let us set up the set of interrupt statistics we are actually interested in, by
71  * setting a boot-arg.  If we want to track a statistic, the bit corresponding to the index for that
72  * statistic should be set in the bitmask.
73  *
74  * There is a bit of a mismatch here, in that our IOReporting channel namespace allows for 256 statistics,
75  * but this bitmask actually limits it to 32.
76  */
77 extern uint32_t gInterruptAccountingStatisticBitmask;
78 
79 /*
80  * Check the bitmask by statistic index; useful for setting the initial value and conditionalizing code.
81  */
82 #define IA_GET_ENABLE_BIT(statisticIndex) \
83     (((uint32_t) 1) << ((uint32_t) statisticIndex))
84 
85 #define IA_GET_STATISTIC_ENABLED(statisticIndex) \
86     (IA_GET_ENABLE_BIT(statisticIndex) & gInterruptAccountingStatisticBitmask)
87 
88 /*
89  * Check if any valid statistics are enabled.
90  */
91 #define IA_ANY_STATISTICS_ENABLED \
92     ((IA_GET_ENABLE_BIT(kInterruptAccountingInvalidStatisticIndex) - 1) & gInterruptAccountingStatisticBitmask)
93 
94 /*
95  * Actual string names for the statistics we gather.
96  */
97 #define kInterruptAccountingChannelNameFirstLevelCount       ("               First Level Interrupt Handler Count")
98 #define kInterruptAccountingChannelNameSecondLevelCount      ("              Second Level Interrupt Handler Count")
99 #define kInterruptAccountingChannelNameFirstLevelTime        ("        First Level Interrupt Handler Time (MATUs)")
100 #define kInterruptAccountingChannelNameSecondLevelCPUTime    ("   Second Level Interrupt Handler CPU Time (MATUs)")
101 #define kInterruptAccountingChannelNameSecondLevelSystemTime ("Second Level Interrupt Handler System Time (MATUs)")
102 #define kInterruptAccountingChannelNameNoThreadWakeups       ("      Interrupts that did not try to wake a thread")
103 #define kInterruptAccountingChannelNameTotalThreadWakeups    ("       Sleeping threads woken up by this interrupt")
104 #define kInterruptAccountingChannelNamePackageWakeups        ("          Package wakeups caused by this interrupt")
105 #define kInterruptAccountingChannelNameCPUWakeups            ("              CPU wakeups caused by this interrupt")
106 #define kInterruptAccountingChannelNameIdleExits             ("               Idle exits caused by this interrupt")
107 
108 static const char * const kInterruptAccountingStatisticNameArray[IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS] = {
109 	[kInterruptAccountingFirstLevelCountIndex] = kInterruptAccountingChannelNameFirstLevelCount,
110 	[kInterruptAccountingSecondLevelCountIndex] = kInterruptAccountingChannelNameSecondLevelCount,
111 	[kInterruptAccountingFirstLevelTimeIndex] = kInterruptAccountingChannelNameFirstLevelTime,
112 	[kInterruptAccountingSecondLevelCPUTimeIndex] = kInterruptAccountingChannelNameSecondLevelCPUTime,
113 	[kInterruptAccountingSecondLevelSystemTimeIndex] = kInterruptAccountingChannelNameSecondLevelSystemTime,
114 	[kInterruptAccountingNoThreadWakeupsIndex] = kInterruptAccountingChannelNameNoThreadWakeups,
115 	[kInterruptAccountingTotalThreadWakeupsIndex] = kInterruptAccountingChannelNameTotalThreadWakeups,
116 	[kInterruptAccountingPackageWakeupsIndex] = kInterruptAccountingChannelNamePackageWakeups,
117 	[kInterruptAccountingCPUWakeupsIndex] = kInterruptAccountingChannelNameCPUWakeups,
118 	[kInterruptAccountingIdleExitsIndex] = kInterruptAccountingChannelNameIdleExits,
119 };
120 
121 /*
122  * For updating the statistics in the data structure.  We cannot guarantee all of our platforms will be
123  * able to do a 64-bit store in a single transaction.  So, for new platforms, call out to the hardware
124  * atomic add routine; it will either be unsupported, or do the right thing.  For architectures or
125  * platforms that do support it; just do regular assignment.
126  *
127  * We use this routine instead of a lock because at the moment, there is no way (in the interrupt context)
128  * to reconcile a lock (even a spinlock) with the IOReporting synchonization (as we have no guarantee that
129  * IOReporting will not block on a mutex, which would result in a panic if it held a spinlock).  This
130  * means that reported values may have a disparity if we update the reporter values while an interrupt is
131  * being handled.
132  *
133  * Atomic modification should not be strictly required, as a given interrupt should not be dispatched to
134  * two processors at once (and the interrupt should serve to force out stores), and the second level
135  * handler should be synchonized by the work loop it runs on.
136  */
137 #if __x86_64__ || __arm64__
138 #define IA_ADD_VALUE(target, value) \
139     (*(target) += (value))
140 #else /* !(__x86_64__ || __arm64__) */
141 #define IA_ADD_VALUE(target, value) \
142     (OSAddAtomic64((value), (target)))
143 #endif /* !(__x86_64__ || __arm64__) */
144 
145 /*
146  * TODO: Should this be an OSObject?  Or properly pull in its methods as member functions?
147  */
148 struct IOInterruptAccountingData {
149 	OSObject * owner; /* The owner of the statistics; currently always an IOIES or a subclass of it */
150 	queue_chain_t chain;
151 	/*
152 	 * We have no guarantee that the owner will not temporarily mutate its index value (i.e, in setWorkLoop
153 	 * for IOIES).  To ensure we can properly recalculate our own identity (and our channel IDs for the
154 	 * reporter), stash the index we set up the reporter with here.
155 	 *
156 	 * Note that we should never remap the interrupt (point it to a different specifier).  The mutation of
157 	 * the index value is usually to negate it; I am uncertain of the reason for this at the moment.  The
158 	 * practical impact being that we should never need to update the stashed index value; it should stay
159 	 * valid for the lifetime of the owner.
160 	 */
161 	int interruptIndex;
162 
163 	bool enablePrimaryTimestamp;
164 	volatile uint64_t primaryTimestamp __attribute__((aligned(8)));
165 
166 	/*
167 	 * As long as we are based on the simple reporter, all our channels will be 64 bits.  Align the data
168 	 * to allow for safe atomic updates (we don't want to cross a cache line on any platform, but for some
169 	 * it would cause a panic).
170 	 */
171 	volatile uint64_t interruptStatistics[IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS] __attribute__((aligned(8)));
172 };
173 
174 /*
175  * Initializes global values/structures related to interrupt accounting.
176  */
177 void interruptAccountingInit(void);
178 
179 /*
180  * Routines for adding and removing objects from the global queue of IOInterruptAccountingData objects;
181  * the queue exists as a debugging aid (no entities other than these routines should care about the
182  * queue at runtime).
183  */
184 void interruptAccountingDataAddToList(IOInterruptAccountingData * data);
185 void interruptAccountingDataRemoveFromList(IOInterruptAccountingData * data);
186 
187 /*
188  * Updates reporter with the statistics contained within data.  Invoked when IOReporting has been asked
189  * for updated statistics; requiring explicit synchronization of data between the statistic fields and
190  * the reporter helps keep interrupt accounting overhead down.
191  */
192 void interruptAccountingDataUpdateChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter);
193 
194 /*
195  * Initializes the statistics in data using the statistics currently held by reporter.  Typically invoked
196  * when data is first associated with reporter.  The nub that an interrupt is associated with will be
197  * longer lived than the interrupt; as a result, our owner may not be the first to register for a
198  * particular interrupt index with that nub, so we need to inherit the existing statistics (as we describe
199  * statistics in terms of {nub id, index}, not in terms of our owner).
200  */
201 void interruptAccountingDataInheritChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter);
202 
203 #endif /* __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H */
204