1 /* $NetBSD: clock.c,v 1.3 2002/10/05 17:01:49 chs 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 #include <shark/shark/hat.h> 142 143 void sysbeepstop(void *); 144 void sysbeep(int, int); 145 void rtcinit(void); 146 int timer_hz_to_count(int); 147 148 static void findcpuspeed(void); 149 static void init_isa_timer_tables(void); 150 static void delayloop(int); 151 static int clockintr(void *); 152 static int gettick(void); 153 154 void startrtclock(void); 155 156 __inline u_int mc146818_read(void *, u_int); 157 __inline void mc146818_write(void *, u_int, u_int); 158 159 #define SECMIN ((unsigned)60) /* seconds per minute */ 160 #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ 161 #define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ 162 #define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ 163 164 __inline u_int 165 mc146818_read(sc, reg) 166 void *sc; /* XXX use it? */ 167 u_int reg; 168 { 169 170 outb(IO_RTC, reg); 171 return (inb(IO_RTC+1)); 172 } 173 174 __inline void 175 mc146818_write(sc, reg, datum) 176 void *sc; /* XXX use it? */ 177 u_int reg, datum; 178 { 179 180 outb(IO_RTC, reg); 181 outb(IO_RTC+1, datum); 182 } 183 184 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */ 185 186 /* number of timer ticks in a Musec = 2^20 usecs */ 187 #define TIMER_MUSECFREQ\ 188 (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000) 189 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x)) 190 191 /* 192 * microtime() makes use of the following globals. 193 * timer_msb_table[] and timer_lsb_table[] are used to compute the 194 * microsecond increment. 195 * 196 * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb]; 197 */ 198 199 u_short isa_timer_msb_table[256]; /* timer->usec MSB */ 200 u_short isa_timer_lsb_table[256]; /* timer->usec conversion for LSB */ 201 202 /* 64 bit counts from timer 0 */ 203 struct count64 { 204 unsigned lo; /* low 32 bits */ 205 unsigned hi; /* high 32 bits */ 206 }; 207 208 #define TIMER0_ROLLOVER 0xFFFF /* maximum rollover for 8254 counter */ 209 210 struct count64 timer0count; 211 struct count64 timer0_at_last_clockintr; 212 unsigned timer0last; 213 214 /*#define TESTHAT*/ 215 #ifdef TESTHAT 216 #define HATSTACKSIZE 1024 217 #define HATHZ 50000 218 #define HATHZ2 10000 219 unsigned char hatStack[HATSTACKSIZE]; 220 221 unsigned testHatOn = 0; 222 unsigned nHats = 0; 223 unsigned nHatWedges = 0; 224 unsigned fiqReason = 0; 225 unsigned hatCount = 0; 226 unsigned hatCount2 = 0; 227 228 void hatTest(int testReason) 229 { 230 fiqReason |= testReason; 231 nHats++; 232 233 } 234 235 void hatWedge(int nFIQs) 236 { 237 printf("Unwedging the HAT. fiqs_happened = %d\n", nFIQs); 238 nHatWedges++; 239 } 240 #endif 241 242 void 243 startrtclock() 244 { 245 findcpuspeed(); /* use the clock (while it's free) 246 to find the cpu speed */ 247 248 init_isa_timer_tables(); 249 250 timer0count.lo = 0; 251 timer0count.hi = 0; 252 timer0_at_last_clockintr.lo = 0; 253 timer0_at_last_clockintr.hi = 0; 254 timer0last = 0; 255 256 /* initialize 8253 clock */ 257 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 258 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256); 259 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256); 260 261 #ifdef TESTHAT 262 hatCount = timer_hz_to_count(HATHZ); 263 hatCount2 = timer_hz_to_count(HATHZ2); 264 printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount); 265 #endif 266 } 267 268 static void 269 init_isa_timer_tables() 270 { 271 int s; 272 u_long t, msbmillion, quotient, remainder; 273 274 for (s = 0; s < 256; s++) { 275 /* LSB table is easy, just divide and round */ 276 t = ((u_long) s * 1000000 * 2) / TIMER_FREQ; 277 isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1)); 278 279 msbmillion = s * 1000000; 280 quotient = msbmillion / TIMER_FREQ; 281 remainder = msbmillion % TIMER_FREQ; 282 t = (remainder * 256 * 2) / TIMER_FREQ; 283 isa_timer_msb_table[s] = 284 (u_short)((t / 2) + (t & 1) + (quotient * 256)); 285 286 #ifdef DIAGNOSTIC 287 if ((s > 0) && 288 (isa_timer_msb_table[s] < 289 (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF]))) 290 panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n", 291 s, isa_timer_msb_table[s], 292 isa_timer_msb_table[s - 1], 293 isa_timer_lsb_table[0xFF], 294 isa_timer_msb_table[s - 1] + 295 isa_timer_lsb_table[0xFF]); 296 #endif 297 } /* END for */ 298 } 299 300 int 301 timer_hz_to_count(timer_hz) 302 int timer_hz; 303 { 304 u_long tval; 305 306 tval = (TIMER_FREQ * 2) / (u_long) timer_hz; 307 tval = (tval / 2) + (tval & 0x1); 308 309 return (int)tval; 310 311 } 312 313 void gettimer0count(struct count64 *); 314 315 /* must be called at SPL_CLOCK or higher */ 316 void gettimer0count(pcount) 317 struct count64 *pcount; 318 { 319 unsigned current, ticks, oldlo; 320 321 /* 322 * Latch the current value of the timer and then read it. 323 * This guarentees an atomic reading of the time. 324 */ 325 326 current = gettick(); 327 328 if (timer0last >= current) 329 ticks = timer0last - current; 330 else 331 ticks = timer0last + (TIMER0_ROLLOVER - current); 332 333 timer0last = current; 334 335 oldlo = timer0count.lo; 336 337 if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */ 338 timer0count.hi++; 339 340 *pcount = timer0count; 341 } 342 343 static int 344 clockintr(arg) 345 void *arg; 346 { 347 struct clockframe *frame = arg; /* not strictly necessary */ 348 extern void isa_specific_eoi(int irq); 349 #ifdef TESTHAT 350 static int ticks = 0; 351 #endif 352 static int hatUnwedgeCtr = 0; 353 354 gettimer0count(&timer0_at_last_clockintr); 355 356 mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */ 357 358 /* check to see if the high-availability timer needs to be unwedged */ 359 if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) { 360 hatUnwedgeCtr = 0; 361 hatUnwedge(); 362 } 363 364 #ifdef TESTHAT 365 ++ticks; 366 367 if (testHatOn && ((ticks & 0x3f) == 0)) { 368 if (testHatOn == 1) { 369 hatClkAdjust(hatCount2); 370 testHatOn = 2; 371 } else { 372 testHatOn = 0; 373 hatClkOff(); 374 printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason); 375 } 376 } else if (!testHatOn && (ticks & 0x1ff) == 0) { 377 printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason); 378 testHatOn = 1; 379 nHats = 0; 380 fiqReason = 0; 381 hatClkOn(hatCount, hatTest, 0xfeedface, 382 hatStack + HATSTACKSIZE - sizeof(unsigned), 383 hatWedge); 384 } 385 #endif 386 hardclock(frame); 387 return(0); 388 } 389 390 static int 391 gettick() 392 { 393 u_char lo, hi; 394 u_int savedints; 395 396 /* Don't want someone screwing with the counter while we're here. */ 397 savedints = disable_interrupts(I32_bit); 398 /* Select counter 0 and latch it. */ 399 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 400 lo = inb(IO_TIMER1 + TIMER_CNTR0); 401 hi = inb(IO_TIMER1 + TIMER_CNTR0); 402 restore_interrupts(savedints); 403 return ((hi << 8) | lo); 404 } 405 406 /* modifications from i386 to shark isa version: 407 - removed hardcoded "n -=" values that approximated the time to 408 calculate delay ticks 409 - made the time to calculate delay ticks almost negligable. 4 multiplies 410 = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts; 411 as opposed to 4 multiplies plus a bunch of divides. 412 - removed i386 assembly language hack 413 - put code in findcpuspeed that works even if FIRST_GUESS is orders 414 of magnitude low 415 - put code in delay() to use delayloop() for short delays 416 - microtime no longer in assembly language 417 */ 418 419 /* 420 * Wait "n" microseconds. 421 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 422 * Note: timer had better have been programmed before this is first used! 423 * (Note that we use `rate generator' mode, which counts at 1:1; `square 424 * wave' mode counts at 2:1). 425 */ 426 void 427 delay(n) 428 unsigned n; 429 { 430 int tick, otick; 431 int nticks; 432 433 if (n < 100) { 434 /* it can take a long time (1 usec or longer) just for 1 ISA read, 435 so it's best not to use the timer for short delays */ 436 delayloop((n * count1024usec) >> 10); 437 return; 438 } 439 440 /* 441 * Read the counter first, so that the rest of the setup overhead is 442 * counted. 443 */ 444 otick = gettick(); 445 446 /* 447 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and 448 * without any avoidable overflows. 449 */ 450 { 451 /* a Musec = 2^20 usec */ 452 int Musec = n >> 20, 453 usec = n & ((1 << 20) - 1); 454 nticks 455 = (Musec * TIMER_MUSECFREQ) + 456 (usec * (TIMER_MUSECFREQ >> 20)) + 457 ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) + 458 ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20); 459 } 460 461 while (nticks > 0) { 462 tick = gettick(); 463 if (tick > otick) 464 nticks -= TIMER0_ROLLOVER - (tick - otick); 465 else 466 nticks -= otick - tick; 467 otick = tick; 468 } 469 470 } 471 472 void 473 sysbeepstop(arg) 474 void *arg; 475 { 476 } 477 478 void 479 sysbeep(pitch, period) 480 int pitch, period; 481 { 482 } 483 484 #define FIRST_GUESS 0x2000 485 486 static void 487 findcpuspeed() 488 { 489 int ticks; 490 unsigned int guess = FIRST_GUESS; 491 492 while (1) { /* loop until accurate enough */ 493 /* Put counter in count down mode */ 494 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); 495 outb(IO_TIMER1 + TIMER_CNTR0, 0xff); 496 outb(IO_TIMER1 + TIMER_CNTR0, 0xff); 497 delayloop(guess); 498 499 /* Read the value left in the counter */ 500 /* 501 * Formula for delaycount is: 502 * (loopcount * timer clock speed) / (counter ticks * 1000) 503 */ 504 ticks = 0xFFFF - gettick(); 505 if (ticks == 0) ticks = 1; /* just in case */ 506 if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */ 507 guess *= max(2, (TIMER_MUSECDIV(1024) / ticks)); 508 continue; 509 } 510 count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks; 511 return; 512 } 513 } 514 515 static void 516 delayloop(counts) 517 { 518 while (counts--); 519 } 520 521 void 522 cpu_initclocks() 523 { 524 unsigned hzval; 525 526 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 527 528 /* install RTC interrupt handler */ 529 (void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK, 530 clockintr, 0); 531 532 /* code for values of hz that don't divide 1000000 exactly */ 533 tickfix = 1000000 - (hz * tick); 534 if (tickfix) { 535 int ftp; 536 537 ftp = min(ffs(tickfix), ffs(hz)); 538 tickfix >>= (ftp - 1); 539 tickfixinterval = hz >> (ftp - 1); 540 } 541 542 /* set up periodic interrupt @ hz 543 this is the subset of hz values in kern_clock.c that are 544 supported by the ISA RTC */ 545 switch (hz) { 546 case 64: 547 hzval = MC_RATE_64_Hz; 548 break; 549 case 128: 550 hzval = MC_RATE_128_Hz; 551 break; 552 case 256: 553 hzval = MC_RATE_256_Hz; 554 break; 555 case 1024: 556 hzval = MC_RATE_1024_Hz; 557 break; 558 default: 559 panic("cannot configure hz = %d", hz); 560 } 561 562 rtcinit(); /* make sure basics are done by now */ 563 564 /* blast values to set up clock interrupt */ 565 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval); 566 /* enable periodic interrupt */ 567 mc146818_write(NULL, MC_REGB, 568 mc146818_read(NULL, MC_REGB) | MC_REGB_PIE); 569 } 570 571 void 572 rtcinit() 573 { 574 static int first_rtcopen_ever = 1; 575 576 if (!first_rtcopen_ever) 577 return; 578 first_rtcopen_ever = 0; 579 580 mc146818_write(NULL, MC_REGA, /* XXX softc */ 581 MC_BASE_32_KHz | MC_RATE_1024_Hz); 582 mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */ 583 } 584 585 void 586 setstatclockrate(arg) 587 int arg; 588 { 589 } 590 591 /* 592 * void microtime(struct timeval *tvp) 593 * 594 * Fill in the specified timeval struct with the current time 595 * accurate to the microsecond. 596 */ 597 598 void 599 microtime(tvp) 600 struct timeval *tvp; 601 { 602 int s; 603 unsigned lsb, msb; 604 int tm; 605 static struct timeval oldtv; 606 struct count64 timer0current; 607 int ticks; 608 609 s = splstatclock(); 610 611 gettimer0count(&timer0current); 612 613 tm = time.tv_usec; 614 615 /* unsigned arithmetic should take care of overflow */ 616 /* with a >= 32 Hz clock, ticks will always be < 0x7FFF */ 617 ticks = (int)((unsigned) 618 (timer0current.lo - timer0_at_last_clockintr.lo)); 619 620 #ifdef DIAGNOSTIC 621 if ((ticks < 0) || (ticks > 0xffff)) 622 printf("microtime bug: ticks = %x\n", ticks); 623 #endif 624 625 while (ticks > 0) { 626 627 if (ticks < 0xffff) { 628 msb = (ticks >> 8) & 0xFF; 629 lsb = ticks & 0xFF; 630 } else { 631 msb = 0xff; 632 lsb = 0xff; 633 } 634 635 /* see comments above */ 636 tm += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb]; 637 638 /* for a 64 Hz RTC, ticks will never overflow table */ 639 /* microtime will be less accurate if the RTC is < 36 Hz */ 640 ticks -= 0xffff; 641 } 642 643 tvp->tv_sec = time.tv_sec; 644 if (tm >= 1000000) { 645 tvp->tv_sec += 1; 646 tm -= 1000000; 647 } 648 649 tvp->tv_usec = tm; 650 651 /* Make sure the time has advanced. */ 652 653 if (tvp->tv_sec == oldtv.tv_sec && 654 tvp->tv_usec <= oldtv.tv_usec) { 655 tvp->tv_usec = oldtv.tv_usec + 1; 656 if (tvp->tv_usec >= 1000000) { 657 tvp->tv_usec -= 1000000; 658 ++tvp->tv_sec; 659 } 660 } 661 662 oldtv = *tvp; 663 (void)splx(s); 664 } 665 666 /* End of clock.c */ 667