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_H
30 #define __IOKIT_IOINTERRUPTACCOUNTING_H
31 
32 #include <IOKit/IOReportTypes.h>
33 
34 /*
35  * This header contains definitions that will be needed by userspace clients of the interrupt accounting
36  * mechanisms.
37  */
38 
39 #define IA_INDEX_MAX (255)
40 #define IA_INDEX_MASK (0xFFULL)
41 #define IA_STATISTIC_INDEX_SHIFT (0ULL)
42 #define IA_INTERRUPT_INDEX_SHIFT (16ULL)
43 
44 /*
45  * For the moment, the indices aren't preprocessor visible, so any changes to this code will need to be
46  * careful to ensure that the defined number of statistics matches (or is greater than) the actual number
47  * of statistics, to avoid channel ID collisions... because that would be bad.
48  */
49 #define IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS (10)
50 
51 /*
52  * Channel ID related definitions.  These serve to denote the namespace of interrupt accounting in the
53  * context of IOReporter-based clients.  Interrupt accounting distinguishes between interrupts based on
54  * the nub the interrupt was registered relative to, and the nub relative interrupt index (i.e, the
55  * namespace for interrupt accounting is {nub ID, interrupt index}).  IOReporting already knows about
56  * nubs (in the context of IOService), however it has no built in knowledge of interrupt accounting.
57  * As a result of this, it is the responsibility of the IOReporting client to request any desired
58  * statistics on a per-index basis (i.e, if you want to get the first level interrupt count for all
59  * interrupts, you must express an interest in the first level interrupt count statistic for index 0, 1,
60  * 2, and so on, to a reasonable maximum).
61  */
62 
63 /*
64  * These delimit the channel ID namespace for interrupt accounting.
65  */
66 #define IA_BASE_CHANNEL_ID IOREPORT_MAKEID('I', 'n', 't', 'r', 0, 0, 0, 0) /* First valid channel ID */
67 #define IA_MAX_CHANNEL_ID IOREPORT_MAKEID('I', 'n', 't', 'r', 0xFF, 0xFF, 0xFF, 0xFF) /* Last valid channel ID */
68 
69 /*
70  * Given a nub-relative interrupt index (an index into the interrupt specifiers), and the index of a
71  * interrupt accounting statistic, returns the channel id for that statistic.
72  */
73 #define IA_GET_CHANNEL_ID(interruptIndex, statisticIndex) \
74     ((IA_BASE_CHANNEL_ID) + \
75     ((interruptIndex % IA_INDEX_MASK) << IA_INTERRUPT_INDEX_SHIFT) + \
76     ((statisticIndex % IA_INDEX_MASK) << IA_STATISTIC_INDEX_SHIFT))
77 
78 /*
79  * Extracts the interrupt index, given a channel ID.
80  */
81 #define IA_GET_INTERRUPT_INDEX(channelID) \
82     (((channelID - IA_BASE_CHANNEL_ID) >> IA_INTERRUPT_INDEX_SHIFT) % IA_INDEX_MASK)
83 
84 /*
85  * Extracts the statistic index, given a channel ID.
86  */
87 #define IA_GET_STATISTIC_INDEX(channelID) \
88     (((channelID - IA_BASE_CHANNEL_ID) >> IA_STATISTIC_INDEX_SHIFT) % IA_INDEX_MASK)
89 
90 /*
91  * This enum defines the basic statistics we gather for each interrupt.  Currently, the information
92  * we gather falls into roughly three buckets: interrupt related (counts, times), scheduler related
93  * (thread wakeups), and power related (package/cpu state changes).
94  *
95  * First Level Count: This represents the number of times that this interrupt has fired (more
96  *   specifically, the number of times we have run the handler we expect to run in interrupt context).
97  *
98  * Second Level Count: This represents the number of times we have run any second level handler for
99  *   this interrupt (more specifically, the handler we expect to be run in the regular kernel context).
100  *
101  * First Level Time: This represents the aggregate time spent running the first level handler.  For
102  *   some interrupts, this value will be 0, as this is not meant to track time spent running generic
103  *   IOKit code for the interrupt (i.e, IOInterruptEventSource code), but instead any custom code run
104  *   at the interrupt context (i.e, the filter installed for an IOFilterInterruptEventSource).
105  *
106  * Second Level CPU Time: This represents the aggregate time spent actually running the second level
107  *   handler on the CPU.  As the second level handler may block or be preempted, it is meaningful to
108  *   distinguish this from the system time spent handling the interrupt.  As was the case for the
109  *   first level handler, this does not attempt to track the time spent running generic IOKit code
110  *   (i.e, IOInterruptEventSource code or IOWorkLoop code), but instead attempts to track the time
111  *   spent running the handler that was installed.
112  *
113  * Second Level System Time: This represents the aggregate time spent in the second level handler;
114  *   this will include time where the handler was blocked or had been preempted.  This should equate
115  *   to the wall time spent handling an interrupt (as long as we don't allow the system to go to
116  *   sleep while a second level handler is running).
117  *
118  * No Thread Wakeups: The number of times that the interrupt did not attempt to wake up a thread
119  *   (typically the work loop for the interrupt source is woken up).
120  *
121  * Total Thread Wakeups: The aggregate number of threads (non-unique) woken up by the interrupt.
122  *   If no threads were actually woken up for an interrupt (i.e, the work loop thread was already
123  *   runnable), this value will not change.
124  *
125  * Package Wakeups: The number of times that this interrupt woke up the package (as defined by the
126  *   scheduler).
127  *
128  * CPU Wakeups: The number of times that this interrupt woke up a CPU (forcing it to go through the
129  *   reset path).
130  *
131  * Idle Exits: The number of times that this interrupt forced a CPU out of the idle loop (the CPU
132  *   had to exit an idle state to handle the interrupt, but it did not need to go through the reset
133  *   path).
134  */
135 enum {
136 	kInterruptAccountingFirstLevelCountIndex = 0, /* Number of times we invoked the top level handler */
137 	kInterruptAccountingSecondLevelCountIndex, /* Number of times we invoked the workloop action */
138 	kInterruptAccountingFirstLevelTimeIndex, /* Time spent in the top level handler, if one was installed */
139 	kInterruptAccountingSecondLevelCPUTimeIndex, /* CPU time spent in the workloop action */
140 	kInterruptAccountingSecondLevelSystemTimeIndex, /* System time spent in the workloop action */
141 	kInterruptAccountingNoThreadWakeupsIndex, /* Number of first level (filter) invocations that did not wake up a thread */
142 	kInterruptAccountingTotalThreadWakeupsIndex, /* Number of actual thread wakeups caused by this interrupt */
143 	kInterruptAccountingPackageWakeupsIndex, /* Number of times this interrupt woke up the package */
144 	kInterruptAccountingCPUWakeupsIndex, /* Number of times this interrupt woke up a CPU */
145 	kInterruptAccountingIdleExitsIndex, /* Number of times this interrupt forced a CPU out of the idle loop */
146 	kInterruptAccountingInvalidStatisticIndex /* Sentinel value for checking for a nonsensical index */
147 };
148 
149 /*
150  * IOReporting group name; exposed publicly for the purpose of getting channels by group
151  * name; other strings (subgroup names, statistic names) are not exposed, as we may want
152  * to change them in the future.
153  */
154 #define kInterruptAccountingGroupName "Interrupt Statistics (by index)"
155 
156 #endif /* __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H */
157