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 | |