[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     ! 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