152118Smckusick /*
252118Smckusick * Copyright (c) 1988 University of Utah.
363218Sbostic * Copyright (c) 1992, 1993
463218Sbostic * 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*67799Smckusick * @(#)clock.c 8.2 (Berkeley) 10/09/94
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 */
cpu_initclocks()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
setstatclockrate(newhz)6156229Sralph setstatclockrate(newhz)
6256229Sralph int newhz;
6356229Sralph {
6456229Sralph }
6556229Sralph
6656229Sralph /*
67*67799Smckusick * This is the amount to add to the value stored in the clock chip
68*67799Smckusick * to get the current year.
69*67799Smckusick */
70*67799Smckusick #define YR_OFFSET 22
71*67799Smckusick
72*67799Smckusick /*
7352118Smckusick * This code is defunct after 2099.
7452118Smckusick * Will Unix still be here then??
7552118Smckusick */
7652118Smckusick static short dayyr[12] = {
7752118Smckusick 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
7852118Smckusick };
7952118Smckusick
8052118Smckusick /*
8152118Smckusick * Initialze the time of day register, based on the time base which is, e.g.
8252118Smckusick * from a filesystem. Base provides the time to within six months,
8352118Smckusick * and the time of year clock (if any) provides the rest.
8452118Smckusick */
8553204Sralph void
inittodr(base)8652118Smckusick inittodr(base)
8752118Smckusick time_t base;
8852118Smckusick {
8952118Smckusick register volatile struct chiptime *c;
9052118Smckusick register int days, yr;
9152118Smckusick int sec, min, hour, day, mon, year;
9253204Sralph long deltat;
9353204Sralph int badbase, s;
9452118Smckusick
9552118Smckusick if (base < 5*SECYR) {
9653204Sralph printf("WARNING: preposterous time in file system");
9752118Smckusick /* read the system clock anyway */
9852118Smckusick base = 6*SECYR + 186*SECDAY + SECDAY/2;
9952118Smckusick badbase = 1;
10053204Sralph } else
10153204Sralph badbase = 0;
10252118Smckusick
10356828Sralph c = Mach_clock_addr;
10452118Smckusick /* don't read clock registers while they are being updated */
10552699Sralph s = splclock();
10652118Smckusick while ((c->rega & REGA_UIP) == 1)
10752118Smckusick ;
10852118Smckusick sec = c->sec;
10952118Smckusick min = c->min;
11052118Smckusick hour = c->hour;
11152118Smckusick day = c->day;
11252118Smckusick mon = c->mon;
113*67799Smckusick year = c->year + YR_OFFSET;
11452118Smckusick splx(s);
11552699Sralph
11652118Smckusick /* simple sanity checks */
11752118Smckusick if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
11852118Smckusick hour > 23 || min > 59 || sec > 59) {
11952118Smckusick /*
12052118Smckusick * Believe the time in the file system for lack of
12152118Smckusick * anything better, resetting the TODR.
12252118Smckusick */
12352118Smckusick time.tv_sec = base;
12453204Sralph if (!badbase) {
125*67799Smckusick printf("WARNING: preposterous clock chip time");
12652118Smckusick resettodr();
12753204Sralph }
12853204Sralph goto bad;
12952118Smckusick }
13052118Smckusick days = 0;
13152118Smckusick for (yr = 70; yr < year; yr++)
13252118Smckusick days += LEAPYEAR(yr) ? 366 : 365;
13352118Smckusick days += dayyr[mon - 1] + day - 1;
13452118Smckusick if (LEAPYEAR(yr) && mon > 2)
13552118Smckusick days++;
13652118Smckusick /* now have days since Jan 1, 1970; the rest is easy... */
13752118Smckusick time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
13852118Smckusick
13952118Smckusick if (!badbase) {
14052118Smckusick /*
14152118Smckusick * See if we gained/lost two or more days;
14252118Smckusick * if so, assume something is amiss.
14352118Smckusick */
14452118Smckusick deltat = time.tv_sec - base;
14552118Smckusick if (deltat < 0)
14652118Smckusick deltat = -deltat;
14752118Smckusick if (deltat < 2 * SECDAY)
14852118Smckusick return;
14952118Smckusick printf("WARNING: clock %s %d days",
15052118Smckusick time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
15152118Smckusick }
15253204Sralph bad:
15352118Smckusick printf(" -- CHECK AND RESET THE DATE!\n");
15452118Smckusick }
15552118Smckusick
15652118Smckusick /*
15752118Smckusick * Reset the TODR based on the time value; used when the TODR
15852118Smckusick * has a preposterous value and also when the time is reset
15952118Smckusick * by the stime system call. Also called when the TODR goes past
16052118Smckusick * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
16152118Smckusick * to wrap the TODR around.
16252118Smckusick */
resettodr()16352118Smckusick resettodr()
16452118Smckusick {
16552118Smckusick register volatile struct chiptime *c;
16653204Sralph register int t, t2;
16753204Sralph int sec, min, hour, day, mon, year;
16852699Sralph int s;
16952118Smckusick
17052118Smckusick /* compute the year */
17152118Smckusick t2 = time.tv_sec / SECDAY;
17253204Sralph year = 69;
17352118Smckusick while (t2 >= 0) { /* whittle off years */
17453204Sralph t = t2;
17553204Sralph year++;
17653204Sralph t2 -= LEAPYEAR(year) ? 366 : 365;
17752118Smckusick }
17852699Sralph
17953204Sralph /* t = month + day; separate */
18053204Sralph t2 = LEAPYEAR(year);
18153204Sralph for (mon = 1; mon < 12; mon++)
18253204Sralph if (t < dayyr[mon] + (t2 && mon > 1))
18352118Smckusick break;
18452118Smckusick
18553204Sralph day = t - dayyr[mon - 1] + 1;
18653204Sralph if (t2 && mon > 2)
18753204Sralph day--;
18852118Smckusick
18952118Smckusick /* the rest is easy */
19052118Smckusick t = time.tv_sec % SECDAY;
19153204Sralph hour = t / 3600;
19252118Smckusick t %= 3600;
19353204Sralph min = t / 60;
19453204Sralph sec = t % 60;
19553204Sralph
19656828Sralph c = Mach_clock_addr;
19753204Sralph s = splclock();
19853204Sralph t = c->regb;
19953204Sralph c->regb = t | REGB_SET_TIME;
20052699Sralph MachEmptyWriteBuffer();
20153204Sralph c->sec = sec;
20253204Sralph c->min = min;
20353204Sralph c->hour = hour;
20453204Sralph c->day = day;
20553204Sralph c->mon = mon;
206*67799Smckusick c->year = year - YR_OFFSET;
20753204Sralph c->regb = t;
20853204Sralph MachEmptyWriteBuffer();
20952699Sralph splx(s);
21052118Smckusick }
211