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