xref: /illumos-gate/usr/src/uts/common/sys/cpu_event.h (revision fb2caebe)
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