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