Home | History | Annotate | Download | only in sys
      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