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 37 #ifndef _SYS_SYSTIMER_H_ 38 #define _SYS_SYSTIMER_H_ 39 40 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES) 41 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 49 struct intrframe; 50 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 *); 55 56 typedef struct systimer { 57 TAILQ_ENTRY(systimer) node; 58 systimerq_t queue; 59 sysclock_t time; /* absolute time next intr */ 60 sysclock_t periodic; /* non-zero if periodic */ 61 systimer_func_t func; 62 void *data; 63 int flags; 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 */ 68 } *systimer_t; 69 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 */ 78 79 #ifdef _KERNEL 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 *, 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); 93 94 /* 95 * The cputimer interface. This provides a free-running (non-interrupt) 96 * and monotonically increasing timebase for the system. 97 * 98 * The cputimer structure holds the fixed cputimer frequency, determining 99 * the granularity of sys_cputimer->count(). 100 * 101 * Note that sys_cputimer->count() always returns a full-width wrapping 102 * counter. 103 * 104 * The 64 bit versions of the frequency are used for converting count 105 * values into uS or nS as follows: 106 * 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 * 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. 117 */ 118 119 struct cputimer { 120 SLIST_ENTRY(cputimer) next; 121 const char *name; 122 int pri; 123 int type; 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 */ 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 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 150 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 161 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 *); 170 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. 196 * pcpuhand -- Per-cpu handler (could be NULL). 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); 212 void (*pcpuhand) 213 (struct cputimer_intr *); 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_ */ 219 void *priv; /* private data */ 220 }; 221 222 #define CPUTIMER_INTR_8254 0 223 #define CPUTIMER_INTR_LAPIC 1 224 #define CPUTIMER_INTR_VKERNEL 2 225 #define CPUTIMER_INTR_VMM 3 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 231 #define CPUTIMER_INTR_PRIO_VMM 500 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 */ 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); 275 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); 313 #endif /* _KERNEL */ 314 315 #endif /* _KERNEL || _KERNEL_STRUCTURES */ 316 317 #endif /* !_SYS_SYSTIMER_H_ */ 318