Annotation of sys/arch/mips64/mips64/clock.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: clock.c,v 1.18 2007/04/29 17:35:27 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
! 19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: *
! 27: */
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/kernel.h>
! 31: #include <sys/systm.h>
! 32: #include <sys/device.h>
! 33: #include <sys/evcount.h>
! 34: #include <sys/timetc.h>
! 35:
! 36: #include <machine/autoconf.h>
! 37: #include <machine/cpu.h>
! 38: #include <mips64/dev/clockvar.h>
! 39: #include <mips64/archtype.h>
! 40:
! 41: static struct evcount clk_count;
! 42: static int clk_irq = 5;
! 43:
! 44: /* Definition of the driver for autoconfig. */
! 45: int clockmatch(struct device *, void *, void *);
! 46: void clockattach(struct device *, struct device *, void *);
! 47: intrmask_t clock_int5_dummy(intrmask_t, struct trap_frame *);
! 48: intrmask_t clock_int5(intrmask_t, struct trap_frame *);
! 49: void clock_int5_init(struct clock_softc *);
! 50:
! 51: struct cfdriver clock_cd = {
! 52: NULL, "clock", DV_DULL, NULL, 0
! 53: };
! 54:
! 55: struct cfattach clock_ca = {
! 56: sizeof(struct clock_softc), clockmatch, clockattach
! 57: };
! 58:
! 59: int clock_started = 0;
! 60: u_int32_t cpu_counter_last;
! 61: u_int32_t cpu_counter_interval;
! 62: u_int32_t pendingticks;
! 63: u_int32_t ticktime;
! 64:
! 65: u_int cp0_get_timecount(struct timecounter *);
! 66:
! 67: struct timecounter cp0_timecounter = {
! 68: cp0_get_timecount, /* get_timecount */
! 69: 0, /* no poll_pps */
! 70: 0xffffffff, /* counter_mask */
! 71: 0, /* frequency */
! 72: "CP0", /* name */
! 73: 0 /* quality */
! 74: };
! 75:
! 76: #define SECMIN (60) /* seconds per minute */
! 77: #define SECHOUR (60*SECMIN) /* seconds per hour */
! 78:
! 79: #define YEARDAYS(year) (((((year) + 1900) % 4) == 0 && \
! 80: ((((year) + 1900) % 100) != 0 || \
! 81: (((year) + 1900) % 400) == 0)) ? 366 : 365)
! 82:
! 83: int
! 84: clockmatch(struct device *parent, void *cfdata, void *aux)
! 85: {
! 86: struct confargs *ca = aux;
! 87: struct cfdata *cf = cfdata;
! 88:
! 89: /* Make sure that we're looking for a clock. */
! 90: if (strcmp(ca->ca_name, clock_cd.cd_name) != 0)
! 91: return (0);
! 92:
! 93: if (cf->cf_unit >= 1)
! 94: return 0;
! 95: return 10; /* Try to get clock early */
! 96: }
! 97:
! 98: void
! 99: clockattach(struct device *parent, struct device *self, void *aux)
! 100: {
! 101: struct clock_softc *sc;
! 102:
! 103: md_clk_attach(parent, self, aux);
! 104: sc = (struct clock_softc *)self;
! 105:
! 106: switch (sys_config.system_type) {
! 107: case ALGOR_P4032:
! 108: case ALGOR_P5064:
! 109: case MOMENTUM_CP7000:
! 110: case MOMENTUM_CP7000G:
! 111: case MOMENTUM_JAGUAR:
! 112: case GALILEO_EV64240:
! 113: case SGI_INDY:
! 114: case SGI_O2:
! 115: case SGI_O200:
! 116: printf(" ticker on int5 using count register");
! 117: set_intr(INTPRI_CLOCK, CR_INT_5, clock_int5);
! 118: ticktime = sys_config.cpu[0].clock / 2000;
! 119: break;
! 120:
! 121: default:
! 122: panic("clockattach: it didn't get here. really.");
! 123: }
! 124:
! 125: printf("\n");
! 126: }
! 127:
! 128: /*
! 129: * Clock interrupt code for machines using the on cpu chip
! 130: * counter register. This register counts at half the pipeline
! 131: * frequency so the frequency must be known and the options
! 132: * register wired to allow it's use.
! 133: *
! 134: * The code is enabled by setting 'cpu_counter_interval'.
! 135: */
! 136: void
! 137: clock_int5_init(struct clock_softc *sc)
! 138: {
! 139: int s;
! 140:
! 141: s = splclock();
! 142: cpu_counter_interval = sys_config.cpu[0].clock / (hz * 2);
! 143: cpu_counter_last = cp0_get_count() + cpu_counter_interval * 4;
! 144: cp0_set_compare(cpu_counter_last);
! 145: splx(s);
! 146: }
! 147:
! 148: /*
! 149: * Dummy count register interrupt handler used on some targets.
! 150: * Just resets the compare register and acknowledge the interrupt.
! 151: */
! 152: intrmask_t
! 153: clock_int5_dummy(intrmask_t mask, struct trap_frame *tf)
! 154: {
! 155: cp0_set_compare(0); /* Shut up counter int's for a while */
! 156: return CR_INT_5; /* Clock is always on 5 */
! 157: }
! 158:
! 159: /*
! 160: * Interrupt handler for targets using the internal count register
! 161: * as interval clock. Normally the system is run with the clock
! 162: * interrupt always enabled. Masking is done here and if the clock
! 163: * can not be run the tick is just counted and handled later when
! 164: * the clock is unmasked again.
! 165: */
! 166: intrmask_t
! 167: clock_int5(intrmask_t mask, struct trap_frame *tf)
! 168: {
! 169: u_int32_t clkdiff;
! 170:
! 171: /*
! 172: * If clock is started count the tick, else just arm for a new.
! 173: */
! 174: if (clock_started && cpu_counter_interval != 0) {
! 175: clkdiff = cp0_get_count() - cpu_counter_last;
! 176: while (clkdiff >= cpu_counter_interval) {
! 177: cpu_counter_last += cpu_counter_interval;
! 178: clkdiff = cp0_get_count() - cpu_counter_last;
! 179: pendingticks++;
! 180: }
! 181: cpu_counter_last += cpu_counter_interval;
! 182: pendingticks++;
! 183: } else {
! 184: cpu_counter_last = cpu_counter_interval + cp0_get_count();
! 185: }
! 186:
! 187: cp0_set_compare(cpu_counter_last);
! 188: /* Make sure that next clock tick has not passed */
! 189: clkdiff = cp0_get_count() - cpu_counter_last;
! 190: if (clkdiff > 0) {
! 191: cpu_counter_last += cpu_counter_interval;
! 192: pendingticks++;
! 193: cp0_set_compare(cpu_counter_last);
! 194: }
! 195:
! 196: if ((tf->cpl & SPL_CLOCKMASK) == 0) {
! 197: while (pendingticks) {
! 198: clk_count.ec_count++;
! 199: hardclock(tf);
! 200: pendingticks--;
! 201: }
! 202: }
! 203:
! 204: return CR_INT_5; /* Clock is always on 5 */
! 205: }
! 206:
! 207: /*
! 208: * Wait "n" microseconds.
! 209: */
! 210: void
! 211: delay(int n)
! 212: {
! 213: int dly;
! 214: int p, c;
! 215:
! 216: p = cp0_get_count();
! 217: dly = (sys_config.cpu[0].clock / 1000000) * n / 2;
! 218: while (dly > 0) {
! 219: c = cp0_get_count();
! 220: dly -= c - p;
! 221: p = c;
! 222: }
! 223: }
! 224:
! 225: /*
! 226: * Wait "n" nanoseconds.
! 227: */
! 228: void
! 229: nanodelay(int n)
! 230: {
! 231: int dly;
! 232: int p, c;
! 233:
! 234: p = cp0_get_count();
! 235: dly = ((sys_config.cpu[0].clock * n) / 1000000000) / 2;
! 236: while (dly > 0) {
! 237: c = cp0_get_count();
! 238: dly -= c - p;
! 239: p = c;
! 240: }
! 241: }
! 242:
! 243: /*
! 244: * Mips machine independent clock routines.
! 245: */
! 246:
! 247: /*
! 248: * Start the real-time and statistics clocks. Leave stathz 0 since there
! 249: * are no other timers available.
! 250: */
! 251: void
! 252: cpu_initclocks()
! 253: {
! 254: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
! 255: struct tod_time ct;
! 256: u_int first_cp0, second_cp0, cycles_per_sec;
! 257: int first_sec;
! 258:
! 259: hz = sc->sc_clock.clk_hz;
! 260: stathz = sc->sc_clock.clk_stathz;
! 261: profhz = sc->sc_clock.clk_profhz;
! 262:
! 263: evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
! 264:
! 265: /* Start the clock. */
! 266: if (sc->sc_clock.clk_init != NULL)
! 267: (*sc->sc_clock.clk_init)(sc);
! 268:
! 269: /*
! 270: * Calibrate the cycle counter frequency.
! 271: */
! 272: if (sc->sc_clock.clk_get != NULL) {
! 273: (*sc->sc_clock.clk_get)(sc, 0, &ct);
! 274: first_sec = ct.sec;
! 275:
! 276: /* Let the clock tick one second. */
! 277: do {
! 278: first_cp0 = cp0_get_count();
! 279: (*sc->sc_clock.clk_get)(sc, 0, &ct);
! 280: } while (ct.sec == first_sec);
! 281: first_sec = ct.sec;
! 282: /* Let the clock tick one more second. */
! 283: do {
! 284: second_cp0 = cp0_get_count();
! 285: (*sc->sc_clock.clk_get)(sc, 0, &ct);
! 286: } while (ct.sec == first_sec);
! 287:
! 288: cycles_per_sec = second_cp0 - first_cp0;
! 289: sys_config.cpu[0].clock = cycles_per_sec * 2;
! 290: }
! 291:
! 292: tick = 1000000 / hz; /* number of micro-seconds between interrupts */
! 293: tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */
! 294:
! 295: cp0_timecounter.tc_frequency = sys_config.cpu[0].clock / 2;
! 296: tc_init(&cp0_timecounter);
! 297:
! 298: clock_started++;
! 299: }
! 300:
! 301: /*
! 302: * We assume newhz is either stathz or profhz, and that neither will
! 303: * change after being set up above. Could recalculate intervals here
! 304: * but that would be a drag.
! 305: */
! 306: void
! 307: setstatclockrate(newhz)
! 308: int newhz;
! 309: {
! 310: }
! 311:
! 312: /*
! 313: * This code is defunct after 2099. Will Unix still be here then??
! 314: */
! 315: static short dayyr[12] = {
! 316: 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
! 317: };
! 318:
! 319: /*
! 320: * Initialize the time of day register, based on the time base which
! 321: * is, e.g. from a filesystem.
! 322: */
! 323: void
! 324: inittodr(time_t base)
! 325: {
! 326: struct timespec ts;
! 327: struct tod_time c;
! 328: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
! 329: int days, yr;
! 330:
! 331: ts.tv_nsec = 0;
! 332:
! 333: if (base < 15*SECYR) {
! 334: printf("WARNING: preposterous time in file system");
! 335: /* read the system clock anyway */
! 336: base = 17*SECYR + 186*SECDAY + SECDAY/2;
! 337: }
! 338:
! 339: /*
! 340: * Read RTC chip registers NOTE: Read routines are responsible
! 341: * for sanity checking clock. Dates after 19991231 should be
! 342: * returned as year >= 100.
! 343: */
! 344: if (sc->sc_clock.clk_get) {
! 345: (*sc->sc_clock.clk_get)(sc, base, &c);
! 346: } else {
! 347: printf("WARNING: No TOD clock, believing file system.\n");
! 348: goto bad;
! 349: }
! 350:
! 351: days = 0;
! 352: for (yr = 70; yr < c.year; yr++) {
! 353: days += YEARDAYS(yr);
! 354: }
! 355:
! 356: days += dayyr[c.mon - 1] + c.day - 1;
! 357: if (YEARDAYS(c.year) == 366 && c.mon > 2) {
! 358: days++;
! 359: }
! 360:
! 361: /* now have days since Jan 1, 1970; the rest is easy... */
! 362: ts.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec;
! 363: tc_setclock(&ts);
! 364: sc->sc_initted = 1;
! 365:
! 366: /*
! 367: * See if we gained/lost time.
! 368: */
! 369: if (base < ts.tv_sec - 5*SECYR) {
! 370: printf("WARNING: file system time much less than clock time\n");
! 371: } else if (base > ts.tv_sec + 5*SECYR) {
! 372: printf("WARNING: clock time much less than file system time\n");
! 373: printf("WARNING: using file system time\n");
! 374: } else {
! 375: return;
! 376: }
! 377:
! 378: bad:
! 379: ts.tv_sec = base;
! 380: tc_setclock(&ts);
! 381: sc->sc_initted = 1;
! 382: printf("WARNING: CHECK AND RESET THE DATE!\n");
! 383: }
! 384:
! 385: /*
! 386: * Reset the TOD clock. This is done when the system is halted or
! 387: * when the time is reset by the stime system call.
! 388: */
! 389: void
! 390: resettodr()
! 391: {
! 392: struct tod_time c;
! 393: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
! 394: register int t, t2;
! 395:
! 396: /*
! 397: * Don't reset clock if time has not been set!
! 398: */
! 399: if (!sc->sc_initted) {
! 400: return;
! 401: }
! 402:
! 403: /* compute the day of week. 1 is Sunday*/
! 404: t2 = time_second / SECDAY;
! 405: c.dow = (t2 + 5) % 7 + 1; /* 1/1/1970 was thursday */
! 406:
! 407: /* compute the year */
! 408: t2 = time_second / SECDAY;
! 409: c.year = 69;
! 410: while (t2 >= 0) { /* whittle off years */
! 411: t = t2;
! 412: c.year++;
! 413: t2 -= YEARDAYS(c.year);
! 414: }
! 415:
! 416: /* t = month + day; separate */
! 417: t2 = YEARDAYS(c.year);
! 418: for (c.mon = 1; c.mon < 12; c.mon++) {
! 419: if (t < dayyr[c.mon] + (t2 == 366 && c.mon > 1))
! 420: break;
! 421: }
! 422:
! 423: c.day = t - dayyr[c.mon - 1] + 1;
! 424: if (t2 == 366 && c.mon > 2) {
! 425: c.day--;
! 426: }
! 427:
! 428: t = time_second % SECDAY;
! 429: c.hour = t / 3600;
! 430: t %= 3600;
! 431: c.min = t / 60;
! 432: c.sec = t % 60;
! 433:
! 434: if (sc->sc_clock.clk_set) {
! 435: (*sc->sc_clock.clk_set)(sc, &c);
! 436: }
! 437: }
! 438:
! 439: u_int
! 440: cp0_get_timecount(struct timecounter *tc)
! 441: {
! 442: return (cp0_get_count());
! 443: }
CVSweb