Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: clock.c,v 1.124 2024/07/12 22:31:40 andvar 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 #include <sys/cdefs.h>
     58 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.124 2024/07/12 22:31:40 andvar Exp $");
     59 
     60 #include "opt_multiprocessor.h"
     61 
     62 /*
     63  * Clock driver.  This is the id prom and eeprom driver as well
     64  * and includes the timer register functions too.
     65  */
     66 
     67 /* Define this for a 1/4s clock to ease debugging */
     68 /* #define INTR_DEBUG */
     69 
     70 #include <sys/param.h>
     71 #include <sys/kernel.h>
     72 #include <sys/device.h>
     73 #include <sys/proc.h>
     74 #include <sys/resourcevar.h>
     75 #include <sys/systm.h>
     76 #include <sys/timetc.h>
     77 #ifdef GPROF
     78 #include <sys/gmon.h>
     79 #endif
     80 
     81 #include <uvm/uvm_extern.h>
     82 
     83 #include <sys/bus.h>
     84 #include <machine/autoconf.h>
     85 #include <machine/eeprom.h>
     86 #include <machine/cpu.h>
     87 
     88 #include <sparc64/sparc64/intreg.h>
     89 #include <sparc64/sparc64/timerreg.h>
     90 #include <sparc64/dev/iommureg.h>
     91 
     92 #include "psycho.h"
     93 /* just because US-IIe STICK registers live in psycho space */
     94 #if NPSYCHO > 0
     95 #include <dev/pci/pcivar.h>
     96 #include <dev/pci/pcireg.h>
     97 #include <sparc64/dev/iommureg.h>
     98 #include <sparc64/dev/iommuvar.h>
     99 #include <sparc64/dev/psychoreg.h>
    100 #include <sparc64/dev/psychovar.h>
    101 #endif
    102 
    103 /*
    104  * Clock assignments:
    105  *
    106  * machine		hardclock	statclock	timecounter
    107  *  counter-timer	 timer#0	 timer#1	 %tick
    108  *  counter-timer + SMP	 timer#0/%tick	 -		 timer#1 or %tick
    109  *  no counter-timer	 %tick		 -		 %tick
    110  *  US-IIe		 STICK		 -		 STICK
    111  *  US-IIIi		 %stick		 -		 %stick
    112  *  sun4v		 %stick		 -		 %stick
    113  *
    114  * US-IIe and US-IIIi could use %tick as statclock
    115  */
    116 
    117 /*
    118  * Statistics clock interval and variance, in usec.  Variance must be a
    119  * power of two.  Since this gives us an even number, not an odd number,
    120  * we discard one case and compensate.  That is, a variance of 1024 would
    121  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
    122  * This is symmetric about the point 512, or statvar/2, and thus averages
    123  * to that value (assuming uniform random numbers).
    124  */
    125 /* XXX fix comment to match value */
    126 int statvar = 8192;
    127 int statmin;			/* statclock interval - 1/2*variance */
    128 int timerok;
    129 #ifndef MULTIPROCESSOR
    130 static int statscheddiv;
    131 static struct intrhand *schedint;
    132 #endif
    133 
    134 static int	timermatch(device_t, cfdata_t, void *);
    135 static void	timerattach(device_t, device_t, void *);
    136 
    137 struct timerreg_4u	timerreg_4u;	/* XXX - need more cleanup */
    138 
    139 CFATTACH_DECL_NEW(timer, 0,
    140     timermatch, timerattach, NULL, NULL);
    141 
    142 struct chiptime;
    143 void stopcounter(struct timer_4u *);
    144 
    145 int timerblurb = 10; /* Guess a value; used before clock is attached */
    146 
    147 static u_int tick_get_timecount(struct timecounter *);
    148 static u_int stick_get_timecount(struct timecounter *);
    149 #if NPSYCHO > 0
    150 static u_int stick2e_get_timecount(struct timecounter *);
    151 #endif
    152 
    153 /*
    154  * define timecounter "tick-counter"
    155  */
    156 
    157 static struct timecounter tick_timecounter = {
    158 	.tc_get_timecount = tick_get_timecount,
    159 	.tc_counter_mask = ~0u,
    160 	.tc_name = "tick-counter",
    161 	.tc_quality = 100,
    162 };
    163 
    164 /* US-III %stick */
    165 
    166 static struct timecounter stick_timecounter = {
    167 	.tc_get_timecount = stick_get_timecount,
    168 	.tc_counter_mask = ~0u,
    169 	.tc_name = "stick-counter",
    170 	.tc_quality = 200,
    171 };
    172 
    173 /* US-IIe STICK counter */
    174 #if NPSYCHO > 0
    175 static struct timecounter stick2e_timecounter = {
    176 	.tc_get_timecount = stick2e_get_timecount,
    177 	.tc_counter_mask = ~0u,
    178 	.tc_name = "stick-counter",
    179 	.tc_quality = 200,
    180 };
    181 #endif
    182 
    183 /*
    184  * tick_get_timecount provide current tick counter value
    185  */
    186 static u_int
    187 tick_get_timecount(struct timecounter *tc)
    188 {
    189 	return gettick();
    190 }
    191 
    192 static u_int
    193 stick_get_timecount(struct timecounter *tc)
    194 {
    195 	return getstick();
    196 }
    197 
    198 #if NPSYCHO > 0
    199 static u_int
    200 stick2e_get_timecount(struct timecounter *tc)
    201 {
    202 	return psycho_getstick32();
    203 }
    204 #endif
    205 
    206 #ifdef MULTIPROCESSOR
    207 static u_int counter_get_timecount(struct timecounter *);
    208 
    209 /*
    210  * define timecounter "counter-timer"
    211  */
    212 
    213 static struct timecounter counter_timecounter = {
    214 	counter_get_timecount,	/* get_timecount */
    215 	0,			/* no poll_pps */
    216 	TMR_LIM_MASK,		/* counter_mask */
    217 	1000000,		/* frequency */
    218 	"counter-timer",	/* name */
    219 	200,			/* quality */
    220 	0,			/* private reference - UNUSED */
    221 	NULL			/* next timecounter */
    222 };
    223 
    224 /*
    225  * counter_get_timecount provide current counter value
    226  */
    227 static u_int
    228 counter_get_timecount(struct timecounter *tc)
    229 {
    230 	return (u_int)ldxa((vaddr_t)&timerreg_4u.t_timer[1].t_count,
    231 			   ASI_NUCLEUS) & TMR_LIM_MASK;
    232 }
    233 #endif
    234 
    235 /*
    236  * The sun4u OPENPROMs call the timer the "counter-timer", except for
    237  * the lame UltraSPARC IIi PCI machines that don't have them.
    238  */
    239 static int
    240 timermatch(device_t parent, cfdata_t cf, void *aux)
    241 {
    242 	struct mainbus_attach_args *ma = aux;
    243 
    244 	return (strcmp("counter-timer", ma->ma_name) == 0);
    245 }
    246 
    247 static void
    248 timerattach(device_t parent, device_t self, void *aux)
    249 {
    250 	struct mainbus_attach_args *ma = aux;
    251 	u_int *va = ma->ma_address;
    252 #if 0
    253 	volatile int64_t *cnt = NULL, *lim = NULL;
    254 #endif
    255 
    256 	/*
    257 	 * What we should have are 3 sets of registers that reside on
    258 	 * different parts of SYSIO or PSYCHO.  We'll use the prom
    259 	 * mappings cause we can't get rid of them and set up appropriate
    260 	 * pointers on the timerreg_4u structure.
    261 	 */
    262 	timerreg_4u.t_timer = (struct timer_4u *)(u_long)va[0];
    263 	timerreg_4u.t_clrintr = (int64_t *)(u_long)va[1];
    264 	timerreg_4u.t_mapintr = (int64_t *)(u_long)va[2];
    265 
    266 	/*
    267 	 * Disable interrupts for now.
    268 	 * N.B. By default timer[0] is disabled and timer[1] is enabled.
    269 	 */
    270 	stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS,
    271 	     (timerreg_4u.t_mapintr[0] & ~(INTMAP_V|INTMAP_TID)) |
    272 	     (CPU_UPAID << INTMAP_TID_SHIFT));
    273 	stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS,
    274 	     (timerreg_4u.t_mapintr[1] & ~(INTMAP_V|INTMAP_TID)) |
    275 	     (CPU_UPAID << INTMAP_TID_SHIFT));
    276 
    277 	/* Install the appropriate interrupt vector here */
    278 	struct intrhand *level10 = intrhand_alloc();
    279 	level10->ih_fun = clockintr;
    280 	level10->ih_pil = PIL_CLOCK;
    281 	level10->ih_number = INTVEC(ma->ma_interrupts[0]);
    282 	level10->ih_clr = &timerreg_4u.t_clrintr[0];
    283 	intr_establish(PIL_CLOCK, true, level10);
    284 	printf(" irq vectors %lx", (u_long)level10->ih_number);
    285 #ifndef MULTIPROCESSOR
    286 	/*
    287 	 * On SMP kernel, don't establish interrupt to use it as timecounter.
    288 	 */
    289 	struct intrhand *level14 = intrhand_alloc();
    290 	level14->ih_fun = statintr;
    291 	level14->ih_pil = PIL_STATCLOCK;
    292 	level14->ih_number = INTVEC(ma->ma_interrupts[1]);
    293 	level14->ih_clr = &timerreg_4u.t_clrintr[1];
    294 	intr_establish(PIL_STATCLOCK, true, level14);
    295 	printf(" and %lx", (u_long)level14->ih_number);
    296 #endif
    297 
    298 #if 0
    299 	cnt = &(timerreg_4u.t_timer[0].t_count);
    300 	lim = &(timerreg_4u.t_timer[0].t_limit);
    301 
    302 	/*
    303 	 * Calibrate delay() by tweaking the magic constant
    304 	 * until a delay(100) actually reads (at least) 100 us
    305 	 * on the clock.  Since we're using the %tick register
    306 	 * which should be running at exactly the CPU clock rate, it
    307 	 * has a period of somewhere between 7ns and 3ns.
    308 	 */
    309 
    310 #ifdef DEBUG
    311 	printf("Delay calibration....\n");
    312 #endif
    313 	for (timerblurb = 1; timerblurb > 0; timerblurb++) {
    314 		volatile int discard;
    315 		register int t0, t1;
    316 
    317 		/* Reset counter register by writing some large limit value */
    318 		discard = *lim;
    319 		*lim = tmr_ustolim(TMR_MASK-1);
    320 
    321 		t0 = *cnt;
    322 		delay(100);
    323 		t1 = *cnt;
    324 
    325 		if (t1 & TMR_LIMIT)
    326 			panic("delay calibration");
    327 
    328 		t0 = (t0 >> TMR_SHIFT) & TMR_MASK;
    329 		t1 = (t1 >> TMR_SHIFT) & TMR_MASK;
    330 
    331 		if (t1 >= t0 + 100)
    332 			break;
    333 	}
    334 
    335 	printf(" delay constant %d\n", timerblurb);
    336 #endif
    337 	printf("\n");
    338 	timerok = 1;
    339 }
    340 
    341 void
    342 stopcounter(struct timer_4u *creg)
    343 {
    344 	volatile struct timer_4u *reg = creg;
    345 
    346 	/* Stop the clock */
    347 	(void)reg->t_limit;
    348 	reg->t_limit = 0;
    349 }
    350 
    351 /*
    352  * Untill interrupts are established per CPU, we rely on the special
    353  * handling of tickintr in locore.s.
    354  * We establish this interrupt if there is no real counter-timer on
    355  * the machine, or on secondary CPUs. The latter would normally not be
    356  * able to dispatch the interrupt (established on cpu0) to another cpu,
    357  * but the shortcut during dispatch makes it work.
    358  */
    359 void
    360 tickintr_establish(int pil, int (*fun)(void *))
    361 {
    362 	int s;
    363 	struct intrhand *ih;
    364 	struct cpu_info *ci = curcpu();
    365 
    366 	ih = sparc_softintr_establish(pil, fun, NULL);
    367 	ih->ih_number = 1;
    368 	if (CPU_IS_PRIMARY(ci))
    369 		intr_establish(pil, true, ih);
    370 	ci->ci_tick_ih = ih;
    371 
    372 	/* set the next interrupt time */
    373 	ci->ci_tick_increment = ci->ci_cpu_clockrate[0] / hz;
    374 
    375 	s = intr_disable();
    376 	next_tick(ci->ci_tick_increment);
    377 	intr_restore(s);
    378 }
    379 
    380 void
    381 stickintr_establish(int pil, int (*fun)(void *))
    382 {
    383 	int s;
    384 	struct intrhand *ih;
    385 	struct cpu_info *ci = curcpu();
    386 
    387 	ih = sparc_softintr_establish(pil, fun, NULL);
    388 	ih->ih_number = 1;
    389 	if (CPU_IS_PRIMARY(ci))
    390 		intr_establish(pil, true, ih);
    391 	ci->ci_tick_ih = ih;
    392 
    393 	/* set the next interrupt time */
    394 	ci->ci_tick_increment = ci->ci_system_clockrate[0] / hz;
    395 
    396 	s = intr_disable();
    397 	next_stick_init();
    398 	next_stick(ci->ci_tick_increment);
    399 	intr_restore(s);
    400 }
    401 
    402 #if NPSYCHO > 0
    403 void
    404 stick2eintr_establish(int pil, int (*fun)(void *))
    405 {
    406 	int s;
    407 	struct intrhand *ih;
    408 	struct cpu_info *ci = curcpu();
    409 
    410 	ih = sparc_softintr_establish(pil, fun, NULL);
    411 	ih->ih_number = 1;
    412 	if (CPU_IS_PRIMARY(ci))
    413 		intr_establish(pil, true, ih);
    414 	ci->ci_tick_ih = ih;
    415 
    416 	/* set the next interrupt time */
    417 	ci->ci_tick_increment = ci->ci_system_clockrate[0] / hz;
    418 
    419 	s = intr_disable();
    420 	psycho_nextstick(ci->ci_tick_increment);
    421 	intr_restore(s);
    422 }
    423 #endif
    424 
    425 /*
    426  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
    427  * no alternative timer is available.
    428  *
    429  * The frequencies of these clocks must be an even number of microseconds.
    430  */
    431 void
    432 cpu_initclocks(void)
    433 {
    434 	struct cpu_info *ci = curcpu();
    435 #ifndef MULTIPROCESSOR
    436 	int statint, minint;
    437 #endif
    438 #ifdef DEBUG
    439 	extern int intrdebug;
    440 #endif
    441 
    442 #ifdef DEBUG
    443 	/* Set a 1s clock */
    444 	if (intrdebug) {
    445 		hz = 1;
    446 		tick = 1000000 / hz;
    447 		printf("intrdebug set: 1Hz clock\n");
    448 	}
    449 #endif
    450 
    451 	if (1000000 % hz) {
    452 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
    453 		hz = 100;
    454 		tick = 1000000 / hz;
    455 	}
    456 
    457 	/* Make sure we have a sane cpu_clockrate -- we'll need it */
    458 	if (!ci->ci_cpu_clockrate[0]) {
    459 		/* Default to 200MHz clock XXXXX */
    460 		ci->ci_cpu_clockrate[0] = 200000000;
    461 		ci->ci_cpu_clockrate[1] = 200000000 / 1000000;
    462 	}
    463 
    464 	/* Initialize the %tick register */
    465 	if (CPU_ISSUN4U || CPU_ISSUN4US)
    466 		settick(0);
    467 
    468 	/* Register timecounter "tick-counter" */
    469 	tick_timecounter.tc_frequency = ci->ci_cpu_clockrate[0];
    470 	tc_init(&tick_timecounter);
    471 
    472 	/* Register timecounter "stick-counter" */
    473 	if (ci->ci_system_clockrate[0] != 0) {
    474 		if (CPU_ISSUN4U && CPU_IS_HUMMINGBIRD()) {
    475 #if NPSYCHO > 0
    476 			psycho_setstick(0);
    477 			stick2e_timecounter.tc_frequency =
    478 			    ci->ci_system_clockrate[0];
    479 			tc_init(&stick2e_timecounter);
    480 #endif
    481 		} else {
    482 			if (CPU_ISSUN4U || CPU_ISSUN4US)
    483 				setstick(0);
    484 			stick_timecounter.tc_frequency =
    485 			    ci->ci_system_clockrate[0];
    486 			tc_init(&stick_timecounter);
    487 		}
    488 	}
    489 
    490 	/*
    491 	 * Now handle machines w/o counter-timers.
    492 	 * XXX
    493 	 * If the CPU is an US-IIe and we don't have a psycho we need to fall
    494 	 * back to %tick. Not that a kernel like that would get very far on any
    495 	 * supported hardware ( without PCI... ) - I'm not sure if such hardware
    496 	 * even exists.
    497 	 */
    498 
    499 	if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
    500 
    501 		if (ci->ci_system_clockrate[0] == 0) {
    502 			aprint_normal("No counter-timer -- using %%tick "
    503 			    "at %sMHz as system clock.\n",
    504 			    clockfreq(ci->ci_cpu_clockrate[0]));
    505 
    506 			/* We don't have a counter-timer -- use %tick */
    507 			tickintr_establish(PIL_CLOCK, tickintr);
    508 		} else if (CPU_ISSUN4U && CPU_IS_HUMMINGBIRD()) {
    509 #if NPSYCHO > 0
    510 			aprint_normal("No counter-timer -- using STICK "
    511 			    "at %sMHz as system clock.\n",
    512 			    clockfreq(ci->ci_system_clockrate[0]));
    513 
    514 			/* We don't have a counter-timer -- use STICK */
    515 			stick2eintr_establish(PIL_CLOCK, stick2eintr);
    516 #else
    517 			panic("trying to use STICK without psycho?!");
    518 #endif
    519 		} else {
    520 			aprint_normal("No counter-timer -- using %%stick "
    521 			    "at %sMHz as system clock.\n",
    522 			    clockfreq(ci->ci_system_clockrate[0]));
    523 
    524 			/* We don't have a counter-timer -- use %stick */
    525 			stickintr_establish(PIL_CLOCK, stickintr);
    526 		}
    527 		/* We only have one timer so we have no statclock */
    528 		stathz = 0;
    529 
    530 		return;
    531 	}
    532 
    533 #ifndef MULTIPROCESSOR
    534 	if (stathz == 0)
    535 		stathz = hz;
    536 	if (1000000 % stathz) {
    537 		printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
    538 		stathz = 100;
    539 	}
    540 
    541 	profhz = stathz;		/* always */
    542 
    543 	statint = 1000000 / stathz;
    544 	minint = statint / 2 + 100;
    545 	while (statvar > minint)
    546 		statvar >>= 1;
    547 
    548 	/*
    549 	 * Establish scheduler softint.
    550 	 */
    551 	schedint = sparc_softintr_establish(PIL_SCHED, schedintr, NULL);
    552 	if (stathz > 60)
    553 		schedhz = 16;	/* 16Hz is best according to kern/kern_clock.c */
    554 	else
    555 		schedhz = stathz / 2 + 1;
    556 	statscheddiv = stathz / schedhz;
    557 	if (statscheddiv <= 0)
    558 		panic("statscheddiv");
    559 #endif
    560 
    561 	/*
    562 	 * Enable counter-timer #0 interrupt for clockintr.
    563 	 */
    564 	stxa((vaddr_t)&timerreg_4u.t_timer[0].t_limit, ASI_NUCLEUS,
    565 	     tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD);
    566 	stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS,
    567 	     timerreg_4u.t_mapintr[0]|INTMAP_V);
    568 
    569 #ifdef MULTIPROCESSOR
    570 	/*
    571 	 * Use counter-timer #1 as timecounter.
    572 	 */
    573 	stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
    574 	     TMR_LIM_MASK);
    575 	tc_init(&counter_timecounter);
    576 #else
    577 	/*
    578 	 * Enable counter-timer #1 interrupt for statintr.
    579 	 */
    580 #ifdef DEBUG
    581 	if (intrdebug)
    582 		/* Neglect to enable timer */
    583 		stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
    584 		     tmr_ustolim(statint)|TMR_LIM_RELOAD);
    585 	else
    586 #endif
    587 		stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
    588 		     tmr_ustolim(statint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
    589 	stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS,
    590 	     timerreg_4u.t_mapintr[1]|INTMAP_V|(CPU_UPAID << INTMAP_TID_SHIFT));
    591 
    592 	statmin = statint - (statvar >> 1);
    593 #endif
    594 }
    595 
    596 /*
    597  * Dummy setstatclockrate(), since we know profhz==hz.
    598  */
    599 /* ARGSUSED */
    600 void
    601 setstatclockrate(int newhz)
    602 {
    603 	/* nothing */
    604 }
    605 
    606 /*
    607  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
    608  * console input, we need to check for that here as well, and generate
    609  * a software interrupt to read it.
    610  */
    611 #ifdef	DEBUG
    612 static int clockcheck = 0;
    613 #endif
    614 int
    615 clockintr(void *cap)
    616 {
    617 #ifdef DEBUG
    618 	static int64_t tick_base = 0;
    619 	struct timeval ctime;
    620 	int64_t t = gettick();
    621 
    622 	microtime(&ctime);
    623 	if (!tick_base) {
    624 		tick_base = (ctime.tv_sec * 1000000LL + ctime.tv_usec)
    625 			/ curcpu()->ci_cpu_clockrate[1];
    626 		tick_base -= t;
    627 	} else if (clockcheck) {
    628 		int64_t tk = t;
    629 		int64_t clk = (ctime.tv_sec * 1000000LL + ctime.tv_usec);
    630 		t -= tick_base;
    631 		t = t / curcpu()->ci_cpu_clockrate[1];
    632 		if (t - clk > hz) {
    633 			printf("Clock lost an interrupt!\n");
    634 			printf("Actual: %llx Expected: %llx tick %llx tick_base %llx\n",
    635 			       (long long)t, (long long)clk, (long long)tk, (long long)tick_base);
    636 			tick_base = 0;
    637 		}
    638 	}
    639 #endif
    640 	/* Let locore.s clear the interrupt for us. */
    641 	hardclock((struct clockframe *)cap);
    642 	return (1);
    643 }
    644 
    645 /*
    646  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
    647  * console input, we need to check for that here as well, and generate
    648  * a software interrupt to read it.
    649  *
    650  * %tick is really a level-14 interrupt.  We need to remap this in
    651  * locore.s to a level 10.
    652  */
    653 int
    654 tickintr(void *cap)
    655 {
    656 	int s;
    657 
    658 	hardclock((struct clockframe *)cap);
    659 
    660 	s = intr_disable();
    661 	/* Reset the interrupt */
    662 	next_tick(curcpu()->ci_tick_increment);
    663 	intr_restore(s);
    664 	curcpu()->ci_tick_evcnt.ev_count++;
    665 
    666 	return (1);
    667 }
    668 
    669 int
    670 stickintr(void *cap)
    671 {
    672 	int s;
    673 
    674 	hardclock((struct clockframe *)cap);
    675 
    676 	s = intr_disable();
    677 	/* Reset the interrupt */
    678 	next_stick(curcpu()->ci_tick_increment);
    679 	intr_restore(s);
    680 	curcpu()->ci_tick_evcnt.ev_count++;
    681 
    682 	return (1);
    683 }
    684 
    685 #if NPSYCHO > 0
    686 int
    687 stick2eintr(void *cap)
    688 {
    689 	int s;
    690 
    691 	hardclock((struct clockframe *)cap);
    692 
    693 	s = intr_disable();
    694 	/* Reset the interrupt */
    695 	psycho_nextstick(curcpu()->ci_tick_increment);
    696 	intr_restore(s);
    697 	curcpu()->ci_tick_evcnt.ev_count++;
    698 
    699 	return (1);
    700 }
    701 #endif
    702 
    703 #ifndef MULTIPROCESSOR
    704 /*
    705  * Level 14 (stat clock) interrupt handler.
    706  */
    707 int
    708 statintr(void *cap)
    709 {
    710 	register u_long newint, r, var;
    711 	struct cpu_info *ci = curcpu();
    712 
    713 #ifdef NOT_DEBUG
    714 	printf("statclock: count %x:%x, limit %x:%x\n",
    715 	    timerreg_4u.t_timer[0].t_count, timerreg_4u.t_timer[1].t_count,
    716 	    timerreg_4u.t_timer[0].t_limit, timerreg_4u.t_timer[1].t_limit);
    717 #endif
    718 #ifdef NOT_DEBUG
    719 	prom_printf("!");
    720 #endif
    721 	statclock((struct clockframe *)cap);
    722 #ifdef NOTDEF_DEBUG
    723 	/* Don't re-schedule the IRQ */
    724 	return 1;
    725 #endif
    726 	/*
    727 	 * Compute new randomized interval.  The intervals are uniformly
    728 	 * distributed on [statint - statvar / 2, statint + statvar / 2],
    729 	 * and therefore have mean statint, giving a stathz frequency clock.
    730 	 */
    731 	var = statvar;
    732 	do {
    733 		r = random() & (var - 1);
    734 	} while (r == 0);
    735 	newint = statmin + r;
    736 
    737 	if (schedhz)
    738 		if ((int)(--ci->ci_schedstate.spc_schedticks) <= 0) {
    739 			send_softint(-1, PIL_SCHED, schedint);
    740 			ci->ci_schedstate.spc_schedticks = statscheddiv;
    741 		}
    742 	stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
    743 	     tmr_ustolim(newint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
    744 	return (1);
    745 }
    746 
    747 int
    748 schedintr(void *arg)
    749 {
    750 
    751 	schedclock(curcpu()->ci_onproc);
    752 	return (1);
    753 }
    754 #endif
    755