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

Annotation of sys/arch/sparc64/sparc64/clock.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: clock.c,v 1.33 2007/05/06 14:52:36 kettenis Exp $     */
                      2: /*     $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1992, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  * Copyright (c) 1994 Gordon W. Ross
                      8:  * Copyright (c) 1993 Adam Glass
                      9:  * Copyright (c) 1996 Paul Kranenburg
                     10:  * Copyright (c) 1996
                     11:  *     The President and Fellows of Harvard College. All rights reserved.
                     12:  *
                     13:  * This software was developed by the Computer Systems Engineering group
                     14:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     15:  * contributed to Berkeley.
                     16:  *
                     17:  * All advertising materials mentioning features or use of this software
                     18:  * must display the following acknowledgement:
                     19:  *     This product includes software developed by Harvard University.
                     20:  *     This product includes software developed by the University of
                     21:  *     California, Lawrence Berkeley Laboratory.
                     22:  *
                     23:  * Redistribution and use in source and binary forms, with or without
                     24:  * modification, are permitted provided that the following conditions
                     25:  * are met:
                     26:  *
                     27:  * 1. Redistributions of source code must retain the above copyright
                     28:  *    notice, this list of conditions and the following disclaimer.
                     29:  * 2. Redistributions in binary form must reproduce the above copyright
                     30:  *    notice, this list of conditions and the following disclaimer in the
                     31:  *    documentation and/or other materials provided with the distribution.
                     32:  * 3. All advertising materials mentioning features or use of this software
                     33:  *    must display the following acknowledgement:
                     34:  *     This product includes software developed by the University of
                     35:  *     California, Berkeley and its contributors.
                     36:  *     This product includes software developed by Paul Kranenburg.
                     37:  *     This product includes software developed by Harvard University.
                     38:  * 4. Neither the name of the University nor the names of its contributors
                     39:  *    may be used to endorse or promote products derived from this software
                     40:  *    without specific prior written permission.
                     41:  *
                     42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     52:  * SUCH DAMAGE.
                     53:  *
                     54:  *     @(#)clock.c     8.1 (Berkeley) 6/11/93
                     55:  *
                     56:  */
                     57:
                     58: /*
                     59:  * Clock driver.  This is the id prom and eeprom driver as well
                     60:  * and includes the timer register functions too.
                     61:  */
                     62:
                     63: /* Define this for a 1/4s clock to ease debugging */
                     64: /* #define INTR_DEBUG */
                     65:
                     66: #include <sys/param.h>
                     67: #include <sys/kernel.h>
                     68: #include <sys/device.h>
                     69: #include <sys/proc.h>
                     70: #include <sys/resourcevar.h>
                     71: #include <sys/malloc.h>
                     72: #include <sys/systm.h>
                     73: #ifdef GPROF
                     74: #include <sys/gmon.h>
                     75: #endif
                     76: #include <sys/sched.h>
                     77: #include <sys/timetc.h>
                     78:
                     79: #include <uvm/uvm_extern.h>
                     80:
                     81: #include <machine/bus.h>
                     82: #include <machine/autoconf.h>
                     83: #include <machine/eeprom.h>
                     84: #include <machine/cpu.h>
                     85: #include <machine/idprom.h>
                     86:
                     87: #include <dev/clock_subr.h>
                     88: #include <dev/ic/mk48txxreg.h>
                     89:
                     90: #include <sparc64/sparc64/intreg.h>
                     91: #include <sparc64/sparc64/timerreg.h>
                     92: #include <sparc64/dev/iommureg.h>
                     93: #include <sparc64/dev/sbusreg.h>
                     94: #include <dev/sbus/sbusvar.h>
                     95: #include <sparc64/dev/ebusreg.h>
                     96: #include <sparc64/dev/ebusvar.h>
                     97: #include <sparc64/dev/fhcvar.h>
                     98:
                     99: extern u_int64_t cpu_clockrate;
                    100:
                    101: struct clock_wenable_info {
                    102:        bus_space_tag_t         cwi_bt;
                    103:        bus_space_handle_t      cwi_bh;
                    104:        bus_size_t              cwi_size;
                    105: };
                    106:
                    107: struct cfdriver clock_cd = {
                    108:        NULL, "clock", DV_DULL
                    109: };
                    110:
                    111: u_int tick_get_timecount(struct timecounter *);
                    112:
                    113: struct timecounter tick_timecounter = {
                    114:        tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
                    115: };
                    116:
                    117: /*
                    118:  * Statistics clock interval and variance, in usec.  Variance must be a
                    119:  * power of two.  Since this gives us an even number, not an odd number,
                    120:  * we discard one case and compensate.  That is, a variance of 1024 would
                    121:  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
                    122:  * This is symmetric about the point 512, or statvar/2, and thus averages
                    123:  * to that value (assuming uniform random numbers).
                    124:  */
                    125: /* XXX fix comment to match value */
                    126: int statvar = 8192;
                    127: int statmin;                   /* statclock interval - 1/2*variance */
                    128:
                    129: static long tick_increment;
                    130: int schedintr(void *);
                    131:
                    132: static struct intrhand level10 = { clockintr };
                    133: static struct intrhand level0 = { tickintr };
                    134: static struct intrhand level14 = { statintr };
                    135: static struct intrhand schedint = { schedintr };
                    136:
                    137: /*
                    138:  * clock (eeprom) attaches at the sbus or the ebus (PCI)
                    139:  */
                    140: static int     clockmatch_sbus(struct device *, void *, void *);
                    141: static void    clockattach_sbus(struct device *, struct device *, void *);
                    142: static int     clockmatch_ebus(struct device *, void *, void *);
                    143: static void    clockattach_ebus(struct device *, struct device *, void *);
                    144: static int     clockmatch_fhc(struct device *, void *, void *);
                    145: static void    clockattach_fhc(struct device *, struct device *, void *);
                    146: static void    clockattach(int, bus_space_tag_t, bus_space_handle_t);
                    147:
                    148: struct cfattach clock_sbus_ca = {
                    149:        sizeof(struct device), clockmatch_sbus, clockattach_sbus
                    150: };
                    151:
                    152: struct cfattach clock_ebus_ca = {
                    153:        sizeof(struct device), clockmatch_ebus, clockattach_ebus
                    154: };
                    155:
                    156: struct cfattach clock_fhc_ca = {
                    157:        sizeof(struct device), clockmatch_fhc, clockattach_fhc
                    158: };
                    159:
                    160: /* Global TOD clock handle & idprom pointer */
                    161: todr_chip_handle_t todr_handle = NULL;
                    162: static struct idprom *idprom;
                    163:
                    164: static int     timermatch(struct device *, void *, void *);
                    165: static void    timerattach(struct device *, struct device *, void *);
                    166:
                    167: struct timerreg_4u     timerreg_4u;    /* XXX - need more cleanup */
                    168:
                    169: struct cfattach timer_ca = {
                    170:        sizeof(struct device), timermatch, timerattach
                    171: };
                    172:
                    173: struct cfdriver timer_cd = {
                    174:        NULL, "timer", DV_DULL
                    175: };
                    176:
                    177: int clock_bus_wenable(struct todr_chip_handle *, int);
                    178: struct chiptime;
                    179: void myetheraddr(u_char *);
                    180: struct idprom *getidprom(void);
                    181: int chiptotime(int, int, int, int, int, int);
                    182: void timetochip(struct chiptime *);
                    183: void stopcounter(struct timer_4u *);
                    184:
                    185: int timerblurb = 10; /* Guess a value; used before clock is attached */
                    186:
                    187: /*
                    188:  * The OPENPROM calls the clock the "eeprom", so we have to have our
                    189:  * own special match function to call it the "clock".
                    190:  */
                    191: static int
                    192: clockmatch_sbus(parent, cf, aux)
                    193:        struct device *parent;
                    194:        void *cf;
                    195:        void *aux;
                    196: {
                    197:        struct sbus_attach_args *sa = aux;
                    198:
                    199:        return (strcmp("eeprom", sa->sa_name) == 0);
                    200: }
                    201:
                    202: static int
                    203: clockmatch_ebus(parent, cf, aux)
                    204:        struct device *parent;
                    205:        void *cf;
                    206:        void *aux;
                    207: {
                    208:        struct ebus_attach_args *ea = aux;
                    209:
                    210:        return (strcmp("eeprom", ea->ea_name) == 0);
                    211: }
                    212:
                    213: static int
                    214: clockmatch_fhc(parent, cf, aux)
                    215:        struct device *parent;
                    216:        void *cf;
                    217:        void *aux;
                    218: {
                    219:        struct fhc_attach_args *fa = aux;
                    220:
                    221:        return (strcmp("eeprom", fa->fa_name) == 0);
                    222: }
                    223:
                    224: /*
                    225:  * Attach a clock (really `eeprom') to the sbus or ebus.
                    226:  *
                    227:  * We ignore any existing virtual address as we need to map
                    228:  * this read-only and make it read-write only temporarily,
                    229:  * whenever we read or write the clock chip.  The clock also
                    230:  * contains the ID ``PROM'', and I have already had the pleasure
                    231:  * of reloading the cpu type, Ethernet address, etc, by hand from
                    232:  * the console FORTH interpreter.  I intend not to enjoy it again.
                    233:  *
                    234:  * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
                    235:  * supposed to be identical to it.
                    236:  *
                    237:  * This is *UGLY*!  We probably have multiple mappings.  But I do
                    238:  * know that this all fits inside an 8K page, so I'll just map in
                    239:  * once.
                    240:  *
                    241:  * What we really need is some way to record the bus attach args
                    242:  * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
                    243:  * or not to write enable/disable the device registers.  This is
                    244:  * a non-trivial operation.
                    245:  */
                    246:
                    247: /* ARGSUSED */
                    248: static void
                    249: clockattach_sbus(parent, self, aux)
                    250:        struct device *parent, *self;
                    251:        void *aux;
                    252: {
                    253:        struct sbus_attach_args *sa = aux;
                    254:        bus_space_tag_t bt = sa->sa_bustag;
                    255:        int sz;
                    256:        static struct clock_wenable_info cwi;
                    257:
                    258:        /* use sa->sa_regs[0].size? */
                    259:        sz = 8192;
                    260:
                    261:        if (sbus_bus_map(bt,
                    262:                         sa->sa_slot,
                    263:                         (sa->sa_offset & ~NBPG),
                    264:                         sz,
                    265:                         BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
                    266:                         0, &cwi.cwi_bh) != 0) {
                    267:                printf("%s: can't map register\n", self->dv_xname);
                    268:                return;
                    269:        }
                    270:        clockattach(sa->sa_node, bt, cwi.cwi_bh);
                    271:
                    272:        /* Save info for the clock wenable call. */
                    273:        cwi.cwi_bt = bt;
                    274:        cwi.cwi_size = sz;
                    275:        todr_handle->bus_cookie = &cwi;
                    276:        todr_handle->todr_setwen = clock_bus_wenable;
                    277: }
                    278:
                    279: /*
                    280:  * Write en/dis-able clock registers.  We coordinate so that several
                    281:  * writers can run simultaneously.
                    282:  * XXX There is still a race here.  The page change and the "writers"
                    283:  * change are not atomic.
                    284:  */
                    285: int
                    286: clock_bus_wenable(handle, onoff)
                    287:        struct todr_chip_handle *handle;
                    288:        int onoff;
                    289: {
                    290:        int s, err = 0;
                    291:        int prot; /* nonzero => change prot */
                    292:        volatile static int writers;
                    293:        struct clock_wenable_info *cwi = handle->bus_cookie;
                    294:
                    295:        s = splhigh();
                    296:        if (onoff)
                    297:                prot = writers++ == 0 ?
                    298:                    VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED : 0;
                    299:        else
                    300:                prot = --writers == 0 ?
                    301:                    VM_PROT_READ | PMAP_WIRED : 0;
                    302:        splx(s);
                    303:
                    304:        if (prot) {
                    305:                err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size,
                    306:                    onoff ? 0 : BUS_SPACE_MAP_READONLY);
                    307:                if (err)
                    308:                        printf("clock_wenable_info: WARNING -- cannot %s "
                    309:                            "page protection\n", onoff ? "disable" : "enable");
                    310:        }
                    311:        return (err);
                    312: }
                    313:
                    314: /* ARGSUSED */
                    315: static void
                    316: clockattach_ebus(parent, self, aux)
                    317:        struct device *parent, *self;
                    318:        void *aux;
                    319: {
                    320:        struct ebus_attach_args *ea = aux;
                    321:        bus_space_tag_t bt;
                    322:        int sz;
                    323:        static struct clock_wenable_info cwi;
                    324:
                    325:        /* hard code to 8K? */
                    326:        sz = ea->ea_regs[0].size;
                    327:
                    328:        if (ebus_bus_map(ea->ea_iotag, 0,
                    329:            EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) {
                    330:                bt = ea->ea_iotag;
                    331:        } else if (ebus_bus_map(ea->ea_memtag, 0,
                    332:            EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz,
                    333:            BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
                    334:            0, &cwi.cwi_bh) == 0) {
                    335:                bt = ea->ea_memtag;
                    336:        } else {
                    337:                printf("%s: can't map register\n", self->dv_xname);
                    338:                return;
                    339:        }
                    340:
                    341:        clockattach(ea->ea_node, bt, cwi.cwi_bh);
                    342:
                    343:        /* Save info for the clock wenable call. */
                    344:        cwi.cwi_bt = bt;
                    345:        cwi.cwi_size = sz;
                    346:        todr_handle->bus_cookie = &cwi;
                    347:        todr_handle->todr_setwen = (ea->ea_memtag == bt) ?
                    348:            clock_bus_wenable : NULL;
                    349: }
                    350:
                    351: static void
                    352: clockattach_fhc(parent, self, aux)
                    353:        struct device *parent, *self;
                    354:        void *aux;
                    355: {
                    356:        struct fhc_attach_args *fa = aux;
                    357:        bus_space_tag_t bt = fa->fa_bustag;
                    358:        int sz;
                    359:        static struct clock_wenable_info cwi;
                    360:
                    361:        /* use sa->sa_regs[0].size? */
                    362:        sz = 8192;
                    363:
                    364:        if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot,
                    365:            (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size,
                    366:            BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) {
                    367:                printf("%s: can't map register\n", self->dv_xname);
                    368:                return;
                    369:        }
                    370:
                    371:        clockattach(fa->fa_node, bt, cwi.cwi_bh);
                    372:
                    373:        /* Save info for the clock wenable call. */
                    374:        cwi.cwi_bt = bt;
                    375:        cwi.cwi_size = sz;
                    376:        todr_handle->bus_cookie = &cwi;
                    377:        todr_handle->todr_setwen = clock_bus_wenable;
                    378: }
                    379:
                    380: static void
                    381: clockattach(node, bt, bh)
                    382:        int node;
                    383:        bus_space_tag_t bt;
                    384:        bus_space_handle_t bh;
                    385: {
                    386:        char *model;
                    387:        struct idprom *idp;
                    388:        int h;
                    389:
                    390:        model = getpropstring(node, "model");
                    391:
                    392: #ifdef DIAGNOSTIC
                    393:        if (model == NULL)
                    394:                panic("clockattach: no model property");
                    395: #endif
                    396:
                    397:        /* Our TOD clock year 0 is 1968 */
                    398:        if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL)
                    399:                panic("Can't attach %s tod clock", model);
                    400:
                    401: #define IDPROM_OFFSET (8*1024 - 40)    /* XXX - get nvram sz from driver */
                    402:        if (idprom == NULL) {
                    403:                idp = getidprom();
                    404:                if (idp == NULL)
                    405:                        idp = (struct idprom *)(bus_space_vaddr(bt, bh) +
                    406:                            IDPROM_OFFSET);
                    407:                idprom = idp;
                    408:        } else
                    409:                idp = idprom;
                    410:        h = idp->id_machine << 24;
                    411:        h |= idp->id_hostid[0] << 16;
                    412:        h |= idp->id_hostid[1] << 8;
                    413:        h |= idp->id_hostid[2];
                    414:        hostid = h;
                    415:        printf("\n");
                    416: }
                    417:
                    418: struct idprom *
                    419: getidprom()
                    420: {
                    421:        struct idprom *idp = NULL;
                    422:        int node, n;
                    423:
                    424:        node = findroot();
                    425:        if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0)
                    426:                return (NULL);
                    427:        if (n != 1) {
                    428:                free(idp, M_DEVBUF);
                    429:                return (NULL);
                    430:        }
                    431:        return (idp);
                    432: }
                    433:
                    434: /*
                    435:  * The sun4u OPENPROMs call the timer the "counter-timer", except for
                    436:  * the lame UltraSPARC IIi PCI machines that don't have them.
                    437:  */
                    438: static int
                    439: timermatch(parent, cf, aux)
                    440:        struct device *parent;
                    441:        void *cf;
                    442:        void *aux;
                    443: {
                    444:        struct mainbus_attach_args *ma = aux;
                    445:
                    446:        if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr)
                    447:                return (strcmp("counter-timer", ma->ma_name) == 0);
                    448:        else
                    449:                return (0);
                    450: }
                    451:
                    452: static void
                    453: timerattach(parent, self, aux)
                    454:        struct device *parent, *self;
                    455:        void *aux;
                    456: {
                    457:        struct mainbus_attach_args *ma = aux;
                    458:        u_int *va = ma->ma_address;
                    459:
                    460:        /*
                    461:         * What we should have are 3 sets of registers that reside on
                    462:         * different parts of SYSIO or PSYCHO.  We'll use the prom
                    463:         * mappings cause we can't get rid of them and set up appropriate
                    464:         * pointers on the timerreg_4u structure.
                    465:         */
                    466:        timerreg_4u.t_timer = (struct timer_4u *)(u_long)va[0];
                    467:        timerreg_4u.t_clrintr = (int64_t *)(u_long)va[1];
                    468:        timerreg_4u.t_mapintr = (int64_t *)(u_long)va[2];
                    469:
                    470:        /* Install the appropriate interrupt vector here */
                    471:        level10.ih_number = ma->ma_interrupts[0];
                    472:        level10.ih_clr = (void *)&timerreg_4u.t_clrintr[0];
                    473:        level10.ih_map = (void *)&timerreg_4u.t_mapintr[0];
                    474:        strlcpy(level10.ih_name, "clock", sizeof(level10.ih_name));
                    475:        intr_establish(10, &level10);
                    476:
                    477:        level14.ih_number = ma->ma_interrupts[1];
                    478:        level14.ih_clr = (void *)&timerreg_4u.t_clrintr[1];
                    479:        level14.ih_map = (void *)&timerreg_4u.t_mapintr[1];
                    480:        strlcpy(level14.ih_name, "prof", sizeof(level14.ih_name));
                    481:        intr_establish(14, &level14);
                    482:
                    483:        printf(" ivec 0x%x, 0x%x\n", INTVEC(level10.ih_number),
                    484:            INTVEC(level14.ih_number));
                    485: }
                    486:
                    487: void
                    488: stopcounter(creg)
                    489:        struct timer_4u *creg;
                    490: {
                    491:        /* Stop the clock */
                    492:        volatile int discard;
                    493:        discard = creg->t_limit;
                    494:        creg->t_limit = 0;
                    495: }
                    496:
                    497: /*
                    498:  * XXX this belongs elsewhere
                    499:  */
                    500: void
                    501: myetheraddr(cp)
                    502:        u_char *cp;
                    503: {
                    504:        struct idprom *idp;
                    505:
                    506:        if ((idp = idprom) == NULL) {
                    507:                int node, n;
                    508:
                    509:                node = findroot();
                    510:                if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) ||
                    511:                    n != 1) {
                    512:                        printf("\nmyetheraddr: clock not setup yet, "
                    513:                               "and no idprom property in /\n");
                    514:                        return;
                    515:                }
                    516:        }
                    517:
                    518:        cp[0] = idp->id_ether[0];
                    519:        cp[1] = idp->id_ether[1];
                    520:        cp[2] = idp->id_ether[2];
                    521:        cp[3] = idp->id_ether[3];
                    522:        cp[4] = idp->id_ether[4];
                    523:        cp[5] = idp->id_ether[5];
                    524:        if (idprom == NULL)
                    525:                free(idp, M_DEVBUF);
                    526: }
                    527:
                    528: /*
                    529:  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
                    530:  * no alternative timer is available.
                    531:  *
                    532:  * The frequencies of these clocks must be an even number of microseconds.
                    533:  */
                    534: void
                    535: cpu_initclocks()
                    536: {
                    537:        int statint, minint;
                    538: #ifdef DEBUG
                    539:        extern int intrdebug;
                    540: #endif
                    541:
                    542: #ifdef DEBUG
                    543:        /* Set a 1s clock */
                    544:        if (intrdebug) {
                    545:                hz = 1;
                    546:                tick = 1000000 / hz;
                    547:                printf("intrdebug set: 1Hz clock\n");
                    548:        }
                    549: #endif
                    550:
                    551:        if (1000000 % hz) {
                    552:                printf("cannot get %d Hz clock; using 100 Hz\n", hz);
                    553:                hz = 100;
                    554:                tick = 1000000 / hz;
                    555:        }
                    556:
                    557:        /* Make sure we have a sane cpu_clockrate -- we'll need it */
                    558:        if (!cpu_clockrate)
                    559:                /* Default to 200MHz clock XXXXX */
                    560:                cpu_clockrate = 200000000;
                    561:
                    562:        tick_timecounter.tc_frequency = cpu_clockrate;
                    563:        tc_init(&tick_timecounter);
                    564:
                    565:        /*
                    566:         * Now handle machines w/o counter-timers.
                    567:         */
                    568:
                    569:        if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
                    570:                /* We don't have a counter-timer -- use %tick */
                    571:                level0.ih_clr = 0;
                    572:                /*
                    573:                 * Establish a level 10 interrupt handler
                    574:                 *
                    575:                 * We will have a conflict with the softint handler,
                    576:                 * so we set the ih_number to 1.
                    577:                 */
                    578:                level0.ih_number = 1;
                    579:                strlcpy(level0.ih_name, "clock", sizeof(level0.ih_name));
                    580:                intr_establish(10, &level0);
                    581:                /* We only have one timer so we have no statclock */
                    582:                stathz = 0;
                    583:
                    584:                /* set the next interrupt time */
                    585:                tick_increment = cpu_clockrate / hz;
                    586: #ifdef DEBUG
                    587:                printf("Using %%tick -- intr in %ld cycles...",
                    588:                    tick_increment);
                    589: #endif
                    590:                next_tick(tick_increment);
                    591: #ifdef DEBUG
                    592:                printf("done.\n");
                    593: #endif
                    594:                return;
                    595:        }
                    596:
                    597:        if (stathz == 0)
                    598:                stathz = hz;
                    599:        if (1000000 % stathz) {
                    600:                printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
                    601:                stathz = 100;
                    602:        }
                    603:
                    604:        profhz = stathz;                /* always */
                    605:
                    606:        statint = 1000000 / stathz;
                    607:        minint = statint / 2 + 100;
                    608:        while (statvar > minint)
                    609:                statvar >>= 1;
                    610:
                    611:        /*
                    612:         * Establish scheduler softint.
                    613:         */
                    614:        schedint.ih_pil = PIL_SCHED;
                    615:        schedint.ih_clr = NULL;
                    616:        schedint.ih_arg = 0;
                    617:        schedint.ih_pending = 0;
                    618:        schedhz = stathz/4;
                    619:
                    620:        /*
                    621:         * Enable timers
                    622:         *
                    623:         * Also need to map the interrupts cause we're not a child of the sbus.
                    624:         * N.B. By default timer[0] is disabled and timer[1] is enabled.
                    625:         */
                    626:        stxa((vaddr_t)&timerreg_4u.t_timer[0].t_limit, ASI_NUCLEUS,
                    627:             tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD);
                    628:        stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS,
                    629:             timerreg_4u.t_mapintr[0]|INTMAP_V);
                    630:
                    631: #ifdef DEBUG
                    632:        if (intrdebug)
                    633:                /* Neglect to enable timer */
                    634:                stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
                    635:                     tmr_ustolim(statint)|TMR_LIM_RELOAD);
                    636:        else
                    637: #endif
                    638:                stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
                    639:                     tmr_ustolim(statint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
                    640:        stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS,
                    641:             timerreg_4u.t_mapintr[1]|INTMAP_V);
                    642:
                    643:        statmin = statint - (statvar >> 1);
                    644:
                    645: }
                    646:
                    647: /*
                    648:  * Dummy setstatclockrate(), since we know profhz==hz.
                    649:  */
                    650: /* ARGSUSED */
                    651: void
                    652: setstatclockrate(newhz)
                    653:        int newhz;
                    654: {
                    655:        /* nothing */
                    656: }
                    657:
                    658: /*
                    659:  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
                    660:  * console input, we need to check for that here as well, and generate
                    661:  * a software interrupt to read it.
                    662:  */
                    663: #ifdef DEBUG
                    664: static int clockcheck = 0;
                    665: #endif
                    666: int
                    667: clockintr(cap)
                    668:        void *cap;
                    669: {
                    670: #ifdef DEBUG
                    671:        static int64_t tick_base = 0;
                    672:        struct timeval ctime;
                    673:        int64_t t;
                    674:
                    675:        t = tick() & TICK_TICKS;
                    676:
                    677:        microtime(&ctime);
                    678:        if (!tick_base) {
                    679:                tick_base = (ctime.tv_sec * 1000000LL + ctime.tv_usec)
                    680:                        * 1000000LL / cpu_clockrate;
                    681:                tick_base -= t;
                    682:        } else if (clockcheck) {
                    683:                int64_t tk = t;
                    684:                int64_t clk = (ctime.tv_sec * 1000000LL + ctime.tv_usec);
                    685:                t -= tick_base;
                    686:                t = t * 1000000LL / cpu_clockrate;
                    687:                if (t - clk > hz) {
                    688:                        printf("Clock lost an interrupt!\n");
                    689:                        printf("Actual: %llx Expected: %llx tick %llx "
                    690:                            "tick_base %llx\n", (long long)t, (long long)clk,
                    691:                            (long long)tk, (long long)tick_base);
                    692: #ifdef DDB
                    693:                        Debugger();
                    694: #endif
                    695:                        tick_base = 0;
                    696:                }
                    697:        }
                    698: #endif
                    699:        /* Let locore.s clear the interrupt for us. */
                    700:        hardclock((struct clockframe *)cap);
                    701:
                    702:        level10.ih_count.ec_count++;
                    703:
                    704:        return (1);
                    705: }
                    706:
                    707: /*
                    708:  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
                    709:  * console input, we need to check for that here as well, and generate
                    710:  * a software interrupt to read it.
                    711:  *
                    712:  * %tick is really a level-14 interrupt.  We need to remap this in
                    713:  * locore.s to a level 10.
                    714:  */
                    715: int
                    716: tickintr(cap)
                    717:        void *cap;
                    718: {
                    719:        int s;
                    720:
                    721:        hardclock((struct clockframe *)cap);
                    722:
                    723:        s = splhigh();
                    724:        /* Reset the interrupt */
                    725:        next_tick(tick_increment);
                    726:        level0.ih_count.ec_count++;
                    727:        splx(s);
                    728:
                    729:        return (1);
                    730: }
                    731:
                    732: /*
                    733:  * Level 14 (stat clock) interrupt handler.
                    734:  */
                    735: int
                    736: statintr(cap)
                    737:        void *cap;
                    738: {
                    739:        u_long newint, r, var;
                    740:        struct cpu_info *ci = curcpu();
                    741:
                    742: #ifdef NOT_DEBUG
                    743:        printf("statclock: count %x:%x, limit %x:%x\n",
                    744:               timerreg_4u.t_timer[1].t_count, timerreg_4u.t_timer[1].t_limit);
                    745: #endif
                    746: #ifdef NOT_DEBUG
                    747:        prom_printf("!");
                    748: #endif
                    749:        statclock((struct clockframe *)cap);
                    750: #ifdef NOTDEF_DEBUG
                    751:        /* Don't re-schedule the IRQ */
                    752:        return 1;
                    753: #endif
                    754:        /*
                    755:         * Compute new randomized interval.  The intervals are uniformly
                    756:         * distributed on [statint - statvar / 2, statint + statvar / 2],
                    757:         * and therefore have mean statint, giving a stathz frequency clock.
                    758:         */
                    759:        var = statvar;
                    760:        do {
                    761:                r = random() & (var - 1);
                    762:        } while (r == 0);
                    763:        newint = statmin + r;
                    764:
                    765:        if (schedhz)
                    766:                if ((++ci->ci_schedstate.spc_schedticks & 3) == 0)
                    767:                        send_softint(-1, PIL_SCHED, &schedint);
                    768:        stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
                    769:             tmr_ustolim(newint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
                    770:
                    771:        level14.ih_count.ec_count++;
                    772:
                    773:        return (1);
                    774: }
                    775:
                    776: int
                    777: schedintr(arg)
                    778:        void *arg;
                    779: {
                    780:        if (curproc)
                    781:                schedclock(curproc);
                    782:        return (1);
                    783: }
                    784:
                    785:
                    786: /*
                    787:  * `sparc_clock_time_is_ok' is used in cpu_reboot() to determine
                    788:  * whether it is appropriate to call resettodr() to consolidate
                    789:  * pending time adjustments.
                    790:  */
                    791: int sparc_clock_time_is_ok;
                    792:
                    793: /*
                    794:  * Set up the system's time, given a `reasonable' time value.
                    795:  */
                    796: void
                    797: inittodr(base)
                    798:        time_t base;
                    799: {
                    800:        int badbase = 0, waszero = base == 0;
                    801:        char *bad = NULL;
                    802:        struct timeval tv;
                    803:        struct timespec ts;
                    804:
                    805:        if (base < 5 * SECYR) {
                    806:                /*
                    807:                 * If base is 0, assume filesystem time is just unknown
                    808:                 * in stead of preposterous. Don't bark.
                    809:                 */
                    810:                if (base != 0)
                    811:                        printf("WARNING: preposterous time in file system\n");
                    812:                /* not going to use it anyway, if the chip is readable */
                    813:                base = 21*SECYR + 186*SECDAY + SECDAY/2;
                    814:                badbase = 1;
                    815:        }
                    816:
                    817:        if (todr_handle && (todr_gettime(todr_handle, &tv) != 0 ||
                    818:            tv.tv_sec == 0)) {
                    819:                /*
                    820:                 * Believe the time in the file system for lack of
                    821:                 * anything better, resetting the clock.
                    822:                 */
                    823:                bad = "WARNING: bad date in battery clock";
                    824:                tv.tv_sec = base;
                    825:                tv.tv_usec = 0;
                    826:                if (!badbase)
                    827:                        resettodr();
                    828:        } else {
                    829:                int deltat = tv.tv_sec - base;
                    830:
                    831:                sparc_clock_time_is_ok = 1;
                    832:
                    833:                if (deltat < 0)
                    834:                        deltat = -deltat;
                    835:                if (!(waszero || deltat < 2 * SECDAY)) {
                    836: #ifndef SMALL_KERNEL
                    837:                        printf("WARNING: clock %s %ld days",
                    838:                            tv.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
                    839:                        bad = "";
                    840: #endif
                    841:                }
                    842:        }
                    843:
                    844:        ts.tv_sec = tv.tv_sec;
                    845:        ts.tv_nsec = tv.tv_usec * 1000;
                    846:        tc_setclock(&ts);
                    847:
                    848:        if (bad) {
                    849:                printf("%s", bad);
                    850:                printf(" -- CHECK AND RESET THE DATE!\n");
                    851:        }
                    852: }
                    853:
                    854: /*
                    855:  * Reset the clock based on the current time.
                    856:  * Used when the current clock is preposterous, when the time is changed,
                    857:  * and when rebooting.  Do nothing if the time is not yet known, e.g.,
                    858:  * when crashing during autoconfig.
                    859:  */
                    860: void
                    861: resettodr()
                    862: {
                    863:        struct timeval tv;
                    864:
                    865:        if (time_second == 0)
                    866:                return;
                    867:
                    868:        microtime(&tv);
                    869:
                    870:        sparc_clock_time_is_ok = 1;
                    871:        if (todr_handle == 0 || todr_settime(todr_handle, &tv) != 0)
                    872:                printf("Cannot set time in time-of-day clock\n");
                    873: }
                    874:
                    875: /*
                    876:  * XXX: these may actually belong somewhere else, but since the
                    877:  * EEPROM is so closely tied to the clock on some models, perhaps
                    878:  * it needs to stay here...
                    879:  */
                    880: int
                    881: eeprom_uio(uio)
                    882:        struct uio *uio;
                    883: {
                    884:        return (ENODEV);
                    885: }
                    886:
                    887: u_int
                    888: tick_get_timecount(struct timecounter *tc)
                    889: {
                    890:        u_int64_t tick;
                    891:
                    892:        __asm __volatile("rd %%tick, %0" : "=r" (tick) :);
                    893:
                    894:        return (tick & ~0u);
                    895: }

CVSweb