1 1.42 imil /* $NetBSD: clock.c,v 1.42 2025/02/24 07:18:02 imil Exp $ */ 2 1.1 perry 3 1.1 perry /*- 4 1.1 perry * Copyright (c) 1990 The Regents of the University of California. 5 1.1 perry * All rights reserved. 6 1.1 perry * 7 1.1 perry * This code is derived from software contributed to Berkeley by 8 1.1 perry * William Jolitz and Don Ahn. 9 1.1 perry * 10 1.1 perry * Redistribution and use in source and binary forms, with or without 11 1.1 perry * modification, are permitted provided that the following conditions 12 1.1 perry * are met: 13 1.1 perry * 1. Redistributions of source code must retain the above copyright 14 1.1 perry * notice, this list of conditions and the following disclaimer. 15 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 perry * notice, this list of conditions and the following disclaimer in the 17 1.1 perry * documentation and/or other materials provided with the distribution. 18 1.1 perry * 3. Neither the name of the University nor the names of its contributors 19 1.1 perry * may be used to endorse or promote products derived from this software 20 1.1 perry * without specific prior written permission. 21 1.1 perry * 22 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 perry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 perry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 perry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 perry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 perry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 perry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 perry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 perry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 perry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 perry * SUCH DAMAGE. 33 1.1 perry * 34 1.1 perry * @(#)clock.c 7.2 (Berkeley) 5/12/91 35 1.1 perry */ 36 1.1 perry /*- 37 1.1 perry * Copyright (c) 1993, 1994 Charles M. Hannum. 38 1.1 perry * 39 1.1 perry * This code is derived from software contributed to Berkeley by 40 1.1 perry * William Jolitz and Don Ahn. 41 1.1 perry * 42 1.1 perry * Redistribution and use in source and binary forms, with or without 43 1.1 perry * modification, are permitted provided that the following conditions 44 1.1 perry * are met: 45 1.1 perry * 1. Redistributions of source code must retain the above copyright 46 1.1 perry * notice, this list of conditions and the following disclaimer. 47 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright 48 1.1 perry * notice, this list of conditions and the following disclaimer in the 49 1.1 perry * documentation and/or other materials provided with the distribution. 50 1.1 perry * 3. All advertising materials mentioning features or use of this software 51 1.1 perry * must display the following acknowledgement: 52 1.1 perry * This product includes software developed by the University of 53 1.1 perry * California, Berkeley and its contributors. 54 1.1 perry * 4. Neither the name of the University nor the names of its contributors 55 1.1 perry * may be used to endorse or promote products derived from this software 56 1.1 perry * without specific prior written permission. 57 1.1 perry * 58 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 1.1 perry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 1.1 perry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 1.1 perry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 1.1 perry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 1.1 perry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 1.1 perry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 1.1 perry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 1.1 perry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 1.1 perry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 1.1 perry * SUCH DAMAGE. 69 1.1 perry * 70 1.1 perry * @(#)clock.c 7.2 (Berkeley) 5/12/91 71 1.1 perry */ 72 1.40 riastrad /* 73 1.1 perry * Mach Operating System 74 1.1 perry * Copyright (c) 1991,1990,1989 Carnegie Mellon University 75 1.1 perry * All Rights Reserved. 76 1.40 riastrad * 77 1.1 perry * Permission to use, copy, modify and distribute this software and its 78 1.1 perry * documentation is hereby granted, provided that both the copyright 79 1.1 perry * notice and this permission notice appear in all copies of the 80 1.1 perry * software, derivative works or modified versions, and any portions 81 1.1 perry * thereof, and that both notices appear in supporting documentation. 82 1.40 riastrad * 83 1.1 perry * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 84 1.1 perry * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 85 1.1 perry * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 86 1.40 riastrad * 87 1.1 perry * Carnegie Mellon requests users of this software to return to 88 1.40 riastrad * 89 1.1 perry * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 90 1.1 perry * School of Computer Science 91 1.1 perry * Carnegie Mellon University 92 1.1 perry * Pittsburgh PA 15213-3890 93 1.40 riastrad * 94 1.1 perry * any improvements or extensions that they make and grant Carnegie Mellon 95 1.1 perry * the rights to redistribute these changes. 96 1.1 perry */ 97 1.1 perry /* 98 1.1 perry Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 99 1.1 perry 100 1.1 perry All Rights Reserved 101 1.1 perry 102 1.1 perry Permission to use, copy, modify, and distribute this software and 103 1.1 perry its documentation for any purpose and without fee is hereby 104 1.1 perry granted, provided that the above copyright notice appears in all 105 1.1 perry copies and that both the copyright notice and this permission notice 106 1.1 perry appear in supporting documentation, and that the name of Intel 107 1.1 perry not be used in advertising or publicity pertaining to distribution 108 1.1 perry of the software without specific, written prior permission. 109 1.1 perry 110 1.1 perry INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 111 1.1 perry INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 112 1.1 perry IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 113 1.1 perry CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 114 1.1 perry LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 115 1.1 perry NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 116 1.1 perry WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 117 1.1 perry */ 118 1.1 perry 119 1.1 perry /* 120 1.1 perry * Primitive clock interrupt routines. 121 1.1 perry */ 122 1.1 perry 123 1.1 perry #include <sys/cdefs.h> 124 1.42 imil __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.42 2025/02/24 07:18:02 imil Exp $"); 125 1.1 perry 126 1.1 perry /* #define CLOCKDEBUG */ 127 1.1 perry /* #define CLOCK_PARANOIA */ 128 1.1 perry 129 1.1 perry #include "opt_multiprocessor.h" 130 1.1 perry #include "opt_ntp.h" 131 1.1 perry 132 1.1 perry #include <sys/param.h> 133 1.1 perry #include <sys/systm.h> 134 1.1 perry #include <sys/time.h> 135 1.1 perry #include <sys/timetc.h> 136 1.1 perry #include <sys/kernel.h> 137 1.1 perry #include <sys/device.h> 138 1.9 ad #include <sys/mutex.h> 139 1.20 ad #include <sys/cpu.h> 140 1.20 ad #include <sys/intr.h> 141 1.1 perry 142 1.1 perry #include <machine/pio.h> 143 1.1 perry #include <machine/cpufunc.h> 144 1.20 ad #include <machine/lock.h> 145 1.1 perry 146 1.1 perry #include <dev/isa/isareg.h> 147 1.1 perry #include <dev/isa/isavar.h> 148 1.1 perry #include <dev/ic/mc146818reg.h> 149 1.1 perry #include <dev/ic/i8253reg.h> 150 1.1 perry #include <i386/isa/nvram.h> 151 1.1 perry #include <x86/x86/tsc.h> 152 1.19 christos #include <x86/lock.h> 153 1.40 riastrad #include <machine/specialreg.h> 154 1.33 bouyer #include <x86/rtc.h> 155 1.41 riastrad #include <x86/intr_private.h> 156 1.1 perry 157 1.1 perry #ifndef __x86_64__ 158 1.1 perry #include "mca.h" 159 1.1 perry #endif 160 1.1 perry #if NMCA > 0 161 1.1 perry #include <machine/mca_machdep.h> /* for MCA_system */ 162 1.1 perry #endif 163 1.1 perry 164 1.1 perry #include "pcppi.h" 165 1.1 perry #if (NPCPPI > 0) 166 1.1 perry #include <dev/isa/pcppivar.h> 167 1.1 perry 168 1.27 cube int sysbeepmatch(device_t, cfdata_t, void *); 169 1.27 cube void sysbeepattach(device_t, device_t, void *); 170 1.17 dyoung int sysbeepdetach(device_t, int); 171 1.1 perry 172 1.32 dyoung CFATTACH_DECL3_NEW(sysbeep, 0, 173 1.32 dyoung sysbeepmatch, sysbeepattach, sysbeepdetach, NULL, NULL, NULL, 174 1.32 dyoung DVF_DETACH_SHUTDOWN); 175 1.1 perry 176 1.1 perry static int ppi_attached; 177 1.1 perry static pcppi_tag_t ppicookie; 178 1.1 perry #endif /* PCPPI */ 179 1.1 perry 180 1.1 perry #ifdef CLOCKDEBUG 181 1.1 perry int clock_debug = 0; 182 1.1 perry #define DPRINTF(arg) if (clock_debug) printf arg 183 1.1 perry #else 184 1.1 perry #define DPRINTF(arg) 185 1.1 perry #endif 186 1.1 perry 187 1.34 nonaka void (*x86_delay)(unsigned int) = i8254_delay; 188 1.34 nonaka 189 1.1 perry void sysbeep(int, int); 190 1.1 perry static void tickle_tc(void); 191 1.1 perry 192 1.18 he int sysbeepdetach(device_t, int); 193 1.1 perry 194 1.12 joerg static unsigned int gettick_broken_latch(void); 195 1.1 perry 196 1.1 perry static volatile uint32_t i8254_lastcount; 197 1.1 perry static volatile uint32_t i8254_offset; 198 1.1 perry static volatile int i8254_ticked; 199 1.1 perry 200 1.9 ad /* to protect TC timer variables */ 201 1.9 ad static __cpu_simple_lock_t tmr_lock = __SIMPLELOCK_UNLOCKED; 202 1.1 perry 203 1.1 perry u_int i8254_get_timecount(struct timecounter *); 204 1.1 perry 205 1.1 perry static struct timecounter i8254_timecounter = { 206 1.39 rin .tc_get_timecount = i8254_get_timecount, 207 1.39 rin .tc_counter_mask = ~0u, 208 1.39 rin .tc_frequency = TIMER_FREQ, 209 1.39 rin .tc_name = "i8254", 210 1.39 rin .tc_quality = 100, 211 1.1 perry }; 212 1.1 perry 213 1.37 bouyer u_long x86_rtclock_tval; /* i8254 reload value for countdown */ 214 1.1 perry int rtclock_init = 0; 215 1.1 perry 216 1.1 perry int clock_broken_latch = 0; 217 1.1 perry 218 1.1 perry #ifdef CLOCK_PARANOIA 219 1.1 perry static int ticks[6]; 220 1.1 perry #endif 221 1.1 perry /* 222 1.1 perry * i8254 latch check routine: 223 1.1 perry * National Geode (formerly Cyrix MediaGX) has a serious bug in 224 1.1 perry * its built-in i8254-compatible clock module. 225 1.1 perry * machdep sets the variable 'clock_broken_latch' to indicate it. 226 1.1 perry */ 227 1.1 perry 228 1.12 joerg static unsigned int 229 1.1 perry gettick_broken_latch(void) 230 1.1 perry { 231 1.1 perry int v1, v2, v3; 232 1.1 perry int w1, w2, w3; 233 1.14 ad int s; 234 1.1 perry 235 1.1 perry /* Don't want someone screwing with the counter while we're here. */ 236 1.14 ad s = splhigh(); 237 1.14 ad __cpu_simple_lock(&tmr_lock); 238 1.1 perry v1 = inb(IO_TIMER1+TIMER_CNTR0); 239 1.1 perry v1 |= inb(IO_TIMER1+TIMER_CNTR0) << 8; 240 1.1 perry v2 = inb(IO_TIMER1+TIMER_CNTR0); 241 1.1 perry v2 |= inb(IO_TIMER1+TIMER_CNTR0) << 8; 242 1.1 perry v3 = inb(IO_TIMER1+TIMER_CNTR0); 243 1.1 perry v3 |= inb(IO_TIMER1+TIMER_CNTR0) << 8; 244 1.14 ad __cpu_simple_unlock(&tmr_lock); 245 1.14 ad splx(s); 246 1.1 perry 247 1.1 perry #ifdef CLOCK_PARANOIA 248 1.1 perry if (clock_debug) { 249 1.1 perry ticks[0] = ticks[3]; 250 1.1 perry ticks[1] = ticks[4]; 251 1.1 perry ticks[2] = ticks[5]; 252 1.1 perry ticks[3] = v1; 253 1.1 perry ticks[4] = v2; 254 1.1 perry ticks[5] = v3; 255 1.1 perry } 256 1.1 perry #endif 257 1.1 perry 258 1.1 perry if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200) 259 1.1 perry return (v2); 260 1.1 perry 261 1.1 perry #define _swap_val(a, b) do { \ 262 1.1 perry int c = a; \ 263 1.1 perry a = b; \ 264 1.1 perry b = c; \ 265 1.1 perry } while (0) 266 1.1 perry 267 1.1 perry /* 268 1.1 perry * sort v1 v2 v3 269 1.1 perry */ 270 1.1 perry if (v1 < v2) 271 1.1 perry _swap_val(v1, v2); 272 1.1 perry if (v2 < v3) 273 1.1 perry _swap_val(v2, v3); 274 1.1 perry if (v1 < v2) 275 1.1 perry _swap_val(v1, v2); 276 1.1 perry 277 1.1 perry /* 278 1.1 perry * compute the middle value 279 1.1 perry */ 280 1.1 perry 281 1.1 perry if (v1 - v3 < 0x200) 282 1.1 perry return (v2); 283 1.1 perry 284 1.1 perry w1 = v2 - v3; 285 1.37 bouyer w2 = v3 - v1 + x86_rtclock_tval; 286 1.1 perry w3 = v1 - v2; 287 1.1 perry if (w1 >= w2) { 288 1.1 perry if (w1 >= w3) 289 1.1 perry return (v1); 290 1.1 perry } else { 291 1.1 perry if (w2 >= w3) 292 1.1 perry return (v2); 293 1.1 perry } 294 1.1 perry return (v3); 295 1.1 perry } 296 1.1 perry 297 1.1 perry /* minimal initialization, enough for delay() */ 298 1.1 perry void 299 1.1 perry initrtclock(u_long freq) 300 1.1 perry { 301 1.1 perry u_long tval; 302 1.9 ad 303 1.38 bouyer if (vm_guest == VM_GUEST_XENPVH) 304 1.38 bouyer return; 305 1.38 bouyer 306 1.1 perry /* 307 1.1 perry * Compute timer_count, the count-down count the timer will be 308 1.1 perry * set to. Also, correctly round 309 1.1 perry * this by carrying an extra bit through the division. 310 1.1 perry */ 311 1.1 perry tval = (freq * 2) / (u_long) hz; 312 1.1 perry tval = (tval / 2) + (tval & 0x1); 313 1.1 perry 314 1.1 perry /* initialize 8254 clock */ 315 1.1 perry outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 316 1.1 perry 317 1.1 perry /* Correct rounding will buy us a better precision in timekeeping */ 318 1.1 perry outb(IO_TIMER1+TIMER_CNTR0, tval % 256); 319 1.1 perry outb(IO_TIMER1+TIMER_CNTR0, tval / 256); 320 1.1 perry 321 1.37 bouyer x86_rtclock_tval = tval ? tval : 0xFFFF; 322 1.1 perry rtclock_init = 1; 323 1.1 perry } 324 1.1 perry 325 1.1 perry void 326 1.1 perry startrtclock(void) 327 1.1 perry { 328 1.1 perry int s; 329 1.1 perry 330 1.42 imil /* 331 1.42 imil * Check that RTC is present, bits 0 to 6 of register D are 332 1.42 imil * read-only and must be 0. At least on QEMU/microvm, when 333 1.42 imil * rtc=off, all bits are set to 1 334 1.42 imil */ 335 1.42 imil if ((mc146818_read(NULL, MC_REGD) & 0x7f) != 0) 336 1.42 imil return; 337 1.42 imil 338 1.1 perry if (!rtclock_init) 339 1.1 perry initrtclock(TIMER_FREQ); 340 1.1 perry 341 1.1 perry /* Check diagnostic status */ 342 1.1 perry if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) { /* XXX softc */ 343 1.1 perry char bits[128]; 344 1.31 christos snprintb(bits, sizeof(bits), NVRAM_DIAG_BITS, s); 345 1.31 christos printf("RTC BIOS diagnostic error %s\n", bits); 346 1.1 perry } 347 1.1 perry 348 1.1 perry tc_init(&i8254_timecounter); 349 1.1 perry rtc_register(); 350 1.1 perry } 351 1.1 perry 352 1.9 ad /* 353 1.14 ad * Must be called at splsched(). 354 1.9 ad */ 355 1.1 perry static void 356 1.40 riastrad tickle_tc(void) 357 1.1 perry { 358 1.1 perry #if defined(MULTIPROCESSOR) 359 1.1 perry struct cpu_info *ci = curcpu(); 360 1.1 perry /* 361 1.1 perry * If we are not the primary CPU, we're not allowed to do 362 1.1 perry * any more work. 363 1.1 perry */ 364 1.1 perry if (CPU_IS_PRIMARY(ci) == 0) 365 1.1 perry return; 366 1.1 perry #endif 367 1.37 bouyer if (x86_rtclock_tval && 368 1.37 bouyer timecounter->tc_get_timecount == i8254_get_timecount) { 369 1.9 ad __cpu_simple_lock(&tmr_lock); 370 1.1 perry if (i8254_ticked) 371 1.1 perry i8254_ticked = 0; 372 1.1 perry else { 373 1.37 bouyer i8254_offset += x86_rtclock_tval; 374 1.1 perry i8254_lastcount = 0; 375 1.1 perry } 376 1.9 ad __cpu_simple_unlock(&tmr_lock); 377 1.1 perry } 378 1.1 perry 379 1.1 perry } 380 1.1 perry 381 1.41 riastrad int 382 1.41 riastrad i8254_clockintr(void *arg, struct intrframe *frame) 383 1.1 perry { 384 1.1 perry tickle_tc(); 385 1.1 perry 386 1.8 yamt hardclock((struct clockframe *)frame); 387 1.1 perry 388 1.1 perry #if NMCA > 0 389 1.1 perry if (MCA_system) { 390 1.1 perry /* Reset PS/2 clock interrupt by asserting bit 7 of port 0x61 */ 391 1.1 perry outb(0x61, inb(0x61) | 0x80); 392 1.1 perry } 393 1.1 perry #endif 394 1.1 perry return -1; 395 1.1 perry } 396 1.1 perry 397 1.1 perry u_int 398 1.7 christos i8254_get_timecount(struct timecounter *tc) 399 1.1 perry { 400 1.1 perry u_int count; 401 1.14 ad uint16_t rdval; 402 1.30 ad u_long psl; 403 1.1 perry 404 1.1 perry /* Don't want someone screwing with the counter while we're here. */ 405 1.30 ad psl = x86_read_psl(); 406 1.30 ad x86_disable_intr(); 407 1.9 ad __cpu_simple_lock(&tmr_lock); 408 1.40 riastrad /* Select timer0 and latch counter value. */ 409 1.1 perry outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 410 1.14 ad /* insb to make the read atomic */ 411 1.30 ad rdval = inb(IO_TIMER1+TIMER_CNTR0); 412 1.30 ad rdval |= (inb(IO_TIMER1+TIMER_CNTR0) << 8); 413 1.37 bouyer count = x86_rtclock_tval - rdval; 414 1.37 bouyer if (x86_rtclock_tval && (count < i8254_lastcount && 415 1.37 bouyer (!i8254_ticked || x86_rtclock_tval == 0xFFFF))) { 416 1.1 perry i8254_ticked = 1; 417 1.37 bouyer i8254_offset += x86_rtclock_tval; 418 1.1 perry } 419 1.1 perry i8254_lastcount = count; 420 1.1 perry count += i8254_offset; 421 1.9 ad __cpu_simple_unlock(&tmr_lock); 422 1.30 ad x86_write_psl(psl); 423 1.1 perry 424 1.1 perry return (count); 425 1.1 perry } 426 1.1 perry 427 1.12 joerg unsigned int 428 1.1 perry gettick(void) 429 1.1 perry { 430 1.14 ad uint16_t rdval; 431 1.30 ad u_long psl; 432 1.40 riastrad 433 1.1 perry if (clock_broken_latch) 434 1.1 perry return (gettick_broken_latch()); 435 1.1 perry 436 1.1 perry /* Don't want someone screwing with the counter while we're here. */ 437 1.30 ad psl = x86_read_psl(); 438 1.30 ad x86_disable_intr(); 439 1.14 ad __cpu_simple_lock(&tmr_lock); 440 1.1 perry /* Select counter 0 and latch it. */ 441 1.1 perry outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 442 1.30 ad rdval = inb(IO_TIMER1+TIMER_CNTR0); 443 1.30 ad rdval |= (inb(IO_TIMER1+TIMER_CNTR0) << 8); 444 1.14 ad __cpu_simple_unlock(&tmr_lock); 445 1.30 ad x86_write_psl(psl); 446 1.14 ad 447 1.14 ad return rdval; 448 1.1 perry } 449 1.1 perry 450 1.1 perry /* 451 1.1 perry * Wait approximately `n' microseconds. 452 1.1 perry * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 453 1.1 perry * Note: timer had better have been programmed before this is first used! 454 1.1 perry * (Note that we use `rate generator' mode, which counts at 1:1; `square 455 1.1 perry * wave' mode counts at 2:1). 456 1.1 perry * Don't rely on this being particularly accurate. 457 1.1 perry */ 458 1.1 perry void 459 1.12 joerg i8254_delay(unsigned int n) 460 1.1 perry { 461 1.12 joerg unsigned int cur_tick, initial_tick; 462 1.12 joerg int remaining; 463 1.1 perry 464 1.1 perry /* allow DELAY() to be used before startrtclock() */ 465 1.1 perry if (!rtclock_init) 466 1.1 perry initrtclock(TIMER_FREQ); 467 1.1 perry 468 1.1 perry /* 469 1.1 perry * Read the counter first, so that the rest of the setup overhead is 470 1.1 perry * counted. 471 1.1 perry */ 472 1.12 joerg initial_tick = gettick(); 473 1.1 perry 474 1.16 joerg if (n <= UINT_MAX / TIMER_FREQ) { 475 1.1 perry /* 476 1.12 joerg * For unsigned arithmetic, division can be replaced with 477 1.12 joerg * multiplication with the inverse and a shift. 478 1.1 perry */ 479 1.12 joerg remaining = n * TIMER_FREQ / 1000000; 480 1.12 joerg } else { 481 1.12 joerg /* This is a very long delay. 482 1.12 joerg * Being slow here doesn't matter. 483 1.1 perry */ 484 1.12 joerg remaining = (unsigned long long) n * TIMER_FREQ / 1000000; 485 1.1 perry } 486 1.1 perry 487 1.30 ad while (remaining > 1) { 488 1.1 perry #ifdef CLOCK_PARANOIA 489 1.1 perry int delta; 490 1.12 joerg cur_tick = gettick(); 491 1.12 joerg if (cur_tick > initial_tick) 492 1.37 bouyer delta = x86_rtclock_tval - (cur_tick - initial_tick); 493 1.1 perry else 494 1.12 joerg delta = initial_tick - cur_tick; 495 1.37 bouyer if (delta < 0 || delta >= x86_rtclock_tval / 2) { 496 1.1 perry DPRINTF(("delay: ignore ticks %.4x-%.4x", 497 1.12 joerg initial_tick, cur_tick)); 498 1.1 perry if (clock_broken_latch) { 499 1.1 perry DPRINTF((" (%.4x %.4x %.4x %.4x %.4x %.4x)\n", 500 1.1 perry ticks[0], ticks[1], ticks[2], 501 1.1 perry ticks[3], ticks[4], ticks[5])); 502 1.1 perry } else { 503 1.1 perry DPRINTF(("\n")); 504 1.1 perry } 505 1.1 perry } else 506 1.12 joerg remaining -= delta; 507 1.1 perry #else 508 1.12 joerg cur_tick = gettick(); 509 1.12 joerg if (cur_tick > initial_tick) 510 1.37 bouyer remaining -= x86_rtclock_tval - (cur_tick - initial_tick); 511 1.1 perry else 512 1.12 joerg remaining -= initial_tick - cur_tick; 513 1.1 perry #endif 514 1.12 joerg initial_tick = cur_tick; 515 1.1 perry } 516 1.1 perry } 517 1.1 perry 518 1.1 perry #if (NPCPPI > 0) 519 1.1 perry int 520 1.27 cube sysbeepmatch(device_t parent, cfdata_t match, void *aux) 521 1.1 perry { 522 1.38 bouyer if (vm_guest == VM_GUEST_XENPVH) 523 1.38 bouyer return 0; 524 1.1 perry return (!ppi_attached); 525 1.1 perry } 526 1.1 perry 527 1.1 perry void 528 1.27 cube sysbeepattach(device_t parent, device_t self, void *aux) 529 1.1 perry { 530 1.1 perry aprint_naive("\n"); 531 1.1 perry aprint_normal("\n"); 532 1.1 perry 533 1.1 perry ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie; 534 1.1 perry ppi_attached = 1; 535 1.15 jmcneill 536 1.15 jmcneill if (!pmf_device_register(self, NULL, NULL)) 537 1.15 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 538 1.1 perry } 539 1.1 perry 540 1.17 dyoung int 541 1.17 dyoung sysbeepdetach(device_t self, int flags) 542 1.17 dyoung { 543 1.17 dyoung pmf_device_deregister(self); 544 1.17 dyoung ppi_attached = 0; 545 1.17 dyoung return 0; 546 1.17 dyoung } 547 1.21 dyoung #endif 548 1.17 dyoung 549 1.1 perry void 550 1.7 christos sysbeep(int pitch, int period) 551 1.1 perry { 552 1.1 perry #if (NPCPPI > 0) 553 1.1 perry if (ppi_attached) 554 1.1 perry pcppi_bell(ppicookie, pitch, period, 0); 555 1.1 perry #endif 556 1.1 perry } 557 1.1 perry 558 1.1 perry void 559 1.1 perry i8254_initclocks(void) 560 1.1 perry { 561 1.1 perry 562 1.1 perry /* 563 1.1 perry * XXX If you're doing strange things with multiple clocks, you might 564 1.1 perry * want to keep track of clock handlers. 565 1.41 riastrad * 566 1.41 riastrad * XXX This is an abuse of the interrupt handler signature with 567 1.41 riastrad * __FPTRCAST which requires a special case for IPL_CLOCK in 568 1.41 riastrad * intr_establish_xname. Please fix this nonsense! See also 569 1.41 riastrad * the comments about i8254_clockintr in x86/x86/intr.c. 570 1.1 perry */ 571 1.1 perry (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, 572 1.41 riastrad __FPTRCAST(int (*)(void *), i8254_clockintr), 0); 573 1.1 perry } 574 1.1 perry 575 1.1 perry void 576 1.7 christos setstatclockrate(int arg) 577 1.1 perry { 578 1.1 perry } 579