xref: /netbsd/sys/arch/hpcmips/hpcmips/clock.c (revision bf9ec67e)
1 /*	$NetBSD: clock.c,v 1.16 2002/01/31 17:57:43 uch Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 Shin Takemura, All rights reserved.
5  * Copyright (c) 1999-2001 SATO Kazumi, All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 /*
33  * Copyright (c) 1988 University of Utah.
34  * Copyright (c) 1992, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * the Systems Programming Group of the University of Utah Computer
39  * Science Department and Ralph Campbell.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *	This product includes software developed by the University of
52  *	California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  * from: Utah Hdr: clock.c 1.18 91/01/21
70  *
71  *	@(#)clock.c	8.1 (Berkeley) 6/10/93
72  */
73 
74 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
75 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.16 2002/01/31 17:57:43 uch Exp $");
76 
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/kernel.h>			/* hz */
80 
81 #include <dev/clock_subr.h>
82 #include <machine/sysconf.h>		/* platform */
83 
84 #define MINYEAR			2002	/* "today" */
85 #define UNIX_YEAR_OFFSET	0
86 
87 /*
88  * platform_clock_attach:
89  *
90  *	Register CPU(VR41XX or TX39XX) dependent clock routine to system.
91  */
92 void
93 platform_clock_attach(void *ctx, struct platform_clock *clock)
94 {
95 
96 	printf("\n");
97 
98 	clock->self = ctx;
99 	platform.clock = clock;
100 }
101 
102 /*
103  * cpu_initclocks:
104  *
105  *	starts periodic timer, which provides hardclock interrupts to
106  *	kern_clock.c.
107  *	Leave stathz 0 since there are no other timers available.
108  */
109 void
110 cpu_initclocks()
111 {
112 	struct platform_clock *clock = platform.clock;
113 
114 	if (clock == NULL)
115 		panic("cpu_initclocks: no clock attached");
116 
117 	hz = clock->hz;
118 	tick = 1000000 / hz;
119 	/* number of microseconds between interrupts */
120 	tickfix = 1000000 - (hz * tick);
121 	if (tickfix) {
122 		int ftp;
123 
124 		ftp = min(ffs(tickfix), ffs(hz));
125 		tickfix >>= (ftp - 1);
126 		tickfixinterval = hz >> (ftp - 1);
127 	}
128 
129 	/* start periodic timer */
130 	(*clock->init)(clock->self);
131 }
132 
133 /*
134  * setstatclockrate:
135  *
136  *	We assume newhz is either stathz or profhz, and that neither will
137  *	change after being set up above.  Could recalculate intervals here
138  *	but that would be a drag.
139  */
140 void
141 setstatclockrate(int newhz)
142 {
143 
144 	/* nothing we can do */
145 }
146 
147 /*
148  * inittodr:
149  *
150  *	initializes the time of day hardware which provides
151  *	date functions.  Its primary function is to use some file
152  *	system information in case the hardare clock lost state.
153  *
154  *	Initialze the time of day register, based on the time base which is,
155  *	e.g. from a filesystem.  Base provides the time to within six months,
156  *	and the time of year clock (if any) provides the rest.
157  */
158 void
159 inittodr(time_t base)
160 {
161 	struct platform_clock *clock = platform.clock;
162 	struct clock_ymdhms dt;
163 	int year, badbase;
164 	time_t deltat;
165 
166 	if (clock == NULL)
167 		panic("inittodr: no clock attached");
168 
169 	if (base < (MINYEAR - 1970) * SECYR) {
170 		printf("WARNING: preposterous time in file system");
171 		/* read the system clock anyway */
172 		base = (MINYEAR - 1970) * SECYR;
173 		badbase = 1;
174 	} else
175 		badbase = 0;
176 
177 	(*clock->rtc_get)(clock->self, base, &dt);
178 #ifdef DEBUG
179 	printf("readclock: %d/%d/%d/%d/%d/%d", dt.dt_year, dt.dt_mon, dt.dt_day,
180 	    dt.dt_hour, dt.dt_min, dt.dt_sec);
181 #endif
182 	clock->start = 1;
183 
184 	year = 1900 + UNIX_YEAR_OFFSET + dt.dt_year;
185 	if (year < 1970)
186 		year += 100;
187 	/* simple sanity checks (2037 = time_t overflow) */
188 	if (year < MINYEAR || year > 2037 ||
189 	    dt.dt_mon < 1 || dt.dt_mon > 12 || dt.dt_day < 1 ||
190 	    dt.dt_day > 31 || dt.dt_hour > 23 || dt.dt_min > 59 ||
191 	    dt.dt_sec > 59) {
192 		/*
193 		 * Believe the time in the file system for lack of
194 		 * anything better, resetting the TODR.
195 		 */
196 		time.tv_sec = base;
197 		if (!badbase) {
198 			printf("WARNING: preposterous clock chip time\n");
199 			resettodr();
200 		}
201 		goto bad;
202 	}
203 
204 	dt.dt_year = year;
205 	time.tv_sec = clock_ymdhms_to_secs(&dt);
206 #ifdef DEBUG
207 	printf("=>%ld (%ld)\n", time.tv_sec, base);
208 #endif
209 
210 	if (!badbase) {
211 		/*
212 		 * See if we gained/lost two or more days;
213 		 * if so, assume something is amiss.
214 		 */
215 		deltat = time.tv_sec - base;
216 		if (deltat < 0)
217 			deltat = -deltat;
218 		if (deltat < 2 * SECDAY)
219 			return;
220 		printf("WARNING: clock %s %ld days",
221 		    time.tv_sec < base ? "lost" : "gained",
222 		    (long)deltat / SECDAY);
223 	}
224  bad:
225 	printf(" -- CHECK AND RESET THE DATE!\n");
226 }
227 
228 /*
229  * resettodr:
230  *
231  *	restores the time of day hardware after a time change.
232  *
233  *	Reset the TODR based on the time value; used when the TODR
234  *	has a preposterous value and also when the time is reset
235  *	by the stime system call.  Also called when the TODR goes past
236  *	TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
237  *	to wrap the TODR around.
238  */
239 void
240 resettodr()
241 {
242 	struct platform_clock *clock = platform.clock;
243 	struct clock_ymdhms dt;
244 
245 	if (clock == NULL)
246 		panic("inittodr: no clock attached");
247 
248 	if (!clock->start)
249 		return;
250 
251 	clock_secs_to_ymdhms(time.tv_sec, &dt);
252 
253 	/* rt clock wants 2 digits XXX */
254 	dt.dt_year = (dt.dt_year - UNIX_YEAR_OFFSET) % 100;
255 #ifdef DEBUG
256 	printf("setclock: %d/%d/%d/%d/%d/%d\n", dt.dt_year, dt.dt_mon,
257 	    dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec);
258 #endif
259 
260 	(*clock->rtc_set)(clock->self, &dt);
261 }
262 
263 /*
264  * microtime:
265  *
266  *	Return the best possible estimate of the time in the timeval to
267  *	which tvp points.  We guarantee that the time will be greater than
268  *	the value obtained by a previous call.
269  */
270 void
271 microtime(struct timeval *tvp)
272 {
273 	int s = splclock();
274 	static struct timeval lasttime;
275 
276 	*tvp = time;
277 
278 	if (tvp->tv_usec >= 1000000) {
279 		tvp->tv_usec -= 1000000;
280 		tvp->tv_sec++;
281 	}
282 
283 	if (tvp->tv_sec == lasttime.tv_sec &&
284 	    tvp->tv_usec <= lasttime.tv_usec &&
285 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
286 		tvp->tv_sec++;
287 		tvp->tv_usec -= 1000000;
288 	}
289 	lasttime = *tvp;
290 	splx(s);
291 }
292 
293 /*
294  * delay:
295  *
296  *	Wait at least "n" microseconds.
297  */
298 void
299 delay(int n)
300 {
301 
302         DELAY(n);
303 }
304