Annotation of sys/arch/macppc/macppc/clock.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: clock.c,v 1.19 2007/04/13 18:48:38 kettenis 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: #include <sys/evcount.h>
! 39: #include <sys/timetc.h>
! 40:
! 41: #include <machine/autoconf.h>
! 42: #include <machine/pio.h>
! 43: #include <machine/intr.h>
! 44: #include <machine/vmparam.h>
! 45: #include <machine/powerpc.h>
! 46: #include <dev/ofw/openfirm.h>
! 47:
! 48: void decr_intr(struct clockframe *frame);
! 49: u_int tb_get_timecount(struct timecounter *);
! 50:
! 51: /*
! 52: * Initially we assume a processor with a bus frequency of 12.5 MHz.
! 53: */
! 54: static u_int32_t ticks_per_sec = 3125000;
! 55: static u_int32_t ns_per_tick = 320;
! 56: static int32_t ticks_per_intr;
! 57: static volatile u_int64_t lasttb;
! 58:
! 59: static struct timecounter tb_timecounter = {
! 60: tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL
! 61: };
! 62:
! 63: time_read_t *time_read;
! 64: time_write_t *time_write;
! 65:
! 66: /* event tracking variables, when the next events of each time should occur */
! 67: u_int64_t nexttimerevent, prevtb, nextstatevent;
! 68:
! 69: /* vars for stats */
! 70: int statint;
! 71: u_int32_t statvar;
! 72: u_int32_t statmin;
! 73:
! 74: static struct evcount clk_count;
! 75: static struct evcount stat_count;
! 76: static int clk_irq = PPC_CLK_IRQ;
! 77: static int stat_irq = PPC_STAT_IRQ;
! 78:
! 79: /*
! 80: * Set up the system's time, given a `reasonable' time value.
! 81: */
! 82: void
! 83: inittodr(time_t base)
! 84: {
! 85: int badbase = 0, waszero = base == 0;
! 86: char *bad = NULL;
! 87: struct timeval tv;
! 88: struct timespec ts;
! 89:
! 90: if (base < 5 * SECYR) {
! 91: /*
! 92: * If base is 0, assume filesystem time is just unknown
! 93: * instead of preposterous. Don't bark.
! 94: */
! 95: if (base != 0)
! 96: printf("WARNING: preposterous time in file system\n");
! 97: /* not going to use it anyway, if the chip is readable */
! 98: base = 21*SECYR + 186*SECDAY + SECDAY/2;
! 99: badbase = 1;
! 100: }
! 101:
! 102: if (time_read != NULL) {
! 103: u_int32_t cursec;
! 104: (*time_read)(&cursec);
! 105: tv.tv_sec = cursec;
! 106: tv.tv_usec = 0;
! 107: } else {
! 108: /* force failure */
! 109: tv.tv_sec = tv.tv_usec = 0;
! 110: }
! 111:
! 112: if (tv.tv_sec == 0) {
! 113: /*
! 114: * Believe the time in the file system for lack of
! 115: * anything better, resetting the clock.
! 116: */
! 117: bad = "WARNING: unable to get date/time";
! 118: tv.tv_sec = base;
! 119: tv.tv_usec = 0;
! 120: if (!badbase)
! 121: resettodr();
! 122: } else {
! 123: int deltat;
! 124:
! 125: tv.tv_sec += tz.tz_minuteswest * 60;
! 126: if (tz.tz_dsttime)
! 127: tv.tv_sec -= 3600;
! 128:
! 129: deltat = tv.tv_sec - base;
! 130:
! 131: if (deltat < 0)
! 132: deltat = -deltat;
! 133: if (!(waszero || deltat < 2 * SECDAY)) {
! 134: printf("WARNING: clock %s %d days",
! 135: tv.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
! 136: bad = "";
! 137:
! 138: if (tv.tv_sec < base && deltat > 1000 * SECDAY) {
! 139: printf(", using FS time");
! 140: tv.tv_sec = base;
! 141: }
! 142: }
! 143: }
! 144:
! 145: ts.tv_sec = tv.tv_sec;
! 146: ts.tv_nsec = tv.tv_usec * 1000;
! 147: tc_setclock(&ts);
! 148:
! 149: if (bad) {
! 150: printf("%s", bad);
! 151: printf(" -- CHECK AND RESET THE DATE!\n");
! 152: }
! 153: }
! 154:
! 155: /*
! 156: * Similar to the above
! 157: */
! 158: void
! 159: resettodr(void)
! 160: {
! 161: struct timeval tv;
! 162:
! 163: if (time_second == 0)
! 164: return;
! 165:
! 166: microtime(&tv);
! 167:
! 168: if (time_write != NULL) {
! 169: tv.tv_sec -= tz.tz_minuteswest * 60;
! 170: if (tz.tz_dsttime) {
! 171: tv.tv_sec += 3600;
! 172: }
! 173: (*time_write)(tv.tv_sec);
! 174: }
! 175: }
! 176:
! 177: volatile int statspending;
! 178:
! 179: void
! 180: decr_intr(struct clockframe *frame)
! 181: {
! 182: u_int64_t tb;
! 183: u_int64_t nextevent;
! 184: int nstats;
! 185: int s;
! 186:
! 187: /*
! 188: * Check whether we are initialized.
! 189: */
! 190: if (!ticks_per_intr)
! 191: return;
! 192:
! 193:
! 194: /*
! 195: * Based on the actual time delay since the last decrementer reload,
! 196: * we arrange for earlier interrupt next time.
! 197: */
! 198:
! 199: tb = ppc_mftb();
! 200: while (nexttimerevent <= tb)
! 201: nexttimerevent += ticks_per_intr;
! 202:
! 203: prevtb = nexttimerevent - ticks_per_intr;
! 204:
! 205: for (nstats = 0; nextstatevent <= tb; nstats++) {
! 206: int r;
! 207: do {
! 208: r = random() & (statvar -1);
! 209: } while (r == 0); /* random == 0 not allowed */
! 210: nextstatevent += statmin + r;
! 211: }
! 212:
! 213: /* only count timer ticks for CLK_IRQ */
! 214: stat_count.ec_count += nstats;
! 215:
! 216: if (nexttimerevent < nextstatevent)
! 217: nextevent = nexttimerevent;
! 218: else
! 219: nextevent = nextstatevent;
! 220:
! 221: /*
! 222: * Need to work about the near constant skew this introduces???
! 223: * reloading tb here could cause a missed tick.
! 224: */
! 225: ppc_mtdec(nextevent - tb);
! 226:
! 227: if (curcpu()->ci_cpl & SPL_CLOCK) {
! 228: statspending += nstats;
! 229: } else {
! 230: nstats += statspending;
! 231: statspending = 0;
! 232:
! 233: s = splclock();
! 234:
! 235: /*
! 236: * Reenable interrupts
! 237: */
! 238: ppc_intr_enable(1);
! 239:
! 240: /*
! 241: * Do standard timer interrupt stuff.
! 242: * Do softclock stuff only on the last iteration.
! 243: */
! 244: frame->pri = s | SINT_CLOCK;
! 245: while (lasttb < prevtb - ticks_per_intr) {
! 246: /* sync lasttb with hardclock */
! 247: lasttb += ticks_per_intr;
! 248: clk_count.ec_count++;
! 249: hardclock(frame);
! 250: }
! 251:
! 252: frame->pri = s;
! 253: while (lasttb < prevtb) {
! 254: /* sync lasttb with hardclock */
! 255: lasttb += ticks_per_intr;
! 256: clk_count.ec_count++;
! 257: hardclock(frame);
! 258: }
! 259:
! 260: while (nstats-- > 0)
! 261: statclock(frame);
! 262:
! 263: splx(s);
! 264: (void) ppc_intr_disable();
! 265:
! 266: /* if a tick has occurred while dealing with these,
! 267: * dont service it now, delay until the next tick.
! 268: */
! 269: }
! 270: }
! 271:
! 272: void
! 273: cpu_initclocks()
! 274: {
! 275: int intrstate;
! 276: int r;
! 277: int minint;
! 278: u_int64_t nextevent;
! 279:
! 280: intrstate = ppc_intr_disable();
! 281:
! 282: stathz = 100;
! 283: profhz = 1000; /* must be a multiple of stathz */
! 284:
! 285: /* init secondary clock to stathz */
! 286: statint = ticks_per_sec / stathz;
! 287: statvar = 0x40000000; /* really big power of two */
! 288: /* find largest 2^n which is nearly smaller than statint/2 */
! 289: minint = statint / 2 + 100;
! 290: while (statvar > minint)
! 291: statvar >>= 1;
! 292:
! 293: statmin = statint - (statvar >> 1);
! 294:
! 295:
! 296: lasttb = ppc_mftb();
! 297: nexttimerevent = lasttb + ticks_per_intr;
! 298: do {
! 299: r = random() & (statvar -1);
! 300: } while (r == 0); /* random == 0 not allowed */
! 301: nextstatevent = lasttb + statmin + r;
! 302:
! 303: if (nexttimerevent < nextstatevent)
! 304: nextevent = nexttimerevent;
! 305: else
! 306: nextevent = nextstatevent;
! 307:
! 308: evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
! 309: evcount_attach(&stat_count, "stat", (void *)&stat_irq, &evcount_intr);
! 310:
! 311: tb_timecounter.tc_frequency = ticks_per_sec;
! 312: tc_init(&tb_timecounter);
! 313:
! 314: ppc_mtdec(nextevent-lasttb);
! 315: ppc_intr_enable(intrstate);
! 316: }
! 317:
! 318: void
! 319: calc_delayconst(void)
! 320: {
! 321: int qhandle, phandle;
! 322: char name[32];
! 323: int s;
! 324:
! 325: /*
! 326: * Get this info during autoconf? XXX
! 327: */
! 328: for (qhandle = OF_peer(0); qhandle; qhandle = phandle) {
! 329: if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0
! 330: && !strcmp(name, "cpu")
! 331: && OF_getprop(qhandle, "timebase-frequency",
! 332: &ticks_per_sec, sizeof ticks_per_sec) >= 0) {
! 333: /*
! 334: * Should check for correct CPU here? XXX
! 335: */
! 336: s = ppc_intr_disable();
! 337: ns_per_tick = 1000000000 / ticks_per_sec;
! 338: ticks_per_intr = ticks_per_sec / hz;
! 339: ppc_intr_enable(s);
! 340: break;
! 341: }
! 342: if ((phandle = OF_child(qhandle)))
! 343: continue;
! 344: while (qhandle) {
! 345: if ((phandle = OF_peer(qhandle)))
! 346: break;
! 347: qhandle = OF_parent(qhandle);
! 348: }
! 349: }
! 350:
! 351: if (!phandle)
! 352: panic("no cpu node");
! 353: }
! 354:
! 355: /*
! 356: * Wait for about n microseconds (us) (at least!).
! 357: */
! 358: void
! 359: delay(unsigned n)
! 360: {
! 361: u_int64_t tb;
! 362: u_int32_t tbh, tbl, scratch;
! 363:
! 364: tb = ppc_mftb();
! 365: tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
! 366: tbh = tb >> 32;
! 367: tbl = (u_int32_t)tb;
! 368: asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;"
! 369: " mftb %0; cmplw %0,%2; blt 1b; 2:"
! 370: :: "r"(scratch), "r"(tbh), "r"(tbl));
! 371: }
! 372:
! 373: /*
! 374: * Nothing to do.
! 375: */
! 376: void
! 377: setstatclockrate(int newhz)
! 378: {
! 379: int minint;
! 380: int intrstate;
! 381:
! 382: intrstate = ppc_intr_disable();
! 383:
! 384: statint = ticks_per_sec / newhz;
! 385: statvar = 0x40000000; /* really big power of two */
! 386: /* find largest 2^n which is nearly smaller than statint/2 */
! 387: minint = statint / 2 + 100;
! 388: while (statvar > minint)
! 389: statvar >>= 1;
! 390:
! 391: statmin = statint - (statvar >> 1);
! 392: ppc_intr_enable(intrstate);
! 393:
! 394: /*
! 395: * XXX this allows the next stat timer to occur then it switches
! 396: * to the new frequency. Rather than switching instantly.
! 397: */
! 398: }
! 399:
! 400: u_int
! 401: tb_get_timecount(struct timecounter *tc)
! 402: {
! 403: return ppc_mftbl();
! 404: }
CVSweb