clock.c revision 1.34
1/*	$OpenBSD: clock.c,v 1.34 2006/02/12 19:55:39 miod Exp $	*/
2/*	$NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $	*/
3
4/*-
5 * Copyright (c) 1993, 1994 Charles Hannum.
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz and Don Ahn.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)clock.c	7.2 (Berkeley) 5/12/91
37 */
38/*
39 * Mach Operating System
40 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
41 * All Rights Reserved.
42 *
43 * Permission to use, copy, modify and distribute this software and its
44 * documentation is hereby granted, provided that both the copyright
45 * notice and this permission notice appear in all copies of the
46 * software, derivative works or modified versions, and any portions
47 * thereof, and that both notices appear in supporting documentation.
48 *
49 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
50 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
51 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
52 *
53 * Carnegie Mellon requests users of this software to return to
54 *
55 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
56 *  School of Computer Science
57 *  Carnegie Mellon University
58 *  Pittsburgh PA 15213-3890
59 *
60 * any improvements or extensions that they make and grant Carnegie Mellon
61 * the rights to redistribute these changes.
62 */
63/*
64  Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
65
66		All Rights Reserved
67
68Permission to use, copy, modify, and distribute this software and
69its documentation for any purpose and without fee is hereby
70granted, provided that the above copyright notice appears in all
71copies and that both the copyright notice and this permission notice
72appear in supporting documentation, and that the name of Intel
73not be used in advertising or publicity pertaining to distribution
74of the software without specific, written prior permission.
75
76INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
77INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
78IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
79CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
80LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
81NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
82WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
83*/
84
85/*
86 * Primitive clock interrupt routines.
87 */
88#include <sys/types.h>
89#include <sys/param.h>
90#include <sys/systm.h>
91#include <sys/time.h>
92#include <sys/kernel.h>
93#include <sys/device.h>
94#include <sys/timeout.h>
95
96#include <machine/cpu.h>
97#include <machine/intr.h>
98#include <machine/pio.h>
99#include <machine/cpufunc.h>
100
101#include <dev/clock_subr.h>
102#include <dev/isa/isareg.h>
103#include <dev/isa/isavar.h>
104#include <dev/ic/mc146818reg.h>
105#include <i386/isa/nvram.h>
106#include <i386/isa/timerreg.h>
107
108void	spinwait(int);
109void	findcpuspeed(void);
110int	clockintr(void *);
111int	gettick(void);
112int	rtcget(mc_todregs *);
113void	rtcput(mc_todregs *);
114int 	hexdectodec(int);
115int	dectohexdec(int);
116int	rtcintr(void *);
117void	rtcdrain(void *);
118
119u_int mc146818_read(void *, u_int);
120void mc146818_write(void *, u_int, u_int);
121
122#if defined(I586_CPU) || defined(I686_CPU)
123int pentium_mhz;
124#endif
125#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
126int clock_broken_latch;
127#endif
128
129#define	SECMIN	((unsigned)60)			/* seconds per minute */
130#define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
131
132u_int
133mc146818_read(sc, reg)
134	void *sc;					/* XXX use it? */
135	u_int reg;
136{
137	int s;
138	u_char v;
139
140	s = splhigh();
141	outb(IO_RTC, reg);
142	DELAY(1);
143	v = inb(IO_RTC+1);
144	DELAY(1);
145	splx(s);
146	return (v);
147}
148
149void
150mc146818_write(sc, reg, datum)
151	void *sc;					/* XXX use it? */
152	u_int reg, datum;
153{
154	int s;
155
156	s = splhigh();
157	outb(IO_RTC, reg);
158	DELAY(1);
159	outb(IO_RTC+1, datum);
160	DELAY(1);
161	splx(s);
162}
163
164void
165startrtclock()
166{
167	int s;
168
169	findcpuspeed();		/* use the clock (while it's free)
170					to find the cpu speed */
171	initrtclock();
172
173	/* Check diagnostic status */
174	if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0)	/* XXX softc */
175		printf("RTC BIOS diagnostic error %b\n", (unsigned int) s,
176		    NVRAM_DIAG_BITS);
177}
178
179void
180rtcdrain(void *v)
181{
182	struct timeout *to = (struct timeout *)v;
183
184	if (to != NULL)
185		timeout_del(to);
186
187	/*
188	 * Drain any un-acknowledged RTC interrupts.
189	 * See comment in cpu_initclocks().
190	 */
191  	while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF)
192		; /* Nothing. */
193}
194
195void
196initrtclock()
197{
198	/* initialize 8253 clock */
199	outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
200
201	/* Correct rounding will buy us a better precision in timekeeping */
202	outb(IO_TIMER1, TIMER_DIV(hz) % 256);
203	outb(IO_TIMER1, TIMER_DIV(hz) / 256);
204}
205
206int
207clockintr(arg)
208	void *arg;
209{
210	struct clockframe *frame = arg;		/* not strictly necessary */
211
212	hardclock(frame);
213	return (1);
214}
215
216int
217rtcintr(arg)
218	void *arg;
219{
220	struct clockframe *frame = arg;		/* not strictly necessary */
221	u_int stat = 0;
222
223	/*
224	 * If rtcintr is 'late', next intr may happen immediately.
225	 * Get them all. (Also, see comment in cpu_initclocks().)
226	 */
227	while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) {
228		statclock(frame);
229		stat = 1;
230	}
231	return (stat);
232}
233
234int
235gettick()
236{
237
238#if defined(I586_CPU) || defined(I686_CPU)
239	if (clock_broken_latch) {
240		int v1, v2, v3;
241		int w1, w2, w3;
242
243		disable_intr();
244
245		v1 = inb(TIMER_CNTR0);
246		v1 |= inb(TIMER_CNTR0) << 8;
247		v2 = inb(TIMER_CNTR0);
248		v2 |= inb(TIMER_CNTR0) << 8;
249		v3 = inb(TIMER_CNTR0);
250		v3 |= inb(TIMER_CNTR0) << 8;
251
252		enable_intr();
253
254		if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
255			return (v2);
256
257#define _swap_val(a, b) do { \
258	int c = a; \
259	a = b; \
260	b = c; \
261} while (0)
262
263		/* sort v1 v2 v3 */
264		if (v1 < v2)
265			_swap_val(v1, v2);
266		if (v2 < v3)
267			_swap_val(v2, v3);
268		if (v1 < v2)
269			_swap_val(v1, v2);
270
271		/* compute the middle value */
272		if (v1 - v3 < 0x200)
273			return (v2);
274		w1 = v2 - v3;
275		w2 = v3 - v1 + TIMER_DIV(hz);
276		w3 = v1 - v2;
277		if (w1 >= w2) {
278			if (w1 >= w3)
279				return (v1);
280		} else {
281			if (w2 >= w3)
282				return (v2);
283		}
284		return (v3);
285	} else
286#endif
287	{
288		u_char lo, hi;
289
290		disable_intr();
291		/* Select counter 0 and latch it. */
292		outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
293		lo = inb(TIMER_CNTR0);
294		hi = inb(TIMER_CNTR0);
295
296		enable_intr();
297		return ((hi << 8) | lo);
298	}
299}
300
301/*
302 * Wait "n" microseconds.
303 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
304 * Note: timer had better have been programmed before this is first used!
305 * (Note that we use `rate generator' mode, which counts at 1:1; `square
306 * wave' mode counts at 2:1).
307 */
308void
309i8254_delay(n)
310	int n;
311{
312	int limit, tick, otick;
313
314	/*
315	 * Read the counter first, so that the rest of the setup overhead is
316	 * counted.
317	 */
318	otick = gettick();
319
320#ifdef __GNUC__
321	/*
322	 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so
323	 * we can take advantage of the intermediate 64-bit quantity to prevent
324	 * loss of significance.
325	 */
326	n -= 5;
327	if (n < 0)
328		return;
329	__asm __volatile("mul %2\n\tdiv %3"
330			 : "=a" (n)
331			 : "0" (n), "r" (TIMER_FREQ), "r" (1000000)
332			 : "%edx", "cc");
333#else
334	/*
335	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
336	 * without any avoidable overflows.
337	 */
338	n -= 20;
339	{
340		int sec = n / 1000000,
341		    usec = n % 1000000;
342		n = sec * TIMER_FREQ +
343		    usec * (TIMER_FREQ / 1000000) +
344		    usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
345		    usec * (TIMER_FREQ % 1000) / 1000000;
346	}
347#endif
348
349	limit = TIMER_FREQ / hz;
350
351	while (n > 0) {
352		tick = gettick();
353		if (tick > otick)
354			n -= limit - (tick - otick);
355		else
356			n -= otick - tick;
357		otick = tick;
358	}
359}
360
361unsigned int delaycount;	/* calibrated loop variable (1 millisecond) */
362
363#define FIRST_GUESS   0x2000
364
365void
366findcpuspeed()
367{
368	int i;
369	int remainder;
370
371	/* Put counter in count down mode */
372	outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
373	outb(TIMER_CNTR0, 0xff);
374	outb(TIMER_CNTR0, 0xff);
375	for (i = FIRST_GUESS; i; i--)
376		;
377	/* Read the value left in the counter */
378	remainder = gettick();
379	/*
380	 * Formula for delaycount is:
381	 *  (loopcount * timer clock speed) / (counter ticks * 1000)
382	 */
383	delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder);
384}
385
386#if defined(I586_CPU) || defined(I686_CPU)
387void
388calibrate_cyclecounter()
389{
390	unsigned long long count, last_count;
391
392	__asm __volatile("rdtsc" : "=A" (last_count));
393	delay(1000000);
394	__asm __volatile("rdtsc" : "=A" (count));
395	pentium_mhz = ((count - last_count) + 500000) / 1000000;
396}
397#endif
398
399void
400i8254_initclocks()
401{
402	static struct timeout rtcdrain_timeout;
403	stathz = 128;
404	profhz = 1024;
405
406	/*
407	 * XXX If you're doing strange things with multiple clocks, you might
408	 * want to keep track of clock handlers.
409	 */
410	(void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr,
411	    0, "clock");
412	(void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr,
413	    0, "rtc");
414
415	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
416	mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE);
417
418	/*
419	 * On a number of i386 systems, the rtc will fail to start when booting
420	 * the system. This is due to us missing to acknowledge an interrupt
421	 * during early stages of the boot process. If we do not acknowledge
422	 * the interrupt, the rtc clock will not generate further interrupts.
423	 * To solve this, once interrupts are enabled, use a timeout (once)
424	 * to drain any un-acknowledged rtc interrupt(s).
425	 */
426
427	timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout);
428	timeout_add(&rtcdrain_timeout, 1);
429}
430
431int
432rtcget(regs)
433	mc_todregs *regs;
434{
435	if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
436		return (-1);
437	MC146818_GETTOD(NULL, regs);			/* XXX softc */
438	return (0);
439}
440
441void
442rtcput(regs)
443	mc_todregs *regs;
444{
445	MC146818_PUTTOD(NULL, regs);			/* XXX softc */
446}
447
448int
449hexdectodec(n)
450	int n;
451{
452
453	return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
454}
455
456int
457dectohexdec(n)
458	int n;
459{
460
461	return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
462}
463
464static int timeset;
465
466/*
467 * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
468 * to be called at splclock()
469 */
470int cmoscheck(void);
471int
472cmoscheck()
473{
474	int i;
475	unsigned short cksum = 0;
476
477	for (i = 0x10; i <= 0x2d; i++)
478		cksum += mc146818_read(NULL, i); /* XXX softc */
479
480	return (cksum == (mc146818_read(NULL, 0x2e) << 8)
481			  + mc146818_read(NULL, 0x2f));
482}
483
484/*
485 * patchable to control century byte handling:
486 * 1: always update
487 * -1: never touch
488 * 0: try to figure out itself
489 */
490int rtc_update_century = 0;
491
492/*
493 * Expand a two-digit year as read from the clock chip
494 * into full width.
495 * Being here, deal with the CMOS century byte.
496 */
497int clock_expandyear(int);
498int
499clock_expandyear(clockyear)
500	int clockyear;
501{
502	int s, clockcentury, cmoscentury;
503
504	clockcentury = (clockyear < 70) ? 20 : 19;
505	clockyear += 100 * clockcentury;
506
507	if (rtc_update_century < 0)
508		return (clockyear);
509
510	s = splclock();
511	if (cmoscheck())
512		cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
513	else
514		cmoscentury = 0;
515	splx(s);
516	if (!cmoscentury) {
517#ifdef DIAGNOSTIC
518		printf("clock: unknown CMOS layout\n");
519#endif
520		return (clockyear);
521	}
522	cmoscentury = hexdectodec(cmoscentury);
523
524	if (cmoscentury != clockcentury) {
525		/* XXX note: saying "century is 20" might confuse the naive. */
526		printf("WARNING: NVRAM century is %d but RTC year is %d\n",
527		       cmoscentury, clockyear);
528
529		/* Kludge to roll over century. */
530		if ((rtc_update_century > 0) ||
531		    ((cmoscentury == 19) && (clockcentury == 20) &&
532		     (clockyear == 2000))) {
533			printf("WARNING: Setting NVRAM century to %d\n",
534			       clockcentury);
535			s = splclock();
536			mc146818_write(NULL, NVRAM_CENTURY,
537				       dectohexdec(clockcentury));
538			splx(s);
539		}
540	} else if (cmoscentury == 19 && rtc_update_century == 0)
541		rtc_update_century = 1; /* will update later in resettodr() */
542
543	return (clockyear);
544}
545
546/*
547 * Initialize the time of day register, based on the time base which is, e.g.
548 * from a filesystem.
549 */
550void
551inittodr(base)
552	time_t base;
553{
554	mc_todregs rtclk;
555	struct clock_ymdhms dt;
556	int s;
557
558	/*
559	 * We mostly ignore the suggested time and go for the RTC clock time
560	 * stored in the CMOS RAM.  If the time can't be obtained from the
561	 * CMOS, or if the time obtained from the CMOS is 5 or more years
562	 * less than the suggested time, we used the suggested time.  (In
563	 * the latter case, it's likely that the CMOS battery has died.)
564	 */
565
566	if (base < 15*SECYR) {	/* if before 1985, something's odd... */
567		printf("WARNING: preposterous time in file system\n");
568		/* read the system clock anyway */
569		base = 17*SECYR + 186*SECDAY + SECDAY/2;
570	}
571
572	time.tv_usec = 0;
573
574	s = splclock();
575	if (rtcget(&rtclk)) {
576		splx(s);
577		printf("WARNING: invalid time in clock chip\n");
578		goto fstime;
579	}
580	splx(s);
581
582	dt.dt_sec = hexdectodec(rtclk[MC_SEC]);
583	dt.dt_min = hexdectodec(rtclk[MC_MIN]);
584	dt.dt_hour = hexdectodec(rtclk[MC_HOUR]);
585	dt.dt_day = hexdectodec(rtclk[MC_DOM]);
586	dt.dt_mon = hexdectodec(rtclk[MC_MONTH]);
587	dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR]));
588
589
590	/*
591	 * If time_t is 32 bits, then the "End of Time" is
592	 * Mon Jan 18 22:14:07 2038 (US/Eastern)
593	 * This code copes with RTC's past the end of time if time_t
594	 * is an int32 or less. Needed because sometimes RTCs screw
595	 * up or are badly set, and that would cause the time to go
596	 * negative in the calculation below, which causes Very Bad
597	 * Mojo. This at least lets the user boot and fix the problem.
598	 * Note the code is self eliminating once time_t goes to 64 bits.
599	 */
600	if (sizeof(time_t) <= sizeof(int32_t)) {
601		if (dt.dt_year >= 2038) {
602			printf("WARNING: RTC time at or beyond 2038.\n");
603			dt.dt_year = 2037;
604			printf("WARNING: year set back to 2037.\n");
605			printf("WARNING: CHECK AND RESET THE DATE!\n");
606		}
607	}
608
609	time.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
610	if (tz.tz_dsttime)
611		time.tv_sec -= 3600;
612
613	if (base < time.tv_sec - 5*SECYR)
614		printf("WARNING: file system time much less than clock time\n");
615	else if (base > time.tv_sec + 5*SECYR) {
616		printf("WARNING: clock time much less than file system time\n");
617		printf("WARNING: using file system time\n");
618		goto fstime;
619	}
620
621	timeset = 1;
622	return;
623
624fstime:
625	timeset = 1;
626	time.tv_sec = base;
627	printf("WARNING: CHECK AND RESET THE DATE!\n");
628}
629
630/*
631 * Reset the clock.
632 */
633void
634resettodr()
635{
636	mc_todregs rtclk;
637	struct clock_ymdhms dt;
638	int diff;
639	int century;
640	int s;
641
642	/*
643	 * We might have been called by boot() due to a crash early
644	 * on.  Don't reset the clock chip in this case.
645	 */
646	if (!timeset)
647		return;
648
649	s = splclock();
650	if (rtcget(&rtclk))
651		bzero(&rtclk, sizeof(rtclk));
652	splx(s);
653
654	diff = tz.tz_minuteswest * 60;
655	if (tz.tz_dsttime)
656		diff -= 3600;
657	clock_secs_to_ymdhms(time.tv_sec - diff, &dt);
658
659	rtclk[MC_SEC] = dectohexdec(dt.dt_sec);
660	rtclk[MC_MIN] = dectohexdec(dt.dt_min);
661	rtclk[MC_HOUR] = dectohexdec(dt.dt_hour);
662	rtclk[MC_DOW] = dt.dt_wday;
663	rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100);
664	rtclk[MC_MONTH] = dectohexdec(dt.dt_mon);
665	rtclk[MC_DOM] = dectohexdec(dt.dt_day);
666	s = splclock();
667	rtcput(&rtclk);
668	if (rtc_update_century > 0) {
669		century = dectohexdec(dt.dt_year / 100);
670		mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */
671	}
672	splx(s);
673}
674
675void
676setstatclockrate(arg)
677	int arg;
678{
679	if (arg == stathz)
680		mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
681	else
682		mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
683}
684