1 /* 2 * SYS/SYSTIMER.H 3 * 4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@backplane.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 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 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. 22 * 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 34 * SUCH DAMAGE. 35 * 36 * $DragonFly: src/sys/sys/systimer.h,v 1.13 2007/04/30 06:57:36 dillon Exp $ 37 */ 38 39 #ifndef _SYS_SYSTIMER_H_ 40 #define _SYS_SYSTIMER_H_ 41 42 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES) 43 44 #ifndef _SYS_TYPES_H_ 45 #include <sys/types.h> 46 #endif 47 #ifndef _SYS_QUEUE_H_ 48 #include <sys/queue.h> 49 #endif 50 51 /* XXX fix sys/kinfo.h */ 52 #ifndef __BOOLEAN_T_DEFINED__ 53 #define __BOOLEAN_T_DEFINED__ 54 typedef __boolean_t boolean_t; 55 #endif 56 57 struct intrframe; 58 59 typedef __uint32_t sysclock_t; 60 typedef int32_t ssysclock_t; 61 typedef TAILQ_HEAD(systimerq, systimer) *systimerq_t; 62 typedef void (*systimer_func_t)(struct systimer *, int, struct intrframe *); 63 64 typedef struct systimer { 65 TAILQ_ENTRY(systimer) node; 66 systimerq_t queue; 67 sysclock_t time; /* absolute time next intr */ 68 sysclock_t periodic; /* if non-zero */ 69 systimer_func_t func; 70 void *data; 71 int flags; 72 int freq; /* frequency if periodic */ 73 struct cputimer *which; /* which timer was used? */ 74 struct globaldata *gd; /* cpu owning structure */ 75 } *systimer_t; 76 77 #define SYSTF_ONQUEUE 0x0001 78 #define SYSTF_IPIRUNNING 0x0002 79 #define SYSTF_NONQUEUED 0x0004 80 #define SYSTF_MSSYNC 0x0008 /* 1Khz coincident sync */ 81 #define SYSTF_100KHZSYNC 0x0010 /* 100Khz coincident sync */ 82 #define SYSTF_FIRST 0x0020 /* order first if coincident */ 83 84 void systimer_intr_enable(void); 85 void systimer_intr(sysclock_t *, int, struct intrframe *); 86 void systimer_add(systimer_t); 87 void systimer_del(systimer_t); 88 void systimer_init_periodic(systimer_t, systimer_func_t, void *, int); 89 void systimer_init_periodic_nq(systimer_t, systimer_func_t, void *, int); 90 void systimer_init_periodic_nq1khz(systimer_t, systimer_func_t, void *, int); 91 void systimer_init_periodic_nq100khz(systimer_t, systimer_func_t, void *, int); 92 void systimer_init_periodic_flags(systimer_t, systimer_func_t, void *, 93 int, int); 94 void systimer_adjust_periodic(systimer_t, int); 95 void systimer_init_oneshot(systimer_t, systimer_func_t, void *, int); 96 97 /* 98 * The cputimer interface. This provides a free-running (non-interrupt) 99 * and monotonically increasing timebase for the system. 100 * 101 * The cputimer structure holds the fixed cputimer frequency, determining 102 * the granularity of sys_cputimer->count(). 103 * 104 * Note that sys_cputimer->count() always returns a full-width wrapping 105 * counter. 106 * 107 * The 64 bit versions of the frequency are used for converting count 108 * values into uS or nS as follows: 109 * 110 * usec = (sys_cputimer->freq64_usec * count) >> 32 111 * 112 * NOTE: If count > sys_cputimer->freq, above conversion may overflow. 113 * 114 * REQUIREMENT FOR CPUTIMER IMPLEMENTATION: 115 * 116 * - 'freq' should not be too high, i.e. sysclock_t, which is 32 bits, 117 * must be able to hold several seconds at least. 118 * - The values returned by count() must be MP synchronized. 119 * - The values returned by count() must be stable under all situation, 120 * e.g. when the platform enters power saving mode. 121 * - The values returned by count() must be monotonically increasing. 122 */ 123 124 struct cputimer { 125 SLIST_ENTRY(cputimer) next; 126 const char *name; 127 int pri; 128 int type; 129 sysclock_t (*count)(void); 130 sysclock_t (*fromhz)(int freq); 131 sysclock_t (*fromus)(int us); 132 void (*construct)(struct cputimer *, sysclock_t); 133 void (*destruct)(struct cputimer *); 134 sysclock_t sync_base; /* periodic synchronization base */ 135 sysclock_t base; /* (implementation dependant) */ 136 sysclock_t freq; /* in Hz */ 137 int64_t freq64_usec; /* in (1e6 << 32) / freq */ 138 int64_t freq64_nsec; /* in (1e9 << 32) / freq */ 139 }; 140 141 extern struct cputimer *sys_cputimer; 142 143 #define CPUTIMER_DUMMY 0 144 #define CPUTIMER_8254_SEL1 1 145 #define CPUTIMER_8254_SEL2 2 146 #define CPUTIMER_ACPI 3 147 #define CPUTIMER_VKERNEL 4 148 #define CPUTIMER_HPET 5 149 #define CPUTIMER_GEODE 6 150 #define CPUTIMER_CS5536 7 151 #define CPUTIMER_TSC 8 152 #define CPUTIMER_VMM 9 153 #define CPUTIMER_VMM1 10 154 #define CPUTIMER_VMM2 11 155 156 #define CPUTIMER_PRI_DUMMY -10 157 #define CPUTIMER_PRI_8254 0 158 #define CPUTIMER_PRI_ACPI 10 159 #define CPUTIMER_PRI_HPET 20 160 #define CPUTIMER_PRI_CS5536 30 161 #define CPUTIMER_PRI_GEODE 40 162 #define CPUTIMER_PRI_VKERNEL 200 163 #define CPUTIMER_PRI_TSC 250 164 #define CPUTIMER_PRI_VMM 1000 165 #define CPUTIMER_PRI_VMM_HI 2000 166 167 void cputimer_select(struct cputimer *, int); 168 void cputimer_register(struct cputimer *); 169 void cputimer_deregister(struct cputimer *); 170 void cputimer_set_frequency(struct cputimer *, sysclock_t); 171 sysclock_t cputimer_default_fromhz(int); 172 sysclock_t cputimer_default_fromus(int); 173 void cputimer_default_construct(struct cputimer *, sysclock_t); 174 void cputimer_default_destruct(struct cputimer *); 175 176 /* 177 * Interrupt cputimer interface. 178 * 179 * Interrupt cputimers are normally one shot timers which will 180 * generate interrupt upon expiration. 181 * 182 * initclock -- Called at SI_BOOT2_CLOCKREG, SI_ORDER_SECOND. The 183 * interrupt timer could deregister itself here, if it 184 * is not the selected system interrupt cputimer. Before 185 * this function is called, 'enable' and 'reload' will 186 * not be called. 187 * enable -- Enable interrupt. It is called by each CPU. It is 188 * only called once during boot. Before this function 189 * is called, 'reload' will not be called. 190 * reload -- Called by each CPU when it wants to to reprogram the 191 * one shot timer expiration time. The reload value is 192 * measured in sys_cputimer->freq. 193 * config -- Setup the interrupt cputimer according to the passed 194 * in non-interrupt cputimer. It will be called when 195 * sys_cputimer's frequency is changed or when sys_cputimer 196 * itself is changed. It is also called when this interrupt 197 * cputimer gets registered. 198 * restart -- Start the possibly stalled interrupt cputimer immediately. 199 * Do fixup if necessary. 200 * pmfixup -- Called after ACPI power management is enabled. 201 * pcpuhand -- Per-cpu handler (could be NULL). 202 */ 203 struct cputimer_intr { 204 sysclock_t freq; 205 void (*reload) 206 (struct cputimer_intr *, sysclock_t); 207 void (*enable) 208 (struct cputimer_intr *); 209 void (*config) 210 (struct cputimer_intr *, const struct cputimer *); 211 void (*restart) 212 (struct cputimer_intr *); 213 void (*pmfixup) 214 (struct cputimer_intr *); 215 void (*initclock) 216 (struct cputimer_intr *, boolean_t); 217 void (*pcpuhand) 218 (struct cputimer_intr *); 219 SLIST_ENTRY(cputimer_intr) next; 220 const char *name; 221 int type; /* CPUTIMER_INTR_ */ 222 int prio; /* CPUTIMER_INTR_PRIO_ */ 223 uint32_t caps; /* CPUTIMER_INTR_CAP_ */ 224 void *priv; /* private data */ 225 }; 226 227 #define CPUTIMER_INTR_8254 0 228 #define CPUTIMER_INTR_LAPIC 1 229 #define CPUTIMER_INTR_VKERNEL 2 230 #define CPUTIMER_INTR_VMM 3 231 232 /* NOTE: Keep the new values less than CPUTIMER_INTR_PRIO_MAX */ 233 #define CPUTIMER_INTR_PRIO_8254 0 234 #define CPUTIMER_INTR_PRIO_LAPIC 10 235 #define CPUTIMER_INTR_PRIO_VKERNEL 20 236 #define CPUTIMER_INTR_PRIO_VMM 500 237 #define CPUTIMER_INTR_PRIO_MAX 1000 238 239 #define CPUTIMER_INTR_CAP_NONE 0 240 #define CPUTIMER_INTR_CAP_PS 0x1 /* works during powersaving */ 241 242 /* 243 * Interrupt cputimer implementation interfaces 244 * 245 * NOTE: 246 * cputimer_intr_deregister() is _not_ allowed to be called 247 * with the currently selected interrupt cputimer. 248 */ 249 void cputimer_intr_register(struct cputimer_intr *); 250 void cputimer_intr_deregister(struct cputimer_intr *); 251 int cputimer_intr_select(struct cputimer_intr *, int); 252 253 /* 254 * Interrupt cputimer implementation helper functions 255 * 256 * default_enable -- NOP 257 * default_restart -- reload(0) 258 * default_config -- NOP 259 * default_pmfixup -- NOP 260 * default_initclock -- NOP 261 */ 262 void cputimer_intr_default_enable(struct cputimer_intr *); 263 void cputimer_intr_default_restart(struct cputimer_intr *); 264 void cputimer_intr_default_config(struct cputimer_intr *, 265 const struct cputimer *); 266 void cputimer_intr_default_pmfixup(struct cputimer_intr *); 267 void cputimer_intr_default_initclock(struct cputimer_intr *, boolean_t); 268 269 /* 270 * Interrupt cputimer external interfaces 271 */ 272 void cputimer_intr_enable(void); 273 void cputimer_intr_pmfixup(void); 274 void cputimer_intr_config(const struct cputimer *); 275 void cputimer_intr_reload(sysclock_t); 276 void cputimer_intr_restart(void); 277 int cputimer_intr_select_caps(uint32_t); 278 int cputimer_intr_powersave_addreq(void); 279 void cputimer_intr_powersave_remreq(void); 280 281 /* 282 * The cpucounter interface. 283 * 284 * REQUIREMENT FOR CPUCOUNTER IMPLEMENTATION: 285 * 286 * - The values returned by count() must be MP synchronized, if 287 * CPUCOUNTER_FLAG_MPSYNC is set on 'flags'. 288 * - The values returned by count() must be stable under all situation, 289 * e.g. when the platform enters power saving mode. 290 * - The values returned by count() must be monotonically increasing. 291 */ 292 struct cpucounter { 293 uint64_t freq; 294 uint64_t (*count)(void); 295 uint16_t flags; /* CPUCOUNTER_FLAG_ */ 296 uint16_t prio; /* CPUCOUNTER_PRIO_ */ 297 uint16_t type; /* CPUCOUNTER_ */ 298 uint16_t reserved; 299 SLIST_ENTRY(cpucounter) link; 300 } __cachealign; 301 302 #define CPUCOUNTER_FLAG_MPSYNC 0x0001 303 304 #define CPUCOUNTER_DUMMY 0 305 #define CPUCOUNTER_TSC 1 306 #define CPUCOUNTER_VMM 2 307 #define CPUCOUNTER_VMM1 3 308 #define CPUCOUNTER_VMM2 4 309 310 #define CPUCOUNTER_PRIO_DUMMY 0 311 #define CPUCOUNTER_PRIO_TSC 50 312 #define CPUCOUNTER_PRIO_VMM 100 313 #define CPUCOUNTER_PRIO_VMM_HI 150 314 315 void cpucounter_register(struct cpucounter *); 316 const struct cpucounter *cpucounter_find_pcpu(void); 317 const struct cpucounter *cpucounter_find(void); 318 319 #endif /* _KERNEL || _KERNEL_STRUCTURES */ 320 321 #endif /* !_SYS_SYSTIMER_H_ */ 322