xref: /openbsd/sys/arch/sparc64/sparc64/clock.c (revision e1f14dc3)
1 /*	$OpenBSD: clock.c,v 1.87 2024/04/08 20:05:51 miod 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/malloc.h>
70 #include <sys/systm.h>
71 #include <sys/clockintr.h>
72 #include <sys/sched.h>
73 #include <sys/stdint.h>
74 #include <sys/timetc.h>
75 #include <sys/atomic.h>
76 
77 #include <machine/bus.h>
78 #include <machine/autoconf.h>
79 #include <machine/cpu.h>
80 #include <machine/idprom.h>
81 
82 #include <dev/clock_subr.h>
83 #include <dev/ic/mk48txxreg.h>
84 
85 #include <sparc64/dev/iommureg.h>
86 #include <sparc64/dev/sbusreg.h>
87 #include <dev/sbus/sbusvar.h>
88 #include <sparc64/dev/ebusreg.h>
89 #include <sparc64/dev/ebusvar.h>
90 #include <sparc64/dev/fhcvar.h>
91 
92 extern u_int64_t cpu_clockrate;
93 
94 struct clock_wenable_info {
95 	bus_space_tag_t		cwi_bt;
96 	bus_space_handle_t	cwi_bh;
97 	bus_size_t		cwi_size;
98 };
99 
100 struct cfdriver clock_cd = {
101 	NULL, "clock", DV_DULL
102 };
103 
104 u_int tick_get_timecount(struct timecounter *);
105 
106 struct timecounter tick_timecounter = {
107 	.tc_get_timecount = tick_get_timecount,
108 	.tc_counter_mask = ~0u,
109 	.tc_frequency = 0,
110 	.tc_name = "tick",
111 	.tc_quality = 0,
112 	.tc_priv = NULL,
113 	.tc_user = TC_TICK,
114 };
115 
116 u_int sys_tick_get_timecount(struct timecounter *);
117 
118 struct timecounter sys_tick_timecounter = {
119 	.tc_get_timecount = sys_tick_get_timecount,
120 	.tc_counter_mask = ~0u,
121 	.tc_frequency = 0,
122 	.tc_name = "sys_tick",
123 	.tc_quality = 1000,
124 	.tc_priv = NULL,
125 	.tc_user = TC_SYS_TICK,
126 };
127 
128 void	tick_start(void);
129 void	sys_tick_start(void);
130 void	stick_start(void);
131 
132 int	tickintr(void *);
133 int	sys_tickintr(void *);
134 int	stickintr(void *);
135 
136 /* %TICK is at most a 63-bit counter. */
137 #define TICK_COUNT_MASK 0x7fffffffffffffff
138 
139 uint64_t tick_nsec_cycle_ratio;
140 uint64_t tick_nsec_max;
141 
142 void tick_rearm(void *, uint64_t);
143 void tick_trigger(void *);
144 
145 const struct intrclock tick_intrclock = {
146 	.ic_rearm = tick_rearm,
147 	.ic_trigger = tick_trigger
148 };
149 
150 /* %STICK is at most a 63-bit counter. */
151 #define STICK_COUNT_MASK 0x7fffffffffffffff
152 
153 uint64_t sys_tick_nsec_cycle_ratio;
154 uint64_t sys_tick_nsec_max;
155 
156 void sys_tick_rearm(void *, uint64_t);
157 void sys_tick_trigger(void *);
158 
159 const struct intrclock sys_tick_intrclock = {
160 	.ic_rearm = sys_tick_rearm,
161 	.ic_trigger = sys_tick_trigger
162 };
163 
164 void stick_rearm(void *, uint64_t);
165 void stick_trigger(void *);
166 
167 const struct intrclock stick_intrclock = {
168 	.ic_rearm = stick_rearm,
169 	.ic_trigger = stick_trigger
170 };
171 
172 void sparc64_raise_clockintr(void);
173 
174 static struct intrhand level10 = {
175 	.ih_fun = tickintr,
176 	.ih_number = 1,
177 	.ih_pil = 10,
178 	.ih_name = "clock"
179 };
180 
181 /*
182  * clock (eeprom) attaches at the sbus or the ebus (PCI)
183  */
184 static int	clockmatch_sbus(struct device *, void *, void *);
185 static void	clockattach_sbus(struct device *, struct device *, void *);
186 static int	clockmatch_ebus(struct device *, void *, void *);
187 static void	clockattach_ebus(struct device *, struct device *, void *);
188 static int	clockmatch_fhc(struct device *, void *, void *);
189 static void	clockattach_fhc(struct device *, struct device *, void *);
190 static void	clockattach(int, bus_space_tag_t, bus_space_handle_t);
191 
192 const struct cfattach clock_sbus_ca = {
193 	sizeof(struct device), clockmatch_sbus, clockattach_sbus
194 };
195 
196 const struct cfattach clock_ebus_ca = {
197 	sizeof(struct device), clockmatch_ebus, clockattach_ebus
198 };
199 
200 const struct cfattach clock_fhc_ca = {
201 	sizeof(struct device), clockmatch_fhc, clockattach_fhc
202 };
203 
204 /* Global TOD clock handle & idprom pointer */
205 extern todr_chip_handle_t todr_handle;
206 static struct idprom *idprom;
207 
208 int clock_bus_wenable(struct todr_chip_handle *, int);
209 void myetheraddr(u_char *);
210 struct idprom *getidprom(void);
211 
212 /*
213  * The OPENPROM calls the clock the "eeprom", so we have to have our
214  * own special match function to call it the "clock".
215  */
216 static int
clockmatch_sbus(struct device * parent,void * cf,void * aux)217 clockmatch_sbus(struct device *parent, void *cf, void *aux)
218 {
219 	struct sbus_attach_args *sa = aux;
220 
221 	return (strcmp("eeprom", sa->sa_name) == 0);
222 }
223 
224 static int
clockmatch_ebus(struct device * parent,void * cf,void * aux)225 clockmatch_ebus(struct device *parent, void *cf, void *aux)
226 {
227 	struct ebus_attach_args *ea = aux;
228 
229 	return (strcmp("eeprom", ea->ea_name) == 0);
230 }
231 
232 static int
clockmatch_fhc(struct device * parent,void * cf,void * aux)233 clockmatch_fhc(struct device *parent, void *cf, void *aux)
234 {
235 	struct fhc_attach_args *fa = aux;
236 
237 	return (strcmp("eeprom", fa->fa_name) == 0);
238 }
239 
240 /*
241  * Attach a clock (really `eeprom') to the sbus or ebus.
242  *
243  * We ignore any existing virtual address as we need to map
244  * this read-only and make it read-write only temporarily,
245  * whenever we read or write the clock chip.  The clock also
246  * contains the ID ``PROM'', and I have already had the pleasure
247  * of reloading the cpu type, Ethernet address, etc, by hand from
248  * the console FORTH interpreter.  I intend not to enjoy it again.
249  *
250  * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
251  * supposed to be identical to it.
252  *
253  * This is *UGLY*!  We probably have multiple mappings.  But I do
254  * know that this all fits inside an 8K page, so I'll just map in
255  * once.
256  *
257  * What we really need is some way to record the bus attach args
258  * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
259  * or not to write enable/disable the device registers.  This is
260  * a non-trivial operation.
261  */
262 
263 static void
clockattach_sbus(struct device * parent,struct device * self,void * aux)264 clockattach_sbus(struct device *parent, struct device *self, void *aux)
265 {
266 	struct sbus_attach_args *sa = aux;
267 	bus_space_tag_t bt = sa->sa_bustag;
268 	int sz;
269 	static struct clock_wenable_info cwi;
270 
271 	/* use sa->sa_regs[0].size? */
272 	sz = 8192;
273 
274 	if (sbus_bus_map(bt,
275 			 sa->sa_slot,
276 			 (sa->sa_offset & ~NBPG),
277 			 sz,
278 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
279 			 0, &cwi.cwi_bh) != 0) {
280 		printf("%s: can't map register\n", self->dv_xname);
281 		return;
282 	}
283 	clockattach(sa->sa_node, bt, cwi.cwi_bh);
284 
285 	/* Save info for the clock wenable call. */
286 	cwi.cwi_bt = bt;
287 	cwi.cwi_size = sz;
288 	todr_handle->bus_cookie = &cwi;
289 	todr_handle->todr_setwen = clock_bus_wenable;
290 }
291 
292 /*
293  * Write en/dis-able clock registers.  We coordinate so that several
294  * writers can run simultaneously.
295  * XXX There is still a race here.  The page change and the "writers"
296  * change are not atomic.
297  */
298 int
clock_bus_wenable(struct todr_chip_handle * handle,int onoff)299 clock_bus_wenable(struct todr_chip_handle *handle, int onoff)
300 {
301 	int s, err = 0;
302 	int prot; /* nonzero => change prot */
303 	volatile static int writers;
304 	struct clock_wenable_info *cwi = handle->bus_cookie;
305 
306 	s = splhigh();
307 	if (onoff)
308 		prot = writers++ == 0 ? 1 : 0;
309 	else
310 		prot = --writers == 0 ? 1 : 0;
311 	splx(s);
312 
313 	if (prot) {
314 		err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size,
315 		    onoff ? 0 : BUS_SPACE_MAP_READONLY);
316 		if (err)
317 			printf("clock_wenable_info: WARNING -- cannot %s "
318 			    "page protection\n", onoff ? "disable" : "enable");
319 	}
320 	return (err);
321 }
322 
323 static void
clockattach_ebus(struct device * parent,struct device * self,void * aux)324 clockattach_ebus(struct device *parent, struct device *self, void *aux)
325 {
326 	struct ebus_attach_args *ea = aux;
327 	bus_space_tag_t bt;
328 	int sz;
329 	static struct clock_wenable_info cwi;
330 
331 	/* hard code to 8K? */
332 	sz = ea->ea_regs[0].size;
333 
334 	if (ebus_bus_map(ea->ea_iotag, 0,
335 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) {
336 		bt = ea->ea_iotag;
337 	} else if (ebus_bus_map(ea->ea_memtag, 0,
338 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz,
339 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
340 	    0, &cwi.cwi_bh) == 0) {
341 		bt = ea->ea_memtag;
342 	} else {
343 		printf("%s: can't map register\n", self->dv_xname);
344 		return;
345 	}
346 
347 	clockattach(ea->ea_node, bt, cwi.cwi_bh);
348 
349 	/* Save info for the clock wenable call. */
350 	cwi.cwi_bt = bt;
351 	cwi.cwi_size = sz;
352 	todr_handle->bus_cookie = &cwi;
353 	todr_handle->todr_setwen = (ea->ea_memtag == bt) ?
354 	    clock_bus_wenable : NULL;
355 }
356 
357 static void
clockattach_fhc(struct device * parent,struct device * self,void * aux)358 clockattach_fhc(struct device *parent, struct device *self, void *aux)
359 {
360 	struct fhc_attach_args *fa = aux;
361 	bus_space_tag_t bt = fa->fa_bustag;
362 	int sz;
363 	static struct clock_wenable_info cwi;
364 
365 	/* use sa->sa_regs[0].size? */
366 	sz = 8192;
367 
368 	if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot,
369 	    (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size,
370 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) {
371 		printf("%s: can't map register\n", self->dv_xname);
372 		return;
373 	}
374 
375 	clockattach(fa->fa_node, bt, cwi.cwi_bh);
376 
377 	/* Save info for the clock wenable call. */
378 	cwi.cwi_bt = bt;
379 	cwi.cwi_size = sz;
380 	todr_handle->bus_cookie = &cwi;
381 	todr_handle->todr_setwen = clock_bus_wenable;
382 }
383 
384 static void
clockattach(int node,bus_space_tag_t bt,bus_space_handle_t bh)385 clockattach(int node, bus_space_tag_t bt, bus_space_handle_t bh)
386 {
387 	char *model;
388 	struct idprom *idp;
389 	int h;
390 
391 	model = getpropstring(node, "model");
392 
393 #ifdef DIAGNOSTIC
394 	if (model == NULL)
395 		panic("clockattach: no model property");
396 #endif
397 
398 	/* Our TOD clock year 0 is 1968 */
399 	if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL)
400 		panic("Can't attach %s tod clock", model);
401 
402 #define IDPROM_OFFSET (8*1024 - 40)	/* XXX - get nvram sz from driver */
403 	if (idprom == NULL) {
404 		idp = getidprom();
405 		if (idp == NULL)
406 			idp = (struct idprom *)(bus_space_vaddr(bt, bh) +
407 			    IDPROM_OFFSET);
408 		idprom = idp;
409 	} else
410 		idp = idprom;
411 	h = idp->id_machine << 24;
412 	h |= idp->id_hostid[0] << 16;
413 	h |= idp->id_hostid[1] << 8;
414 	h |= idp->id_hostid[2];
415 	hostid = h;
416 	printf("\n");
417 }
418 
419 struct idprom *
getidprom(void)420 getidprom(void)
421 {
422 	struct idprom *idp = NULL;
423 	int node, n;
424 
425 	node = findroot();
426 	if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0)
427 		return (NULL);
428 	if (n != 1) {
429 		free(idp, M_DEVBUF, 0);
430 		return (NULL);
431 	}
432 	return (idp);
433 }
434 
435 /*
436  * XXX this belongs elsewhere
437  */
438 void
myetheraddr(u_char * cp)439 myetheraddr(u_char *cp)
440 {
441 	struct idprom *idp;
442 
443 	if ((idp = idprom) == NULL) {
444 		int node, n;
445 
446 		node = findroot();
447 		if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) ||
448 		    n != 1) {
449 			printf("\nmyetheraddr: clock not setup yet, "
450 			       "and no idprom property in /\n");
451 			return;
452 		}
453 	}
454 
455 	cp[0] = idp->id_ether[0];
456 	cp[1] = idp->id_ether[1];
457 	cp[2] = idp->id_ether[2];
458 	cp[3] = idp->id_ether[3];
459 	cp[4] = idp->id_ether[4];
460 	cp[5] = idp->id_ether[5];
461 	if (idprom == NULL)
462 		free(idp, M_DEVBUF, 0);
463 }
464 
465 /*
466  * Set up the real-time and statistics clocks.
467  *
468  * The frequencies of these clocks must be an even number of microseconds.
469  */
470 void
cpu_initclocks(void)471 cpu_initclocks(void)
472 {
473 	u_int sys_tick_rate;
474 	int impl = 0;
475 
476 	if (1000000 % hz) {
477 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
478 		hz = 100;
479 		tick = 1000000 / hz;
480 		tick_nsec = 1000000000 / hz;
481 	}
482 
483 	stathz = hz;
484 	profhz = stathz * 10;
485 	statclock_is_randomized = 1;
486 
487 	/* Make sure we have a sane cpu_clockrate -- we'll need it */
488 	if (!cpu_clockrate)
489 		/* Default to 200MHz clock XXXXX */
490 		cpu_clockrate = 200000000;
491 
492 	tick_timecounter.tc_frequency = cpu_clockrate;
493 	tc_init(&tick_timecounter);
494 
495 	/*
496 	 * UltraSPARC IIe processors do have a STICK register, but it
497 	 * lives on the PCI host bridge and isn't accessible through
498 	 * ASR24.
499 	 */
500 	if (CPU_ISSUN4U || CPU_ISSUN4US)
501 		impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT;
502 
503 	sys_tick_rate = getpropint(findroot(), "stick-frequency", 0);
504 	if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) {
505 		sys_tick_timecounter.tc_frequency = sys_tick_rate;
506 		tc_init(&sys_tick_timecounter);
507 	}
508 
509 	struct cpu_info *ci;
510 
511 	/*
512 	 * Establish a level 10 interrupt handler
513 	 *
514 	 * We will have a conflict with the softint handler,
515 	 * so we set the ih_number to 1.
516 	 */
517 	intr_establish(&level10);
518 	evcount_percpu(&level10.ih_count);
519 
520 	if (sys_tick_rate > 0) {
521 		sys_tick_nsec_cycle_ratio =
522 		    sys_tick_rate * (1ULL << 32) / 1000000000;
523 		sys_tick_nsec_max = UINT64_MAX / sys_tick_nsec_cycle_ratio;
524 		if (impl == IMPL_HUMMINGBIRD) {
525 			level10.ih_fun = stickintr;
526 			cpu_start_clock = stick_start;
527 		} else {
528 			level10.ih_fun = sys_tickintr;
529 			cpu_start_clock = sys_tick_start;
530 		}
531 	} else {
532 		tick_nsec_cycle_ratio =
533 		    cpu_clockrate * (1ULL << 32) / 1000000000;
534 		tick_nsec_max = UINT64_MAX / tick_nsec_cycle_ratio;
535 		level10.ih_fun = tickintr;
536 		cpu_start_clock = tick_start;
537 	}
538 
539 	for (ci = cpus; ci != NULL; ci = ci->ci_next)
540 		memcpy(&ci->ci_tickintr, &level10, sizeof(level10));
541 }
542 
543 void
cpu_startclock(void)544 cpu_startclock(void)
545 {
546 	cpu_start_clock();
547 }
548 
549 void
setstatclockrate(int newhz)550 setstatclockrate(int newhz)
551 {
552 }
553 
554 /*
555  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
556  * console input, we need to check for that here as well, and generate
557  * a software interrupt to read it.
558  *
559  * %tick is really a level-14 interrupt.  We need to remap this in
560  * locore.s to a level 10.
561  */
562 int
tickintr(void * cap)563 tickintr(void *cap)
564 {
565 	clockintr_dispatch(cap);
566 	evcount_inc(&level10.ih_count);
567 	return (1);
568 }
569 
570 int
sys_tickintr(void * cap)571 sys_tickintr(void *cap)
572 {
573 	clockintr_dispatch(cap);
574 	evcount_inc(&level10.ih_count);
575 	return (1);
576 }
577 
578 int
stickintr(void * cap)579 stickintr(void *cap)
580 {
581 	clockintr_dispatch(cap);
582 	evcount_inc(&level10.ih_count);
583 	return (1);
584 }
585 
586 void
tick_start(void)587 tick_start(void)
588 {
589 	tick_enable();
590 
591 	clockintr_cpu_init(&tick_intrclock);
592 	clockintr_trigger();
593 }
594 
595 void
tick_rearm(void * unused,uint64_t nsecs)596 tick_rearm(void *unused, uint64_t nsecs)
597 {
598 	uint64_t s, t0;
599 	uint32_t cycles;
600 
601 	if (nsecs > tick_nsec_max)
602 		nsecs = tick_nsec_max;
603 	cycles = (nsecs * tick_nsec_cycle_ratio) >> 32;
604 
605 	s = intr_disable();
606 	t0 = tick();
607 	tickcmpr_set((t0 + cycles) & TICK_COUNT_MASK);
608 	if (cycles <= ((tick() - t0) & TICK_COUNT_MASK))
609 		sparc64_raise_clockintr();
610 	intr_restore(s);
611 }
612 
613 void
tick_trigger(void * unused)614 tick_trigger(void *unused)
615 {
616 	sparc64_raise_clockintr();
617 }
618 
619 void
sys_tick_start(void)620 sys_tick_start(void)
621 {
622 	if (CPU_ISSUN4U || CPU_ISSUN4US) {
623 		tick_enable();
624 		sys_tick_enable();
625 	}
626 
627 	clockintr_cpu_init(&sys_tick_intrclock);
628 	clockintr_trigger();
629 }
630 
631 void
sys_tick_rearm(void * unused,uint64_t nsecs)632 sys_tick_rearm(void *unused, uint64_t nsecs)
633 {
634 	uint64_t s, t0;
635 	uint32_t cycles;
636 
637 	if (nsecs > sys_tick_nsec_max)
638 		nsecs = sys_tick_nsec_max;
639 	cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32;
640 
641 	s = intr_disable();
642 	t0 = sys_tick();
643 	sys_tickcmpr_set((t0 + cycles) & STICK_COUNT_MASK);
644 	if (cycles <= ((sys_tick() - t0) & STICK_COUNT_MASK))
645 		sparc64_raise_clockintr();
646 	intr_restore(s);
647 }
648 
649 void
sys_tick_trigger(void * unused)650 sys_tick_trigger(void *unused)
651 {
652 	sparc64_raise_clockintr();
653 }
654 
655 void
stick_start(void)656 stick_start(void)
657 {
658 	tick_enable();
659 
660 	clockintr_cpu_init(&stick_intrclock);
661 	clockintr_trigger();
662 }
663 
664 void
stick_rearm(void * unused,uint64_t nsecs)665 stick_rearm(void *unused, uint64_t nsecs)
666 {
667 	uint64_t s, t0;
668 	uint32_t cycles;
669 
670 	if (nsecs > sys_tick_nsec_max)
671 		nsecs = sys_tick_nsec_max;
672 	cycles = (nsecs * sys_tick_nsec_cycle_ratio) >> 32;
673 
674 	s = intr_disable();
675 	t0 = stick();
676 	stickcmpr_set((t0 + cycles) & STICK_COUNT_MASK);
677 	if (cycles <= ((stick() - t0) & STICK_COUNT_MASK))
678 		sparc64_raise_clockintr();
679 	intr_restore(s);
680 }
681 
682 void
stick_trigger(void * unused)683 stick_trigger(void *unused)
684 {
685 	sparc64_raise_clockintr();
686 }
687 
688 u_int
tick_get_timecount(struct timecounter * tc)689 tick_get_timecount(struct timecounter *tc)
690 {
691 	u_int64_t tick;
692 
693 	__asm volatile("rd %%tick, %0" : "=r" (tick));
694 
695 	return (tick & ~0u);
696 }
697 
698 u_int
sys_tick_get_timecount(struct timecounter * tc)699 sys_tick_get_timecount(struct timecounter *tc)
700 {
701 	u_int64_t tick;
702 
703 	__asm volatile("rd %%sys_tick, %0" : "=r" (tick));
704 
705 	return (tick & ~0u);
706 }
707 
708 void
sparc64_raise_clockintr(void)709 sparc64_raise_clockintr(void)
710 {
711 	send_softint(PIL_CLOCK, &curcpu()->ci_tickintr);
712 }
713