xref: /openbsd/sys/arch/sparc64/sparc64/clock.c (revision 3bef86f7)
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