xref: /original-bsd/sys/pmax/pmax/clock.c (revision 948d00a2)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department and Ralph Campbell.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: clock.c 1.18 91/01/21$
13  *
14  *	@(#)clock.c	8.2 (Berkeley) 10/09/94
15  */
16 
17 #include <sys/param.h>
18 #include <sys/kernel.h>
19 
20 #include <machine/machConst.h>
21 #include <pmax/pmax/clockreg.h>
22 
23 /*
24  * Machine-dependent clock routines.
25  *
26  * Startrtclock restarts the real-time clock, which provides
27  * hardclock interrupts to kern_clock.c.
28  *
29  * Inittodr initializes the time of day hardware which provides
30  * date functions.  Its primary function is to use some file
31  * system information in case the hardare clock lost state.
32  *
33  * Resettodr restores the time of day hardware after a time change.
34  */
35 
36 volatile struct chiptime *Mach_clock_addr;
37 
38 /*
39  * Start the real-time and statistics clocks. Leave stathz 0 since there
40  * are no other timers available.
41  */
42 cpu_initclocks()
43 {
44 	register volatile struct chiptime *c;
45 	extern int tickadj;
46 
47 	tick = 15625;		/* number of micro-seconds between interrupts */
48 	hz = 1000000 / 15625;	/* 64 Hz */
49 	tickadj = 240000 / (60000000 / 15625);
50 	c = Mach_clock_addr;
51 	c->rega = REGA_TIME_BASE | SELECTED_RATE;
52 	c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
53 }
54 
55 /*
56  * We assume newhz is either stathz or profhz, and that neither will
57  * change after being set up above.  Could recalculate intervals here
58  * but that would be a drag.
59  */
60 void
61 setstatclockrate(newhz)
62 	int newhz;
63 {
64 }
65 
66 /*
67  * This is the amount to add to the value stored in the clock chip
68  * to get the current year.
69  */
70 #define YR_OFFSET	22
71 
72 /*
73  * This code is defunct after 2099.
74  * Will Unix still be here then??
75  */
76 static short dayyr[12] = {
77 	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
78 };
79 
80 /*
81  * Initialze the time of day register, based on the time base which is, e.g.
82  * from a filesystem.  Base provides the time to within six months,
83  * and the time of year clock (if any) provides the rest.
84  */
85 void
86 inittodr(base)
87 	time_t base;
88 {
89 	register volatile struct chiptime *c;
90 	register int days, yr;
91 	int sec, min, hour, day, mon, year;
92 	long deltat;
93 	int badbase, s;
94 
95 	if (base < 5*SECYR) {
96 		printf("WARNING: preposterous time in file system");
97 		/* read the system clock anyway */
98 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
99 		badbase = 1;
100 	} else
101 		badbase = 0;
102 
103 	c = Mach_clock_addr;
104 	/* don't read clock registers while they are being updated */
105 	s = splclock();
106 	while ((c->rega & REGA_UIP) == 1)
107 		;
108 	sec = c->sec;
109 	min = c->min;
110 	hour = c->hour;
111 	day = c->day;
112 	mon = c->mon;
113 	year = c->year + YR_OFFSET;
114 	splx(s);
115 
116 	/* simple sanity checks */
117 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
118 	    hour > 23 || min > 59 || sec > 59) {
119 		/*
120 		 * Believe the time in the file system for lack of
121 		 * anything better, resetting the TODR.
122 		 */
123 		time.tv_sec = base;
124 		if (!badbase) {
125 			printf("WARNING: preposterous clock chip time");
126 			resettodr();
127 		}
128 		goto bad;
129 	}
130 	days = 0;
131 	for (yr = 70; yr < year; yr++)
132 		days += LEAPYEAR(yr) ? 366 : 365;
133 	days += dayyr[mon - 1] + day - 1;
134 	if (LEAPYEAR(yr) && mon > 2)
135 		days++;
136 	/* now have days since Jan 1, 1970; the rest is easy... */
137 	time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
138 
139 	if (!badbase) {
140 		/*
141 		 * See if we gained/lost two or more days;
142 		 * if so, assume something is amiss.
143 		 */
144 		deltat = time.tv_sec - base;
145 		if (deltat < 0)
146 			deltat = -deltat;
147 		if (deltat < 2 * SECDAY)
148 			return;
149 		printf("WARNING: clock %s %d days",
150 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
151 	}
152 bad:
153 	printf(" -- CHECK AND RESET THE DATE!\n");
154 }
155 
156 /*
157  * Reset the TODR based on the time value; used when the TODR
158  * has a preposterous value and also when the time is reset
159  * by the stime system call.  Also called when the TODR goes past
160  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
161  * to wrap the TODR around.
162  */
163 resettodr()
164 {
165 	register volatile struct chiptime *c;
166 	register int t, t2;
167 	int sec, min, hour, day, mon, year;
168 	int s;
169 
170 	/* compute the year */
171 	t2 = time.tv_sec / SECDAY;
172 	year = 69;
173 	while (t2 >= 0) {	/* whittle off years */
174 		t = t2;
175 		year++;
176 		t2 -= LEAPYEAR(year) ? 366 : 365;
177 	}
178 
179 	/* t = month + day; separate */
180 	t2 = LEAPYEAR(year);
181 	for (mon = 1; mon < 12; mon++)
182 		if (t < dayyr[mon] + (t2 && mon > 1))
183 			break;
184 
185 	day = t - dayyr[mon - 1] + 1;
186 	if (t2 && mon > 2)
187 		day--;
188 
189 	/* the rest is easy */
190 	t = time.tv_sec % SECDAY;
191 	hour = t / 3600;
192 	t %= 3600;
193 	min = t / 60;
194 	sec = t % 60;
195 
196 	c = Mach_clock_addr;
197 	s = splclock();
198 	t = c->regb;
199 	c->regb = t | REGB_SET_TIME;
200 	MachEmptyWriteBuffer();
201 	c->sec = sec;
202 	c->min = min;
203 	c->hour = hour;
204 	c->day = day;
205 	c->mon = mon;
206 	c->year = year - YR_OFFSET;
207 	c->regb = t;
208 	MachEmptyWriteBuffer();
209 	splx(s);
210 }
211