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 76 #ifdef _KERNEL 77 void systimer_intr_enable(void); 78 void systimer_intr(sysclock_t *, int, struct intrframe *); 79 void systimer_add(systimer_t); 80 void systimer_del(systimer_t); 81 void systimer_init_periodic(systimer_t, systimer_func_t, void *, int); 82 void systimer_init_periodic_nq(systimer_t, systimer_func_t, void *, int); 83 void systimer_init_periodic_nq1khz(systimer_t, systimer_func_t, void *, int); 84 void systimer_init_periodic_nq100khz(systimer_t, systimer_func_t, void *, int); 85 void systimer_init_periodic_flags(systimer_t, systimer_func_t, void *, 86 int, 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 sync_base; /* periodic synchronization base */ 128 sysclock_t base; /* (implementation dependant) */ 129 sysclock_t freq; /* in Hz */ 130 int64_t freq64_usec; /* in (1e6 << 32) / freq */ 131 int64_t freq64_nsec; /* in (1e9 << 32) / freq */ 132 }; 133 134 extern struct cputimer *sys_cputimer; 135 136 #define CPUTIMER_DUMMY 0 137 #define CPUTIMER_8254_SEL1 1 138 #define CPUTIMER_8254_SEL2 2 139 #define CPUTIMER_ACPI 3 140 #define CPUTIMER_VKERNEL 4 141 #define CPUTIMER_HPET 5 142 #define CPUTIMER_GEODE 6 143 #define CPUTIMER_CS5536 7 144 #define CPUTIMER_TSC 8 145 #define CPUTIMER_VMM 9 146 #define CPUTIMER_VMM1 10 147 #define CPUTIMER_VMM2 11 148 149 #define CPUTIMER_PRI_DUMMY -10 150 #define CPUTIMER_PRI_8254 0 151 #define CPUTIMER_PRI_ACPI 10 152 #define CPUTIMER_PRI_HPET 20 153 #define CPUTIMER_PRI_CS5536 30 154 #define CPUTIMER_PRI_GEODE 40 155 #define CPUTIMER_PRI_VKERNEL 200 156 #define CPUTIMER_PRI_TSC 250 157 #define CPUTIMER_PRI_VMM 1000 158 #define CPUTIMER_PRI_VMM_HI 2000 159 160 void cputimer_select(struct cputimer *, int); 161 void cputimer_register(struct cputimer *); 162 void cputimer_deregister(struct cputimer *); 163 void cputimer_set_frequency(struct cputimer *, sysclock_t); 164 sysclock_t cputimer_default_fromhz(int); 165 sysclock_t cputimer_default_fromus(int); 166 void cputimer_default_construct(struct cputimer *, sysclock_t); 167 void cputimer_default_destruct(struct cputimer *); 168 169 /* 170 * Interrupt cputimer interface. 171 * 172 * Interrupt cputimers are normally one shot timers which will 173 * generate interrupt upon expiration. 174 * 175 * initclock -- Called at SI_BOOT2_CLOCKREG, SI_ORDER_SECOND. The 176 * interrupt timer could deregister itself here, if it 177 * is not the selected system interrupt cputimer. Before 178 * this function is called, 'enable' and 'reload' will 179 * not be called. 180 * enable -- Enable interrupt. It is called by each CPU. It is 181 * only called once during boot. Before this function 182 * is called, 'reload' will not be called. 183 * reload -- Called by each CPU when it wants to to reprogram the 184 * one shot timer expiration time. The reload value is 185 * measured in sys_cputimer->freq. 186 * config -- Setup the interrupt cputimer according to the passed 187 * in non-interrupt cputimer. It will be called when 188 * sys_cputimer's frequency is changed or when sys_cputimer 189 * itself is changed. It is also called when this interrupt 190 * cputimer gets registered. 191 * restart -- Start the possibly stalled interrupt cputimer immediately. 192 * Do fixup if necessary. 193 * pmfixup -- Called after ACPI power management is enabled. 194 * pcpuhand -- Per-cpu handler (could be NULL). 195 */ 196 struct cputimer_intr { 197 sysclock_t freq; 198 void (*reload) 199 (struct cputimer_intr *, sysclock_t); 200 void (*enable) 201 (struct cputimer_intr *); 202 void (*config) 203 (struct cputimer_intr *, const struct cputimer *); 204 void (*restart) 205 (struct cputimer_intr *); 206 void (*pmfixup) 207 (struct cputimer_intr *); 208 void (*initclock) 209 (struct cputimer_intr *, boolean_t); 210 void (*pcpuhand) 211 (struct cputimer_intr *); 212 SLIST_ENTRY(cputimer_intr) next; 213 const char *name; 214 int type; /* CPUTIMER_INTR_ */ 215 int prio; /* CPUTIMER_INTR_PRIO_ */ 216 uint32_t caps; /* CPUTIMER_INTR_CAP_ */ 217 void *priv; /* private data */ 218 }; 219 220 #define CPUTIMER_INTR_8254 0 221 #define CPUTIMER_INTR_LAPIC 1 222 #define CPUTIMER_INTR_VKERNEL 2 223 #define CPUTIMER_INTR_VMM 3 224 225 /* NOTE: Keep the new values less than CPUTIMER_INTR_PRIO_MAX */ 226 #define CPUTIMER_INTR_PRIO_8254 0 227 #define CPUTIMER_INTR_PRIO_LAPIC 10 228 #define CPUTIMER_INTR_PRIO_VKERNEL 20 229 #define CPUTIMER_INTR_PRIO_VMM 500 230 #define CPUTIMER_INTR_PRIO_MAX 1000 231 232 #define CPUTIMER_INTR_CAP_NONE 0 233 #define CPUTIMER_INTR_CAP_PS 0x1 /* works during powersaving */ 234 235 /* 236 * Interrupt cputimer implementation interfaces 237 * 238 * NOTE: 239 * cputimer_intr_deregister() is _not_ allowed to be called 240 * with the currently selected interrupt cputimer. 241 */ 242 void cputimer_intr_register(struct cputimer_intr *); 243 void cputimer_intr_deregister(struct cputimer_intr *); 244 int cputimer_intr_select(struct cputimer_intr *, int); 245 246 /* 247 * Interrupt cputimer implementation helper functions 248 * 249 * default_enable -- NOP 250 * default_restart -- reload(0) 251 * default_config -- NOP 252 * default_pmfixup -- NOP 253 * default_initclock -- NOP 254 */ 255 void cputimer_intr_default_enable(struct cputimer_intr *); 256 void cputimer_intr_default_restart(struct cputimer_intr *); 257 void cputimer_intr_default_config(struct cputimer_intr *, 258 const struct cputimer *); 259 void cputimer_intr_default_pmfixup(struct cputimer_intr *); 260 void cputimer_intr_default_initclock(struct cputimer_intr *, boolean_t); 261 262 /* 263 * Interrupt cputimer external interfaces 264 */ 265 void cputimer_intr_enable(void); 266 void cputimer_intr_pmfixup(void); 267 void cputimer_intr_config(const struct cputimer *); 268 void cputimer_intr_reload(sysclock_t); 269 void cputimer_intr_restart(void); 270 int cputimer_intr_select_caps(uint32_t); 271 int cputimer_intr_powersave_addreq(void); 272 void cputimer_intr_powersave_remreq(void); 273 274 /* 275 * The cpucounter interface. 276 * 277 * REQUIREMENT FOR CPUCOUNTER IMPLEMENTATION: 278 * 279 * - The values returned by count() must be MP synchronized, if 280 * CPUCOUNTER_FLAG_MPSYNC is set on 'flags'. 281 * - The values returned by count() must be stable under all situation, 282 * e.g. when the platform enters power saving mode. 283 * - The values returned by count() must be monotonically increasing. 284 */ 285 struct cpucounter { 286 uint64_t freq; 287 uint64_t (*count)(void); 288 uint16_t flags; /* CPUCOUNTER_FLAG_ */ 289 uint16_t prio; /* CPUCOUNTER_PRIO_ */ 290 uint16_t type; /* CPUCOUNTER_ */ 291 uint16_t reserved; 292 SLIST_ENTRY(cpucounter) link; 293 } __cachealign; 294 295 #define CPUCOUNTER_FLAG_MPSYNC 0x0001 296 297 #define CPUCOUNTER_DUMMY 0 298 #define CPUCOUNTER_TSC 1 299 #define CPUCOUNTER_VMM 2 300 #define CPUCOUNTER_VMM1 3 301 #define CPUCOUNTER_VMM2 4 302 303 #define CPUCOUNTER_PRIO_DUMMY 0 304 #define CPUCOUNTER_PRIO_TSC 50 305 #define CPUCOUNTER_PRIO_VMM 100 306 #define CPUCOUNTER_PRIO_VMM_HI 150 307 308 void cpucounter_register(struct cpucounter *); 309 const struct cpucounter *cpucounter_find_pcpu(void); 310 const struct cpucounter *cpucounter_find(void); 311 #endif /* _KERNEL */ 312 313 #endif /* _KERNEL || _KERNEL_STRUCTURES */ 314 315 #endif /* !_SYS_SYSTIMER_H_ */ 316