Annotation of sys/arch/mvmeppc/dev/clock.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: clock.c,v 1.10 2004/12/24 22:50:30 miod Exp $ */
! 2: /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996 Wolfgang Solfrank.
! 6: * Copyright (C) 1995, 1996 TooLs GmbH.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by TooLs GmbH.
! 20: * 4. The name of TooLs GmbH may not be used to endorse or promote products
! 21: * derived from this software without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 27: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/systm.h>
! 38:
! 39: #include <machine/pio.h>
! 40: #include <machine/intr.h>
! 41: #include <machine/powerpc.h>
! 42:
! 43: #include "bugtty.h"
! 44:
! 45: void resettodr(void);
! 46: void decr_intr(struct clockframe *);
! 47: void calc_delayconst(void);
! 48:
! 49: /*
! 50: * Initially we assume a processor with a bus frequency of 12.5 MHz.
! 51: */
! 52: static u_long ticks_per_sec = 3125000;
! 53: static u_long ns_per_tick = 320;
! 54: static long ticks_per_intr;
! 55: static volatile u_long lasttb;
! 56:
! 57: /*
! 58: * BCD to decimal and decimal to BCD.
! 59: */
! 60: #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
! 61: #define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
! 62:
! 63: #define SECDAY (24 * 60 * 60)
! 64: #define SECYR (SECDAY * 365)
! 65: #define LEAPYEAR(y) (((y) & 3) == 0)
! 66: #define YEAR0 1900
! 67:
! 68: tps_t *tps;
! 69: clock_read_t *clock_read;
! 70: clock_write_t *clock_write;
! 71: time_read_t *time_read;
! 72: time_write_t *time_write;
! 73:
! 74: static u_int32_t chiptotime(int, int, int, int, int, int);
! 75:
! 76: /* event tracking variables, when the next event of each time should occur */
! 77: u_int64_t nexttimerevent, prevtb, nextstatevent;
! 78:
! 79: /* vars for stats */
! 80: int statint;
! 81: u_int32_t statvar;
! 82: u_int32_t statmin;
! 83:
! 84: struct chiptime {
! 85: int sec;
! 86: int min;
! 87: int hour;
! 88: int wday;
! 89: int day;
! 90: int mon;
! 91: int year;
! 92: };
! 93:
! 94: static void timetochip(struct chiptime *c);
! 95:
! 96: /*
! 97: * For now we let the machine run with boot time, not changing the clock
! 98: * at inittodr at all.
! 99: *
! 100: * We might continue to do this due to setting up the real wall clock with
! 101: * a user level utility in the future.
! 102: */
! 103:
! 104: /* ARGSUSED */
! 105: void
! 106: inittodr(time_t base)
! 107: {
! 108: int sec, min, hour, day, mon, year;
! 109:
! 110: int badbase = 0, waszero = base == 0;
! 111:
! 112: if (base < 5 * SECYR) {
! 113: /*
! 114: * If base is 0, assume filesystem time is just unknown
! 115: * instead of preposterous. Don't bark.
! 116: */
! 117: if (base != 0)
! 118: printf("WARNING: preposterous time in file system\n");
! 119: /* not going to use it anyway, if the chip is readable */
! 120: base = 21*SECYR + 186*SECDAY + SECDAY/2;
! 121: badbase = 1;
! 122: }
! 123:
! 124: if (clock_read != NULL ) {
! 125: (*clock_read)( &sec, &min, &hour, &day, &mon, &year);
! 126: time.tv_sec = chiptotime(sec, min, hour, day, mon, year);
! 127: } else if (time_read != NULL) {
! 128: u_int32_t cursec;
! 129: (*time_read)(&cursec);
! 130: time.tv_sec = cursec;
! 131: } else {
! 132: /* force failure */
! 133: time.tv_sec = 0;
! 134: }
! 135:
! 136: if (time.tv_sec == 0) {
! 137: printf("WARNING: unable to get date/time");
! 138: /*
! 139: * Believe the time in the file system for lack of
! 140: * anything better, resetting the clock.
! 141: */
! 142: time.tv_sec = base;
! 143: if (!badbase)
! 144: resettodr();
! 145: } else {
! 146: int deltat;
! 147:
! 148: time.tv_sec += tz.tz_minuteswest * 60;
! 149: if (tz.tz_dsttime)
! 150: time.tv_sec -= 3600;
! 151:
! 152: deltat = time.tv_sec - base;
! 153:
! 154: if (deltat < 0)
! 155: deltat = -deltat;
! 156: if (waszero || deltat < 2 * SECDAY)
! 157: return;
! 158: printf("WARNING: clock %s %d days",
! 159: time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
! 160:
! 161: if (time.tv_sec < base && deltat > 1000 * SECDAY) {
! 162: printf(", using FS time");
! 163: time.tv_sec = base;
! 164: }
! 165: }
! 166: printf(" -- CHECK AND RESET THE DATE!\n");
! 167: }
! 168:
! 169: /*
! 170: * This code is defunct after 2068.
! 171: * Will Unix still be here then??
! 172: */
! 173: const short dayyr[12] =
! 174: { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
! 175:
! 176: static u_int32_t
! 177: chiptotime(int sec, int min, int hour, int day, int mon, int year)
! 178: {
! 179: int days, yr;
! 180:
! 181: sec = FROMBCD(sec);
! 182: min = FROMBCD(min);
! 183: hour = FROMBCD(hour);
! 184: day = FROMBCD(day);
! 185: mon = FROMBCD(mon);
! 186: year = FROMBCD(year) + YEAR0;
! 187:
! 188: /* simple sanity checks */
! 189: if (year < 1970 || mon < 1 || mon > 12 || day < 1 || day > 31)
! 190: return (0);
! 191: days = 0;
! 192: for (yr = 1970; yr < year; yr++)
! 193: days += LEAPYEAR(yr) ? 366 : 365;
! 194: days += dayyr[mon - 1] + day - 1;
! 195: if (LEAPYEAR(yr) && mon > 2)
! 196: days++;
! 197: /* now have days since Jan 1, 1970; the rest is easy... */
! 198: return (days * SECDAY + hour * 3600 + min * 60 + sec);
! 199: }
! 200:
! 201: void
! 202: timetochip(struct chiptime *c)
! 203: {
! 204: int t, t2, t3, now = time.tv_sec;
! 205:
! 206: /* January 1 1970 was a Thursday (4 in unix wdays) */
! 207: /* compute the days since the epoch */
! 208: t2 = now / SECDAY;
! 209:
! 210: t3 = (t2 + 4) % 7; /* day of week */
! 211: c->wday = TOBCD(t3 + 1);
! 212:
! 213: /* compute the year */
! 214: t = 69;
! 215: while (t2 >= 0) { /* whittle off years */
! 216: t3 = t2;
! 217: t++;
! 218: t2 -= LEAPYEAR(t) ? 366 : 365;
! 219: }
! 220: c->year = t;
! 221:
! 222: /* t3 = month + day; separate */
! 223: t = LEAPYEAR(t);
! 224: for (t2 = 1; t2 < 12; t2++)
! 225: if (t3 < (dayyr[t2] + ((t && (t2 > 1)) ? 1:0)))
! 226: break;
! 227:
! 228: /* t2 is month */
! 229: c->mon = t2;
! 230: c->day = t3 - dayyr[t2 - 1] + 1;
! 231: if (t && t2 > 2)
! 232: c->day--;
! 233:
! 234: /* the rest is easy */
! 235: t = now % SECDAY;
! 236: c->hour = t / 3600;
! 237: t %= 3600;
! 238: c->min = t / 60;
! 239: c->sec = t % 60;
! 240:
! 241: c->sec = TOBCD(c->sec);
! 242: c->min = TOBCD(c->min);
! 243: c->hour = TOBCD(c->hour);
! 244: c->day = TOBCD(c->day);
! 245: c->mon = TOBCD(c->mon);
! 246: c->year = TOBCD((c->year - YEAR0) % 100);
! 247: }
! 248:
! 249:
! 250: /*
! 251: * Similar to the above
! 252: */
! 253: void
! 254: resettodr()
! 255: {
! 256: struct timeval curtime = time;
! 257: if (clock_write != NULL) {
! 258: struct chiptime c;
! 259: timetochip(&c);
! 260: (*clock_write)(c.sec, c.min, c.hour, c.day, c.mon, c.year);
! 261: } else if (time_write != NULL) {
! 262: curtime.tv_sec -= tz.tz_minuteswest * 60;
! 263: if (tz.tz_dsttime) {
! 264: curtime.tv_sec += 3600;
! 265: }
! 266: (*time_write)(curtime.tv_sec);
! 267: }
! 268: }
! 269:
! 270: volatile int statspending;
! 271:
! 272: void
! 273: decr_intr(struct clockframe *frame)
! 274: {
! 275: u_int64_t tb;
! 276: u_int64_t nextevent;
! 277: int nstats;
! 278: int s;
! 279:
! 280: /*
! 281: * Check whether we are initialized.
! 282: */
! 283: if (!ticks_per_intr)
! 284: return;
! 285:
! 286: /*
! 287: * Based on the actual time delay since the last decrementer reload,
! 288: * we arrange for earlier interrupt next time.
! 289: */
! 290:
! 291: tb = ppc_mftb();
! 292: while (nexttimerevent <= tb)
! 293: nexttimerevent += ticks_per_intr;
! 294:
! 295: prevtb = nexttimerevent - ticks_per_intr;
! 296:
! 297: for (nstats = 0; nextstatevent <= tb; nstats++) {
! 298: int r;
! 299: do {
! 300: r = random() & (statvar - 1);
! 301: } while (r == 0); /* random == 0 not allowed */
! 302: nextstatevent += statmin + r;
! 303: }
! 304:
! 305: if (nexttimerevent < nextstatevent)
! 306: nextevent = nexttimerevent;
! 307: else
! 308: nextevent = nextstatevent;
! 309:
! 310: /*
! 311: * Need to work about the near constant skew this introduces???
! 312: * reloading tb here could cause a missed tick.
! 313: */
! 314: ppc_mtdec(nextevent - tb);
! 315:
! 316: if (cpl & SPL_CLOCK) {
! 317: statspending += nstats;
! 318: } else {
! 319: nstats += statspending;
! 320: statspending = 0;
! 321:
! 322: s = splclock();
! 323:
! 324: /*
! 325: * Reenable interrupts
! 326: */
! 327: ppc_intr_enable(1);
! 328:
! 329: /*
! 330: * Do standard timer interrupt stuff.
! 331: * Do softclock stuff only on the last iteration.
! 332: */
! 333: frame->pri = s | SINT_CLOCK;
! 334: while (lasttb < prevtb - ticks_per_intr) {
! 335: /* sync lasttb with hardclock */
! 336: lasttb += ticks_per_intr;
! 337: hardclock(frame);
! 338: }
! 339:
! 340: frame->pri = s;
! 341: while (lasttb < prevtb) {
! 342: /* sync lasttb with hardclock */
! 343: lasttb += ticks_per_intr;
! 344: hardclock(frame);
! 345: #if NBUGTTY > 0
! 346: {
! 347: extern void bugtty_chkinput(void);
! 348: bugtty_chkinput();
! 349: }
! 350: #endif
! 351: }
! 352:
! 353: while (nstats-- > 0)
! 354: statclock(frame);
! 355:
! 356: splx(s);
! 357: ppc_intr_disable();
! 358:
! 359: /*
! 360: * If a tick has occurred while dealing with these,
! 361: * don't service it now, delay until the next tick.
! 362: */
! 363: }
! 364: }
! 365:
! 366: void
! 367: cpu_initclocks()
! 368: {
! 369: int intrstate;
! 370: int r;
! 371: int minint;
! 372: u_int64_t nextevent;
! 373:
! 374: intrstate = ppc_intr_disable();
! 375:
! 376: stathz = 100;
! 377: profhz = 1000; /* must be a multiple of stathz */
! 378:
! 379: /* init secondary clock to stathz */
! 380: statint = ticks_per_sec / stathz;
! 381: statvar = 0x40000000; /* really big power of two */
! 382: /* find largest 2^n which is nearly smaller than statint/2 */
! 383: minint = statint / 2 + 100;
! 384: while (statvar > minint)
! 385: statvar >>= 1;
! 386:
! 387: statmin = statint - (statvar >> 1);
! 388:
! 389: lasttb = ppc_mftb();
! 390: nexttimerevent = lasttb + ticks_per_intr;
! 391: do {
! 392: r = random() & (statvar - 1);
! 393: } while (r == 0); /* random == 0 not allowed */
! 394: nextstatevent = lasttb + statmin + r;
! 395:
! 396: if (nexttimerevent < nextstatevent)
! 397: nextevent = nexttimerevent;
! 398: else
! 399: nextevent = nextstatevent;
! 400:
! 401: ppc_mtdec(nextevent - lasttb);
! 402: ppc_intr_enable(intrstate);
! 403: }
! 404:
! 405: void
! 406: calc_delayconst(void)
! 407: {
! 408: int s;
! 409:
! 410: ticks_per_sec = (*tps)();
! 411: s = ppc_intr_disable();
! 412: ns_per_tick = 1000000000 / ticks_per_sec;
! 413: ticks_per_intr = ticks_per_sec / hz;
! 414: ppc_intr_enable(s);
! 415: }
! 416:
! 417: /*
! 418: * Fill in *tvp with current time with microsecond resolution.
! 419: */
! 420: void
! 421: microtime(struct timeval *tvp)
! 422: {
! 423: u_int64_t tb;
! 424: u_int32_t ticks;
! 425: int s;
! 426:
! 427: s = ppc_intr_disable();
! 428: tb = ppc_mftb();
! 429: ticks = ((tb - lasttb) * ns_per_tick) / 1000;
! 430: *tvp = time;
! 431: ppc_intr_enable(s);
! 432: tvp->tv_usec += ticks;
! 433: while (tvp->tv_usec >= 1000000) {
! 434: tvp->tv_usec -= 1000000;
! 435: tvp->tv_sec++;
! 436: }
! 437: }
! 438:
! 439: /*
! 440: * Wait for about n microseconds (us) (at least!).
! 441: */
! 442: void
! 443: delay(unsigned n)
! 444: {
! 445: u_int64_t tb;
! 446: u_int32_t tbh, tbl, scratch;
! 447:
! 448: tb = ppc_mftb();
! 449: tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
! 450: tbh = tb >> 32;
! 451: tbl = (u_int32_t)tb;
! 452: asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;"
! 453: " mftb %0; cmplw %0,%2; blt 1b; 2:"
! 454: :: "r"(scratch), "r"(tbh), "r"(tbl));
! 455: }
! 456:
! 457: void
! 458: setstatclockrate(int newhz)
! 459: {
! 460: int minint;
! 461: int intrstate;
! 462:
! 463: intrstate = ppc_intr_disable();
! 464:
! 465: statint = ticks_per_sec / newhz;
! 466: statvar = 0x40000000; /* really big power of two */
! 467: /* find largest 2^n which is nearly smaller than statint/2 */
! 468: minint = statint / 2 + 100;
! 469: while (statvar > minint)
! 470: statvar >>= 1;
! 471:
! 472: statmin = statint - (statvar >> 1);
! 473: ppc_intr_enable(intrstate);
! 474:
! 475: /*
! 476: * XXX this allows the next stat timer to occur then it switches
! 477: * to the new frequency. Rather than switching instantly.
! 478: */
! 479: }
CVSweb