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 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 *, int); 86 void systimer_init_periodic_nq(systimer_t, systimer_func_t, void *, int); 87 void systimer_adjust_periodic(systimer_t, int); 88 void systimer_init_oneshot(systimer_t, systimer_func_t, void *, int); 89 90 /* 91 * The cputimer interface. This provides a free-running (non-interrupt) 92 * and monotonically increasing timebase for the system. 93 * 94 * The cputimer structure holds the fixed cputimer frequency, determining 95 * the granularity of sys_cputimer->count(). 96 * 97 * Note that sys_cputimer->count() always returns a full-width wrapping 98 * counter. 99 * 100 * The 64 bit versions of the frequency are used for converting count 101 * values into uS or nS as follows: 102 * 103 * usec = (sys_cputimer->freq64_usec * count) >> 32 104 * 105 * NOTE: If count > sys_cputimer->freq, above conversion may overflow. 106 * 107 * REQUIREMENT FOR CPUTIMER IMPLEMENTATION: 108 * 109 * - 'freq' should not be too high, i.e. sysclock_t, which is 32 bits, 110 * must be able to hold several seconds at least. 111 * - The values returned by count() must be MP synchronized. 112 * - The values returned by count() must be stable under all situation, 113 * e.g. when the platform enters power saving mode. 114 * - The values returned by count() must be monotonically increasing. 115 */ 116 117 struct cputimer { 118 SLIST_ENTRY(cputimer) next; 119 const char *name; 120 int pri; 121 int type; 122 sysclock_t (*count)(void); 123 sysclock_t (*fromhz)(int freq); 124 sysclock_t (*fromus)(int us); 125 void (*construct)(struct cputimer *, sysclock_t); 126 void (*destruct)(struct cputimer *); 127 sysclock_t base; /* (implementation dependant) */ 128 sysclock_t freq; /* in Hz */ 129 int64_t freq64_usec; /* in (1e6 << 32) / freq */ 130 int64_t freq64_nsec; /* in (1e9 << 32) / freq */ 131 }; 132 133 extern struct cputimer *sys_cputimer; 134 135 #define CPUTIMER_DUMMY 0 136 #define CPUTIMER_8254_SEL1 1 137 #define CPUTIMER_8254_SEL2 2 138 #define CPUTIMER_ACPI 3 139 #define CPUTIMER_VKERNEL 4 140 #define CPUTIMER_HPET 5 141 #define CPUTIMER_GEODE 6 142 #define CPUTIMER_CS5536 7 143 #define CPUTIMER_TSC 8 144 #define CPUTIMER_VMM 9 145 #define CPUTIMER_VMM1 10 146 #define CPUTIMER_VMM2 11 147 148 #define CPUTIMER_PRI_DUMMY -10 149 #define CPUTIMER_PRI_8254 0 150 #define CPUTIMER_PRI_ACPI 10 151 #define CPUTIMER_PRI_HPET 20 152 #define CPUTIMER_PRI_CS5536 30 153 #define CPUTIMER_PRI_GEODE 40 154 #define CPUTIMER_PRI_VKERNEL 200 155 #define CPUTIMER_PRI_TSC 250 156 #define CPUTIMER_PRI_VMM 1000 157 #define CPUTIMER_PRI_VMM_HI 2000 158 159 void cputimer_select(struct cputimer *, int); 160 void cputimer_register(struct cputimer *); 161 void cputimer_deregister(struct cputimer *); 162 void cputimer_set_frequency(struct cputimer *, sysclock_t); 163 sysclock_t cputimer_default_fromhz(int); 164 sysclock_t cputimer_default_fromus(int); 165 void cputimer_default_construct(struct cputimer *, sysclock_t); 166 void cputimer_default_destruct(struct cputimer *); 167 168 /* 169 * Interrupt cputimer interface. 170 * 171 * Interrupt cputimers are normally one shot timers which will 172 * generate interrupt upon expiration. 173 * 174 * initclock -- Called at SI_BOOT2_CLOCKREG, SI_ORDER_SECOND. The 175 * interrupt timer could deregister itself here, if it 176 * is not the selected system interrupt cputimer. Before 177 * this function is called, 'enable' and 'reload' will 178 * not be called. 179 * enable -- Enable interrupt. It is called by each CPU. It is 180 * only called once during boot. Before this function 181 * is called, 'reload' will not be called. 182 * reload -- Called by each CPU when it wants to to reprogram the 183 * one shot timer expiration time. The reload value is 184 * measured in sys_cputimer->freq. 185 * config -- Setup the interrupt cputimer according to the passed 186 * in non-interrupt cputimer. It will be called when 187 * sys_cputimer's frequency is changed or when sys_cputimer 188 * itself is changed. It is also called when this interrupt 189 * cputimer gets registered. 190 * restart -- Start the possibly stalled interrupt cputimer immediately. 191 * Do fixup if necessary. 192 * pmfixup -- Called after ACPI power management is enabled. 193 * pcpuhand -- Per-cpu handler (could be NULL). 194 */ 195 struct cputimer_intr { 196 sysclock_t freq; 197 void (*reload) 198 (struct cputimer_intr *, sysclock_t); 199 void (*enable) 200 (struct cputimer_intr *); 201 void (*config) 202 (struct cputimer_intr *, const struct cputimer *); 203 void (*restart) 204 (struct cputimer_intr *); 205 void (*pmfixup) 206 (struct cputimer_intr *); 207 void (*initclock) 208 (struct cputimer_intr *, boolean_t); 209 void (*pcpuhand) 210 (struct cputimer_intr *); 211 SLIST_ENTRY(cputimer_intr) next; 212 const char *name; 213 int type; /* CPUTIMER_INTR_ */ 214 int prio; /* CPUTIMER_INTR_PRIO_ */ 215 uint32_t caps; /* CPUTIMER_INTR_CAP_ */ 216 void *priv; /* private data */ 217 }; 218 219 #define CPUTIMER_INTR_8254 0 220 #define CPUTIMER_INTR_LAPIC 1 221 #define CPUTIMER_INTR_VKERNEL 2 222 #define CPUTIMER_INTR_VMM 3 223 224 /* NOTE: Keep the new values less than CPUTIMER_INTR_PRIO_MAX */ 225 #define CPUTIMER_INTR_PRIO_8254 0 226 #define CPUTIMER_INTR_PRIO_LAPIC 10 227 #define CPUTIMER_INTR_PRIO_VKERNEL 20 228 #define CPUTIMER_INTR_PRIO_VMM 500 229 #define CPUTIMER_INTR_PRIO_MAX 1000 230 231 #define CPUTIMER_INTR_CAP_NONE 0 232 #define CPUTIMER_INTR_CAP_PS 0x1 /* works during powersaving */ 233 234 /* 235 * Interrupt cputimer implementation interfaces 236 * 237 * NOTE: 238 * cputimer_intr_deregister() is _not_ allowed to be called 239 * with the currently selected interrupt cputimer. 240 */ 241 void cputimer_intr_register(struct cputimer_intr *); 242 void cputimer_intr_deregister(struct cputimer_intr *); 243 int cputimer_intr_select(struct cputimer_intr *, int); 244 245 /* 246 * Interrupt cputimer implementation helper functions 247 * 248 * default_enable -- NOP 249 * default_restart -- reload(0) 250 * default_config -- NOP 251 * default_pmfixup -- NOP 252 * default_initclock -- NOP 253 */ 254 void cputimer_intr_default_enable(struct cputimer_intr *); 255 void cputimer_intr_default_restart(struct cputimer_intr *); 256 void cputimer_intr_default_config(struct cputimer_intr *, 257 const struct cputimer *); 258 void cputimer_intr_default_pmfixup(struct cputimer_intr *); 259 void cputimer_intr_default_initclock(struct cputimer_intr *, boolean_t); 260 261 /* 262 * Interrupt cputimer external interfaces 263 */ 264 void cputimer_intr_enable(void); 265 void cputimer_intr_pmfixup(void); 266 void cputimer_intr_config(const struct cputimer *); 267 void cputimer_intr_reload(sysclock_t); 268 void cputimer_intr_restart(void); 269 int cputimer_intr_select_caps(uint32_t); 270 int cputimer_intr_powersave_addreq(void); 271 void cputimer_intr_powersave_remreq(void); 272 273 /* 274 * The cpucounter interface. 275 * 276 * REQUIREMENT FOR CPUCOUNTER IMPLEMENTATION: 277 * 278 * - The values returned by count() must be MP synchronized, if 279 * CPUCOUNTER_FLAG_MPSYNC is set on 'flags'. 280 * - The values returned by count() must be stable under all situation, 281 * e.g. when the platform enters power saving mode. 282 * - The values returned by count() must be monotonically increasing. 283 */ 284 struct cpucounter { 285 uint64_t freq; 286 uint64_t (*count)(void); 287 uint16_t flags; /* CPUCOUNTER_FLAG_ */ 288 uint16_t prio; /* CPUCOUNTER_PRIO_ */ 289 uint16_t type; /* CPUCOUNTER_ */ 290 uint16_t reserved; 291 SLIST_ENTRY(cpucounter) link; 292 } __cachealign; 293 294 #define CPUCOUNTER_FLAG_MPSYNC 0x0001 295 296 #define CPUCOUNTER_DUMMY 0 297 #define CPUCOUNTER_TSC 1 298 #define CPUCOUNTER_VMM 2 299 #define CPUCOUNTER_VMM1 3 300 #define CPUCOUNTER_VMM2 4 301 302 #define CPUCOUNTER_PRIO_DUMMY 0 303 #define CPUCOUNTER_PRIO_TSC 50 304 #define CPUCOUNTER_PRIO_VMM 100 305 #define CPUCOUNTER_PRIO_VMM_HI 150 306 307 void cpucounter_register(struct cpucounter *); 308 const struct cpucounter *cpucounter_find_pcpu(void); 309 const struct cpucounter *cpucounter_find(void); 310 311 #endif /* _KERNEL || _KERNEL_STRUCTURES */ 312 313 #endif /* !_SYS_SYSTIMER_H_ */ 314