clock.c revision 1.17
1/* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ 2 3/*- 4 * Copyright (c) 1993, 1994 Charles Hannum. 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * William Jolitz and Don Ahn. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)clock.c 7.2 (Berkeley) 5/12/91 40 */ 41/* 42 * Mach Operating System 43 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 44 * All Rights Reserved. 45 * 46 * Permission to use, copy, modify and distribute this software and its 47 * documentation is hereby granted, provided that both the copyright 48 * notice and this permission notice appear in all copies of the 49 * software, derivative works or modified versions, and any portions 50 * thereof, and that both notices appear in supporting documentation. 51 * 52 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 53 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 54 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 55 * 56 * Carnegie Mellon requests users of this software to return to 57 * 58 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 59 * School of Computer Science 60 * Carnegie Mellon University 61 * Pittsburgh PA 15213-3890 62 * 63 * any improvements or extensions that they make and grant Carnegie Mellon 64 * the rights to redistribute these changes. 65 */ 66/* 67 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 68 69 All Rights Reserved 70 71Permission to use, copy, modify, and distribute this software and 72its documentation for any purpose and without fee is hereby 73granted, provided that the above copyright notice appears in all 74copies and that both the copyright notice and this permission notice 75appear in supporting documentation, and that the name of Intel 76not be used in advertising or publicity pertaining to distribution 77of the software without specific, written prior permission. 78 79INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 80INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 81IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 82CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 83LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 84NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 85WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 86*/ 87 88/* 89 * Primitive clock interrupt routines. 90 */ 91#include <sys/param.h> 92#include <sys/systm.h> 93#include <sys/time.h> 94#include <sys/kernel.h> 95#include <sys/device.h> 96 97#include <machine/cpu.h> 98#include <machine/intr.h> 99#include <machine/pio.h> 100#include <machine/cpufunc.h> 101 102#include <dev/isa/isareg.h> 103#include <dev/isa/isavar.h> 104#include <dev/ic/mc146818reg.h> 105#include <i386/isa/nvram.h> 106#include <i386/isa/timerreg.h> 107 108#include "pcppi.h" 109#if (NPCPPI > 0) 110#include <dev/isa/pcppivar.h> 111 112#define __BROKEN_INDIRECT_CONFIG /* XXX */ 113#ifdef __BROKEN_INDIRECT_CONFIG 114int sysbeepmatch __P((struct device *, void *, void *)); 115#else 116int sysbeepmatch __P((struct device *, struct cfdata *, void *)); 117#endif 118void sysbeepattach __P((struct device *, struct device *, void *)); 119 120struct cfattach sysbeep_ca = { 121 sizeof(struct device), sysbeepmatch, sysbeepattach 122}; 123 124struct cfdriver sysbeep_cd = { 125 NULL, "sysbeep", DV_DULL 126}; 127 128static int ppi_attached; 129static pcppi_tag_t ppicookie; 130#endif /* PCPPI */ 131 132void spinwait __P((int)); 133void findcpuspeed __P((void)); 134int clockintr __P((void *)); 135int gettick __P((void)); 136void sysbeep __P((int, int)); 137int rtcget __P((mc_todregs *)); 138void rtcput __P((mc_todregs *)); 139static int yeartoday __P((int)); 140int hexdectodec __P((int)); 141int dectohexdec __P((int)); 142int rtcintr __P((void *)); 143 144__inline u_int mc146818_read __P((void *, u_int)); 145__inline void mc146818_write __P((void *, u_int, u_int)); 146 147#if defined(I586_CPU) || defined(I686_CPU) 148int pentium_mhz; 149#endif 150 151#define SECMIN ((unsigned)60) /* seconds per minute */ 152#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ 153#define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ 154#define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ 155 156__inline u_int 157mc146818_read(sc, reg) 158 void *sc; /* XXX use it? */ 159 u_int reg; 160{ 161 162 outb(IO_RTC, reg); 163 return (inb(IO_RTC+1)); 164} 165 166__inline void 167mc146818_write(sc, reg, datum) 168 void *sc; /* XXX use it? */ 169 u_int reg, datum; 170{ 171 172 outb(IO_RTC, reg); 173 outb(IO_RTC+1, datum); 174} 175 176void 177startrtclock() 178{ 179 int s; 180 181 findcpuspeed(); /* use the clock (while it's free) 182 to find the cpu speed */ 183 /* initialize 8253 clock */ 184 outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 185 186 /* Correct rounding will buy us a better precision in timekeeping */ 187 outb(IO_TIMER1, TIMER_DIV(hz) % 256); 188 outb(IO_TIMER1, TIMER_DIV(hz) / 256); 189 190 /* Check diagnostic status */ 191 if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ 192 printf("RTC BIOS diagnostic error %b\n", (unsigned int) s, 193 NVRAM_DIAG_BITS); 194} 195 196int 197clockintr(arg) 198 void *arg; 199{ 200 struct clockframe *frame = arg; /* not strictly necessary */ 201 202 hardclock(frame); 203 return 1; 204} 205 206int 207rtcintr(arg) 208 void *arg; 209{ 210 struct clockframe *frame = arg; /* not strictly neccecary */ 211 u_int stat; 212 213 stat = mc146818_read(NULL, MC_REGC); 214 if (stat & MC_REGC_PF) { 215 statclock(frame); 216 return 1; 217 } 218 return 0; 219} 220 221int 222gettick() 223{ 224 u_char lo, hi; 225 226 /* Don't want someone screwing with the counter while we're here. */ 227 disable_intr(); 228 /* Select counter 0 and latch it. */ 229 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 230 lo = inb(TIMER_CNTR0); 231 hi = inb(TIMER_CNTR0); 232 enable_intr(); 233 return ((hi << 8) | lo); 234} 235 236/* 237 * Wait "n" microseconds. 238 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 239 * Note: timer had better have been programmed before this is first used! 240 * (Note that we use `rate generator' mode, which counts at 1:1; `square 241 * wave' mode counts at 2:1). 242 */ 243void 244delay(n) 245 int n; 246{ 247 int limit, tick, otick; 248 249 /* 250 * Read the counter first, so that the rest of the setup overhead is 251 * counted. 252 */ 253 otick = gettick(); 254 255#ifdef __GNUC__ 256 /* 257 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so 258 * we can take advantage of the intermediate 64-bit quantity to prevent 259 * loss of significance. 260 */ 261 n -= 5; 262 if (n < 0) 263 return; 264 {register int m; 265 __asm __volatile("mul %3" 266 : "=a" (n), "=d" (m) 267 : "0" (n), "r" (TIMER_FREQ)); 268 __asm __volatile("div %3" 269 : "=a" (n) 270 : "0" (n), "d" (m), "r" (1000000) 271 : "%edx");} 272#else 273 /* 274 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and 275 * without any avoidable overflows. 276 */ 277 n -= 20; 278 { 279 int sec = n / 1000000, 280 usec = n % 1000000; 281 n = sec * TIMER_FREQ + 282 usec * (TIMER_FREQ / 1000000) + 283 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + 284 usec * (TIMER_FREQ % 1000) / 1000000; 285 } 286#endif 287 288 limit = TIMER_FREQ / hz; 289 290 while (n > 0) { 291 tick = gettick(); 292 if (tick > otick) 293 n -= limit - (tick - otick); 294 else 295 n -= otick - tick; 296 otick = tick; 297 } 298} 299 300#if (NPCPPI > 0) 301int 302sysbeepmatch(parent, match, aux) 303 struct device *parent; 304#ifdef __BROKEN_INDIRECT_CONFIG 305 void *match; 306#else 307 struct cfdata *match; 308#endif 309 void *aux; 310{ 311 return (!ppi_attached); 312} 313 314void 315sysbeepattach(parent, self, aux) 316 struct device *parent, *self; 317 void *aux; 318{ 319 printf("\n"); 320 321 ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie; 322 ppi_attached = 1; 323} 324#endif 325 326void 327sysbeep(pitch, period) 328 int pitch, period; 329{ 330#if (NPCPPI > 0) 331 if (ppi_attached) 332 pcppi_bell(ppicookie, pitch, period, 0); 333#endif 334} 335 336unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ 337 338#define FIRST_GUESS 0x2000 339 340void 341findcpuspeed() 342{ 343 int i; 344 int remainder; 345 346 /* Put counter in count down mode */ 347 outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 348 outb(TIMER_CNTR0, 0xff); 349 outb(TIMER_CNTR0, 0xff); 350 for (i = FIRST_GUESS; i; i--) 351 ; 352 /* Read the value left in the counter */ 353 remainder = gettick(); 354 /* 355 * Formula for delaycount is: 356 * (loopcount * timer clock speed) / (counter ticks * 1000) 357 */ 358 delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder); 359} 360 361#if defined(I586_CPU) || defined(I686_CPU) 362void 363calibrate_cyclecounter() 364{ 365 unsigned long long count, last_count; 366#ifdef NTP 367 extern long time_precision; 368#endif 369 370 __asm __volatile(".byte 0xf, 0x31" : "=A" (last_count)); 371 delay(1000000); 372 __asm __volatile(".byte 0xf, 0x31" : "=A" (count)); 373 pentium_mhz = ((count - last_count) + 500000) / 1000000; 374#ifdef NTP 375 time_precision = 1; /* XXX */ 376#endif 377} 378#endif 379 380void 381cpu_initclocks() 382{ 383 stathz = 128; 384 profhz = 1024; 385 386 /* 387 * XXX If you're doing strange things with multiple clocks, you might 388 * want to keep track of clock handlers. 389 */ 390 (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr, 391 0, "clock"); 392 (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr, 393 0, "rtc"); 394 395 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 396 mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE); 397} 398 399int 400rtcget(regs) 401 mc_todregs *regs; 402{ 403 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ 404 return (-1); 405 MC146818_GETTOD(NULL, regs); /* XXX softc */ 406 return (0); 407} 408 409void 410rtcput(regs) 411 mc_todregs *regs; 412{ 413 MC146818_PUTTOD(NULL, regs); /* XXX softc */ 414} 415 416static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 417 418static int 419yeartoday(year) 420 int year; 421{ 422 423 return (((year % 4) == 0 && 424 ((year % 100) != 0 || (year % 400) == 0))? 366 : 365); 425} 426 427int 428hexdectodec(n) 429 int n; 430{ 431 432 return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); 433} 434 435int 436dectohexdec(n) 437 int n; 438{ 439 440 return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); 441} 442 443static int timeset; 444 445/* 446 * Initialize the time of day register, based on the time base which is, e.g. 447 * from a filesystem. 448 */ 449void 450inittodr(base) 451 time_t base; 452{ 453 mc_todregs rtclk; 454 time_t n; 455 int sec, min, hr, dom, mon, yr; 456 int i, days = 0; 457 int s; 458 459 /* 460 * We mostly ignore the suggested time and go for the RTC clock time 461 * stored in the CMOS RAM. If the time can't be obtained from the 462 * CMOS, or if the time obtained from the CMOS is 5 or more years 463 * less than the suggested time, we used the suggested time. (In 464 * the latter case, it's likely that the CMOS battery has died.) 465 */ 466 467 if (base < 15*SECYR) { /* if before 1985, something's odd... */ 468 printf("WARNING: preposterous time in file system\n"); 469 /* read the system clock anyway */ 470 base = 17*SECYR + 186*SECDAY + SECDAY/2; 471 } 472 473 s = splclock(); 474 if (rtcget(&rtclk)) { 475 splx(s); 476 printf("WARNING: invalid time in clock chip\n"); 477 goto fstime; 478 } 479 splx(s); 480 481 sec = hexdectodec(rtclk[MC_SEC]); 482 min = hexdectodec(rtclk[MC_MIN]); 483 hr = hexdectodec(rtclk[MC_HOUR]); 484 dom = hexdectodec(rtclk[MC_DOM]); 485 mon = hexdectodec(rtclk[MC_MONTH]); 486 yr = hexdectodec(rtclk[MC_YEAR]); 487 yr = (yr < 70) ? yr+100 : yr; 488 489 n = sec + 60 * min + 3600 * hr; 490 n += (dom - 1) * 3600 * 24; 491 492 if (yeartoday(yr) == 366) 493 month[1] = 29; 494 for (i = mon - 2; i >= 0; i--) 495 days += month[i]; 496 month[1] = 28; 497 for (i = 70; i < yr; i++) 498 days += yeartoday(i); 499 n += days * 3600 * 24; 500 501 n += tz.tz_minuteswest * 60; 502 if (tz.tz_dsttime) 503 n -= 3600; 504 505 if (base < n - 5*SECYR) 506 printf("WARNING: file system time much less than clock time\n"); 507 else if (base > n + 5*SECYR) { 508 printf("WARNING: clock time much less than file system time\n"); 509 printf("WARNING: using file system time\n"); 510 goto fstime; 511 } 512 513 timeset = 1; 514 time.tv_sec = n; 515 time.tv_usec = 0; 516 return; 517 518fstime: 519 timeset = 1; 520 time.tv_sec = base; 521 time.tv_usec = 0; 522 printf("WARNING: CHECK AND RESET THE DATE!\n"); 523} 524 525/* 526 * Reset the clock. 527 */ 528void 529resettodr() 530{ 531 mc_todregs rtclk; 532 time_t n; 533 int diff, i, j; 534 int s; 535 536 /* 537 * We might have been called by boot() due to a crash early 538 * on. Don't reset the clock chip in this case. 539 */ 540 if (!timeset) 541 return; 542 543 s = splclock(); 544 if (rtcget(&rtclk)) 545 bzero(&rtclk, sizeof(rtclk)); 546 splx(s); 547 548 diff = tz.tz_minuteswest * 60; 549 if (tz.tz_dsttime) 550 diff -= 3600; 551 n = (time.tv_sec - diff) % (3600 * 24); /* hrs+mins+secs */ 552 rtclk[MC_SEC] = dectohexdec(n % 60); 553 n /= 60; 554 rtclk[MC_MIN] = dectohexdec(n % 60); 555 rtclk[MC_HOUR] = dectohexdec(n / 60); 556 557 n = (time.tv_sec - diff) / (3600 * 24); /* days */ 558 rtclk[MC_DOW] = (n + 4) % 7; /* 1/1/70 is Thursday */ 559 560 for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j)) 561 n -= i; 562 563 rtclk[MC_YEAR] = dectohexdec(j - 1900); 564 565 if (i == 366) 566 month[1] = 29; 567 for (i = 0; n >= month[i]; i++) 568 n -= month[i]; 569 month[1] = 28; 570 rtclk[MC_MONTH] = dectohexdec(++i); 571 572 rtclk[MC_DOM] = dectohexdec(++n); 573 574 s = splclock(); 575 rtcput(&rtclk); 576 splx(s); 577} 578 579void 580setstatclockrate(arg) 581 int arg; 582{ 583 if (arg == stathz) 584 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 585 else 586 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz); 587} 588