Commit | Line | Data |
---|---|---|
88c4d2f6 MD |
1 | /* |
2 | * SYS/SYSTIMER.H | |
27a6bce6 | 3 | * |
8c10bfcf | 4 | * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. |
27a6bce6 | 5 | * |
8c10bfcf MD |
6 | * This code is derived from software contributed to The DragonFly Project |
7 | * by Matthew Dillon <dillon@backplane.com> | |
27a6bce6 | 8 | * |
88c4d2f6 MD |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
27a6bce6 | 12 | * |
88c4d2f6 MD |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
8c10bfcf MD |
16 | * notice, this list of conditions and the following disclaimer in |
17 | * the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * 3. Neither the name of The DragonFly Project nor the names of its | |
20 | * contributors may be used to endorse or promote products derived | |
21 | * from this software without specific, prior written permission. | |
27a6bce6 | 22 | * |
8c10bfcf MD |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
27 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
28 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
31 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
88c4d2f6 | 34 | * SUCH DAMAGE. |
88c4d2f6 MD |
35 | */ |
36 | ||
37 | #ifndef _SYS_SYSTIMER_H_ | |
38 | #define _SYS_SYSTIMER_H_ | |
39 | ||
59ef3aa7 SZ |
40 | #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES) |
41 | ||
1bd40720 MD |
42 | #ifndef _SYS_TYPES_H_ |
43 | #include <sys/types.h> | |
44 | #endif | |
45 | #ifndef _SYS_QUEUE_H_ | |
46 | #include <sys/queue.h> | |
47 | #endif | |
48 | ||
88c4d2f6 MD |
49 | struct intrframe; |
50 | ||
8fbc264d MD |
51 | typedef __uint64_t sysclock_t; |
52 | typedef int64_t ssysclock_t; | |
88c4d2f6 | 53 | typedef TAILQ_HEAD(systimerq, systimer) *systimerq_t; |
96d52ac8 | 54 | typedef void (*systimer_func_t)(struct systimer *, int, struct intrframe *); |
88c4d2f6 MD |
55 | |
56 | typedef struct systimer { | |
57 | TAILQ_ENTRY(systimer) node; | |
58 | systimerq_t queue; | |
59 | sysclock_t time; /* absolute time next intr */ | |
8fbc264d | 60 | sysclock_t periodic; /* non-zero if periodic */ |
96d52ac8 | 61 | systimer_func_t func; |
88c4d2f6 MD |
62 | void *data; |
63 | int flags; | |
8fbc264d MD |
64 | int us; /* non-zero if one-shot */ |
65 | ssysclock_t freq; /* frequency if periodic */ | |
4b52d1af | 66 | struct cputimer *which; /* which timer was used? */ |
88c4d2f6 MD |
67 | struct globaldata *gd; /* cpu owning structure */ |
68 | } *systimer_t; | |
69 | ||
70 | #define SYSTF_ONQUEUE 0x0001 | |
71 | #define SYSTF_IPIRUNNING 0x0002 | |
0d1dffdf | 72 | #define SYSTF_NONQUEUED 0x0004 |
c6a766f4 MD |
73 | #define SYSTF_MSSYNC 0x0008 /* 1Khz coincident sync */ |
74 | #define SYSTF_100KHZSYNC 0x0010 /* 100Khz coincident sync */ | |
75 | #define SYSTF_FIRST 0x0020 /* order first if coincident */ | |
880fb308 | 76 | #define SYSTF_OFFSET50 0x0040 /* add 1/2 interval offset */ |
91dc43dd | 77 | #define SYSTF_OFFSETCPU 0x0080 /* add cpu*periodic/ncpus */ |
88c4d2f6 | 78 | |
27a6bce6 | 79 | #ifdef _KERNEL |
8fbc264d | 80 | void systimer_changed(void); |
43adde98 | 81 | void systimer_intr_enable(void); |
b8a98473 | 82 | void systimer_intr(sysclock_t *, int, struct intrframe *); |
0ded555b MD |
83 | void systimer_add(systimer_t); |
84 | void systimer_del(systimer_t); | |
8fbc264d MD |
85 | void systimer_init_periodic(systimer_t, systimer_func_t, void *, int64_t); |
86 | void systimer_init_periodic_nq(systimer_t, systimer_func_t, void *, int64_t); | |
87 | void systimer_init_periodic_nq1khz(systimer_t, systimer_func_t, void *, int64_t); | |
88 | void systimer_init_periodic_nq100khz(systimer_t, systimer_func_t, void *, int64_t); | |
c6a766f4 | 89 | void systimer_init_periodic_flags(systimer_t, systimer_func_t, void *, |
8fbc264d MD |
90 | int64_t, int); |
91 | void systimer_adjust_periodic(systimer_t, int64_t); | |
92 | void systimer_init_oneshot(systimer_t, systimer_func_t, void *, int64_t); | |
88c4d2f6 | 93 | |
88c4d2f6 | 94 | /* |
27a6bce6 | 95 | * The cputimer interface. This provides a free-running (non-interrupt) |
9800d437 | 96 | * and monotonically increasing timebase for the system. |
044ee7c4 | 97 | * |
9800d437 SZ |
98 | * The cputimer structure holds the fixed cputimer frequency, determining |
99 | * the granularity of sys_cputimer->count(). | |
624051cd | 100 | * |
9800d437 SZ |
101 | * Note that sys_cputimer->count() always returns a full-width wrapping |
102 | * counter. | |
88c4d2f6 | 103 | * |
9800d437 SZ |
104 | * The 64 bit versions of the frequency are used for converting count |
105 | * values into uS or nS as follows: | |
88c4d2f6 | 106 | * |
9800d437 SZ |
107 | * usec = (sys_cputimer->freq64_usec * count) >> 32 |
108 | * | |
109 | * NOTE: If count > sys_cputimer->freq, above conversion may overflow. | |
110 | * | |
111 | * REQUIREMENT FOR CPUTIMER IMPLEMENTATION: | |
112 | * | |
9800d437 SZ |
113 | * - The values returned by count() must be MP synchronized. |
114 | * - The values returned by count() must be stable under all situation, | |
115 | * e.g. when the platform enters power saving mode. | |
116 | * - The values returned by count() must be monotonically increasing. | |
88c4d2f6 | 117 | */ |
044ee7c4 MD |
118 | |
119 | struct cputimer { | |
d8fdd978 | 120 | SLIST_ENTRY(cputimer) next; |
044ee7c4 MD |
121 | const char *name; |
122 | int pri; | |
123 | int type; | |
124 | sysclock_t (*count)(void); | |
8fbc264d MD |
125 | sysclock_t (*fromhz)(int64_t freq); |
126 | sysclock_t (*fromus)(int64_t us); | |
624051cd SZ |
127 | void (*construct)(struct cputimer *, sysclock_t); |
128 | void (*destruct)(struct cputimer *); | |
c6a766f4 | 129 | sysclock_t sync_base; /* periodic synchronization base */ |
93631e64 | 130 | sysclock_t base; /* (implementation dependant) */ |
044ee7c4 | 131 | sysclock_t freq; /* in Hz */ |
9800d437 SZ |
132 | int64_t freq64_usec; /* in (1e6 << 32) / freq */ |
133 | int64_t freq64_nsec; /* in (1e9 << 32) / freq */ | |
044ee7c4 MD |
134 | }; |
135 | ||
136 | extern struct cputimer *sys_cputimer; | |
137 | ||
138 | #define CPUTIMER_DUMMY 0 | |
139 | #define CPUTIMER_8254_SEL1 1 | |
140 | #define CPUTIMER_8254_SEL2 2 | |
141 | #define CPUTIMER_ACPI 3 | |
60297eb4 | 142 | #define CPUTIMER_VKERNEL 4 |
bea6e278 | 143 | #define CPUTIMER_HPET 5 |
a75ee873 | 144 | #define CPUTIMER_GEODE 6 |
96d52ac8 | 145 | #define CPUTIMER_CS5536 7 |
8d23b56c | 146 | #define CPUTIMER_TSC 8 |
45de427d | 147 | #define CPUTIMER_VMM 9 |
52df6187 SZ |
148 | #define CPUTIMER_VMM1 10 |
149 | #define CPUTIMER_VMM2 11 | |
044ee7c4 MD |
150 | |
151 | #define CPUTIMER_PRI_DUMMY -10 | |
152 | #define CPUTIMER_PRI_8254 0 | |
153 | #define CPUTIMER_PRI_ACPI 10 | |
f9ddf8c9 SZ |
154 | #define CPUTIMER_PRI_HPET 20 |
155 | #define CPUTIMER_PRI_CS5536 30 | |
156 | #define CPUTIMER_PRI_GEODE 40 | |
157 | #define CPUTIMER_PRI_VKERNEL 200 | |
8d23b56c | 158 | #define CPUTIMER_PRI_TSC 250 |
45de427d | 159 | #define CPUTIMER_PRI_VMM 1000 |
52df6187 | 160 | #define CPUTIMER_PRI_VMM_HI 2000 |
044ee7c4 | 161 | |
0ded555b MD |
162 | void cputimer_select(struct cputimer *, int); |
163 | void cputimer_register(struct cputimer *); | |
164 | void cputimer_deregister(struct cputimer *); | |
e2addb3d | 165 | void cputimer_set_frequency(struct cputimer *, sysclock_t); |
8fbc264d MD |
166 | sysclock_t cputimer_default_fromhz(int64_t); |
167 | sysclock_t cputimer_default_fromus(int64_t); | |
0ded555b MD |
168 | void cputimer_default_construct(struct cputimer *, sysclock_t); |
169 | void cputimer_default_destruct(struct cputimer *); | |
044ee7c4 | 170 | |
ef612539 SZ |
171 | /* |
172 | * Interrupt cputimer interface. | |
173 | * | |
174 | * Interrupt cputimers are normally one shot timers which will | |
175 | * generate interrupt upon expiration. | |
176 | * | |
177 | * initclock -- Called at SI_BOOT2_CLOCKREG, SI_ORDER_SECOND. The | |
178 | * interrupt timer could deregister itself here, if it | |
179 | * is not the selected system interrupt cputimer. Before | |
180 | * this function is called, 'enable' and 'reload' will | |
181 | * not be called. | |
182 | * enable -- Enable interrupt. It is called by each CPU. It is | |
183 | * only called once during boot. Before this function | |
184 | * is called, 'reload' will not be called. | |
185 | * reload -- Called by each CPU when it wants to to reprogram the | |
186 | * one shot timer expiration time. The reload value is | |
187 | * measured in sys_cputimer->freq. | |
188 | * config -- Setup the interrupt cputimer according to the passed | |
189 | * in non-interrupt cputimer. It will be called when | |
190 | * sys_cputimer's frequency is changed or when sys_cputimer | |
191 | * itself is changed. It is also called when this interrupt | |
192 | * cputimer gets registered. | |
193 | * restart -- Start the possibly stalled interrupt cputimer immediately. | |
194 | * Do fixup if necessary. | |
195 | * pmfixup -- Called after ACPI power management is enabled. | |
42098fc3 | 196 | * pcpuhand -- Per-cpu handler (could be NULL). |
ef612539 SZ |
197 | */ |
198 | struct cputimer_intr { | |
199 | sysclock_t freq; | |
200 | void (*reload) | |
201 | (struct cputimer_intr *, sysclock_t); | |
202 | void (*enable) | |
203 | (struct cputimer_intr *); | |
204 | void (*config) | |
205 | (struct cputimer_intr *, const struct cputimer *); | |
206 | void (*restart) | |
207 | (struct cputimer_intr *); | |
208 | void (*pmfixup) | |
209 | (struct cputimer_intr *); | |
210 | void (*initclock) | |
211 | (struct cputimer_intr *, boolean_t); | |
42098fc3 SZ |
212 | void (*pcpuhand) |
213 | (struct cputimer_intr *); | |
ef612539 SZ |
214 | SLIST_ENTRY(cputimer_intr) next; |
215 | const char *name; | |
216 | int type; /* CPUTIMER_INTR_ */ | |
217 | int prio; /* CPUTIMER_INTR_PRIO_ */ | |
218 | uint32_t caps; /* CPUTIMER_INTR_CAP_ */ | |
42098fc3 | 219 | void *priv; /* private data */ |
ef612539 SZ |
220 | }; |
221 | ||
222 | #define CPUTIMER_INTR_8254 0 | |
223 | #define CPUTIMER_INTR_LAPIC 1 | |
224 | #define CPUTIMER_INTR_VKERNEL 2 | |
e3c41896 | 225 | #define CPUTIMER_INTR_VMM 3 |
ef612539 SZ |
226 | |
227 | /* NOTE: Keep the new values less than CPUTIMER_INTR_PRIO_MAX */ | |
228 | #define CPUTIMER_INTR_PRIO_8254 0 | |
229 | #define CPUTIMER_INTR_PRIO_LAPIC 10 | |
230 | #define CPUTIMER_INTR_PRIO_VKERNEL 20 | |
e3c41896 | 231 | #define CPUTIMER_INTR_PRIO_VMM 500 |
ef612539 SZ |
232 | #define CPUTIMER_INTR_PRIO_MAX 1000 |
233 | ||
234 | #define CPUTIMER_INTR_CAP_NONE 0 | |
235 | #define CPUTIMER_INTR_CAP_PS 0x1 /* works during powersaving */ | |
236 | ||
237 | /* | |
238 | * Interrupt cputimer implementation interfaces | |
239 | * | |
240 | * NOTE: | |
241 | * cputimer_intr_deregister() is _not_ allowed to be called | |
242 | * with the currently selected interrupt cputimer. | |
243 | */ | |
244 | void cputimer_intr_register(struct cputimer_intr *); | |
245 | void cputimer_intr_deregister(struct cputimer_intr *); | |
246 | int cputimer_intr_select(struct cputimer_intr *, int); | |
247 | ||
248 | /* | |
249 | * Interrupt cputimer implementation helper functions | |
250 | * | |
251 | * default_enable -- NOP | |
252 | * default_restart -- reload(0) | |
253 | * default_config -- NOP | |
254 | * default_pmfixup -- NOP | |
255 | * default_initclock -- NOP | |
256 | */ | |
257 | void cputimer_intr_default_enable(struct cputimer_intr *); | |
258 | void cputimer_intr_default_restart(struct cputimer_intr *); | |
259 | void cputimer_intr_default_config(struct cputimer_intr *, | |
260 | const struct cputimer *); | |
261 | void cputimer_intr_default_pmfixup(struct cputimer_intr *); | |
262 | void cputimer_intr_default_initclock(struct cputimer_intr *, boolean_t); | |
263 | ||
264 | /* | |
265 | * Interrupt cputimer external interfaces | |
266 | */ | |
43adde98 | 267 | void cputimer_intr_enable(void); |
ef612539 SZ |
268 | void cputimer_intr_pmfixup(void); |
269 | void cputimer_intr_config(const struct cputimer *); | |
270 | void cputimer_intr_reload(sysclock_t); | |
271 | void cputimer_intr_restart(void); | |
272 | int cputimer_intr_select_caps(uint32_t); | |
e80ea409 SZ |
273 | int cputimer_intr_powersave_addreq(void); |
274 | void cputimer_intr_powersave_remreq(void); | |
88c4d2f6 | 275 | |
6b91ee43 SZ |
276 | /* |
277 | * The cpucounter interface. | |
278 | * | |
279 | * REQUIREMENT FOR CPUCOUNTER IMPLEMENTATION: | |
280 | * | |
281 | * - The values returned by count() must be MP synchronized, if | |
282 | * CPUCOUNTER_FLAG_MPSYNC is set on 'flags'. | |
283 | * - The values returned by count() must be stable under all situation, | |
284 | * e.g. when the platform enters power saving mode. | |
285 | * - The values returned by count() must be monotonically increasing. | |
286 | */ | |
287 | struct cpucounter { | |
288 | uint64_t freq; | |
289 | uint64_t (*count)(void); | |
290 | uint16_t flags; /* CPUCOUNTER_FLAG_ */ | |
291 | uint16_t prio; /* CPUCOUNTER_PRIO_ */ | |
292 | uint16_t type; /* CPUCOUNTER_ */ | |
293 | uint16_t reserved; | |
294 | SLIST_ENTRY(cpucounter) link; | |
295 | } __cachealign; | |
296 | ||
297 | #define CPUCOUNTER_FLAG_MPSYNC 0x0001 | |
298 | ||
299 | #define CPUCOUNTER_DUMMY 0 | |
300 | #define CPUCOUNTER_TSC 1 | |
301 | #define CPUCOUNTER_VMM 2 | |
302 | #define CPUCOUNTER_VMM1 3 | |
303 | #define CPUCOUNTER_VMM2 4 | |
304 | ||
305 | #define CPUCOUNTER_PRIO_DUMMY 0 | |
306 | #define CPUCOUNTER_PRIO_TSC 50 | |
307 | #define CPUCOUNTER_PRIO_VMM 100 | |
308 | #define CPUCOUNTER_PRIO_VMM_HI 150 | |
309 | ||
310 | void cpucounter_register(struct cpucounter *); | |
311 | const struct cpucounter *cpucounter_find_pcpu(void); | |
312 | const struct cpucounter *cpucounter_find(void); | |
27a6bce6 | 313 | #endif /* _KERNEL */ |
6b91ee43 | 314 | |
59ef3aa7 SZ |
315 | #endif /* _KERNEL || _KERNEL_STRUCTURES */ |
316 | ||
624051cd | 317 | #endif /* !_SYS_SYSTIMER_H_ */ |