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