4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@backplane.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
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.
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
37 #ifndef _SYS_SYSTIMER_H_
38 #define _SYS_SYSTIMER_H_
40 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
43 #include <sys/types.h>
46 #include <sys/queue.h>
51 typedef __uint64_t sysclock_t;
52 typedef int64_t ssysclock_t;
53 typedef TAILQ_HEAD(systimerq, systimer) *systimerq_t;
54 typedef void (*systimer_func_t)(struct systimer *, int, struct intrframe *);
56 typedef struct systimer {
57 TAILQ_ENTRY(systimer) node;
59 sysclock_t time; /* absolute time next intr */
60 sysclock_t periodic; /* non-zero if periodic */
64 int us; /* non-zero if one-shot */
65 ssysclock_t freq; /* frequency if periodic */
66 struct cputimer *which; /* which timer was used? */
67 struct globaldata *gd; /* cpu owning structure */
70 #define SYSTF_ONQUEUE 0x0001
71 #define SYSTF_IPIRUNNING 0x0002
72 #define SYSTF_NONQUEUED 0x0004
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 */
76 #define SYSTF_OFFSET50 0x0040 /* add 1/2 interval offset */
77 #define SYSTF_OFFSETCPU 0x0080 /* add cpu*periodic/ncpus */
80 void systimer_changed(void);
81 void systimer_intr_enable(void);
82 void systimer_intr(sysclock_t *, int, struct intrframe *);
83 void systimer_add(systimer_t);
84 void systimer_del(systimer_t);
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);
89 void systimer_init_periodic_flags(systimer_t, systimer_func_t, void *,
91 void systimer_adjust_periodic(systimer_t, int64_t);
92 void systimer_init_oneshot(systimer_t, systimer_func_t, void *, int64_t);
95 * The cputimer interface. This provides a free-running (non-interrupt)
96 * and monotonically increasing timebase for the system.
98 * The cputimer structure holds the fixed cputimer frequency, determining
99 * the granularity of sys_cputimer->count().
101 * Note that sys_cputimer->count() always returns a full-width wrapping
104 * The 64 bit versions of the frequency are used for converting count
105 * values into uS or nS as follows:
107 * usec = (sys_cputimer->freq64_usec * count) >> 32
109 * NOTE: If count > sys_cputimer->freq, above conversion may overflow.
111 * REQUIREMENT FOR CPUTIMER IMPLEMENTATION:
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.
120 SLIST_ENTRY(cputimer) next;
124 sysclock_t (*count)(void);
125 sysclock_t (*fromhz)(int64_t freq);
126 sysclock_t (*fromus)(int64_t us);
127 void (*construct)(struct cputimer *, sysclock_t);
128 void (*destruct)(struct cputimer *);
129 sysclock_t sync_base; /* periodic synchronization base */
130 sysclock_t base; /* (implementation dependant) */
131 sysclock_t freq; /* in Hz */
132 int64_t freq64_usec; /* in (1e6 << 32) / freq */
133 int64_t freq64_nsec; /* in (1e9 << 32) / freq */
136 extern struct cputimer *sys_cputimer;
138 #define CPUTIMER_DUMMY 0
139 #define CPUTIMER_8254_SEL1 1
140 #define CPUTIMER_8254_SEL2 2
141 #define CPUTIMER_ACPI 3
142 #define CPUTIMER_VKERNEL 4
143 #define CPUTIMER_HPET 5
144 #define CPUTIMER_GEODE 6
145 #define CPUTIMER_CS5536 7
146 #define CPUTIMER_TSC 8
147 #define CPUTIMER_VMM 9
148 #define CPUTIMER_VMM1 10
149 #define CPUTIMER_VMM2 11
151 #define CPUTIMER_PRI_DUMMY -10
152 #define CPUTIMER_PRI_8254 0
153 #define CPUTIMER_PRI_ACPI 10
154 #define CPUTIMER_PRI_HPET 20
155 #define CPUTIMER_PRI_CS5536 30
156 #define CPUTIMER_PRI_GEODE 40
157 #define CPUTIMER_PRI_VKERNEL 200
158 #define CPUTIMER_PRI_TSC 250
159 #define CPUTIMER_PRI_VMM 1000
160 #define CPUTIMER_PRI_VMM_HI 2000
162 void cputimer_select(struct cputimer *, int);
163 void cputimer_register(struct cputimer *);
164 void cputimer_deregister(struct cputimer *);
165 void cputimer_set_frequency(struct cputimer *, sysclock_t);
166 sysclock_t cputimer_default_fromhz(int64_t);
167 sysclock_t cputimer_default_fromus(int64_t);
168 void cputimer_default_construct(struct cputimer *, sysclock_t);
169 void cputimer_default_destruct(struct cputimer *);
172 * Interrupt cputimer interface.
174 * Interrupt cputimers are normally one shot timers which will
175 * generate interrupt upon expiration.
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
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.
196 * pcpuhand -- Per-cpu handler (could be NULL).
198 struct cputimer_intr {
201 (struct cputimer_intr *, sysclock_t);
203 (struct cputimer_intr *);
205 (struct cputimer_intr *, const struct cputimer *);
207 (struct cputimer_intr *);
209 (struct cputimer_intr *);
211 (struct cputimer_intr *, boolean_t);
213 (struct cputimer_intr *);
214 SLIST_ENTRY(cputimer_intr) next;
216 int type; /* CPUTIMER_INTR_ */
217 int prio; /* CPUTIMER_INTR_PRIO_ */
218 uint32_t caps; /* CPUTIMER_INTR_CAP_ */
219 void *priv; /* private data */
222 #define CPUTIMER_INTR_8254 0
223 #define CPUTIMER_INTR_LAPIC 1
224 #define CPUTIMER_INTR_VKERNEL 2
225 #define CPUTIMER_INTR_VMM 3
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
231 #define CPUTIMER_INTR_PRIO_VMM 500
232 #define CPUTIMER_INTR_PRIO_MAX 1000
234 #define CPUTIMER_INTR_CAP_NONE 0
235 #define CPUTIMER_INTR_CAP_PS 0x1 /* works during powersaving */
238 * Interrupt cputimer implementation interfaces
241 * cputimer_intr_deregister() is _not_ allowed to be called
242 * with the currently selected interrupt cputimer.
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);
249 * Interrupt cputimer implementation helper functions
251 * default_enable -- NOP
252 * default_restart -- reload(0)
253 * default_config -- NOP
254 * default_pmfixup -- NOP
255 * default_initclock -- NOP
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);
265 * Interrupt cputimer external interfaces
267 void cputimer_intr_enable(void);
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);
273 int cputimer_intr_powersave_addreq(void);
274 void cputimer_intr_powersave_remreq(void);
277 * The cpucounter interface.
279 * REQUIREMENT FOR CPUCOUNTER IMPLEMENTATION:
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.
289 uint64_t (*count)(void);
290 uint16_t flags; /* CPUCOUNTER_FLAG_ */
291 uint16_t prio; /* CPUCOUNTER_PRIO_ */
292 uint16_t type; /* CPUCOUNTER_ */
294 SLIST_ENTRY(cpucounter) link;
297 #define CPUCOUNTER_FLAG_MPSYNC 0x0001
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
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
310 void cpucounter_register(struct cpucounter *);
311 const struct cpucounter *cpucounter_find_pcpu(void);
312 const struct cpucounter *cpucounter_find(void);
315 #endif /* _KERNEL || _KERNEL_STRUCTURES */
317 #endif /* !_SYS_SYSTIMER_H_ */