xref: /openbsd/sys/arch/sparc64/sparc64/clock.c (revision 8a2bbcc7)
1*8a2bbcc7Skettenis /*	$OpenBSD: clock.c,v 1.44 2008/07/15 22:49:01 kettenis Exp $	*/
2284584b0Sjason /*	$NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
3284584b0Sjason 
4284584b0Sjason /*
5284584b0Sjason  * Copyright (c) 1992, 1993
6284584b0Sjason  *	The Regents of the University of California.  All rights reserved.
7284584b0Sjason  * Copyright (c) 1994 Gordon W. Ross
8284584b0Sjason  * Copyright (c) 1993 Adam Glass
9284584b0Sjason  * Copyright (c) 1996 Paul Kranenburg
10284584b0Sjason  * Copyright (c) 1996
11284584b0Sjason  * 	The President and Fellows of Harvard College. All rights reserved.
12284584b0Sjason  *
13284584b0Sjason  * This software was developed by the Computer Systems Engineering group
14284584b0Sjason  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
15284584b0Sjason  * contributed to Berkeley.
16284584b0Sjason  *
17284584b0Sjason  * All advertising materials mentioning features or use of this software
18284584b0Sjason  * must display the following acknowledgement:
19284584b0Sjason  *	This product includes software developed by Harvard University.
20284584b0Sjason  *	This product includes software developed by the University of
21284584b0Sjason  *	California, Lawrence Berkeley Laboratory.
22284584b0Sjason  *
23284584b0Sjason  * Redistribution and use in source and binary forms, with or without
24284584b0Sjason  * modification, are permitted provided that the following conditions
25284584b0Sjason  * are met:
26284584b0Sjason  *
27284584b0Sjason  * 1. Redistributions of source code must retain the above copyright
28284584b0Sjason  *    notice, this list of conditions and the following disclaimer.
29284584b0Sjason  * 2. Redistributions in binary form must reproduce the above copyright
30284584b0Sjason  *    notice, this list of conditions and the following disclaimer in the
31284584b0Sjason  *    documentation and/or other materials provided with the distribution.
32284584b0Sjason  * 3. All advertising materials mentioning features or use of this software
33284584b0Sjason  *    must display the following acknowledgement:
34284584b0Sjason  *	This product includes software developed by the University of
35284584b0Sjason  *	California, Berkeley and its contributors.
36284584b0Sjason  *	This product includes software developed by Paul Kranenburg.
37284584b0Sjason  *	This product includes software developed by Harvard University.
38284584b0Sjason  * 4. Neither the name of the University nor the names of its contributors
39284584b0Sjason  *    may be used to endorse or promote products derived from this software
40284584b0Sjason  *    without specific prior written permission.
41284584b0Sjason  *
42284584b0Sjason  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43284584b0Sjason  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44284584b0Sjason  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45284584b0Sjason  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46284584b0Sjason  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47284584b0Sjason  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48284584b0Sjason  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49284584b0Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50284584b0Sjason  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51284584b0Sjason  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52284584b0Sjason  * SUCH DAMAGE.
53284584b0Sjason  *
54284584b0Sjason  *	@(#)clock.c	8.1 (Berkeley) 6/11/93
55284584b0Sjason  *
56284584b0Sjason  */
57284584b0Sjason 
58284584b0Sjason /*
59284584b0Sjason  * Clock driver.  This is the id prom and eeprom driver as well
60284584b0Sjason  * and includes the timer register functions too.
61284584b0Sjason  */
62284584b0Sjason 
63284584b0Sjason /* Define this for a 1/4s clock to ease debugging */
64284584b0Sjason /* #define INTR_DEBUG */
65284584b0Sjason 
66284584b0Sjason #include <sys/param.h>
67284584b0Sjason #include <sys/kernel.h>
68284584b0Sjason #include <sys/device.h>
69284584b0Sjason #include <sys/proc.h>
70284584b0Sjason #include <sys/resourcevar.h>
71284584b0Sjason #include <sys/malloc.h>
72284584b0Sjason #include <sys/systm.h>
73284584b0Sjason #ifdef GPROF
74284584b0Sjason #include <sys/gmon.h>
75284584b0Sjason #endif
76284584b0Sjason #include <sys/sched.h>
7705a26ea5Sart #include <sys/timetc.h>
78284584b0Sjason 
79284584b0Sjason #include <uvm/uvm_extern.h>
80284584b0Sjason 
81284584b0Sjason #include <machine/bus.h>
82284584b0Sjason #include <machine/autoconf.h>
83284584b0Sjason #include <machine/cpu.h>
84284584b0Sjason #include <machine/idprom.h>
85284584b0Sjason 
86284584b0Sjason #include <dev/clock_subr.h>
87284584b0Sjason #include <dev/ic/mk48txxreg.h>
88284584b0Sjason 
89284584b0Sjason #include <sparc64/sparc64/intreg.h>
90284584b0Sjason #include <sparc64/sparc64/timerreg.h>
91284584b0Sjason #include <sparc64/dev/iommureg.h>
92284584b0Sjason #include <sparc64/dev/sbusreg.h>
93284584b0Sjason #include <dev/sbus/sbusvar.h>
94284584b0Sjason #include <sparc64/dev/ebusreg.h>
95284584b0Sjason #include <sparc64/dev/ebusvar.h>
961d2e6c84Sjason #include <sparc64/dev/fhcvar.h>
97284584b0Sjason 
98284584b0Sjason extern u_int64_t cpu_clockrate;
99284584b0Sjason 
100eb79e960Shenric struct clock_wenable_info {
101eb79e960Shenric 	bus_space_tag_t		cwi_bt;
102eb79e960Shenric 	bus_space_handle_t	cwi_bh;
103eb79e960Shenric 	bus_size_t		cwi_size;
104eb79e960Shenric };
105eb79e960Shenric 
106284584b0Sjason struct cfdriver clock_cd = {
107284584b0Sjason 	NULL, "clock", DV_DULL
108284584b0Sjason };
109284584b0Sjason 
11005a26ea5Sart u_int tick_get_timecount(struct timecounter *);
11105a26ea5Sart 
11205a26ea5Sart struct timecounter tick_timecounter = {
11305a26ea5Sart 	tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
11405a26ea5Sart };
11505a26ea5Sart 
116*8a2bbcc7Skettenis u_int sys_tick_get_timecount(struct timecounter *);
117*8a2bbcc7Skettenis 
118*8a2bbcc7Skettenis struct timecounter sys_tick_timecounter = {
119*8a2bbcc7Skettenis 	sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL
120*8a2bbcc7Skettenis };
121*8a2bbcc7Skettenis 
122284584b0Sjason /*
123284584b0Sjason  * Statistics clock interval and variance, in usec.  Variance must be a
124284584b0Sjason  * power of two.  Since this gives us an even number, not an odd number,
125284584b0Sjason  * we discard one case and compensate.  That is, a variance of 1024 would
126284584b0Sjason  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
127284584b0Sjason  * This is symmetric about the point 512, or statvar/2, and thus averages
128284584b0Sjason  * to that value (assuming uniform random numbers).
129284584b0Sjason  */
130284584b0Sjason /* XXX fix comment to match value */
131284584b0Sjason int statvar = 8192;
132284584b0Sjason int statmin;			/* statclock interval - 1/2*variance */
133284584b0Sjason 
13458c73160Skettenis static long tick_increment;
135c4071fd1Smillert int schedintr(void *);
136284584b0Sjason 
137284584b0Sjason static struct intrhand level10 = { clockintr };
138284584b0Sjason static struct intrhand level0 = { tickintr };
139284584b0Sjason static struct intrhand level14 = { statintr };
140284584b0Sjason static struct intrhand schedint = { schedintr };
141284584b0Sjason 
142284584b0Sjason /*
143284584b0Sjason  * clock (eeprom) attaches at the sbus or the ebus (PCI)
144284584b0Sjason  */
145c4071fd1Smillert static int	clockmatch_sbus(struct device *, void *, void *);
146c4071fd1Smillert static void	clockattach_sbus(struct device *, struct device *, void *);
147c4071fd1Smillert static int	clockmatch_ebus(struct device *, void *, void *);
148c4071fd1Smillert static void	clockattach_ebus(struct device *, struct device *, void *);
1491d2e6c84Sjason static int	clockmatch_fhc(struct device *, void *, void *);
1501d2e6c84Sjason static void	clockattach_fhc(struct device *, struct device *, void *);
151c4071fd1Smillert static void	clockattach(int, bus_space_tag_t, bus_space_handle_t);
152284584b0Sjason 
153284584b0Sjason struct cfattach clock_sbus_ca = {
154284584b0Sjason 	sizeof(struct device), clockmatch_sbus, clockattach_sbus
155284584b0Sjason };
156284584b0Sjason 
157284584b0Sjason struct cfattach clock_ebus_ca = {
158284584b0Sjason 	sizeof(struct device), clockmatch_ebus, clockattach_ebus
159284584b0Sjason };
160284584b0Sjason 
1611d2e6c84Sjason struct cfattach clock_fhc_ca = {
1621d2e6c84Sjason 	sizeof(struct device), clockmatch_fhc, clockattach_fhc
1631d2e6c84Sjason };
1641d2e6c84Sjason 
165284584b0Sjason /* Global TOD clock handle & idprom pointer */
166d5e78757Skettenis todr_chip_handle_t todr_handle = NULL;
167284584b0Sjason static struct idprom *idprom;
168284584b0Sjason 
169c4071fd1Smillert static int	timermatch(struct device *, void *, void *);
170c4071fd1Smillert static void	timerattach(struct device *, struct device *, void *);
171284584b0Sjason 
172284584b0Sjason struct timerreg_4u	timerreg_4u;	/* XXX - need more cleanup */
173284584b0Sjason 
174284584b0Sjason struct cfattach timer_ca = {
175284584b0Sjason 	sizeof(struct device), timermatch, timerattach
176284584b0Sjason };
177284584b0Sjason 
178284584b0Sjason struct cfdriver timer_cd = {
179284584b0Sjason 	NULL, "timer", DV_DULL
180284584b0Sjason };
181284584b0Sjason 
182eb79e960Shenric int clock_bus_wenable(struct todr_chip_handle *, int);
183284584b0Sjason struct chiptime;
184c4071fd1Smillert void myetheraddr(u_char *);
185eba3994dSjason struct idprom *getidprom(void);
186c4071fd1Smillert int chiptotime(int, int, int, int, int, int);
187c4071fd1Smillert void timetochip(struct chiptime *);
188c4071fd1Smillert void stopcounter(struct timer_4u *);
189284584b0Sjason 
190284584b0Sjason int timerblurb = 10; /* Guess a value; used before clock is attached */
191284584b0Sjason 
192284584b0Sjason /*
193284584b0Sjason  * The OPENPROM calls the clock the "eeprom", so we have to have our
194284584b0Sjason  * own special match function to call it the "clock".
195284584b0Sjason  */
196284584b0Sjason static int
197284584b0Sjason clockmatch_sbus(parent, cf, aux)
198284584b0Sjason 	struct device *parent;
199284584b0Sjason 	void *cf;
200284584b0Sjason 	void *aux;
201284584b0Sjason {
202284584b0Sjason 	struct sbus_attach_args *sa = aux;
203284584b0Sjason 
204284584b0Sjason 	return (strcmp("eeprom", sa->sa_name) == 0);
205284584b0Sjason }
206284584b0Sjason 
207284584b0Sjason static int
208284584b0Sjason clockmatch_ebus(parent, cf, aux)
209284584b0Sjason 	struct device *parent;
210284584b0Sjason 	void *cf;
211284584b0Sjason 	void *aux;
212284584b0Sjason {
213284584b0Sjason 	struct ebus_attach_args *ea = aux;
214284584b0Sjason 
215284584b0Sjason 	return (strcmp("eeprom", ea->ea_name) == 0);
216284584b0Sjason }
217284584b0Sjason 
218284584b0Sjason static int
2191d2e6c84Sjason clockmatch_fhc(parent, cf, aux)
2201d2e6c84Sjason 	struct device *parent;
2211d2e6c84Sjason 	void *cf;
2221d2e6c84Sjason 	void *aux;
2231d2e6c84Sjason {
2241d2e6c84Sjason 	struct fhc_attach_args *fa = aux;
2251d2e6c84Sjason 
2261d2e6c84Sjason 	return (strcmp("eeprom", fa->fa_name) == 0);
2271d2e6c84Sjason }
2281d2e6c84Sjason 
229284584b0Sjason /*
230284584b0Sjason  * Attach a clock (really `eeprom') to the sbus or ebus.
231284584b0Sjason  *
232284584b0Sjason  * We ignore any existing virtual address as we need to map
233284584b0Sjason  * this read-only and make it read-write only temporarily,
234284584b0Sjason  * whenever we read or write the clock chip.  The clock also
235284584b0Sjason  * contains the ID ``PROM'', and I have already had the pleasure
236284584b0Sjason  * of reloading the cpu type, Ethernet address, etc, by hand from
237284584b0Sjason  * the console FORTH interpreter.  I intend not to enjoy it again.
238284584b0Sjason  *
239284584b0Sjason  * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
240284584b0Sjason  * supposed to be identical to it.
241284584b0Sjason  *
242284584b0Sjason  * This is *UGLY*!  We probably have multiple mappings.  But I do
243284584b0Sjason  * know that this all fits inside an 8K page, so I'll just map in
244284584b0Sjason  * once.
245284584b0Sjason  *
246284584b0Sjason  * What we really need is some way to record the bus attach args
247284584b0Sjason  * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
248284584b0Sjason  * or not to write enable/disable the device registers.  This is
249284584b0Sjason  * a non-trivial operation.
250284584b0Sjason  */
251284584b0Sjason 
252284584b0Sjason /* ARGSUSED */
253284584b0Sjason static void
254284584b0Sjason clockattach_sbus(parent, self, aux)
255284584b0Sjason 	struct device *parent, *self;
256284584b0Sjason 	void *aux;
257284584b0Sjason {
258284584b0Sjason 	struct sbus_attach_args *sa = aux;
259284584b0Sjason 	bus_space_tag_t bt = sa->sa_bustag;
260284584b0Sjason 	int sz;
261eb79e960Shenric 	static struct clock_wenable_info cwi;
262284584b0Sjason 
263284584b0Sjason 	/* use sa->sa_regs[0].size? */
264284584b0Sjason 	sz = 8192;
265284584b0Sjason 
266284584b0Sjason 	if (sbus_bus_map(bt,
267284584b0Sjason 			 sa->sa_slot,
268284584b0Sjason 			 (sa->sa_offset & ~NBPG),
269284584b0Sjason 			 sz,
270284584b0Sjason 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
271eb79e960Shenric 			 0, &cwi.cwi_bh) != 0) {
272284584b0Sjason 		printf("%s: can't map register\n", self->dv_xname);
273284584b0Sjason 		return;
274284584b0Sjason 	}
275eb79e960Shenric 	clockattach(sa->sa_node, bt, cwi.cwi_bh);
276284584b0Sjason 
277284584b0Sjason 	/* Save info for the clock wenable call. */
278eb79e960Shenric 	cwi.cwi_bt = bt;
279eb79e960Shenric 	cwi.cwi_size = sz;
280eb79e960Shenric 	todr_handle->bus_cookie = &cwi;
281eb79e960Shenric 	todr_handle->todr_setwen = clock_bus_wenable;
282284584b0Sjason }
283284584b0Sjason 
284284584b0Sjason /*
285284584b0Sjason  * Write en/dis-able clock registers.  We coordinate so that several
286284584b0Sjason  * writers can run simultaneously.
287eb79e960Shenric  * XXX There is still a race here.  The page change and the "writers"
288eb79e960Shenric  * change are not atomic.
289284584b0Sjason  */
290284584b0Sjason int
291eb79e960Shenric clock_bus_wenable(handle, onoff)
292284584b0Sjason 	struct todr_chip_handle *handle;
293284584b0Sjason 	int onoff;
294284584b0Sjason {
295eb79e960Shenric 	int s, err = 0;
296eb79e960Shenric 	int prot; /* nonzero => change prot */
297eb79e960Shenric 	volatile static int writers;
298eb79e960Shenric 	struct clock_wenable_info *cwi = handle->bus_cookie;
299284584b0Sjason 
300284584b0Sjason 	s = splhigh();
301284584b0Sjason 	if (onoff)
302eb79e960Shenric 		prot = writers++ == 0 ?
303eb79e960Shenric 		    VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED : 0;
304284584b0Sjason 	else
305284584b0Sjason 		prot = --writers == 0 ?
306eb79e960Shenric 		    VM_PROT_READ | PMAP_WIRED : 0;
307284584b0Sjason 	splx(s);
308284584b0Sjason 
309eb79e960Shenric 	if (prot) {
310eb79e960Shenric 		err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size,
311eb79e960Shenric 		    onoff ? 0 : BUS_SPACE_MAP_READONLY);
312eb79e960Shenric 		if (err)
313eb79e960Shenric 			printf("clock_wenable_info: WARNING -- cannot %s "
314eb79e960Shenric 			    "page protection\n", onoff ? "disable" : "enable");
315284584b0Sjason 	}
316284584b0Sjason 	return (err);
317284584b0Sjason }
318284584b0Sjason 
319284584b0Sjason /* ARGSUSED */
320284584b0Sjason static void
321284584b0Sjason clockattach_ebus(parent, self, aux)
322284584b0Sjason 	struct device *parent, *self;
323284584b0Sjason 	void *aux;
324284584b0Sjason {
325284584b0Sjason 	struct ebus_attach_args *ea = aux;
326eb79e960Shenric 	bus_space_tag_t bt;
327284584b0Sjason 	int sz;
328eb79e960Shenric 	static struct clock_wenable_info cwi;
329284584b0Sjason 
330284584b0Sjason 	/* hard code to 8K? */
331284584b0Sjason 	sz = ea->ea_regs[0].size;
332284584b0Sjason 
333e9e8d4c3Skettenis 	if (ea->ea_nvaddrs) {
334e9e8d4c3Skettenis 		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
335e9e8d4c3Skettenis 		    BUS_SPACE_MAP_PROMADDRESS, &cwi.cwi_bh) != 0) {
336e9e8d4c3Skettenis 			printf("%s: can't map register\n", self->dv_xname);
337e9e8d4c3Skettenis 			return;
338e9e8d4c3Skettenis 		}
339e9e8d4c3Skettenis 		bt = ea->ea_memtag;
340e9e8d4c3Skettenis 	} else if (ebus_bus_map(ea->ea_iotag, 0,
341eb79e960Shenric 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) {
342eb79e960Shenric 		bt = ea->ea_iotag;
343eb79e960Shenric 	} else if (ebus_bus_map(ea->ea_memtag, 0,
344eb79e960Shenric 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz,
345eb79e960Shenric 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
346eb79e960Shenric 	    0, &cwi.cwi_bh) == 0) {
347eb79e960Shenric 		bt = ea->ea_memtag;
348eb79e960Shenric 	} else {
349284584b0Sjason 		printf("%s: can't map register\n", self->dv_xname);
350284584b0Sjason 		return;
351284584b0Sjason 	}
352eb79e960Shenric 
353eb79e960Shenric 	clockattach(ea->ea_node, bt, cwi.cwi_bh);
354284584b0Sjason 
355284584b0Sjason 	/* Save info for the clock wenable call. */
356eb79e960Shenric 	cwi.cwi_bt = bt;
357eb79e960Shenric 	cwi.cwi_size = sz;
358eb79e960Shenric 	todr_handle->bus_cookie = &cwi;
359eb79e960Shenric 	todr_handle->todr_setwen = (ea->ea_memtag == bt) ?
360eb79e960Shenric 	    clock_bus_wenable : NULL;
361284584b0Sjason }
362284584b0Sjason 
363284584b0Sjason static void
3641d2e6c84Sjason clockattach_fhc(parent, self, aux)
3651d2e6c84Sjason 	struct device *parent, *self;
3661d2e6c84Sjason 	void *aux;
3671d2e6c84Sjason {
3681d2e6c84Sjason 	struct fhc_attach_args *fa = aux;
3691d2e6c84Sjason 	bus_space_tag_t bt = fa->fa_bustag;
3701d2e6c84Sjason 	int sz;
3711d2e6c84Sjason 	static struct clock_wenable_info cwi;
3721d2e6c84Sjason 
3731d2e6c84Sjason 	/* use sa->sa_regs[0].size? */
3741d2e6c84Sjason 	sz = 8192;
3751d2e6c84Sjason 
3761d2e6c84Sjason 	if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot,
3771d2e6c84Sjason 	    (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size,
3781d2e6c84Sjason 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) {
3791d2e6c84Sjason 		printf("%s: can't map register\n", self->dv_xname);
3801d2e6c84Sjason 		return;
3811d2e6c84Sjason 	}
3821d2e6c84Sjason 
3831d2e6c84Sjason 	clockattach(fa->fa_node, bt, cwi.cwi_bh);
3841d2e6c84Sjason 
3851d2e6c84Sjason 	/* Save info for the clock wenable call. */
3861d2e6c84Sjason 	cwi.cwi_bt = bt;
3871d2e6c84Sjason 	cwi.cwi_size = sz;
3881d2e6c84Sjason 	todr_handle->bus_cookie = &cwi;
3891d2e6c84Sjason 	todr_handle->todr_setwen = clock_bus_wenable;
3901d2e6c84Sjason }
3911d2e6c84Sjason 
3921d2e6c84Sjason static void
393284584b0Sjason clockattach(node, bt, bh)
394284584b0Sjason 	int node;
395284584b0Sjason 	bus_space_tag_t bt;
396284584b0Sjason 	bus_space_handle_t bh;
397284584b0Sjason {
398284584b0Sjason 	char *model;
399284584b0Sjason 	struct idprom *idp;
400284584b0Sjason 	int h;
401284584b0Sjason 
402284584b0Sjason 	model = getpropstring(node, "model");
403284584b0Sjason 
404284584b0Sjason #ifdef DIAGNOSTIC
405284584b0Sjason 	if (model == NULL)
406284584b0Sjason 		panic("clockattach: no model property");
407284584b0Sjason #endif
408284584b0Sjason 
409284584b0Sjason 	/* Our TOD clock year 0 is 1968 */
410284584b0Sjason 	if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL)
411284584b0Sjason 		panic("Can't attach %s tod clock", model);
412284584b0Sjason 
413284584b0Sjason #define IDPROM_OFFSET (8*1024 - 40)	/* XXX - get nvram sz from driver */
414eba3994dSjason 	if (idprom == NULL) {
415eba3994dSjason 		idp = getidprom();
416eba3994dSjason 		if (idp == NULL)
417eb79e960Shenric 			idp = (struct idprom *)(bus_space_vaddr(bt, bh) +
418eb79e960Shenric 			    IDPROM_OFFSET);
419eba3994dSjason 		idprom = idp;
420eba3994dSjason 	} else
421eba3994dSjason 		idp = idprom;
422284584b0Sjason 	h = idp->id_machine << 24;
423284584b0Sjason 	h |= idp->id_hostid[0] << 16;
424284584b0Sjason 	h |= idp->id_hostid[1] << 8;
425284584b0Sjason 	h |= idp->id_hostid[2];
426284584b0Sjason 	hostid = h;
427b4117920Smiod 	printf("\n");
428eba3994dSjason }
429eba3994dSjason 
430eba3994dSjason struct idprom *
431b4117920Smiod getidprom()
432b4117920Smiod {
433eba3994dSjason 	struct idprom *idp = NULL;
434eba3994dSjason 	int node, n;
435eba3994dSjason 
436eba3994dSjason 	node = findroot();
437eba3994dSjason 	if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0)
438eba3994dSjason 		return (NULL);
439eba3994dSjason 	if (n != 1) {
440eba3994dSjason 		free(idp, M_DEVBUF);
441eba3994dSjason 		return (NULL);
442eba3994dSjason 	}
443eba3994dSjason 	return (idp);
444284584b0Sjason }
445284584b0Sjason 
446284584b0Sjason /*
447284584b0Sjason  * The sun4u OPENPROMs call the timer the "counter-timer", except for
448284584b0Sjason  * the lame UltraSPARC IIi PCI machines that don't have them.
449284584b0Sjason  */
450284584b0Sjason static int
451284584b0Sjason timermatch(parent, cf, aux)
452284584b0Sjason 	struct device *parent;
453284584b0Sjason 	void *cf;
454284584b0Sjason 	void *aux;
455284584b0Sjason {
4569d649671Skettenis #ifndef MULTIPROCESSOR
457284584b0Sjason 	struct mainbus_attach_args *ma = aux;
458284584b0Sjason 
459915c144aSmiod 	if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr)
460284584b0Sjason 		return (strcmp("counter-timer", ma->ma_name) == 0);
461915c144aSmiod 	else
4629d649671Skettenis #endif
463915c144aSmiod 		return (0);
464284584b0Sjason }
465284584b0Sjason 
466284584b0Sjason static void
467284584b0Sjason timerattach(parent, self, aux)
468284584b0Sjason 	struct device *parent, *self;
469284584b0Sjason 	void *aux;
470284584b0Sjason {
471284584b0Sjason 	struct mainbus_attach_args *ma = aux;
472284584b0Sjason 	u_int *va = ma->ma_address;
473284584b0Sjason 
474284584b0Sjason 	/*
475284584b0Sjason 	 * What we should have are 3 sets of registers that reside on
476284584b0Sjason 	 * different parts of SYSIO or PSYCHO.  We'll use the prom
477284584b0Sjason 	 * mappings cause we can't get rid of them and set up appropriate
478284584b0Sjason 	 * pointers on the timerreg_4u structure.
479284584b0Sjason 	 */
480284584b0Sjason 	timerreg_4u.t_timer = (struct timer_4u *)(u_long)va[0];
481284584b0Sjason 	timerreg_4u.t_clrintr = (int64_t *)(u_long)va[1];
482284584b0Sjason 	timerreg_4u.t_mapintr = (int64_t *)(u_long)va[2];
483284584b0Sjason 
484284584b0Sjason 	/* Install the appropriate interrupt vector here */
4856fbc409cSkettenis 	level10.ih_number = INTVEC(ma->ma_interrupts[0]);
486284584b0Sjason 	level10.ih_clr = (void *)&timerreg_4u.t_clrintr[0];
487eb79e960Shenric 	level10.ih_map = (void *)&timerreg_4u.t_mapintr[0];
488fc635044Saaron 	strlcpy(level10.ih_name, "clock", sizeof(level10.ih_name));
489284584b0Sjason 	intr_establish(10, &level10);
490eb79e960Shenric 
4916fbc409cSkettenis 	level14.ih_number = INTVEC(ma->ma_interrupts[1]);
492284584b0Sjason 	level14.ih_clr = (void *)&timerreg_4u.t_clrintr[1];
493eb79e960Shenric 	level14.ih_map = (void *)&timerreg_4u.t_mapintr[1];
494fc635044Saaron 	strlcpy(level14.ih_name, "prof", sizeof(level14.ih_name));
495284584b0Sjason 	intr_establish(14, &level14);
496eb79e960Shenric 
49720eecc27Skettenis 	printf(" ivec 0x%x, 0x%x\n", INTVEC(level10.ih_number),
49820eecc27Skettenis 	    INTVEC(level14.ih_number));
499284584b0Sjason }
500284584b0Sjason 
501284584b0Sjason void
502284584b0Sjason stopcounter(creg)
503284584b0Sjason 	struct timer_4u *creg;
504284584b0Sjason {
505284584b0Sjason 	/* Stop the clock */
506284584b0Sjason 	volatile int discard;
507284584b0Sjason 	discard = creg->t_limit;
508284584b0Sjason 	creg->t_limit = 0;
509284584b0Sjason }
510284584b0Sjason 
511284584b0Sjason /*
512284584b0Sjason  * XXX this belongs elsewhere
513284584b0Sjason  */
514284584b0Sjason void
515284584b0Sjason myetheraddr(cp)
516284584b0Sjason 	u_char *cp;
517284584b0Sjason {
518284584b0Sjason 	struct idprom *idp;
519284584b0Sjason 
520284584b0Sjason 	if ((idp = idprom) == NULL) {
521284584b0Sjason 		int node, n;
522284584b0Sjason 
523284584b0Sjason 		node = findroot();
524284584b0Sjason 		if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) ||
525284584b0Sjason 		    n != 1) {
526284584b0Sjason 			printf("\nmyetheraddr: clock not setup yet, "
527284584b0Sjason 			       "and no idprom property in /\n");
528284584b0Sjason 			return;
529284584b0Sjason 		}
530284584b0Sjason 	}
531284584b0Sjason 
532284584b0Sjason 	cp[0] = idp->id_ether[0];
533284584b0Sjason 	cp[1] = idp->id_ether[1];
534284584b0Sjason 	cp[2] = idp->id_ether[2];
535284584b0Sjason 	cp[3] = idp->id_ether[3];
536284584b0Sjason 	cp[4] = idp->id_ether[4];
537284584b0Sjason 	cp[5] = idp->id_ether[5];
538284584b0Sjason 	if (idprom == NULL)
539284584b0Sjason 		free(idp, M_DEVBUF);
540284584b0Sjason }
541284584b0Sjason 
542284584b0Sjason /*
543284584b0Sjason  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
544284584b0Sjason  * no alternative timer is available.
545284584b0Sjason  *
546284584b0Sjason  * The frequencies of these clocks must be an even number of microseconds.
547284584b0Sjason  */
548284584b0Sjason void
549*8a2bbcc7Skettenis cpu_initclocks(void)
550284584b0Sjason {
551284584b0Sjason 	int statint, minint;
552284584b0Sjason #ifdef DEBUG
553284584b0Sjason 	extern int intrdebug;
554284584b0Sjason #endif
555*8a2bbcc7Skettenis 	u_int sys_tick_rate;
556*8a2bbcc7Skettenis 	int impl = 0;
557284584b0Sjason 
558284584b0Sjason #ifdef DEBUG
559284584b0Sjason 	/* Set a 1s clock */
560284584b0Sjason 	if (intrdebug) {
561284584b0Sjason 		hz = 1;
562284584b0Sjason 		tick = 1000000 / hz;
563284584b0Sjason 		printf("intrdebug set: 1Hz clock\n");
564284584b0Sjason 	}
565284584b0Sjason #endif
566284584b0Sjason 
567284584b0Sjason 	if (1000000 % hz) {
568284584b0Sjason 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
569284584b0Sjason 		hz = 100;
570284584b0Sjason 		tick = 1000000 / hz;
571284584b0Sjason 	}
572284584b0Sjason 
573284584b0Sjason 	/* Make sure we have a sane cpu_clockrate -- we'll need it */
574284584b0Sjason 	if (!cpu_clockrate)
575284584b0Sjason 		/* Default to 200MHz clock XXXXX */
576284584b0Sjason 		cpu_clockrate = 200000000;
577284584b0Sjason 
57805a26ea5Sart 	tick_timecounter.tc_frequency = cpu_clockrate;
57905a26ea5Sart 	tc_init(&tick_timecounter);
580284584b0Sjason 
581284584b0Sjason 	/*
582*8a2bbcc7Skettenis 	 * UltraSPARC IIe processors do have a STICK register, but it
583*8a2bbcc7Skettenis 	 * lives on the PCI host bridge and isn't accessable through
584*8a2bbcc7Skettenis 	 * ASR24.
585*8a2bbcc7Skettenis 	 */
586*8a2bbcc7Skettenis 	if (CPU_ISSUN4U || CPU_ISSUN4US)
587*8a2bbcc7Skettenis 		impl = (getver() & VER_IMPL) >> VER_IMPL_SHIFT;
588*8a2bbcc7Skettenis 
589*8a2bbcc7Skettenis 	sys_tick_rate = getpropint(findroot(), "stick-frequency", 0);
590*8a2bbcc7Skettenis 	if (sys_tick_rate > 0 && impl != IMPL_HUMMINGBIRD) {
591*8a2bbcc7Skettenis 		sys_tick_timecounter.tc_frequency = sys_tick_rate;
592*8a2bbcc7Skettenis 		tc_init(&sys_tick_timecounter);
593*8a2bbcc7Skettenis 	}
594*8a2bbcc7Skettenis 
595*8a2bbcc7Skettenis 	/*
596284584b0Sjason 	 * Now handle machines w/o counter-timers.
597284584b0Sjason 	 */
598284584b0Sjason 
599284584b0Sjason 	if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
600284584b0Sjason 		/* We don't have a counter-timer -- use %tick */
601284584b0Sjason 		level0.ih_clr = 0;
602284584b0Sjason 		/*
603284584b0Sjason 		 * Establish a level 10 interrupt handler
604284584b0Sjason 		 *
605284584b0Sjason 		 * We will have a conflict with the softint handler,
606284584b0Sjason 		 * so we set the ih_number to 1.
607284584b0Sjason 		 */
608284584b0Sjason 		level0.ih_number = 1;
609fc635044Saaron 		strlcpy(level0.ih_name, "clock", sizeof(level0.ih_name));
610284584b0Sjason 		intr_establish(10, &level0);
611284584b0Sjason 		/* We only have one timer so we have no statclock */
612284584b0Sjason 		stathz = 0;
613284584b0Sjason 
614284584b0Sjason 		/* set the next interrupt time */
615284584b0Sjason 		tick_increment = cpu_clockrate / hz;
616284584b0Sjason #ifdef DEBUG
617eb79e960Shenric 		printf("Using %%tick -- intr in %ld cycles...",
618eb79e960Shenric 		    tick_increment);
619284584b0Sjason #endif
62092d28d96Skettenis 		tick_start();
621284584b0Sjason #ifdef DEBUG
622284584b0Sjason 		printf("done.\n");
623284584b0Sjason #endif
624284584b0Sjason 		return;
625284584b0Sjason 	}
626284584b0Sjason 
627284584b0Sjason 	if (stathz == 0)
628284584b0Sjason 		stathz = hz;
629284584b0Sjason 	if (1000000 % stathz) {
630284584b0Sjason 		printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
631284584b0Sjason 		stathz = 100;
632284584b0Sjason 	}
633284584b0Sjason 
634284584b0Sjason 	profhz = stathz;		/* always */
635284584b0Sjason 
636284584b0Sjason 	statint = 1000000 / stathz;
637284584b0Sjason 	minint = statint / 2 + 100;
638284584b0Sjason 	while (statvar > minint)
639284584b0Sjason 		statvar >>= 1;
640284584b0Sjason 
641284584b0Sjason 	/*
642284584b0Sjason 	 * Establish scheduler softint.
643284584b0Sjason 	 */
644284584b0Sjason 	schedint.ih_pil = PIL_SCHED;
645284584b0Sjason 	schedint.ih_clr = NULL;
646284584b0Sjason 	schedint.ih_arg = 0;
647284584b0Sjason 	schedint.ih_pending = 0;
648284584b0Sjason 	schedhz = stathz/4;
649284584b0Sjason 
650284584b0Sjason 	/*
651284584b0Sjason 	 * Enable timers
652284584b0Sjason 	 *
653284584b0Sjason 	 * Also need to map the interrupts cause we're not a child of the sbus.
654284584b0Sjason 	 * N.B. By default timer[0] is disabled and timer[1] is enabled.
655284584b0Sjason 	 */
656284584b0Sjason 	stxa((vaddr_t)&timerreg_4u.t_timer[0].t_limit, ASI_NUCLEUS,
657284584b0Sjason 	     tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD);
658284584b0Sjason 	stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS,
659284584b0Sjason 	     timerreg_4u.t_mapintr[0]|INTMAP_V);
660284584b0Sjason 
661284584b0Sjason #ifdef DEBUG
662284584b0Sjason 	if (intrdebug)
663284584b0Sjason 		/* Neglect to enable timer */
664284584b0Sjason 		stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
665284584b0Sjason 		     tmr_ustolim(statint)|TMR_LIM_RELOAD);
666284584b0Sjason 	else
667284584b0Sjason #endif
668284584b0Sjason 		stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
669284584b0Sjason 		     tmr_ustolim(statint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
670284584b0Sjason 	stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS,
671284584b0Sjason 	     timerreg_4u.t_mapintr[1]|INTMAP_V);
672284584b0Sjason 
673284584b0Sjason 	statmin = statint - (statvar >> 1);
674284584b0Sjason 
675284584b0Sjason }
676284584b0Sjason 
677284584b0Sjason /*
678284584b0Sjason  * Dummy setstatclockrate(), since we know profhz==hz.
679284584b0Sjason  */
680284584b0Sjason /* ARGSUSED */
681284584b0Sjason void
682284584b0Sjason setstatclockrate(newhz)
683284584b0Sjason 	int newhz;
684284584b0Sjason {
685284584b0Sjason 	/* nothing */
686284584b0Sjason }
687284584b0Sjason 
688284584b0Sjason /*
689284584b0Sjason  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
690284584b0Sjason  * console input, we need to check for that here as well, and generate
691284584b0Sjason  * a software interrupt to read it.
692284584b0Sjason  */
693284584b0Sjason #ifdef	DEBUG
694284584b0Sjason static int clockcheck = 0;
695284584b0Sjason #endif
696284584b0Sjason int
697284584b0Sjason clockintr(cap)
698284584b0Sjason 	void *cap;
699284584b0Sjason {
700284584b0Sjason #ifdef DEBUG
701284584b0Sjason 	static int64_t tick_base = 0;
702b636f8fdSkettenis 	struct timeval ctime;
7035f018631Sjason 	int64_t t;
7045f018631Sjason 
7055f018631Sjason 	t = tick() & TICK_TICKS;
706284584b0Sjason 
707b636f8fdSkettenis 	microtime(&ctime);
708284584b0Sjason 	if (!tick_base) {
709b636f8fdSkettenis 		tick_base = (ctime.tv_sec * 1000000LL + ctime.tv_usec)
710284584b0Sjason 			* 1000000LL / cpu_clockrate;
711284584b0Sjason 		tick_base -= t;
712284584b0Sjason 	} else if (clockcheck) {
713284584b0Sjason 		int64_t tk = t;
714b636f8fdSkettenis 		int64_t clk = (ctime.tv_sec * 1000000LL + ctime.tv_usec);
715284584b0Sjason 		t -= tick_base;
716284584b0Sjason 		t = t * 1000000LL / cpu_clockrate;
717284584b0Sjason 		if (t - clk > hz) {
718284584b0Sjason 			printf("Clock lost an interrupt!\n");
719eb79e960Shenric 			printf("Actual: %llx Expected: %llx tick %llx "
720eb79e960Shenric 			    "tick_base %llx\n", (long long)t, (long long)clk,
721eb79e960Shenric 			    (long long)tk, (long long)tick_base);
722284584b0Sjason #ifdef DDB
723284584b0Sjason 			Debugger();
724284584b0Sjason #endif
725284584b0Sjason 			tick_base = 0;
726284584b0Sjason 		}
727284584b0Sjason 	}
728284584b0Sjason #endif
729284584b0Sjason 	/* Let locore.s clear the interrupt for us. */
730284584b0Sjason 	hardclock((struct clockframe *)cap);
7315f018631Sjason 
732284584b0Sjason 	return (1);
733284584b0Sjason }
734284584b0Sjason 
735284584b0Sjason /*
736284584b0Sjason  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
737284584b0Sjason  * console input, we need to check for that here as well, and generate
738284584b0Sjason  * a software interrupt to read it.
739284584b0Sjason  *
740284584b0Sjason  * %tick is really a level-14 interrupt.  We need to remap this in
741284584b0Sjason  * locore.s to a level 10.
742284584b0Sjason  */
743284584b0Sjason int
744284584b0Sjason tickintr(cap)
745284584b0Sjason 	void *cap;
746284584b0Sjason {
74754821dc7Skettenis 	struct cpu_info *ci = curcpu();
74854821dc7Skettenis 	u_int64_t s;
749284584b0Sjason 
75092d28d96Skettenis 	/*
75154821dc7Skettenis 	 * No need to worry about overflow; %tick is architecturally
75254821dc7Skettenis 	 * defined not to do that for at least 10 years.
75392d28d96Skettenis 	 */
75454821dc7Skettenis 	while (ci->ci_tick < tick()) {
75554821dc7Skettenis 		ci->ci_tick += tick_increment;
75654821dc7Skettenis 		hardclock((struct clockframe *)cap);
757fc635044Saaron 		level0.ih_count.ec_count++;
75854821dc7Skettenis 	}
75954821dc7Skettenis 
76054821dc7Skettenis 	/* Reset the interrupt. */
76154821dc7Skettenis 	s = intr_disable();
76254821dc7Skettenis 	tickcmpr_set(ci->ci_tick);
76392d28d96Skettenis 	intr_restore(s);
764284584b0Sjason 
765284584b0Sjason 	return (1);
766284584b0Sjason }
767284584b0Sjason 
768284584b0Sjason /*
769284584b0Sjason  * Level 14 (stat clock) interrupt handler.
770284584b0Sjason  */
771284584b0Sjason int
772284584b0Sjason statintr(cap)
773284584b0Sjason 	void *cap;
774284584b0Sjason {
775eb79e960Shenric 	u_long newint, r, var;
776284584b0Sjason 	struct cpu_info *ci = curcpu();
777284584b0Sjason 
778284584b0Sjason #ifdef NOT_DEBUG
779284584b0Sjason 	printf("statclock: count %x:%x, limit %x:%x\n",
780284584b0Sjason 	       timerreg_4u.t_timer[1].t_count, timerreg_4u.t_timer[1].t_limit);
781284584b0Sjason #endif
782284584b0Sjason #ifdef NOT_DEBUG
783284584b0Sjason 	prom_printf("!");
784284584b0Sjason #endif
785284584b0Sjason 	statclock((struct clockframe *)cap);
786284584b0Sjason #ifdef NOTDEF_DEBUG
787284584b0Sjason 	/* Don't re-schedule the IRQ */
788284584b0Sjason 	return 1;
789284584b0Sjason #endif
790284584b0Sjason 	/*
791284584b0Sjason 	 * Compute new randomized interval.  The intervals are uniformly
792284584b0Sjason 	 * distributed on [statint - statvar / 2, statint + statvar / 2],
793284584b0Sjason 	 * and therefore have mean statint, giving a stathz frequency clock.
794284584b0Sjason 	 */
795284584b0Sjason 	var = statvar;
796284584b0Sjason 	do {
797284584b0Sjason 		r = random() & (var - 1);
798284584b0Sjason 	} while (r == 0);
799284584b0Sjason 	newint = statmin + r;
800284584b0Sjason 
801284584b0Sjason 	if (schedhz)
802284584b0Sjason 		if ((++ci->ci_schedstate.spc_schedticks & 3) == 0)
803284584b0Sjason 			send_softint(-1, PIL_SCHED, &schedint);
804284584b0Sjason 	stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
805284584b0Sjason 	     tmr_ustolim(newint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
806fc635044Saaron 
807284584b0Sjason 	return (1);
808284584b0Sjason }
809284584b0Sjason 
810284584b0Sjason int
811284584b0Sjason schedintr(arg)
812284584b0Sjason 	void *arg;
813284584b0Sjason {
814284584b0Sjason 	if (curproc)
815284584b0Sjason 		schedclock(curproc);
816284584b0Sjason 	return (1);
817284584b0Sjason }
818284584b0Sjason 
819284584b0Sjason 
820284584b0Sjason /*
821284584b0Sjason  * `sparc_clock_time_is_ok' is used in cpu_reboot() to determine
822284584b0Sjason  * whether it is appropriate to call resettodr() to consolidate
823284584b0Sjason  * pending time adjustments.
824284584b0Sjason  */
825284584b0Sjason int sparc_clock_time_is_ok;
826284584b0Sjason 
827284584b0Sjason /*
828284584b0Sjason  * Set up the system's time, given a `reasonable' time value.
829284584b0Sjason  */
830284584b0Sjason void
831284584b0Sjason inittodr(base)
832284584b0Sjason 	time_t base;
833284584b0Sjason {
834284584b0Sjason 	int badbase = 0, waszero = base == 0;
8354da6a00eSderaadt 	char *bad = NULL;
83605a26ea5Sart 	struct timeval tv;
83705a26ea5Sart 	struct timespec ts;
838284584b0Sjason 
839284584b0Sjason 	if (base < 5 * SECYR) {
840284584b0Sjason 		/*
841284584b0Sjason 		 * If base is 0, assume filesystem time is just unknown
842284584b0Sjason 		 * in stead of preposterous. Don't bark.
843284584b0Sjason 		 */
844284584b0Sjason 		if (base != 0)
845284584b0Sjason 			printf("WARNING: preposterous time in file system\n");
846284584b0Sjason 		/* not going to use it anyway, if the chip is readable */
847284584b0Sjason 		base = 21*SECYR + 186*SECDAY + SECDAY/2;
848284584b0Sjason 		badbase = 1;
849284584b0Sjason 	}
850284584b0Sjason 
85105a26ea5Sart 	if (todr_handle && (todr_gettime(todr_handle, &tv) != 0 ||
85205a26ea5Sart 	    tv.tv_sec == 0)) {
853284584b0Sjason 		/*
854284584b0Sjason 		 * Believe the time in the file system for lack of
855284584b0Sjason 		 * anything better, resetting the clock.
856284584b0Sjason 		 */
8574da6a00eSderaadt 		bad = "WARNING: bad date in battery clock";
85805a26ea5Sart 		tv.tv_sec = base;
85905a26ea5Sart 		tv.tv_usec = 0;
860284584b0Sjason 		if (!badbase)
861284584b0Sjason 			resettodr();
862284584b0Sjason 	} else {
86305a26ea5Sart 		int deltat = tv.tv_sec - base;
864284584b0Sjason 
865284584b0Sjason 		sparc_clock_time_is_ok = 1;
866284584b0Sjason 
867284584b0Sjason 		if (deltat < 0)
868284584b0Sjason 			deltat = -deltat;
86905a26ea5Sart 		if (!(waszero || deltat < 2 * SECDAY)) {
8704da6a00eSderaadt #ifndef SMALL_KERNEL
871eb79e960Shenric 			printf("WARNING: clock %s %ld days",
87205a26ea5Sart 			    tv.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
8734da6a00eSderaadt 			bad = "";
8744da6a00eSderaadt #endif
875284584b0Sjason 		}
8760f9af073Sderaadt 	}
87705a26ea5Sart 
87805a26ea5Sart 	ts.tv_sec = tv.tv_sec;
87905a26ea5Sart 	ts.tv_nsec = tv.tv_usec * 1000;
88005a26ea5Sart 	tc_setclock(&ts);
88105a26ea5Sart 
8824da6a00eSderaadt 	if (bad) {
8834da6a00eSderaadt 		printf("%s", bad);
884284584b0Sjason 		printf(" -- CHECK AND RESET THE DATE!\n");
885284584b0Sjason 	}
8864da6a00eSderaadt }
887284584b0Sjason 
888284584b0Sjason /*
889284584b0Sjason  * Reset the clock based on the current time.
890284584b0Sjason  * Used when the current clock is preposterous, when the time is changed,
891284584b0Sjason  * and when rebooting.  Do nothing if the time is not yet known, e.g.,
892284584b0Sjason  * when crashing during autoconfig.
893284584b0Sjason  */
894284584b0Sjason void
895284584b0Sjason resettodr()
896284584b0Sjason {
89705a26ea5Sart 	struct timeval tv;
898284584b0Sjason 
89905a26ea5Sart 	if (time_second == 0)
900284584b0Sjason 		return;
901284584b0Sjason 
90205a26ea5Sart 	microtime(&tv);
90305a26ea5Sart 
904284584b0Sjason 	sparc_clock_time_is_ok = 1;
90505a26ea5Sart 	if (todr_handle == 0 || todr_settime(todr_handle, &tv) != 0)
906284584b0Sjason 		printf("Cannot set time in time-of-day clock\n");
907284584b0Sjason }
908284584b0Sjason 
90958c73160Skettenis void
91058c73160Skettenis tick_start(void)
91158c73160Skettenis {
91254821dc7Skettenis 	struct cpu_info *ci = curcpu();
91354821dc7Skettenis 	u_int64_t s;
91458c73160Skettenis 
91558c73160Skettenis 	/*
91658c73160Skettenis 	 * Try to make the tick interrupts as synchronously as possible on
91754821dc7Skettenis 	 * all CPUs to avoid inaccuracies for migrating processes.
91858c73160Skettenis 	 */
91958c73160Skettenis 
92058c73160Skettenis 	s = intr_disable();
92154821dc7Skettenis 	ci->ci_tick = roundup(tick(), tick_increment);
92254821dc7Skettenis 	tickcmpr_set(ci->ci_tick);
92358c73160Skettenis 	intr_restore(s);
92458c73160Skettenis }
92558c73160Skettenis 
92605a26ea5Sart u_int
92705a26ea5Sart tick_get_timecount(struct timecounter *tc)
928bec6c41fSjason {
929bec6c41fSjason 	u_int64_t tick;
930bec6c41fSjason 
931bec6c41fSjason 	__asm __volatile("rd %%tick, %0" : "=r" (tick) :);
932bec6c41fSjason 
93305a26ea5Sart 	return (tick & ~0u);
934bec6c41fSjason }
935*8a2bbcc7Skettenis 
936*8a2bbcc7Skettenis u_int
937*8a2bbcc7Skettenis sys_tick_get_timecount(struct timecounter *tc)
938*8a2bbcc7Skettenis {
939*8a2bbcc7Skettenis 	u_int64_t tick;
940*8a2bbcc7Skettenis 
941*8a2bbcc7Skettenis 	__asm __volatile("rd %%sys_tick, %0" : "=r" (tick) :);
942*8a2bbcc7Skettenis 
943*8a2bbcc7Skettenis 	return (tick & ~0u);
944*8a2bbcc7Skettenis }
945