1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, Intel Corporation. 23 * All rights reserved. 24 */ 25 26 #ifndef _SYS_CPU_EVENT_H 27 #define _SYS_CPU_EVENT_H 28 #include <sys/types.h> 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #ifdef _KERNEL 35 36 /* 37 * CPU idle notification callbacks are divided into three priority classes: 38 * 1. Statically assigned high priority callbacks. 39 * 2. Dynamically allocated normal priority callbacks. 40 * 3. Statically assigned low priority callbacks. 41 * 42 * All registered callbacks will be called in priority order from high 43 * to low just before CPU enters hardware idle state and from low to 44 * high just after CPU wakes from idle state. 45 * 46 * The high and low priority classes are designed to support hardware 47 * ordering requirements. A dynamically assigned priority allows the 48 * framework to choose the order in which the callback is processed. 49 * If a callback has no dependency on other callbacks, it should use 50 * dynamic priority to avoid priority conflicts. 51 * 52 * Note that the priority doesn't describe how important a callback 53 * is, but just the order in which they are processed. If a callback 54 * needs processing early in the idle notification cycle, it should 55 * have a higher priority. If it needs to be at the end, or early on 56 * the exit, then it should have a lower priority. 57 */ 58 59 #define CPU_IDLE_CB_PRIO_LOW_BASE 0x20000000U 60 #define CPU_IDLE_CB_PRIO_DYN_BASE 0x40000000U 61 #define CPU_IDLE_CB_PRIO_HIGH_BASE 0x40000001U 62 #define CPU_IDLE_CB_PRIO_RESV_BASE 0x80000000U 63 64 /* 65 * Indicating dynamic priority to cpu_idle_{un}register_callback(). 66 */ 67 #define CPU_IDLE_CB_PRIO_DYNAMIC CPU_IDLE_CB_PRIO_DYN_BASE 68 /* Priority assigned to dtrace probe callback. */ 69 #define CPU_IDLE_CB_PRIO_DTRACE (CPU_IDLE_CB_PRIO_LOW_BASE + 0xC000000) 70 71 72 #ifdef __x86 73 /* Priority assigned to TLB flush callback. */ 74 #define CPU_IDLE_CB_PRIO_TLB (CPU_IDLE_CB_PRIO_LOW_BASE + 0x100000) 75 #endif 76 77 /* Name of properties supported by CPU idle notification. */ 78 #define CPU_IDLE_PROP_IDLE_STATE "idle-state" 79 #define CPU_IDLE_PROP_ENTER_TIMESTAMP "enter-ts" 80 #define CPU_IDLE_PROP_EXIT_TIMESTAMP "exit-ts" 81 #define CPU_IDLE_PROP_LAST_IDLE_TIME "last-idle-time" 82 #define CPU_IDLE_PROP_LAST_BUSY_TIME "last-busy-time" 83 #define CPU_IDLE_PROP_TOTAL_IDLE_TIME "total-idle-time" 84 #define CPU_IDLE_PROP_TOTAL_BUSY_TIME "total-busy-time" 85 #define CPU_IDLE_PROP_INTERRUPT_COUNT "interupt-count" 86 87 /* 88 * sizeof(cpu_idle_prop_value_t) should be power of 2 to align on cache line. 89 */ 90 typedef union cpu_idle_prop_value { 91 intptr_t cipv_intptr; 92 uint32_t cipv_uint32; 93 uint64_t cipv_uint64; 94 hrtime_t cipv_hrtime; 95 } cpu_idle_prop_value_t; 96 97 typedef enum cpu_idle_prop_type { 98 CPU_IDLE_PROP_TYPE_INTPTR, 99 CPU_IDLE_PROP_TYPE_UINT32, 100 CPU_IDLE_PROP_TYPE_UINT64, 101 CPU_IDLE_PROP_TYPE_HRTIME, 102 } cpu_idle_prop_type_t; 103 104 typedef void *cpu_idle_callback_handle_t; 105 typedef void *cpu_idle_callback_context_t; 106 typedef void *cpu_idle_prop_handle_t; 107 108 /* 109 * Function prototype for checking CPU wakeup events. 110 * If CPU has already been awakened, check_wakeup callback should call 111 * cpu_idle_exit() to notify CPU idle framework if it has been called yet. 112 */ 113 typedef void (* cpu_idle_check_wakeup_t)(void *arg); 114 115 /* 116 * Function prototype for entering idle state notification callback. 117 * Callback for entering idle state notification must obey all constraints 118 * which apply to idle thread because it will be called in idle thread context. 119 * The callback will be called with interrupt disabled. The callback may enable 120 * interrupt if it can cooperate with corresponding idle_exit callback to 121 * handle interrupt happening after enabling interrupt. If idle_enter callback 122 * enables interrupt, the corresponding idle_exit callback may be called before 123 * returning from idle_enter callback. 124 */ 125 typedef void (* cpu_idle_enter_cbfn_t)(void *arg, 126 cpu_idle_callback_context_t ctx, 127 cpu_idle_check_wakeup_t check_func, void *check_arg); 128 129 /* 130 * Function prototype for exiting idle state notification callback. 131 * Callback for exiting idle state notification will be called in idle thread 132 * context or interrupt context with interrupt disabled. 133 * There is a flag to distinguish the calling context. 134 * The callback must not try to enable interrupts. 135 */ 136 typedef void (* cpu_idle_exit_cbfn_t)(void *arg, 137 cpu_idle_callback_context_t ctx, int flag); 138 139 #define CPU_IDLE_CB_FLAG_INTR 0x1 /* Called in interrupt context. */ 140 #define CPU_IDLE_CB_FLAG_IDLE 0x2 /* Called in idle thread context. */ 141 142 typedef struct cpu_idle_callback { 143 int version; 144 cpu_idle_enter_cbfn_t idle_enter; 145 cpu_idle_exit_cbfn_t idle_exit; 146 } cpu_idle_callback_t; 147 148 #define CPU_IDLE_CALLBACK_VER0 0 149 #define CPU_IDLE_CALLBACK_VERS CPU_IDLE_CALLBACK_VER0 150 151 /* 152 * Register a callback to be called when CPU idle state changes. 153 * All registered callbacks will be called in priority order from high to low 154 * when CPU enters idle state and from low to high when CPU leaves idle state. 155 * If CPU is predicted to sleep for a short time or be under heavy load, 156 * framework may skip calling registered callbacks when idle state changes to 157 * avoid overhead and reduce performance penalties. 158 * It's guaranteed that each exiting notification will be paired with each 159 * entering notification. 160 * Return zero on success and error code on failure. 161 * N.B.: this interface shouldn't be called from following conditions: 162 * 1) from callback. 163 */ 164 extern int cpu_idle_register_callback(uint_t prio, cpu_idle_callback_t *cbp, 165 void *arg, cpu_idle_callback_handle_t *hdlp); 166 167 /* 168 * Un-register a registered callback. 169 * Return zero on success and error code on failure. 170 * N.B.: this interface shouldn't be called from following cases: 171 * 1) from callback. 172 */ 173 extern int cpu_idle_unregister_callback(cpu_idle_callback_handle_t hdl); 174 175 /* 176 * Called by CPU idle handler to notify entering idle state. 177 * It should be called with interrupt disabled. 178 * state: platform specific information of idle state to enter. 179 * On x86, it's CPU C state. 180 * Idle thread should cancel entering hardware idle state if cpu_idle_enter 181 * returns non-zero value. 182 */ 183 extern int cpu_idle_enter(int state, int flag, 184 cpu_idle_check_wakeup_t check_func, void *check_arg); 185 186 /* 187 * Called by CPU idle handler to notify exiting idle state. 188 * It should be called with interrupt disabled. 189 */ 190 extern void cpu_idle_exit(int flag); 191 192 /* 193 * Get CPU idle notification context corresponding to current CPU. 194 */ 195 extern cpu_idle_callback_context_t cpu_idle_get_context(void); 196 197 /* 198 * Prototype of function called to update property value on demand. 199 * The callback should update property value corresponding to current CPU. 200 */ 201 typedef int (* cpu_idle_prop_update_t)(void *arg, uint64_t seqnum, 202 cpu_idle_prop_value_t *valp); 203 204 /* 205 * Create a property with name and type. 206 * If parameter update is not NULL, it will be called on demand to update 207 * value of property corresponding to current CPU. 208 * If parameter update is NULL, provider should call cpu_idle_property_set 209 * to update property value for each CPU. 210 * Return zero on success with handle stored in hdlp, otherwise error code. 211 */ 212 extern int cpu_idle_prop_create_property(const char *name, 213 cpu_idle_prop_type_t type, cpu_idle_prop_update_t update, void *arg, 214 cpu_idle_prop_handle_t *hdlp); 215 216 /* 217 * Destroy property corresponding to hdl. 218 * Return zero on success, otherwise error code. 219 */ 220 extern int cpu_idle_prop_destroy_property(cpu_idle_prop_handle_t hdl); 221 222 /* 223 * Create handle for property with name 'name'. 224 * Return zero on success with handle stored in hdlp, otherwise error code. 225 */ 226 extern int cpu_idle_prop_create_handle(const char *name, 227 cpu_idle_prop_handle_t *hdlp); 228 229 /* 230 * Destroy property handle. 231 * Return zero on success, otherwise error code. 232 */ 233 extern int cpu_idle_prop_destroy_handle(cpu_idle_prop_handle_t hdl); 234 235 /* 236 * CPU idle property manipulation functions. 237 * All cpu_idle_prop_get/set_xxx functions with argument ctx should only be used 238 * to manipulate properties associated with current CPU. 239 * Context ctx shouldn't be passed to other CPUs to manipulate properties. 240 */ 241 extern cpu_idle_prop_type_t cpu_idle_prop_get_type(cpu_idle_prop_handle_t hdl); 242 extern const char *cpu_idle_prop_get_name(cpu_idle_prop_handle_t hdl); 243 extern int cpu_idle_prop_get_value(cpu_idle_prop_handle_t hdl, 244 cpu_idle_callback_context_t ctx, cpu_idle_prop_value_t *valp); 245 extern uint32_t cpu_idle_prop_get_uint32(cpu_idle_prop_handle_t hdl, 246 cpu_idle_callback_context_t ctx); 247 extern uint64_t cpu_idle_prop_get_uint64(cpu_idle_prop_handle_t hdl, 248 cpu_idle_callback_context_t ctx); 249 extern intptr_t cpu_idle_prop_get_intptr(cpu_idle_prop_handle_t hdl, 250 cpu_idle_callback_context_t ctx); 251 extern hrtime_t cpu_idle_prop_get_hrtime(cpu_idle_prop_handle_t hdl, 252 cpu_idle_callback_context_t ctx); 253 extern void cpu_idle_prop_set_value(cpu_idle_prop_handle_t hdl, 254 cpu_idle_callback_context_t ctx, cpu_idle_prop_value_t val); 255 extern void cpu_idle_prop_set_all(cpu_idle_prop_handle_t hdl, 256 cpu_idle_prop_value_t val); 257 258 extern uint_t cpu_idle_get_cpu_state(cpu_t *cp); 259 260 extern void cpu_event_init(void); 261 extern void cpu_event_init_cpu(cpu_t *cp); 262 extern void cpu_event_fini_cpu(cpu_t *cp); 263 264 #endif /* _KERNEL */ 265 266 #ifdef __cplusplus 267 } 268 #endif 269 270 #endif /* _SYS_CPU_EVENT_H */ 271