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 41class OSObject; 42class 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 */ 77extern 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 108static 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 * IOReporting group names. 123 */ 124static const char * const kInterruptAccountingGroupName = "Interrupt Statistics (by index)"; 125 126/* 127 * TODO: Generate the subgroup name strings? 128 */ 129#define IA_MAX_SUBGROUP_NAME (32) 130 131static const char * const kInterruptAccountingSubgroupNames[IA_MAX_SUBGROUP_NAME] = { 132 "0", "1", "2" , "3", "4", "5", "6", "7", 133 "8", "9", "10", "11", "12", "13", "14", "15", 134 "16", "17", "18", "19", "20", "21", "22", "23", 135 "24", "25", "26", "27", "28", "29", "30", "31"}; 136 137/* 138 * As long as we use a lookup table, we may be out of bounds for a valid index. In this case, fall 139 * back on a generic subgroup name that indicates we have screwed up. 140 */ 141static const char * const kInterruptAccountingGenericSubgroupName = "(Index > 31)"; 142 143/* 144 * For updating the statistics in the data structure. We cannot guarantee all of our platforms will be 145 * able to do a 64-bit store in a single transaction. So, for new platforms, call out to the hardware 146 * atomic add routine; it will either be unsupported, or do the right thing. For architectures or 147 * platforms that do support it; just do regular assignment. 148 * 149 * We use this routine instead of a lock because at the moment, there is no way (in the interrupt context) 150 * to reconcile a lock (even a spinlock) with the IOReporting synchonization (as we have no guarantee that 151 * IOReporting will not block on a mutex, which would result in a panic if it held a spinlock). This 152 * means that reported values may have a disparity if we update the reporter values while an interrupt is 153 * being handled. 154 * 155 * Atomic modification should not be strictly required, as a given interrupt should not be dispatched to 156 * two processors at once (and the interrupt should serve to force out stores), and the second level 157 * handler should be synchonized by the work loop it runs on. 158 */ 159#if __x86_64__ || __arm64 160#define IA_ADD_VALUE(target, value) \ 161 (*(target) += (value)) 162#else 163#define IA_ADD_VALUE(target, value) \ 164 (OSAddAtomic64((value), (target))) 165#endif 166 167/* 168 * TODO: Should this be an OSObject? Or properly pull in its methods as member functions? 169 */ 170struct IOInterruptAccountingData { 171 OSObject * owner; /* The owner of the statistics; currently always an IOIES or a subclass of it */ 172 queue_chain_t chain; 173 /* 174 * We have no guarantee that the owner will not temporarily mutate its index value (i.e, in setWorkLoop 175 * for IOIES). To ensure we can properly recalculate our own identity (and our channel IDs for the 176 * reporter), stash the index we set up the reporter with here. 177 * 178 * Note that we should never remap the interrupt (point it to a different specifier). The mutation of 179 * the index value is usually to negate it; I am uncertain of the reason for this at the moment. The 180 * practical impact being that we should never need to update the stashed index value; it should stay 181 * valid for the lifetime of the owner. 182 */ 183 int interruptIndex; 184 185 /* 186 * As long as we are based on the simple reporter, all our channels will be 64 bits. Align the data 187 * to allow for safe atomic updates (we don't want to cross a cache line on any platform, but for some 188 * it would cause a panic). 189 */ 190 volatile uint64_t interruptStatistics[IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS] __attribute__((aligned(8))); 191}; 192 193/* 194 * Initializes global values/structures related to interrupt accounting. 195 */ 196void interruptAccountingInit(void); 197 198/* 199 * Routines for adding and removing objects from the global queue of IOInterruptAccountingData objects; 200 * the queue exists as a debugging aid (no entities other than these routines should care about the 201 * queue at runtime). 202 */ 203void interruptAccountingDataAddToList(IOInterruptAccountingData * data); 204void interruptAccountingDataRemoveFromList(IOInterruptAccountingData * data); 205 206/* 207 * Updates reporter with the statistics contained within data. Invoked when IOReporting has been asked 208 * for updated statistics; requiring explicit synchronization of data between the statistic fields and 209 * the reporter helps keep interrupt accounting overhead down. 210 */ 211void interruptAccountingDataUpdateChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter); 212 213/* 214 * Initializes the statistics in data using the statistics currently held by reporter. Typically invoked 215 * when data is first associated with reporter. The nub that an interrupt is associated with will be 216 * longer lived than the interrupt; as a result, our owner may not be the first to register for a 217 * particular interrupt index with that nub, so we need to inherit the existing statistics (as we describe 218 * statistics in terms of {nub id, index}, not in terms of our owner). 219 */ 220void interruptAccountingDataInheritChannels(IOInterruptAccountingData * data, IOSimpleReporter * reporter); 221 222#endif /* __IOKIT_IOINTERRUPTACCOUNTING_PRIVATE_H */ 223 224