xref: /netbsd/sys/arch/sparc/sparc/clock.c (revision bf9ec67e)
1 /*	$NetBSD: clock.c,v 1.89 2002/05/02 13:01:45 martin 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 /*
58  * Common timer, clock and eeprom routines.
59  *
60  * Overview of timer and time-of-day devices on sparc machines:
61  *
62  * sun4/100 & sun4/200
63  *	have the Intersil 7170 time-of-day and timer chip (oclock.c)
64  *	eeprom device in OBIO space (eeprom.c)
65  *
66  * sun4/300 & sun4/400
67  *	Mostek MK48T02 clock/nvram device, includes eeprom (mkclock.c)
68  *	2 system timers (timer.c)
69  *
70  * sun4c
71  *	Mostek MK48T02 or MK48T08 clock/nvram device (mkclock.c)
72  *	system timer in OBIO space
73  *	2 system timers (timer.c)
74  *
75  * sun4m
76  *	Mostek MK48T08 clock/nvram device (mkclock.c)
77  *	1 global system timer (timer.c)
78  *	1 configurable counter/timer per CPU (timer.c)
79  *
80  * microSPARC-IIep:
81  *	DS1287A time-of-day chip on EBUS (dev/rtc.c)
82  *	the system timer is part of the PCI controller (timer.c)
83  *
84  * All system use the timer interrupt (at IPL 10) to drive hardclock().
85  * The second or per-CPU timer interrupt (at IPL 14) is used to drive
86  * statclock() (except on sun4/100 and sun4/200 machines, which don't
87  * have a spare timer device).
88  */
89 
90 #include "opt_sparc_arch.h"
91 
92 #include <sys/param.h>
93 #include <sys/kernel.h>
94 #include <sys/device.h>
95 #include <sys/proc.h>
96 #include <sys/malloc.h>
97 #include <sys/systm.h>
98 
99 #include <machine/bus.h>
100 #include <machine/autoconf.h>
101 #include <machine/eeprom.h>
102 #include <machine/cpu.h>
103 #include <machine/idprom.h>
104 
105 #include <dev/clock_subr.h>
106 
107 /* Variables shared with timer.c, mkclock.c, oclock.c */
108 int timerblurb = 10;	/* Guess a value; used before clock is attached */
109 int oldclk = 0;
110 
111 void	(*timer_init)(void);	/* Called from cpu_initclocks() */
112 int	(*eeprom_nvram_wenable)(int);
113 
114 /*
115  * Statistics clock interval and variance, in usec.  Variance must be a
116  * power of two.  Since this gives us an even number, not an odd number,
117  * we discard one case and compensate.  That is, a variance of 1024 would
118  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
119  * This is symmetric about the point 512, or statvar/2, and thus averages
120  * to that value (assuming uniform random numbers).
121  */
122 /* XXX fix comment to match value */
123 int statvar = 8192;
124 int statmin;			/* statclock interval - 1/2*variance */
125 int statint;
126 
127 
128 /*
129  * Common eeprom I/O routines.
130  */
131 char		*eeprom_va = NULL;
132 #if defined(SUN4)
133 static int	eeprom_busy = 0;
134 static int	eeprom_wanted = 0;
135 static int	eeprom_take(void);
136 static void	eeprom_give(void);
137 static int	eeprom_update(char *, int, int);
138 #endif
139 
140 /* Global TOD clock handle & idprom pointer */
141 todr_chip_handle_t todr_handle;
142 struct idprom *idprom;
143 
144 void establish_hostid(struct idprom *);
145 void myetheraddr(u_char *);
146 
147 
148 /*
149  * XXX this belongs elsewhere
150  */
151 void
152 myetheraddr(cp)
153 	u_char *cp;
154 {
155 	struct idprom *idp = idprom;
156 
157 	cp[0] = idp->id_ether[0];
158 	cp[1] = idp->id_ether[1];
159 	cp[2] = idp->id_ether[2];
160 	cp[3] = idp->id_ether[3];
161 	cp[4] = idp->id_ether[4];
162 	cp[5] = idp->id_ether[5];
163 }
164 
165 void
166 establish_hostid(idp)
167 	struct idprom *idp;
168 {
169 	u_long h;
170 
171 	h = idp->id_machine << 24;
172 	h |= idp->id_hostid[0] << 16;
173 	h |= idp->id_hostid[1] << 8;
174 	h |= idp->id_hostid[2];
175 
176 	printf(": hostid %lx\n", h);
177 
178 	/* Save IDPROM pointer and Host ID in globals */
179 	idprom = idp;
180 	hostid = h;
181 }
182 
183 
184 /*
185  * Set up the real-time and statistics clocks.
186  * Leave stathz 0 only if no alternative timer is available.
187  *
188  * The frequencies of these clocks must be an even number of microseconds.
189  */
190 void
191 cpu_initclocks()
192 {
193 	int minint;
194 
195 	if (1000000 % hz) {
196 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
197 		hz = 100;
198 		tick = 1000000 / hz;
199 	}
200 	if (stathz == 0)
201 		stathz = hz;
202 	if (1000000 % stathz) {
203 		printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
204 		stathz = 100;
205 	}
206 	profhz = stathz;		/* always */
207 
208 	statint = 1000000 / stathz;
209 	minint = statint / 2 + 100;
210 	while (statvar > minint)
211 		statvar >>= 1;
212 	statmin = statint - (statvar >> 1);
213 
214 	if (timer_init != NULL)
215 		(*timer_init)();
216 }
217 
218 /*
219  * Dummy setstatclockrate(), since we know profhz==hz.
220  */
221 /* ARGSUSED */
222 void
223 setstatclockrate(newhz)
224 	int newhz;
225 {
226 	/* nothing */
227 }
228 
229 
230 /*
231  * `sparc_clock_time_is_ok' is used in cpu_reboot() to determine
232  * whether it is appropriate to call resettodr() to consolidate
233  * pending time adjustments.
234  */
235 int sparc_clock_time_is_ok;
236 
237 /*
238  * Set up the system's time, given a `reasonable' time value.
239  */
240 void
241 inittodr(base)
242 	time_t base;
243 {
244 	int badbase = 0, waszero = base == 0;
245 
246 	if (base < 5 * SECYR) {
247 		/*
248 		 * If base is 0, assume filesystem time is just unknown
249 		 * in stead of preposterous. Don't bark.
250 		 */
251 		if (base != 0)
252 			printf("WARNING: preposterous time in file system\n");
253 		/* not going to use it anyway, if the chip is readable */
254 		base = 21*SECYR + 186*SECDAY + SECDAY/2;
255 		badbase = 1;
256 	}
257 
258 	if (todr_gettime(todr_handle, (struct timeval *)&time) != 0 ||
259 	    time.tv_sec == 0) {
260 
261 		printf("WARNING: bad date in battery clock");
262 		/*
263 		 * Believe the time in the file system for lack of
264 		 * anything better, resetting the clock.
265 		 */
266 		time.tv_sec = base;
267 		if (!badbase)
268 			resettodr();
269 	} else {
270 		int deltat = time.tv_sec - base;
271 
272 		sparc_clock_time_is_ok = 1;
273 
274 		if (deltat < 0)
275 			deltat = -deltat;
276 		if (waszero || deltat < 2 * SECDAY)
277 			return;
278 		printf("WARNING: clock %s %d days",
279 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
280 	}
281 	printf(" -- CHECK AND RESET THE DATE!\n");
282 }
283 
284 /*
285  * Reset the clock based on the current time.
286  * Used when the current clock is preposterous, when the time is changed,
287  * and when rebooting.  Do nothing if the time is not yet known, e.g.,
288  * when crashing during autoconfig.
289  */
290 void
291 resettodr()
292 {
293 
294 	if (time.tv_sec == 0)
295 		return;
296 
297 	sparc_clock_time_is_ok = 1;
298 	if (todr_settime(todr_handle, (struct timeval *)&time) != 0)
299 		printf("Cannot set time in time-of-day clock\n");
300 }
301 
302 #if defined(SUN4)
303 /*
304  * Return the best possible estimate of the time in the timeval
305  * to which tvp points.  We do this by returning the current time
306  * plus the amount of time since the last clock interrupt.
307  *
308  * Check that this time is no less than any previously-reported time,
309  * which could happen around the time of a clock adjustment.  Just for
310  * fun, we guarantee that the time will be greater than the value
311  * obtained by a previous call.
312  */
313 void
314 microtime(tvp)
315 	struct timeval *tvp;
316 {
317 	int s;
318 	static struct timeval lasttime;
319 	static struct timeval oneusec = {0, 1};
320 
321 	if (!oldclk) {
322 		lo_microtime(tvp);
323 		return;
324 	}
325 
326 	s = splhigh();
327 	*tvp = time;
328 	splx(s);
329 
330 	if (timercmp(tvp, &lasttime, <=))
331 		timeradd(&lasttime, &oneusec, tvp);
332 
333 	lasttime = *tvp;
334 }
335 #endif /* SUN4 */
336 
337 /*
338  * XXX: these may actually belong somewhere else, but since the
339  * EEPROM is so closely tied to the clock on some models, perhaps
340  * it needs to stay here...
341  */
342 int
343 eeprom_uio(uio)
344 	struct uio *uio;
345 {
346 #if defined(SUN4)
347 	int error;
348 	int off;	/* NOT off_t */
349 	u_int cnt, bcnt;
350 	caddr_t buf = NULL;
351 
352 	if (!CPU_ISSUN4)
353 		return (ENODEV);
354 
355 	if (eeprom_va == NULL) {
356 		error = ENXIO;
357 		goto out;
358 	}
359 
360 	off = uio->uio_offset;
361 	if (off > EEPROM_SIZE)
362 		return (EFAULT);
363 
364 	cnt = uio->uio_resid;
365 	if (cnt > (EEPROM_SIZE - off))
366 		cnt = (EEPROM_SIZE - off);
367 
368 	if ((error = eeprom_take()) != 0)
369 		return (error);
370 
371 	/*
372 	 * The EEPROM can only be accessed one byte at a time, yet
373 	 * uiomove() will attempt long-word access.  To circumvent
374 	 * this, we byte-by-byte copy the eeprom contents into a
375 	 * temporary buffer.
376 	 */
377 	buf = malloc(EEPROM_SIZE, M_DEVBUF, M_WAITOK);
378 	if (buf == NULL) {
379 		error = EAGAIN;
380 		goto out;
381 	}
382 
383 	if (uio->uio_rw == UIO_READ)
384 		for (bcnt = 0; bcnt < EEPROM_SIZE; ++bcnt)
385 			*(char *)(buf + bcnt) = *(char *)(eeprom_va + bcnt);
386 
387 	if ((error = uiomove(buf + off, (int)cnt, uio)) != 0)
388 		goto out;
389 
390 	if (uio->uio_rw != UIO_READ)
391 		error = eeprom_update(buf, off, cnt);
392 
393  out:
394 	if (buf)
395 		free(buf, M_DEVBUF);
396 	eeprom_give();
397 	return (error);
398 #else /* ! SUN4 */
399 	return (ENODEV);
400 #endif /* SUN4 */
401 }
402 
403 #if defined(SUN4)
404 /*
405  * Update the EEPROM from the passed buf.
406  */
407 static int
408 eeprom_update(buf, off, cnt)
409 	char *buf;
410 	int off, cnt;
411 {
412 	int error = 0;
413 	volatile char *ep;
414 	char *bp;
415 
416 	if (eeprom_va == NULL)
417 		return (ENXIO);
418 
419 	ep = eeprom_va + off;
420 	bp = buf + off;
421 
422 	if (eeprom_nvram_wenable != NULL)
423 		(*eeprom_nvram_wenable)(1);
424 
425 	while (cnt > 0) {
426 		/*
427 		 * DO NOT WRITE IT UNLESS WE HAVE TO because the
428 		 * EEPROM has a limited number of write cycles.
429 		 * After some number of writes it just fails!
430 		 */
431 		if (*ep != *bp) {
432 			*ep = *bp;
433 			/*
434 			 * We have written the EEPROM, so now we must
435 			 * sleep for at least 10 milliseconds while
436 			 * holding the lock to prevent all access to
437 			 * the EEPROM while it recovers.
438 			 */
439 			(void)tsleep(eeprom_va, PZERO - 1, "eeprom", hz/50);
440 		}
441 		/* Make sure the write worked. */
442 		if (*ep != *bp) {
443 			error = EIO;
444 			goto out;
445 		}
446 		++ep;
447 		++bp;
448 		--cnt;
449 	}
450  out:
451 	if (eeprom_nvram_wenable != NULL)
452 		(*eeprom_nvram_wenable)(0);
453 
454 	return (error);
455 }
456 
457 /* Take a lock on the eeprom. */
458 static int
459 eeprom_take()
460 {
461 	int error = 0;
462 
463 	while (eeprom_busy) {
464 		eeprom_wanted = 1;
465 		error = tsleep(&eeprom_busy, PZERO | PCATCH, "eeprom", 0);
466 		eeprom_wanted = 0;
467 		if (error)	/* interrupted */
468 			goto out;
469 	}
470 	eeprom_busy = 1;
471  out:
472 	return (error);
473 }
474 
475 /* Give a lock on the eeprom away. */
476 static void
477 eeprom_give()
478 {
479 
480 	eeprom_busy = 0;
481 	if (eeprom_wanted) {
482 		eeprom_wanted = 0;
483 		wakeup(&eeprom_busy);
484 	}
485 }
486 #endif /* SUN4 */
487