xref: /onnv-gate/usr/src/uts/common/sys/cpu_event.h (revision 9637:60f2a2d63713)
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