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

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