1 /* $NetBSD: timer.c,v 1.3 2002/03/28 20:04:27 uwe Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1994 Gordon W. Ross 7 * Copyright (c) 1993 Adam Glass 8 * Copyright (c) 1996 Paul Kranenburg 9 * Copyright (c) 1996 10 * The President and Fellows of Harvard College. All rights reserved. 11 * 12 * This software was developed by the Computer Systems Engineering group 13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 * contributed to Berkeley. 15 * 16 * All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Harvard University. 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by the University of 34 * California, Berkeley and its contributors. 35 * This product includes software developed by Paul Kranenburg. 36 * This product includes software developed by Harvard University. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)clock.c 8.1 (Berkeley) 6/11/93 54 * 55 */ 56 57 /* 58 * Kernel clocks provided by "timer" device. The 59 * hardclock is provided by the timer register (aka system counter). 60 * The statclock is provided by per cpu counter register(s) (aka 61 * processor counter(s)). 62 * 63 */ 64 #include "opt_sparc_arch.h" 65 66 #include <sys/param.h> 67 #include <sys/kernel.h> 68 #include <sys/device.h> 69 #include <sys/systm.h> 70 71 #include <machine/bus.h> 72 #include <machine/autoconf.h> 73 #include <machine/eeprom.h> 74 #include <machine/idprom.h> 75 76 #include <sparc/sparc/vaddrs.h> 77 #include <sparc/sparc/cpuvar.h> 78 #include <sparc/sparc/timerreg.h> 79 80 #if defined(MSIIEP) 81 #include <sparc/sparc/msiiepreg.h> 82 #include <sparc/sparc/msiiepvar.h> 83 #endif 84 85 static struct intrhand level10; 86 static struct intrhand level14; 87 88 #if defined(SUN4) || defined(SUN4C) 89 static int clockintr_4(void *); 90 static int statintr_4(void *); 91 static void timer_init_4(void); 92 #endif 93 94 #if defined(SUN4M) 95 static int clockintr_4m(void *); 96 static int statintr_4m(void *); 97 static void timer_init_4m(void); 98 #endif 99 100 #if defined(MSIIEP) 101 static int clockintr_msiiep(void *); 102 static int statintr_msiiep(void *); 103 static void timer_init_msiiep(void); 104 #endif 105 106 static int timermatch_mainbus(struct device *, struct cfdata *, void *); 107 static int timermatch_obio(struct device *, struct cfdata *, void *); 108 static int timermatch_msiiep(struct device *, struct cfdata *, void *); 109 static void timerattach_mainbus(struct device *, struct device *, void *); 110 static void timerattach_obio(struct device *, struct device *, void *); 111 static void timerattach_msiiep(struct device *, struct device *, void *); 112 113 static void timerattach(volatile int *, volatile int *); 114 115 static int timerok; 116 117 /* Imported from clock.c: */ 118 extern int statvar, statmin, statint; 119 extern int timerblurb; 120 extern void (*timer_init)(void); 121 122 123 #if defined(SUN4) || defined(SUN4C) 124 #define timerreg4 ((struct timerreg_4 *)TIMERREG_VA) 125 #endif 126 127 #if defined(SUN4M) 128 struct timer_4m *timerreg4m; 129 #define counterreg4m cpuinfo.counterreg_4m 130 #endif 131 132 #if defined(MSIIEP) 133 /* XXX: move this stuff to msiiepreg.h? */ 134 135 /* ms-IIep PCIC registers mapped at fixed VA (see vaddrs.h) */ 136 #define msiiep ((volatile struct msiiep_pcic_reg *)MSIIEP_PCIC_VA) 137 138 /* 139 * ms-IIep counters tick every 4 cpu clock @100MHz. 140 * counter is reset to 1 when new limit is written. 141 */ 142 #define tmr_ustolimIIep(n) ((n) * 25 + 1) 143 #endif /* MSIIEP */ 144 145 146 struct cfattach timer_mainbus_ca = { 147 sizeof(struct device), timermatch_mainbus, timerattach_mainbus 148 }; 149 150 struct cfattach timer_obio_ca = { 151 sizeof(struct device), timermatch_obio, timerattach_obio 152 }; 153 154 struct cfattach timer_msiiep_ca = { 155 sizeof(struct device), timermatch_msiiep, timerattach_msiiep 156 }; 157 158 /* 159 * The sun4c OPENPROM calls the timer the "counter-timer". 160 */ 161 static int 162 timermatch_mainbus(parent, cf, aux) 163 struct device *parent; 164 struct cfdata *cf; 165 void *aux; 166 { 167 struct mainbus_attach_args *ma = aux; 168 169 return (strcmp("counter-timer", ma->ma_name) == 0); 170 } 171 172 /* 173 * The sun4m OPENPROM calls the timer the "counter". 174 * The sun4 timer must be probed. 175 */ 176 static int 177 timermatch_obio(parent, cf, aux) 178 struct device *parent; 179 struct cfdata *cf; 180 void *aux; 181 { 182 union obio_attach_args *uoba = aux; 183 struct obio4_attach_args *oba; 184 185 if (uoba->uoba_isobio4 == 0) 186 return (strcmp("counter", uoba->uoba_sbus.sa_name) == 0); 187 188 if (!CPU_ISSUN4) { 189 printf("timermatch_obio: attach args mixed up\n"); 190 return (0); 191 } 192 193 /* Only these sun4s have "timer" (others have "oclock") */ 194 if (cpuinfo.cpu_type != CPUTYP_4_300 && 195 cpuinfo.cpu_type != CPUTYP_4_400) 196 return (0); 197 198 /* Make sure there is something there */ 199 oba = &uoba->uoba_oba4; 200 return (bus_space_probe(oba->oba_bustag, oba->oba_paddr, 201 4, /* probe size */ 202 0, /* offset */ 203 0, /* flags */ 204 NULL, NULL)); 205 } 206 207 static int 208 timermatch_msiiep(parent, cf, aux) 209 struct device *parent; 210 struct cfdata *cf; 211 void *aux; 212 { 213 #if defined(MSIIEP) 214 struct msiiep_attach_args *msa = aux; 215 216 return (strcmp(msa->msa_name, "timer") == 0); 217 #else 218 return (0); 219 #endif 220 } 221 222 /* ARGSUSED */ 223 static void 224 timerattach_mainbus(parent, self, aux) 225 struct device *parent, *self; 226 void *aux; 227 { 228 #if defined(SUN4) || defined(SUN4C) 229 struct mainbus_attach_args *ma = aux; 230 bus_space_handle_t bh; 231 232 /* 233 * This time, we ignore any existing virtual address because 234 * we have a fixed virtual address for the timer, to make 235 * microtime() faster. 236 */ 237 if (bus_space_map2(ma->ma_bustag, 238 ma->ma_paddr, 239 sizeof(struct timerreg_4), 240 BUS_SPACE_MAP_LINEAR, 241 TIMERREG_VA, &bh) != 0) { 242 printf("%s: can't map register\n", self->dv_xname); 243 return; 244 } 245 246 timerattach(&timerreg4->t_c14.t_counter, &timerreg4->t_c14.t_limit); 247 #endif /* SUN4/SUN4C */ 248 } 249 250 static void 251 timerattach_obio(parent, self, aux) 252 struct device *parent, *self; 253 void *aux; 254 { 255 union obio_attach_args *uoba = aux; 256 257 if (uoba->uoba_isobio4 == 0) { 258 /* sun4m timer at obio */ 259 #if defined(SUN4M) 260 struct sbus_attach_args *sa = &uoba->uoba_sbus; 261 bus_space_handle_t bh; 262 int i; 263 264 if (sa->sa_nreg < 2) { 265 printf("%s: only %d register sets\n", self->dv_xname, 266 sa->sa_nreg); 267 return; 268 } 269 270 /* Map the system timer */ 271 i = sa->sa_nreg - 1; 272 if (bus_space_map2(sa->sa_bustag, 273 BUS_ADDR( 274 sa->sa_reg[i].sbr_slot, 275 sa->sa_reg[i].sbr_offset), 276 sizeof(struct timer_4m), 277 BUS_SPACE_MAP_LINEAR, 278 TIMERREG_VA, &bh) != 0) { 279 printf("%s: can't map register\n", self->dv_xname); 280 return; 281 } 282 timerreg4m = (struct timer_4m *)TIMERREG_VA; 283 284 /* Map each CPU's counter */ 285 for (i = 0; i < sa->sa_nreg - 1; i++) { 286 struct cpu_info *cpi = NULL; 287 int n; 288 289 /* 290 * Check whether the CPU corresponding to this 291 * timer register is installed. 292 */ 293 for (n = 0; n < ncpu; n++) { 294 if ((cpi = cpus[n]) == NULL) 295 continue; 296 if ((i == 0 && ncpu == 1) || cpi->mid == i + 8) 297 /* We got a corresponding MID */ 298 break; 299 cpi = NULL; 300 } 301 if (cpi == NULL) 302 continue; 303 if (sbus_bus_map(sa->sa_bustag, 304 sa->sa_reg[i].sbr_slot, 305 sa->sa_reg[i].sbr_offset, 306 sizeof(struct timer_4m), 307 BUS_SPACE_MAP_LINEAR, 308 &bh) != 0) { 309 printf("%s: can't map register\n", 310 self->dv_xname); 311 return; 312 } 313 cpi->counterreg_4m = (struct counter_4m *)bh; 314 } 315 316 /* Put processor counter in "timer" mode */ 317 timerreg4m->t_cfg = 0; 318 319 timerattach(&counterreg4m->t_counter, &counterreg4m->t_limit); 320 #endif /* SUN4M */ 321 return; 322 } else { 323 #if defined(SUN4) 324 /* sun4 timer at obio */ 325 struct obio4_attach_args *oba = &uoba->uoba_oba4; 326 bus_space_handle_t bh; 327 328 if (bus_space_map2(oba->oba_bustag, 329 oba->oba_paddr, 330 sizeof(struct timerreg_4), 331 BUS_SPACE_MAP_LINEAR, 332 TIMERREG_VA, 333 &bh) != 0) { 334 printf("%s: can't map register\n", self->dv_xname); 335 return; 336 } 337 timerattach(&timerreg4->t_c14.t_counter, 338 &timerreg4->t_c14.t_limit); 339 #endif /* SUN4 */ 340 } 341 } 342 343 /* 344 * sun4/sun4c/sun4m common timer attach code 345 */ 346 static void 347 timerattach(cntreg, limreg) 348 volatile int *cntreg, *limreg; 349 { 350 351 /* 352 * Calibrate delay() by tweaking the magic constant 353 * until a delay(100) actually reads (at least) 100 us on the clock. 354 * Note: sun4m clocks tick with 500ns periods. 355 */ 356 for (timerblurb = 1; ; timerblurb++) { 357 volatile int discard; 358 int t0, t1; 359 360 /* Reset counter register by writing some large limit value */ 361 discard = *limreg; 362 *limreg = tmr_ustolim(TMR_MASK-1); 363 364 t0 = *cntreg; 365 delay(100); 366 t1 = *cntreg; 367 368 if (t1 & TMR_LIMIT) 369 panic("delay calibration"); 370 371 t0 = (t0 >> TMR_SHIFT) & TMR_MASK; 372 t1 = (t1 >> TMR_SHIFT) & TMR_MASK; 373 374 if (t1 >= t0 + 100) 375 break; 376 } 377 378 printf(" delay constant %d\n", timerblurb); 379 380 #if defined(SUN4) || defined(SUN4C) 381 if (CPU_ISSUN4OR4C) { 382 timer_init = timer_init_4; 383 level10.ih_fun = clockintr_4; 384 level14.ih_fun = statintr_4; 385 } 386 #endif 387 #if defined(SUN4M) 388 if (CPU_ISSUN4M) { 389 timer_init = timer_init_4m; 390 level10.ih_fun = clockintr_4m; 391 level14.ih_fun = statintr_4m; 392 } 393 #endif 394 /* link interrupt handlers */ 395 intr_establish(10, &level10); 396 intr_establish(14, &level14); 397 398 timerok = 1; 399 } 400 401 402 /* ARGSUSED */ 403 static void 404 timerattach_msiiep(parent, self, aux) 405 struct device *parent, *self; 406 void *aux; 407 { 408 #if defined(MSIIEP) 409 /* 410 * Attach system and cpu counters (kernel hard and stat clocks) 411 * for ms-IIep. Counters are part of the PCIC and there's no 412 * PROM node for them. 413 */ 414 /* Put processor counter in "counter" mode */ 415 msiiep->pcic_pc_ctl = 0; /* stop user timer (just in case) */ 416 msiiep->pcic_pc_cfg = 0; /* timer mode disabled (processor counter) */ 417 418 /* 419 * Calibrate delay() by tweaking the magic constant 420 * until a delay(100) actually reads (at least) 100 us on the clock. 421 * Note: ms-IIep clocks ticks every 4 processor cycles. 422 */ 423 for (timerblurb = 1; ; ++timerblurb) { 424 volatile int discard; 425 int t; 426 427 discard = msiiep->pcic_pclr; /* clear the limit bit */ 428 msiiep->pcic_pclr = 0; /* reset counter to 1, free run */ 429 delay(100); 430 t = msiiep->pcic_pccr; 431 432 if (t & TMR_LIMIT) /* cannot happen */ 433 panic("delay calibration"); 434 435 /* counter ticks -> usec, inverse of tmr_ustolimIIep */ 436 t = (t - 1) / 25; 437 if (t >= 100) 438 break; 439 } 440 printf(" delay constant %d\n", timerblurb); 441 442 /* 443 * Set counter interrupt priority assignment: 444 * upper 4 bits are for system counter: level 10 445 * lower 4 bits are for processor counter: level 14 446 */ 447 msiiep->pcic_cipar = 0xae; 448 449 timer_init = timer_init_msiiep; 450 level10.ih_fun = clockintr_msiiep; 451 level14.ih_fun = statintr_msiiep; 452 453 /* link interrupt handlers */ 454 intr_establish(10, &level10); 455 intr_establish(14, &level14); 456 457 timerok = 1; 458 #endif /* MSIIEP */ 459 } 460 461 /* 462 * Set up the real-time and statistics clocks. 463 * Leave stathz 0 only if no alternative timer is available. 464 * 465 * The frequencies of these clocks must be an even number of microseconds. 466 */ 467 #if defined(SUN4) || defined(SUN4C) 468 void 469 timer_init_4() 470 { 471 timerreg4->t_c10.t_limit = tmr_ustolim(tick); 472 timerreg4->t_c14.t_limit = tmr_ustolim(statint); 473 ienab_bis(IE_L14 | IE_L10); 474 } 475 #endif 476 477 #if defined(SUN4M) 478 void 479 timer_init_4m() 480 { 481 int n; 482 timerreg4m->t_limit = tmr_ustolim4m(tick); 483 for (n = 0; n < ncpu; n++) { 484 struct cpu_info *cpi; 485 if ((cpi = cpus[n]) == NULL) 486 continue; 487 cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint); 488 } 489 ienab_bic(SINTR_T); 490 } 491 #endif 492 493 #if defined(MSIIEP) 494 void 495 timer_init_msiiep() 496 { 497 /* ms-IIep kernels support *only* IIep */ 498 msiiep->pcic_sclr = tmr_ustolimIIep(tick); 499 msiiep->pcic_pclr = tmr_ustolimIIep(statint); 500 /* XXX: ensure interrupt target mask doesn't masks them? */ 501 } 502 #endif /* MSIIEP */ 503 504 #if defined(SUN4) || defined(SUN4C) 505 /* 506 * Level 10 (clock) interrupts from system counter. 507 */ 508 int 509 clockintr_4(cap) 510 void *cap; 511 { 512 volatile int discard; 513 514 /* read the limit register to clear the interrupt */ 515 discard = timerreg4->t_c10.t_limit; 516 hardclock((struct clockframe *)cap); 517 return (1); 518 } 519 #endif /* SUN4/SUN4C */ 520 521 #if defined(SUN4M) 522 int 523 clockintr_4m(cap) 524 void *cap; 525 { 526 volatile int discard; 527 int s; 528 529 /* 530 * Protect the clearing of the clock interrupt. If we don't 531 * do this, and we're interrupted (by the zs, for example), 532 * the clock stops! 533 * XXX WHY DOES THIS HAPPEN? 534 */ 535 s = splhigh(); 536 537 /* read the limit register to clear the interrupt */ 538 discard = timerreg4m->t_limit; 539 splx(s); 540 541 hardclock((struct clockframe *)cap); 542 return (1); 543 } 544 #endif /* SUN4M */ 545 546 #if defined(MSIIEP) 547 int 548 clockintr_msiiep(cap) 549 void *cap; 550 { 551 volatile int discard; 552 553 /* read the limit register to clear the interrupt */ 554 discard = msiiep->pcic_sclr; 555 hardclock((struct clockframe *)cap); 556 return (1); 557 } 558 #endif /* MSIIEP */ 559 560 static __inline__ u_long 561 new_interval(void) 562 { 563 u_long newint, r, var; 564 565 /* 566 * Compute new randomized interval. The intervals are uniformly 567 * distributed on [statint - statvar / 2, statint + statvar / 2], 568 * and therefore have mean statint, giving a stathz frequency clock. 569 */ 570 var = statvar; 571 do { 572 r = random() & (var - 1); 573 } while (r == 0); 574 newint = statmin + r; 575 return (newint); 576 } 577 578 /* 579 * Level 14 (stat clock) interrupts from processor counter. 580 */ 581 #if defined(SUN4) || defined(SUN4C) 582 int 583 statintr_4(cap) 584 void *cap; 585 { 586 volatile int discard; 587 u_long newint; 588 589 /* read the limit register to clear the interrupt */ 590 discard = timerreg4->t_c14.t_limit; 591 592 statclock((struct clockframe *)cap); 593 594 /* 595 * Compute new randomized interval. 596 */ 597 newint = new_interval(); 598 599 /* 600 * The sun4/4c timer has no `non-resetting' register; 601 * use the current counter value to compensate the new 602 * limit value for the number of counter ticks elapsed. 603 */ 604 newint -= tmr_cnttous(timerreg4->t_c14.t_counter); 605 timerreg4->t_c14.t_limit = tmr_ustolim(newint); 606 return (1); 607 } 608 #endif /* SUN4/SUN4C */ 609 610 #if defined(SUN4M) 611 int 612 statintr_4m(cap) 613 void *cap; 614 { 615 volatile int discard; 616 u_long newint; 617 618 /* read the limit register to clear the interrupt */ 619 discard = counterreg4m->t_limit; 620 if (timerok == 0) { 621 /* Stop the clock */ 622 printf("note: counter running!\n"); 623 discard = counterreg4m->t_limit; 624 counterreg4m->t_limit = 0; 625 counterreg4m->t_ss = 0; 626 timerreg4m->t_cfg = TMR_CFG_USER; 627 return 1; 628 } 629 630 statclock((struct clockframe *)cap); 631 632 /* 633 * Compute new randomized interval. 634 */ 635 newint = new_interval(); 636 637 /* 638 * Use the `non-resetting' limit register, so we don't 639 * loose the counter ticks that happened since this 640 * interrupt was raised. 641 */ 642 counterreg4m->t_limit_nr = tmr_ustolim4m(newint); 643 return (1); 644 } 645 #endif /* SUN4M */ 646 647 #if defined(MSIIEP) 648 int 649 statintr_msiiep(cap) 650 void *cap; 651 { 652 volatile int discard; 653 u_long newint; 654 655 /* read the limit register to clear the interrupt */ 656 discard = msiiep->pcic_pclr; 657 if (timerok == 0) { 658 /* Stop the clock */ 659 printf("note: counter running!\n"); 660 /* 661 * Turn interrupting processor counter 662 * into non-interrupting user timer. 663 */ 664 msiiep->pcic_pc_cfg = 1; /* make it a user timer */ 665 msiiep->pcic_pc_ctl = 0; /* stop user timer */ 666 return (1); 667 } 668 669 statclock((struct clockframe *)cap); 670 671 /* 672 * Compute new randomized interval. 673 */ 674 newint = new_interval(); 675 676 /* 677 * Use the `non-resetting' limit register, so we don't 678 * loose the counter ticks that happened since this 679 * interrupt was raised. 680 */ 681 msiiep->pcic_pclr_nr = tmr_ustolimIIep(newint); 682 return (1); 683 } 684 #endif /* MSIIEP */ 685