[BACK]Return to clock.c CVS log [TXT][DIR] Up to [local] / sys / arch / mvmeppc / dev

Annotation of sys/arch/mvmeppc/dev/clock.c, Revision 1.1.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