1 /* $NetBSD: clock.c,v 1.1 2002/02/10 01:57:51 thorpej Exp $ */ 2 3 /* 4 * Copyright 1997 5 * Digital Equipment Corporation. All rights reserved. 6 * 7 * This software is furnished under license and may be used and 8 * copied only in accordance with the following terms and conditions. 9 * Subject to these conditions, you may download, copy, install, 10 * use, modify and distribute this software in source and/or binary 11 * form. No title or ownership is transferred hereby. 12 * 13 * 1) Any source code used, modified or distributed must reproduce 14 * and retain this copyright notice and list of conditions as 15 * they appear in the source file. 16 * 17 * 2) No right is granted to use any trade name, trademark, or logo of 18 * Digital Equipment Corporation. Neither the "Digital Equipment 19 * Corporation" name nor any trademark or logo of Digital Equipment 20 * Corporation may be used to endorse or promote products derived 21 * from this software without the prior written permission of 22 * Digital Equipment Corporation. 23 * 24 * 3) This software is provided "AS-IS" and any express or implied 25 * warranties, including but not limited to, any implied warranties 26 * of merchantability, fitness for a particular purpose, or 27 * non-infringement are disclaimed. In no event shall DIGITAL be 28 * liable for any damages whatsoever, and in particular, DIGITAL 29 * shall not be liable for special, indirect, consequential, or 30 * incidental damages or damages for lost profits, loss of 31 * revenue or loss of use, whether such damages arise in contract, 32 * negligence, tort, under statute, in equity, at law or otherwise, 33 * even if advised of the possibility of such damage. 34 */ 35 36 /*- 37 * Copyright (c) 1993, 1994 Charles M. Hannum. 38 * Copyright (c) 1990 The Regents of the University of California. 39 * All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * William Jolitz and Don Ahn. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)clock.c 7.2 (Berkeley) 5/12/91 73 */ 74 /* 75 * Mach Operating System 76 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 77 * All Rights Reserved. 78 * 79 * Permission to use, copy, modify and distribute this software and its 80 * documentation is hereby granted, provided that both the copyright 81 * notice and this permission notice appear in all copies of the 82 * software, derivative works or modified versions, and any portions 83 * thereof, and that both notices appear in supporting documentation. 84 * 85 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 86 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 87 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 88 * 89 * Carnegie Mellon requests users of this software to return to 90 * 91 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 92 * School of Computer Science 93 * Carnegie Mellon University 94 * Pittsburgh PA 15213-3890 95 * 96 * any improvements or extensions that they make and grant Carnegie Mellon 97 * the rights to redistribute these changes. 98 */ 99 /* 100 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 101 102 All Rights Reserved 103 104 Permission to use, copy, modify, and distribute this software and 105 its documentation for any purpose and without fee is hereby 106 granted, provided that the above copyright notice appears in all 107 copies and that both the copyright notice and this permission notice 108 appear in supporting documentation, and that the name of Intel 109 not be used in advertising or publicity pertaining to distribution 110 of the software without specific, written prior permission. 111 112 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 113 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 114 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 115 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 116 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 117 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 118 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 119 */ 120 121 /* 122 * Primitive clock interrupt routines. 123 */ 124 #include <sys/param.h> 125 #include <sys/systm.h> 126 #include <sys/time.h> 127 #include <sys/kernel.h> 128 #include <sys/device.h> 129 130 #include <machine/cpu.h> 131 #include <machine/intr.h> 132 #include <machine/pio.h> 133 #include <arm/cpufunc.h> 134 135 #include <dev/isa/isareg.h> 136 #include <dev/isa/isavar.h> 137 #include <dev/ic/mc146818reg.h> 138 #include <dev/ic/i8253reg.h> 139 #include <shark/isa/nvram.h> 140 #include <shark/isa/spkrreg.h> 141 142 #ifdef SHARK 143 #include <shark/shark/hat.h> 144 #endif 145 146 void sysbeepstop __P((void *)); 147 void sysbeep __P((int, int)); 148 void rtcinit __P((void)); 149 int timer_hz_to_count(int); 150 151 static void findcpuspeed __P((void)); 152 static void init_isa_timer_tables(); 153 static void delayloop(int); 154 static int clockintr __P((void *)); 155 static int gettick __P((void)); 156 157 __inline u_int mc146818_read __P((void *, u_int)); 158 __inline void mc146818_write __P((void *, u_int, u_int)); 159 160 #define SECMIN ((unsigned)60) /* seconds per minute */ 161 #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ 162 #define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ 163 #define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ 164 165 __inline u_int 166 mc146818_read(sc, reg) 167 void *sc; /* XXX use it? */ 168 u_int reg; 169 { 170 171 outb(IO_RTC, reg); 172 return (inb(IO_RTC+1)); 173 } 174 175 __inline void 176 mc146818_write(sc, reg, datum) 177 void *sc; /* XXX use it? */ 178 u_int reg, datum; 179 { 180 181 outb(IO_RTC, reg); 182 outb(IO_RTC+1, datum); 183 } 184 185 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */ 186 187 /* number of timer ticks in a Musec = 2^20 usecs */ 188 #define TIMER_MUSECFREQ\ 189 (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000) 190 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x)) 191 192 /* 193 * microtime() makes use of the following globals. 194 * timer_msb_table[] and timer_lsb_table[] are used to compute the 195 * microsecond increment. 196 * 197 * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb]; 198 */ 199 200 u_short isa_timer_msb_table[256]; /* timer->usec MSB */ 201 u_short isa_timer_lsb_table[256]; /* timer->usec conversion for LSB */ 202 203 /* 64 bit counts from timer 0 */ 204 struct count64 { 205 unsigned lo; /* low 32 bits */ 206 unsigned hi; /* high 32 bits */ 207 }; 208 209 #define TIMER0_ROLLOVER 0xFFFF /* maximum rollover for 8254 counter */ 210 211 struct count64 timer0count; 212 struct count64 timer0_at_last_clockintr; 213 unsigned timer0last; 214 215 /*#define TESTHAT*/ 216 #ifdef TESTHAT 217 #define HATSTACKSIZE 1024 218 #define HATHZ 50000 219 #define HATHZ2 10000 220 unsigned char hatStack[HATSTACKSIZE]; 221 222 unsigned testHatOn = 0; 223 unsigned nHats = 0; 224 unsigned nHatWedges = 0; 225 unsigned fiqReason = 0; 226 unsigned hatCount = 0; 227 unsigned hatCount2 = 0; 228 229 void hatTest(int testReason) 230 { 231 fiqReason |= testReason; 232 nHats++; 233 234 } 235 236 void hatWedge(int nFIQs) 237 { 238 printf("Unwedging the HAT. fiqs_happened = %d\n", nFIQs); 239 nHatWedges++; 240 } 241 #endif 242 243 void 244 startrtclock() 245 { 246 findcpuspeed(); /* use the clock (while it's free) 247 to find the cpu speed */ 248 249 init_isa_timer_tables(); 250 251 timer0count.lo = 0; 252 timer0count.hi = 0; 253 timer0_at_last_clockintr.lo = 0; 254 timer0_at_last_clockintr.hi = 0; 255 timer0last = 0; 256 257 /* initialize 8253 clock */ 258 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 259 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256); 260 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256); 261 262 #ifdef TESTHAT 263 hatCount = timer_hz_to_count(HATHZ); 264 hatCount2 = timer_hz_to_count(HATHZ2); 265 printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount); 266 #endif 267 } 268 269 static void 270 init_isa_timer_tables() 271 { 272 int s; 273 u_long t, msbmillion, quotient, remainder; 274 275 for (s = 0; s < 256; s++) { 276 /* LSB table is easy, just divide and round */ 277 t = ((u_long) s * 1000000 * 2) / TIMER_FREQ; 278 isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1)); 279 280 msbmillion = s * 1000000; 281 quotient = msbmillion / TIMER_FREQ; 282 remainder = msbmillion % TIMER_FREQ; 283 t = (remainder * 256 * 2) / TIMER_FREQ; 284 isa_timer_msb_table[s] = 285 (u_short)((t / 2) + (t & 1) + (quotient * 256)); 286 287 #ifdef DIAGNOSTIC 288 if ((s > 0) && 289 (isa_timer_msb_table[s] < 290 (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF]))) 291 panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n", 292 s, isa_timer_msb_table[s], 293 isa_timer_msb_table[s - 1], 294 isa_timer_lsb_table[0xFF], 295 isa_timer_msb_table[s - 1] + 296 isa_timer_lsb_table[0xFF]); 297 #endif 298 } /* END for */ 299 } 300 301 int 302 timer_hz_to_count(timer_hz) 303 int timer_hz; 304 { 305 u_long tval; 306 307 tval = (TIMER_FREQ * 2) / (u_long) timer_hz; 308 tval = (tval / 2) + (tval & 0x1); 309 310 return (int)tval; 311 312 } 313 314 /* must be called at SPL_CLOCK or higher */ 315 void gettimer0count(pcount) 316 struct count64 *pcount; 317 { 318 unsigned current, ticks, oldlo; 319 320 /* 321 * Latch the current value of the timer and then read it. 322 * This guarentees an atomic reading of the time. 323 */ 324 325 current = gettick(); 326 327 if (timer0last >= current) 328 ticks = timer0last - current; 329 else 330 ticks = timer0last + (TIMER0_ROLLOVER - current); 331 332 timer0last = current; 333 334 oldlo = timer0count.lo; 335 336 if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */ 337 timer0count.hi++; 338 339 *pcount = timer0count; 340 } 341 342 static int 343 clockintr(arg) 344 void *arg; 345 { 346 struct clockframe *frame = arg; /* not strictly necessary */ 347 extern void isa_specific_eoi(int irq); 348 #ifdef TESTHAT 349 static int ticks = 0; 350 #endif 351 #ifdef SHARK 352 static int hatUnwedgeCtr = 0; 353 #endif 354 355 gettimer0count(&timer0_at_last_clockintr); 356 357 mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */ 358 359 #ifdef SHARK 360 /* check to see if the high-availability timer needs to be unwedged */ 361 if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) { 362 hatUnwedgeCtr = 0; 363 hatUnwedge(); 364 } 365 #endif 366 367 #ifdef TESTHAT 368 ++ticks; 369 370 if (testHatOn && ((ticks & 0x3f) == 0)) { 371 if (testHatOn == 1) { 372 hatClkAdjust(hatCount2); 373 testHatOn = 2; 374 } else { 375 testHatOn = 0; 376 hatClkOff(); 377 printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason); 378 } 379 } else if (!testHatOn && (ticks & 0x1ff) == 0) { 380 printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason); 381 testHatOn = 1; 382 nHats = 0; 383 fiqReason = 0; 384 hatClkOn(hatCount, hatTest, 0xfeedface, 385 hatStack + HATSTACKSIZE - sizeof(unsigned), 386 hatWedge); 387 } 388 #endif 389 hardclock(frame); 390 return(0); 391 } 392 393 static int 394 gettick() 395 { 396 u_char lo, hi; 397 u_int savedints; 398 399 /* Don't want someone screwing with the counter while we're here. */ 400 savedints = disable_interrupts(I32_bit); 401 /* Select counter 0 and latch it. */ 402 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 403 lo = inb(IO_TIMER1 + TIMER_CNTR0); 404 hi = inb(IO_TIMER1 + TIMER_CNTR0); 405 restore_interrupts(savedints); 406 return ((hi << 8) | lo); 407 } 408 409 /* modifications from i386 to shark isa version: 410 - removed hardcoded "n -=" values that approximated the time to 411 calculate delay ticks 412 - made the time to calculate delay ticks almost negligable. 4 multiplies 413 = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts; 414 as opposed to 4 multiplies plus a bunch of divides. 415 - removed i386 assembly language hack 416 - put code in findcpuspeed that works even if FIRST_GUESS is orders 417 of magnitude low 418 - put code in delay() to use delayloop() for short delays 419 - microtime no longer in assembly language 420 */ 421 422 /* 423 * Wait "n" microseconds. 424 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 425 * Note: timer had better have been programmed before this is first used! 426 * (Note that we use `rate generator' mode, which counts at 1:1; `square 427 * wave' mode counts at 2:1). 428 */ 429 void 430 delay(n) 431 unsigned n; 432 { 433 int tick, otick; 434 int nticks; 435 436 if (n < 100) { 437 /* it can take a long time (1 usec or longer) just for 1 ISA read, 438 so it's best not to use the timer for short delays */ 439 delayloop((n * count1024usec) >> 10); 440 return; 441 } 442 443 /* 444 * Read the counter first, so that the rest of the setup overhead is 445 * counted. 446 */ 447 otick = gettick(); 448 449 /* 450 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and 451 * without any avoidable overflows. 452 */ 453 { 454 /* a Musec = 2^20 usec */ 455 int Musec = n >> 20, 456 usec = n & ((1 << 20) - 1); 457 nticks 458 = (Musec * TIMER_MUSECFREQ) + 459 (usec * (TIMER_MUSECFREQ >> 20)) + 460 ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) + 461 ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20); 462 } 463 464 while (nticks > 0) { 465 tick = gettick(); 466 if (tick > otick) 467 nticks -= TIMER0_ROLLOVER - (tick - otick); 468 else 469 nticks -= otick - tick; 470 otick = tick; 471 } 472 473 } 474 475 void 476 sysbeepstop(arg) 477 void *arg; 478 { 479 } 480 481 void 482 sysbeep(pitch, period) 483 int pitch, period; 484 { 485 } 486 487 #define FIRST_GUESS 0x2000 488 489 static void 490 findcpuspeed() 491 { 492 int ticks; 493 unsigned int guess = FIRST_GUESS; 494 495 while (1) { /* loop until accurate enough */ 496 /* Put counter in count down mode */ 497 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 498 outb(IO_TIMER1 + TIMER_CNTR0, 0xff); 499 outb(IO_TIMER1 + TIMER_CNTR0, 0xff); 500 delayloop(guess); 501 502 /* Read the value left in the counter */ 503 /* 504 * Formula for delaycount is: 505 * (loopcount * timer clock speed) / (counter ticks * 1000) 506 */ 507 ticks = 0xFFFF - gettick(); 508 if (ticks == 0) ticks = 1; /* just in case */ 509 if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */ 510 guess *= max(2, (TIMER_MUSECDIV(1024) / ticks)); 511 continue; 512 } 513 count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks; 514 return; 515 } 516 } 517 518 static void 519 delayloop(counts) 520 { 521 while (counts--); 522 } 523 524 void 525 cpu_initclocks() 526 { 527 unsigned hzval; 528 529 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 530 531 /* install RTC interrupt handler */ 532 (void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK, 533 clockintr, 0); 534 535 /* code for values of hz that don't divide 1000000 exactly */ 536 tickfix = 1000000 - (hz * tick); 537 if (tickfix) { 538 int ftp; 539 540 ftp = min(ffs(tickfix), ffs(hz)); 541 tickfix >>= (ftp - 1); 542 tickfixinterval = hz >> (ftp - 1); 543 } 544 545 /* set up periodic interrupt @ hz 546 this is the subset of hz values in kern_clock.c that are 547 supported by the ISA RTC */ 548 switch (hz) { 549 case 64: 550 hzval = MC_RATE_64_Hz; 551 break; 552 case 128: 553 hzval = MC_RATE_128_Hz; 554 break; 555 case 256: 556 hzval = MC_RATE_256_Hz; 557 break; 558 case 1024: 559 hzval = MC_RATE_1024_Hz; 560 break; 561 default: 562 panic("cannot configure hz = %d\n", hz); 563 } 564 565 rtcinit(); /* make sure basics are done by now */ 566 567 /* blast values to set up clock interrupt */ 568 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval); 569 /* enable periodic interrupt */ 570 mc146818_write(NULL, MC_REGB, 571 mc146818_read(NULL, MC_REGB) | MC_REGB_PIE); 572 } 573 574 void 575 rtcinit() 576 { 577 static int first_rtcopen_ever = 1; 578 579 if (!first_rtcopen_ever) 580 return; 581 first_rtcopen_ever = 0; 582 583 mc146818_write(NULL, MC_REGA, /* XXX softc */ 584 MC_BASE_32_KHz | MC_RATE_1024_Hz); 585 mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */ 586 } 587 588 void 589 setstatclockrate(arg) 590 int arg; 591 { 592 } 593 594 /* 595 * void microtime(struct timeval *tvp) 596 * 597 * Fill in the specified timeval struct with the current time 598 * accurate to the microsecond. 599 */ 600 601 void 602 microtime(tvp) 603 struct timeval *tvp; 604 { 605 int s; 606 unsigned lsb, msb; 607 int tm; 608 static struct timeval oldtv; 609 struct count64 timer0current; 610 int ticks; 611 612 s = splstatclock(); 613 614 gettimer0count(&timer0current); 615 616 tm = time.tv_usec; 617 618 /* unsigned arithmetic should take care of overflow */ 619 /* with a >= 32 Hz clock, ticks will always be < 0x7FFF */ 620 ticks = (int)((unsigned) 621 (timer0current.lo - timer0_at_last_clockintr.lo)); 622 623 #ifdef DIAGNOSTIC 624 if ((ticks < 0) || (ticks > 0xffff)) 625 printf("microtime bug: ticks = %x\n", ticks); 626 #endif 627 628 while (ticks > 0) { 629 630 if (ticks < 0xffff) { 631 msb = (ticks >> 8) & 0xFF; 632 lsb = ticks & 0xFF; 633 } else { 634 msb = 0xff; 635 lsb = 0xff; 636 } 637 638 /* see comments above */ 639 tm += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb]; 640 641 /* for a 64 Hz RTC, ticks will never overflow table */ 642 /* microtime will be less accurate if the RTC is < 36 Hz */ 643 ticks -= 0xffff; 644 } 645 646 tvp->tv_sec = time.tv_sec; 647 if (tm >= 1000000) { 648 tvp->tv_sec += 1; 649 tm -= 1000000; 650 } 651 652 tvp->tv_usec = tm; 653 654 /* Make sure the time has advanced. */ 655 656 if (tvp->tv_sec == oldtv.tv_sec && 657 tvp->tv_usec <= oldtv.tv_usec) { 658 tvp->tv_usec = oldtv.tv_usec + 1; 659 if (tvp->tv_usec >= 1000000) { 660 tvp->tv_usec -= 1000000; 661 ++tvp->tv_sec; 662 } 663 } 664 665 oldtv = *tvp; 666 (void)splx(s); 667 } 668 669 /* End of clock.c */ 670