xref: /csrg-svn/sys/pmax/pmax/clock.c (revision 63218)
152118Smckusick /*
252118Smckusick  * Copyright (c) 1988 University of Utah.
3*63218Sbostic  * Copyright (c) 1992, 1993
4*63218Sbostic  *	The Regents of the University of California.  All rights reserved.
552118Smckusick  *
652118Smckusick  * This code is derived from software contributed to Berkeley by
752118Smckusick  * the Systems Programming Group of the University of Utah Computer
852118Smckusick  * Science Department and Ralph Campbell.
952118Smckusick  *
1052118Smckusick  * %sccs.include.redist.c%
1152118Smckusick  *
1252118Smckusick  * from: Utah $Hdr: clock.c 1.18 91/01/21$
1352118Smckusick  *
14*63218Sbostic  *	@(#)clock.c	8.1 (Berkeley) 06/10/93
1552118Smckusick  */
1652118Smckusick 
1756524Sbostic #include <sys/param.h>
1856524Sbostic #include <sys/kernel.h>
1952118Smckusick 
2056524Sbostic #include <machine/machConst.h>
2156524Sbostic #include <pmax/pmax/clockreg.h>
2252118Smckusick 
2352118Smckusick /*
2452118Smckusick  * Machine-dependent clock routines.
2552118Smckusick  *
2652118Smckusick  * Startrtclock restarts the real-time clock, which provides
2752118Smckusick  * hardclock interrupts to kern_clock.c.
2852118Smckusick  *
2952118Smckusick  * Inittodr initializes the time of day hardware which provides
3052118Smckusick  * date functions.  Its primary function is to use some file
3152118Smckusick  * system information in case the hardare clock lost state.
3252118Smckusick  *
3352118Smckusick  * Resettodr restores the time of day hardware after a time change.
3452118Smckusick  */
3552118Smckusick 
3656828Sralph volatile struct chiptime *Mach_clock_addr;
3756828Sralph 
3852118Smckusick /*
3956229Sralph  * Start the real-time and statistics clocks. Leave stathz 0 since there
4056229Sralph  * are no other timers available.
4152118Smckusick  */
4256229Sralph cpu_initclocks()
4352118Smckusick {
4452118Smckusick 	register volatile struct chiptime *c;
4552118Smckusick 	extern int tickadj;
4652118Smckusick 
4752118Smckusick 	tick = 15625;		/* number of micro-seconds between interrupts */
4853204Sralph 	hz = 1000000 / 15625;	/* 64 Hz */
4952118Smckusick 	tickadj = 240000 / (60000000 / 15625);
5056828Sralph 	c = Mach_clock_addr;
5152118Smckusick 	c->rega = REGA_TIME_BASE | SELECTED_RATE;
5252118Smckusick 	c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
5352118Smckusick }
5452118Smckusick 
5552118Smckusick /*
5656229Sralph  * We assume newhz is either stathz or profhz, and that neither will
5756229Sralph  * change after being set up above.  Could recalculate intervals here
5856229Sralph  * but that would be a drag.
5956229Sralph  */
6056229Sralph void
6156229Sralph setstatclockrate(newhz)
6256229Sralph 	int newhz;
6356229Sralph {
6456229Sralph }
6556229Sralph 
6656229Sralph /*
6752118Smckusick  * This code is defunct after 2099.
6852118Smckusick  * Will Unix still be here then??
6952118Smckusick  */
7052118Smckusick static short dayyr[12] = {
7152118Smckusick 	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
7252118Smckusick };
7352118Smckusick 
7452118Smckusick /*
7552118Smckusick  * Initialze the time of day register, based on the time base which is, e.g.
7652118Smckusick  * from a filesystem.  Base provides the time to within six months,
7752118Smckusick  * and the time of year clock (if any) provides the rest.
7852118Smckusick  */
7953204Sralph void
8052118Smckusick inittodr(base)
8152118Smckusick 	time_t base;
8252118Smckusick {
8352118Smckusick 	register volatile struct chiptime *c;
8452118Smckusick 	register int days, yr;
8552118Smckusick 	int sec, min, hour, day, mon, year;
8653204Sralph 	long deltat;
8753204Sralph 	int badbase, s;
8852118Smckusick 
8952118Smckusick 	if (base < 5*SECYR) {
9053204Sralph 		printf("WARNING: preposterous time in file system");
9152118Smckusick 		/* read the system clock anyway */
9252118Smckusick 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
9352118Smckusick 		badbase = 1;
9453204Sralph 	} else
9553204Sralph 		badbase = 0;
9652118Smckusick 
9756828Sralph 	c = Mach_clock_addr;
9852118Smckusick 	/* don't read clock registers while they are being updated */
9952699Sralph 	s = splclock();
10052118Smckusick 	while ((c->rega & REGA_UIP) == 1)
10152118Smckusick 		;
10252118Smckusick 	sec = c->sec;
10352118Smckusick 	min = c->min;
10452118Smckusick 	hour = c->hour;
10552118Smckusick 	day = c->day;
10652118Smckusick 	mon = c->mon;
10753204Sralph 	year = c->year + 20; /* must be multiple of 4 because chip knows leap */
10852118Smckusick 	splx(s);
10952699Sralph 
11052118Smckusick 	/* simple sanity checks */
11152118Smckusick 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
11252118Smckusick 	    hour > 23 || min > 59 || sec > 59) {
11352118Smckusick 		/*
11452118Smckusick 		 * Believe the time in the file system for lack of
11552118Smckusick 		 * anything better, resetting the TODR.
11652118Smckusick 		 */
11752118Smckusick 		time.tv_sec = base;
11853204Sralph 		if (!badbase) {
11953204Sralph 			printf("WARNING: preposterous clock chip time\n");
12052118Smckusick 			resettodr();
12153204Sralph 		}
12253204Sralph 		goto bad;
12352118Smckusick 	}
12452118Smckusick 	days = 0;
12552118Smckusick 	for (yr = 70; yr < year; yr++)
12652118Smckusick 		days += LEAPYEAR(yr) ? 366 : 365;
12752118Smckusick 	days += dayyr[mon - 1] + day - 1;
12852118Smckusick 	if (LEAPYEAR(yr) && mon > 2)
12952118Smckusick 		days++;
13052118Smckusick 	/* now have days since Jan 1, 1970; the rest is easy... */
13152118Smckusick 	time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
13252118Smckusick 
13352118Smckusick 	if (!badbase) {
13452118Smckusick 		/*
13552118Smckusick 		 * See if we gained/lost two or more days;
13652118Smckusick 		 * if so, assume something is amiss.
13752118Smckusick 		 */
13852118Smckusick 		deltat = time.tv_sec - base;
13952118Smckusick 		if (deltat < 0)
14052118Smckusick 			deltat = -deltat;
14152118Smckusick 		if (deltat < 2 * SECDAY)
14252118Smckusick 			return;
14352118Smckusick 		printf("WARNING: clock %s %d days",
14452118Smckusick 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
14552118Smckusick 	}
14653204Sralph bad:
14752118Smckusick 	printf(" -- CHECK AND RESET THE DATE!\n");
14852118Smckusick }
14952118Smckusick 
15052118Smckusick /*
15152118Smckusick  * Reset the TODR based on the time value; used when the TODR
15252118Smckusick  * has a preposterous value and also when the time is reset
15352118Smckusick  * by the stime system call.  Also called when the TODR goes past
15452118Smckusick  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
15552118Smckusick  * to wrap the TODR around.
15652118Smckusick  */
15752118Smckusick resettodr()
15852118Smckusick {
15952118Smckusick 	register volatile struct chiptime *c;
16053204Sralph 	register int t, t2;
16153204Sralph 	int sec, min, hour, day, mon, year;
16252699Sralph 	int s;
16352118Smckusick 
16452118Smckusick 	/* compute the year */
16552118Smckusick 	t2 = time.tv_sec / SECDAY;
16653204Sralph 	year = 69;
16752118Smckusick 	while (t2 >= 0) {	/* whittle off years */
16853204Sralph 		t = t2;
16953204Sralph 		year++;
17053204Sralph 		t2 -= LEAPYEAR(year) ? 366 : 365;
17152118Smckusick 	}
17252699Sralph 
17353204Sralph 	/* t = month + day; separate */
17453204Sralph 	t2 = LEAPYEAR(year);
17553204Sralph 	for (mon = 1; mon < 12; mon++)
17653204Sralph 		if (t < dayyr[mon] + (t2 && mon > 1))
17752118Smckusick 			break;
17852118Smckusick 
17953204Sralph 	day = t - dayyr[mon - 1] + 1;
18053204Sralph 	if (t2 && mon > 2)
18153204Sralph 		day--;
18252118Smckusick 
18352118Smckusick 	/* the rest is easy */
18452118Smckusick 	t = time.tv_sec % SECDAY;
18553204Sralph 	hour = t / 3600;
18652118Smckusick 	t %= 3600;
18753204Sralph 	min = t / 60;
18853204Sralph 	sec = t % 60;
18953204Sralph 
19056828Sralph 	c = Mach_clock_addr;
19153204Sralph 	s = splclock();
19253204Sralph 	t = c->regb;
19353204Sralph 	c->regb = t | REGB_SET_TIME;
19452699Sralph 	MachEmptyWriteBuffer();
19553204Sralph 	c->sec = sec;
19653204Sralph 	c->min = min;
19753204Sralph 	c->hour = hour;
19853204Sralph 	c->day = day;
19953204Sralph 	c->mon = mon;
20053204Sralph 	c->year = year - 20; /* must be multiple of 4 because chip knows leap */
20153204Sralph 	c->regb = t;
20253204Sralph 	MachEmptyWriteBuffer();
20352699Sralph 	splx(s);
20452118Smckusick }
205