1 /* $OpenBSD: clock.c,v 1.82 2023/09/17 14:50:51 cheloha Exp $ */ 2 /* $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * Copyright (c) 1994 Gordon W. Ross 8 * Copyright (c) 1993 Adam Glass 9 * Copyright (c) 1996 Paul Kranenburg 10 * Copyright (c) 1996 11 * The President and Fellows of Harvard College. All rights reserved. 12 * 13 * This software was developed by the Computer Systems Engineering group 14 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 15 * contributed to Berkeley. 16 * 17 * All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Harvard University. 20 * This product includes software developed by the University of 21 * California, Lawrence Berkeley Laboratory. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 2. Redistributions in binary form must reproduce the above copyright 30 * notice, this list of conditions and the following disclaimer in the 31 * documentation and/or other materials provided with the distribution. 32 * 3. All advertising materials mentioning features or use of this software 33 * must display the following acknowledgement: 34 * This product includes software developed by the University of 35 * California, Berkeley and its contributors. 36 * This product includes software developed by Paul Kranenburg. 37 * This product includes software developed by Harvard University. 38 * 4. Neither the name of the University nor the names of its contributors 39 * may be used to endorse or promote products derived from this software 40 * without specific prior written permission. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * 54 * @(#)clock.c 8.1 (Berkeley) 6/11/93 55 * 56 */ 57 58 /* 59 * Clock driver. This is the id prom and eeprom driver as well 60 * and includes the timer register functions too. 61 */ 62 63 /* Define this for a 1/4s clock to ease debugging */ 64 /* #define INTR_DEBUG */ 65 66 #include <sys/param.h> 67 #include <sys/kernel.h> 68 #include <sys/device.h> 69 #include <sys/proc.h> 70 #include <sys/resourcevar.h> 71 #include <sys/malloc.h> 72 #include <sys/systm.h> 73 #include <sys/clockintr.h> 74 #ifdef GPROF 75 #include <sys/gmon.h> 76 #endif 77 #include <sys/sched.h> 78 #include <sys/stdint.h> 79 #include <sys/timetc.h> 80 #include <sys/atomic.h> 81 82 #include <machine/bus.h> 83 #include <machine/autoconf.h> 84 #include <machine/cpu.h> 85 #include <machine/idprom.h> 86 87 #include <dev/clock_subr.h> 88 #include <dev/ic/mk48txxreg.h> 89 90 #include <sparc64/sparc64/intreg.h> 91 #include <sparc64/dev/iommureg.h> 92 #include <sparc64/dev/sbusreg.h> 93 #include <dev/sbus/sbusvar.h> 94 #include <sparc64/dev/ebusreg.h> 95 #include <sparc64/dev/ebusvar.h> 96 #include <sparc64/dev/fhcvar.h> 97 98 extern u_int64_t cpu_clockrate; 99 100 struct clock_wenable_info { 101 bus_space_tag_t cwi_bt; 102 bus_space_handle_t cwi_bh; 103 bus_size_t cwi_size; 104 }; 105 106 struct cfdriver clock_cd = { 107 NULL, "clock", DV_DULL 108 }; 109 110 u_int tick_get_timecount(struct timecounter *); 111 112 struct timecounter tick_timecounter = { 113 .tc_get_timecount = tick_get_timecount, 114 .tc_counter_mask = ~0u, 115 .tc_frequency = 0, 116 .tc_name = "tick", 117 .tc_quality = 0, 118 .tc_priv = NULL, 119 .tc_user = TC_TICK, 120 }; 121 122 u_int sys_tick_get_timecount(struct timecounter *); 123 124 struct timecounter sys_tick_timecounter = { 125 .tc_get_timecount = sys_tick_get_timecount, 126 .tc_counter_mask = ~0u, 127 .tc_frequency = 0, 128 .tc_name = "sys_tick", 129 .tc_quality = 1000, 130 .tc_priv = NULL, 131 .tc_user = TC_SYS_TICK, 132 }; 133 134 void tick_start(void); 135 void sys_tick_start(void); 136 void stick_start(void); 137 138 int tickintr(void *); 139 int sys_tickintr(void *); 140 int stickintr(void *); 141 142 /* %TICK is at most a 63-bit counter. */ 143 #define TICK_COUNT_MASK 0x7fffffffffffffff 144 145 uint64_t tick_nsec_cycle_ratio; 146 uint64_t tick_nsec_max; 147 148 void tick_rearm(void *, uint64_t); 149 void tick_trigger(void *); 150 151 const struct intrclock tick_intrclock = { 152 .ic_rearm = tick_rearm, 153 .ic_trigger = tick_trigger 154 }; 155 156 /* %STICK is at most a 63-bit counter. */ 157 #define STICK_COUNT_MASK 0x7fffffffffffffff 158 159 uint64_t sys_tick_nsec_cycle_ratio; 160 uint64_t sys_tick_nsec_max; 161 162 void sys_tick_rearm(void *, uint64_t); 163 void sys_tick_trigger(void *); 164 165 const struct intrclock sys_tick_intrclock = { 166 .ic_rearm = sys_tick_rearm, 167 .ic_trigger = sys_tick_trigger 168 }; 169 170 void stick_rearm(void *, uint64_t); 171 void stick_trigger(void *); 172 173 const struct intrclock stick_intrclock = { 174 .ic_rearm = stick_rearm, 175 .ic_trigger = stick_trigger 176 }; 177 178 void sparc64_raise_clockintr(void); 179 180 static struct intrhand level0 = { tickintr }; 181 182 /* 183 * clock (eeprom) attaches at the sbus or the ebus (PCI) 184 */ 185 static int clockmatch_sbus(struct device *, void *, void *); 186 static void clockattach_sbus(struct device *, struct device *, void *); 187 static int clockmatch_ebus(struct device *, void *, void *); 188 static void clockattach_ebus(struct device *, struct device *, void *); 189 static int clockmatch_fhc(struct device *, void *, void *); 190 static void clockattach_fhc(struct device *, struct device *, void *); 191 static void clockattach(int, bus_space_tag_t, bus_space_handle_t); 192 193 const struct cfattach clock_sbus_ca = { 194 sizeof(struct device), clockmatch_sbus, clockattach_sbus 195 }; 196 197 const struct cfattach clock_ebus_ca = { 198 sizeof(struct device), clockmatch_ebus, clockattach_ebus 199 }; 200 201 const struct cfattach clock_fhc_ca = { 202 sizeof(struct device), clockmatch_fhc, clockattach_fhc 203 }; 204 205 /* Global TOD clock handle & idprom pointer */ 206 extern todr_chip_handle_t todr_handle; 207 static struct idprom *idprom; 208 209 int clock_bus_wenable(struct todr_chip_handle *, int); 210 struct chiptime; 211 void myetheraddr(u_char *); 212 struct idprom *getidprom(void); 213 int chiptotime(int, int, int, int, int, int); 214 void timetochip(struct chiptime *); 215 216 int timerblurb = 10; /* Guess a value; used before clock is attached */ 217 218 /* 219 * The OPENPROM calls the clock the "eeprom", so we have to have our 220 * own special match function to call it the "clock". 221 */ 222 static int 223 clockmatch_sbus(struct device *parent, void *cf, void *aux) 224 { 225 struct sbus_attach_args *sa = aux; 226 227 return (strcmp("eeprom", sa->sa_name) == 0); 228 } 229 230 static int 231 clockmatch_ebus(struct device *parent, void *cf, void *aux) 232 { 233 struct ebus_attach_args *ea = aux; 234 235 return (strcmp("eeprom", ea->ea_name) == 0); 236 } 237 238 static int 239 clockmatch_fhc(struct device *parent, void *cf, void *aux) 240 { 241 struct fhc_attach_args *fa = aux; 242 243 return (strcmp("eeprom", fa->fa_name) == 0); 244 } 245 246 /* 247 * Attach a clock (really `eeprom') to the sbus or ebus. 248 * 249 * We ignore any existing virtual address as we need to map 250 * this read-only and make it read-write only temporarily, 251 * whenever we read or write the clock chip. The clock also 252 * contains the ID ``PROM'', and I have already had the pleasure 253 * of reloading the cpu type, Ethernet address, etc, by hand from 254 * the console FORTH interpreter. I intend not to enjoy it again. 255 * 256 * the MK48T02 is 2K. the MK48T08 is 8K, and the MK48T59 is 257 * supposed to be identical to it. 258 * 259 * This is *UGLY*! We probably have multiple mappings. But I do 260 * know that this all fits inside an 8K page, so I'll just map in 261 * once. 262 * 263 * What we really need is some way to record the bus attach args 264 * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY 265 * or not to write enable/disable the device registers. This is 266 * a non-trivial operation. 267 */ 268 269 static void 270 clockattach_sbus(struct device *parent, struct device *self, void *aux) 271 { 272 struct sbus_attach_args *sa = aux; 273 bus_space_tag_t bt = sa->sa_bustag; 274 int sz; 275 static struct clock_wenable_info cwi; 276 277 /* use sa->sa_regs[0].size? */ 278 sz = 8192; 279 280 if (sbus_bus_map(bt, 281 sa->sa_slot, 282 (sa->sa_offset & ~NBPG), 283 sz, 284 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, 285 0, &cwi.cwi_bh) != 0) { 286 printf("%s: can't map register\n", self->dv_xname); 287 return; 288 } 289 clockattach(sa->sa_node, bt, cwi.cwi_bh); 290 291 /* Save info for the clock wenable call. */ 292 cwi.cwi_bt = bt; 293 cwi.cwi_size = sz; 294 todr_handle->bus_cookie = &cwi; 295 todr_handle->todr_setwen = clock_bus_wenable; 296 } 297 298 /* 299 * Write en/dis-able clock registers. We coordinate so that several 300 * writers can run simultaneously. 301 * XXX There is still a race here. The page change and the "writers" 302 * change are not atomic. 303 */ 304 int 305 clock_bus_wenable(struct todr_chip_handle *handle, int onoff) 306 { 307 int s, err = 0; 308 int prot; /* nonzero => change prot */ 309 volatile static int writers; 310 struct clock_wenable_info *cwi = handle->bus_cookie; 311 312 s = splhigh(); 313 if (onoff) 314 prot = writers++ == 0 ? 1 : 0; 315 else 316 prot = --writers == 0 ? 1 : 0; 317 splx(s); 318 319 if (prot) { 320 err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size, 321 onoff ? 0 : BUS_SPACE_MAP_READONLY); 322 if (err) 323 printf("clock_wenable_info: WARNING -- cannot %s " 324 "page protection\n", onoff ? "disable" : "enable"); 325 } 326 return (err); 327 } 328 329 static void 330 clockattach_ebus(struct device *parent, struct device *self, void *aux) 331 { 332 struct ebus_attach_args *ea = aux; 333 bus_space_tag_t bt; 334 int sz; 335 static struct clock_wenable_info cwi; 336 337 /* hard code to 8K? */ 338 sz = ea->ea_regs[0].size; 339 340 if (ebus_bus_map(ea->ea_iotag, 0, 341 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) { 342 bt = ea->ea_iotag; 343 } else if (ebus_bus_map(ea->ea_memtag, 0, 344 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 345 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, 346 0, &cwi.cwi_bh) == 0) { 347 bt = ea->ea_memtag; 348 } else { 349 printf("%s: can't map register\n", self->dv_xname); 350 return; 351 } 352 353 clockattach(ea->ea_node, bt, cwi.cwi_bh); 354 355 /* Save info for the clock wenable call. */ 356 cwi.cwi_bt = bt; 357 cwi.cwi_size = sz; 358 todr_handle->bus_cookie = &cwi; 359 todr_handle->todr_setwen = (ea->ea_memtag == bt) ? 360 clock_bus_wenable : NULL; 361 } 362 363 static void 364 clockattach_fhc(struct device *parent, struct device *self, void *aux) 365 { 366 struct fhc_attach_args *fa = aux; 367 bus_space_tag_t bt = fa->fa_bustag; 368 int sz; 369 static struct clock_wenable_info cwi; 370 371 /* use sa->sa_regs[0].size? */ 372 sz = 8192; 373 374 if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot, 375 (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size, 376 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) { 377 printf("%s: can't map register\n", self->dv_xname); 378 return; 379 } 380 381 clockattach(fa->fa_node, bt, cwi.cwi_bh); 382 383 /* Save info for the clock wenable call. */ 384 cwi.cwi_bt = bt; 385 cwi.cwi_size = sz; 386 todr_handle->bus_cookie = &cwi; 387 todr_handle->todr_setwen = clock_bus_wenable; 388 } 389 390 static void 391 clockattach(int node, bus_space_tag_t bt, bus_space_handle_t bh) 392 { 393 char *model; 394 struct idprom *idp; 395 int h; 396 397 model = getpropstring(node, "model"); 398 399 #ifdef DIAGNOSTIC 400 if (model == NULL) 401 panic("clockattach: no model property"); 402 #endif 403 404 /* Our TOD clock year 0 is 1968 */ 405 if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL) 406 panic("Can't attach %s tod clock", model); 407 408 #define IDPROM_OFFSET (8*1024 - 40) /* XXX - get nvram sz from driver */ 409 if (idprom == NULL) { 410 idp = getidprom(); 411 if (idp == NULL) 412 idp = (struct idprom *)(bus_space_vaddr(bt, bh) + 413 IDPROM_OFFSET); 414 idprom = idp; 415 } else 416 idp = idprom; 417 h = idp->id_machine << 24; 418 h |= idp->id_hostid[0] << 16; 419 h |= idp->id_hostid[1] << 8; 420 h |= idp->id_hostid[2]; 421 hostid = h; 422 printf("\n"); 423 } 424 425 struct idprom * 426 getidprom(void) 427 { 428 struct idprom *idp = NULL; 429 int node, n; 430 431 node = findroot(); 432 if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0) 433 return (NULL); 434 if (n != 1) { 435 free(idp, M_DEVBUF, 0); 436 return (NULL); 437 } 438 return (idp); 439 } 440 441 /* 442 * XXX this belongs elsewhere 443 */ 444 void 445 myetheraddr(u_char *cp) 446 { 447 struct idprom *idp; 448 449 if ((idp = idprom) == NULL) { 450 int node, n; 451 452 node = findroot(); 453 if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) || 454 n != 1) { 455 printf("\nmyetheraddr: clock not setup yet, " 456 "and no idprom property in /\n"); 457 return; 458 } 459 } 460 461 cp[0] = idp->id_ether[0]; 462 cp[1] = idp->id_ether[1]; 463 cp[2] = idp->id_ether[2]; 464 cp[3] = idp->id_ether[3]; 465 cp[4] = idp->id_ether[4]; 466 cp[5] = idp->id_ether[5]; 467 if (idprom == NULL) 468 free(idp, M_DEVBUF, 0); 469 } 470 471 /* 472 * Set up the real-time and statistics clocks. 473 * 474 * The frequencies of these clocks must be an even number of microseconds. 475 */ 476 void 477 cpu_initclocks(void) 478 { 479 #ifdef DEBUG 480 extern int intrdebug; 481 #endif 482 u_int sys_tick_rate; 483 int impl = 0; 484 485 #ifdef DEBUG 486 /* Set a 1s clock */ 487 if (intrdebug) { 488 hz = 1; 489 tick = 1000000 / hz; 490 tick_nsec = 1000000000 / hz; 491 printf("intrdebug set: 1Hz clock\n"); 492 } 493 #endif 494 495 if (1000000 % hz) { 496 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 497 hz = 100; 498 tick = 1000000 / hz; 499 tick_nsec = 1000000000 / hz; 500 } 501 502 stathz = hz; 503 profhz = stathz * 10; 504 statclock_is_randomized = 1; 505 506 /* Make sure we have a sane cpu_clockrate -- we'll need it */ 507 if (!cpu_clockrate) 508 /* Default to 200MHz clock XXXXX */ 509 cpu_clockrate = 200000000; 510 511 tick_timecounter.tc_frequency = cpu_clockrate; 512 tc_init(&tick_timecounter); 513 514 /* 515 * UltraSPARC IIe processors do have a STICK register, but it 516 * lives on the PCI host bridge and isn't accessible through 517 * ASR24. 518 */ 519 if (CPU_ISSUN4U || CPU_ISSUN4US) 520 impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT; 521 522 sys_tick_rate = getpropint(findroot(), "stick-frequency", 0); 523 if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) { 524 sys_tick_timecounter.tc_frequency = sys_tick_rate; 525 tc_init(&sys_tick_timecounter); 526 } 527 528 struct cpu_info *ci; 529 530 /* We don't have a counter-timer -- use %tick */ 531 level0.ih_clr = 0; 532 533 /* 534 * Establish a level 10 interrupt handler 535 * 536 * We will have a conflict with the softint handler, 537 * so we set the ih_number to 1. 538 */ 539 level0.ih_number = 1; 540 strlcpy(level0.ih_name, "clock", sizeof(level0.ih_name)); 541 intr_establish(10, &level0); 542 evcount_percpu(&level0.ih_count); 543 544 if (sys_tick_rate > 0) { 545 sys_tick_nsec_cycle_ratio = 546 sys_tick_rate * (1ULL << 32) / 1000000000; 547 sys_tick_nsec_max = UINT64_MAX / sys_tick_nsec_cycle_ratio; 548 if (impl == IMPL_HUMMINGBIRD) { 549 level0.ih_fun = stickintr; 550 cpu_start_clock = stick_start; 551 } else { 552 level0.ih_fun = sys_tickintr; 553 cpu_start_clock = sys_tick_start; 554 } 555 } else { 556 tick_nsec_cycle_ratio = 557 cpu_clockrate * (1ULL << 32) / 1000000000; 558 tick_nsec_max = UINT64_MAX / tick_nsec_cycle_ratio; 559 level0.ih_fun = tickintr; 560 cpu_start_clock = tick_start; 561 } 562 563 for (ci = cpus; ci != NULL; ci = ci->ci_next) 564 memcpy(&ci->ci_tickintr, &level0, sizeof(level0)); 565 } 566 567 void 568 cpu_startclock(void) 569 { 570 cpu_start_clock(); 571 } 572 573 void 574 setstatclockrate(int newhz) 575 { 576 } 577 578 /* 579 * Level 10 (clock) interrupts. If we are using the FORTH PROM for 580 * console input, we need to check for that here as well, and generate 581 * a software interrupt to read it. 582 * 583 * %tick is really a level-14 interrupt. We need to remap this in 584 * locore.s to a level 10. 585 */ 586 int 587 tickintr(void *cap) 588 { 589 clockintr_dispatch(cap); 590 evcount_inc(&level0.ih_count); 591 return (1); 592 } 593 594 int 595 sys_tickintr(void *cap) 596 { 597 clockintr_dispatch(cap); 598 evcount_inc(&level0.ih_count); 599 return (1); 600 } 601 602 int 603 stickintr(void *cap) 604 { 605 clockintr_dispatch(cap); 606 evcount_inc(&level0.ih_count); 607 return (1); 608 } 609 610 void 611 tick_start(void) 612 { 613 tick_enable(); 614 615 clockintr_cpu_init(&tick_intrclock); 616 clockintr_trigger(); 617 } 618 619 void 620 tick_rearm(void *unused, uint64_t nsecs) 621 { 622 uint64_t s, t0; 623 uint32_t cycles; 624 625 if (nsecs > tick_nsec_max) 626 nsecs = tick_nsec_max; 627 cycles = (nsecs * tick_nsec_cycle_ratio) >> 32; 628 629 s = intr_disable(); 630 t0 = tick(); 631 tickcmpr_set((t0 + cycles) & TICK_COUNT_MASK); 632 if (cycles <= ((tick() - t0) & TICK_COUNT_MASK)) 633 sparc64_raise_clockintr(); 634 intr_restore(s); 635 } 636 637 void 638 tick_trigger(void *unused) 639 { 640 sparc64_raise_clockintr(); 641 } 642 643 void 644 sys_tick_start(void) 645 { 646 if (CPU_ISSUN4U || CPU_ISSUN4US) { 647 tick_enable(); 648 sys_tick_enable(); 649 } 650 651 clockintr_cpu_init(&sys_tick_intrclock); 652 clockintr_trigger(); 653 } 654 655 void 656 sys_tick_rearm(void *unused, uint64_t nsecs) 657 { 658 uint64_t s, t0; 659 uint32_t cycles; 660 661 if (nsecs > sys_tick_nsec_max) 662 nsecs = sys_tick_nsec_max; 663 cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32; 664 665 s = intr_disable(); 666 t0 = sys_tick(); 667 sys_tickcmpr_set((t0 + cycles) & STICK_COUNT_MASK); 668 if (cycles <= ((sys_tick() - t0) & STICK_COUNT_MASK)) 669 sparc64_raise_clockintr(); 670 intr_restore(s); 671 } 672 673 void 674 sys_tick_trigger(void *unused) 675 { 676 sparc64_raise_clockintr(); 677 } 678 679 void 680 stick_start(void) 681 { 682 tick_enable(); 683 684 clockintr_cpu_init(&stick_intrclock); 685 clockintr_trigger(); 686 } 687 688 void 689 stick_rearm(void *unused, uint64_t nsecs) 690 { 691 uint64_t s, t0; 692 uint32_t cycles; 693 694 if (nsecs > sys_tick_nsec_max) 695 nsecs = sys_tick_nsec_max; 696 cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32; 697 698 s = intr_disable(); 699 t0 = stick(); 700 stickcmpr_set((t0 + cycles) & STICK_COUNT_MASK); 701 if (cycles <= ((stick() - t0) & STICK_COUNT_MASK)) 702 sparc64_raise_clockintr(); 703 intr_restore(s); 704 } 705 706 void 707 stick_trigger(void *unused) 708 { 709 sparc64_raise_clockintr(); 710 } 711 712 u_int 713 tick_get_timecount(struct timecounter *tc) 714 { 715 u_int64_t tick; 716 717 __asm volatile("rd %%tick, %0" : "=r" (tick)); 718 719 return (tick & ~0u); 720 } 721 722 u_int 723 sys_tick_get_timecount(struct timecounter *tc) 724 { 725 u_int64_t tick; 726 727 __asm volatile("rd %%sys_tick, %0" : "=r" (tick)); 728 729 return (tick & ~0u); 730 } 731 732 void 733 sparc64_raise_clockintr(void) 734 { 735 send_softint(-1, PIL_CLOCK, &curcpu()->ci_tickintr); 736 } 737