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

Annotation of sys/arch/sparc/sparc/intr.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: intr.c,v 1.31 2007/05/29 18:10:43 miod Exp $ */
                      2: /*     $NetBSD: intr.c,v 1.20 1997/07/29 09:42:03 fair Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1992, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * This software was developed by the Computer Systems Engineering group
                      9:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     10:  * contributed to Berkeley.
                     11:  *
                     12:  * All advertising materials mentioning features or use of this software
                     13:  * must display the following acknowledgement:
                     14:  *     This product includes software developed by the University of
                     15:  *     California, Lawrence Berkeley Laboratory.
                     16:  *
                     17:  * Redistribution and use in source and binary forms, with or without
                     18:  * modification, are permitted provided that the following conditions
                     19:  * are met:
                     20:  * 1. Redistributions of source code must retain the above copyright
                     21:  *    notice, this list of conditions and the following disclaimer.
                     22:  * 2. Redistributions in binary form must reproduce the above copyright
                     23:  *    notice, this list of conditions and the following disclaimer in the
                     24:  *    documentation and/or other materials provided with the distribution.
                     25:  * 3. Neither the name of the University nor the names of its contributors
                     26:  *    may be used to endorse or promote products derived from this software
                     27:  *    without specific prior written permission.
                     28:  *
                     29:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     30:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     31:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     32:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     33:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     34:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     35:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     36:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     37:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     38:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     39:  * SUCH DAMAGE.
                     40:  *
                     41:  *     @(#)intr.c      8.3 (Berkeley) 11/11/93
                     42:  */
                     43:
                     44: #include <sys/param.h>
                     45: #include <sys/systm.h>
                     46: #include <sys/kernel.h>
                     47: #include <sys/socket.h>
                     48:
                     49: #include <uvm/uvm_extern.h>
                     50:
                     51: #include <dev/cons.h>
                     52:
                     53: #include <net/netisr.h>
                     54: #include <net/if.h>
                     55:
                     56: #include <machine/atomic.h>
                     57: #include <machine/cpu.h>
                     58: #include <machine/ctlreg.h>
                     59: #include <machine/instr.h>
                     60: #include <machine/trap.h>
                     61:
                     62: #include <sparc/sparc/cpuvar.h>
                     63:
                     64: #ifdef INET
                     65: #include <netinet/in.h>
                     66: #include <netinet/if_ether.h>
                     67: #include <netinet/ip_var.h>
                     68: #endif
                     69:
                     70: #ifdef INET6
                     71: # ifndef INET
                     72: #  include <netinet/in.h>
                     73: # endif
                     74: #include <netinet/ip6.h>
                     75: #include <netinet6/ip6_var.h>
                     76: #endif
                     77:
                     78: void   strayintr(struct clockframe *);
                     79: int    soft01intr(void *);
                     80:
                     81: /*
                     82:  * Stray interrupt handler.  Clear it if possible.
                     83:  * If not, and if we get 10 interrupts in 10 seconds, panic.
                     84:  */
                     85: void
                     86: strayintr(fp)
                     87:        struct clockframe *fp;
                     88: {
                     89:        static int straytime, nstray;
                     90:        int timesince;
                     91:
                     92:        printf("stray interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%b\n",
                     93:                fp->ipl, fp->pc, fp->npc, fp->psr, PSR_BITS);
                     94:        timesince = time.tv_sec - straytime;
                     95:        if (timesince <= 10) {
                     96:                if (++nstray > 9)
                     97:                        panic("crazy interrupts");
                     98:        } else {
                     99:                straytime = time.tv_sec;
                    100:                nstray = 1;
                    101:        }
                    102: }
                    103:
                    104: static struct intrhand level10 = { clockintr, NULL, (IPL_CLOCK << 8) };
                    105: static struct intrhand level14 = { statintr, NULL, (IPL_STATCLOCK << 8) };
                    106: union sir sir;
                    107: int netisr;
                    108:
                    109: /*
                    110:  * Level 1 software interrupt (could also be SBus level 1 interrupt).
                    111:  * Three possible reasons:
                    112:  *     ROM console input needed
                    113:  *     Network software interrupt
                    114:  *     Soft clock interrupt
                    115:  */
                    116: int
                    117: soft01intr(fp)
                    118:        void *fp;
                    119: {
                    120:        if (sir.sir_any) {
                    121:                if (sir.sir_which[SIR_NET]) {
                    122:                        int n;
                    123:
                    124:                        sir.sir_which[SIR_NET] = 0;
                    125:                        while ((n = netisr) != 0) {
                    126:                                atomic_clearbits_int(&netisr, n);
                    127:
                    128: #define DONETISR(bit, fn)                                              \
                    129:                                do {                                    \
                    130:                                        if (n & (1 << bit))             \
                    131:                                                fn();                   \
                    132:                                } while (0)
                    133:
                    134: #include <net/netisr_dispatch.h>
                    135:
                    136: #undef DONETISR
                    137:                        }
                    138:                }
                    139:                if (sir.sir_which[SIR_CLOCK]) {
                    140:                        sir.sir_which[SIR_CLOCK] = 0;
                    141:                        softclock();
                    142:                }
                    143:        }
                    144:        return (1);
                    145: }
                    146:
                    147: #if defined(SUN4M)
                    148: void   nmi_hard(void);
                    149: void
                    150: nmi_hard()
                    151: {
                    152:        /*
                    153:          * A level 15 hard interrupt.
                    154:          */
                    155: #ifdef noyet
                    156:        int fatal = 0;
                    157: #endif
                    158:        u_int32_t si;
                    159:        u_int afsr, afva;
                    160:
                    161:        afsr = afva = 0;
                    162:        if ((*cpuinfo.get_asyncflt)(&afsr, &afva) == 0) {
                    163:                printf("Async registers (mid %d): afsr=%b; afva=0x%x%x\n",
                    164:                       cpuinfo.mid, afsr, AFSR_BITS,
                    165:                       (afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
                    166:        }
                    167:
                    168:        if (cpuinfo.master == 0) {
                    169:                /*
                    170:                 * For now, just return.
                    171:                 * Should wait on damage analysis done by the master.
                    172:                 */
                    173:                return;
                    174:        }
                    175:
                    176:        /*
                    177:         * Examine pending system interrupts.
                    178:         */
                    179:        si = *((u_int32_t *)ICR_SI_PEND);
                    180:        printf("NMI: system interrupts: %b\n", si, SINTR_BITS);
                    181:
                    182: #ifdef notyet
                    183:        if ((si & SINTR_M) != 0) {
                    184:                /* ECC memory error */
                    185:                 if (memerr_handler != NULL)
                    186:                         fatal |= (*memerr_handler)();
                    187:         }
                    188:         if ((si & SINTR_I) != 0) {
                    189:                 /* MBus/SBus async error */
                    190:                 if (sbuserr_handler != NULL)
                    191:                         fatal |= (*sbuserr_handler)();
                    192:         }
                    193:         if ((si & SINTR_V) != 0) {
                    194:                 /* VME async error */
                    195:                 if (vmeerr_handler != NULL)
                    196:                         fatal |= (*vmeerr_handler)();
                    197:         }
                    198:         if ((si & SINTR_ME) != 0) {
                    199:                 /* Module async error */
                    200:                 if (moduleerr_handler != NULL)
                    201:                         fatal |= (*moduleerr_handler)();
                    202:         }
                    203:
                    204:         if (fatal)
                    205: #endif
                    206:                 panic("nmi");
                    207: }
                    208: #endif
                    209:
                    210: static struct intrhand level01 = { soft01intr, NULL, (IPL_SOFTINT << 8) };
                    211:
                    212: void
                    213: intr_init()
                    214: {
                    215:        level01.ih_vec = level01.ih_ipl >> 8;
                    216:        evcount_attach(&level01.ih_count, "softintr", &level01.ih_vec,
                    217:            &evcount_intr);
                    218:        level10.ih_vec = level10.ih_ipl >> 8;
                    219:        evcount_attach(&level10.ih_count, "clock", &level10.ih_vec,
                    220:            &evcount_intr);
                    221:        level14.ih_vec = level14.ih_ipl >> 8;
                    222:        evcount_attach(&level14.ih_count, "prof", &level14.ih_vec,
                    223:            &evcount_intr);
                    224: }
                    225:
                    226: /*
                    227:  * Level 15 interrupts are special, and not vectored here.
                    228:  * Only `prewired' interrupts appear here; boot-time configured devices
                    229:  * are attached via intr_establish() below.
                    230:  */
                    231: struct intrhand *intrhand[15] = {
                    232:        NULL,                   /*  0 = error */
                    233:        &level01,               /*  1 = software level 1 + SBus */
                    234:        NULL,                   /*  2 = SBus level 2 (4m: SBus L1) */
                    235:        NULL,                   /*  3 = SCSI + DMA + SBus level 3 (4m: L2,lpt)*/
                    236:        NULL,                   /*  4 = software level 4 (tty softint) (scsi) */
                    237:        NULL,                   /*  5 = Ethernet + SBus level 4 (4m: SBus L3) */
                    238:        NULL,                   /*  6 = software level 6 (not used) (4m: enet)*/
                    239:        NULL,                   /*  7 = video + SBus level 5 */
                    240:        NULL,                   /*  8 = SBus level 6 */
                    241:        NULL,                   /*  9 = SBus level 7 */
                    242:        &level10,               /* 10 = counter 0 = clock */
                    243:        NULL,                   /* 11 = floppy */
                    244:        NULL,                   /* 12 = zs hardware interrupt */
                    245:        NULL,                   /* 13 = audio chip */
                    246:        &level14,               /* 14 = counter 1 = profiling timer */
                    247: };
                    248:
                    249: static int fastvec;            /* marks fast vectors (see below) */
                    250: static struct {
                    251:        int (*cb)(void *);
                    252:        void *data;
                    253: } fastvec_share[15];
                    254:
                    255: extern int sparc_interrupt4m[];
                    256: extern int sparc_interrupt44c[];
                    257:
                    258: /*
                    259:  * Attach an interrupt handler to the vector chain for the given level.
                    260:  * This may not be possible if it has been taken away as a fast vector.
                    261:  */
                    262: void
                    263: intr_establish(level, ih, ipl_block, name)
                    264:        int level;
                    265:        struct intrhand *ih;
                    266:        int ipl_block;
                    267:        const char *name;
                    268: {
                    269:        struct intrhand **p, *q;
                    270: #ifdef DIAGNOSTIC
                    271:        struct trapvec *tv;
                    272:        int displ;
                    273: #endif
                    274:        int s;
                    275:
                    276:        if (ipl_block == -1)
                    277:                ipl_block = level;
                    278:
                    279: #ifdef DIAGNOSTIC
                    280:        /*
                    281:         * If the level we're supposed to block is lower than this interrupts
                    282:         * level someone is doing something very wrong. Most likely it
                    283:         * means that some IPL_ constant in machine/psl.h is preconfigured too
                    284:         * low.
                    285:         */
                    286:        if (ipl_block < level)
                    287:                panic("intr_establish: level (%d) > block (%d)", level,
                    288:                    ipl_block);
                    289:        if (ipl_block > 15)
                    290:                panic("intr_establish: strange block level: %d", ipl_block);
                    291: #endif
                    292:
                    293:        /*
                    294:         * We store the ipl pre-shifted so that we can avoid one instruction
                    295:         * in the interrupt handlers.
                    296:         */
                    297:        ih->ih_vec = ipl_block;
                    298:        ih->ih_ipl = (ipl_block << 8);
                    299:        if (name != NULL)
                    300:                evcount_attach(&ih->ih_count, name, &ih->ih_vec, &evcount_intr);
                    301:
                    302:        s = splhigh();
                    303:
                    304:        /*
                    305:         * Check if this interrupt is already being handled by a fast trap.
                    306:         * If so, attempt to change it back to a regular (thus) shareable
                    307:         * trap.
                    308:         */
                    309:        if (fastvec & (1 << level)) {
                    310:                if (fastvec_share[level].cb == NULL ||
                    311:                    (*fastvec_share[level].cb)(fastvec_share[level].data) != 0)
                    312:                        panic("intr_establish: level %d interrupt tied to fast vector",
                    313:                            level);
                    314:        }
                    315:
                    316: #ifdef DIAGNOSTIC
                    317:        /* double check for legal hardware interrupt */
                    318:        if ((level != 1 && level != 4 && level != 6) || CPU_ISSUN4M ) {
                    319:                tv = &trapbase[T_L1INT - 1 + level];
                    320:                displ = (CPU_ISSUN4M)
                    321:                        ? &sparc_interrupt4m[0] - &tv->tv_instr[1]
                    322:                        : &sparc_interrupt44c[0] - &tv->tv_instr[1];
                    323:
                    324:                /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
                    325:                if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
                    326:                    tv->tv_instr[1] != I_BA(0, displ) ||
                    327:                    tv->tv_instr[2] != I_RDPSR(I_L0))
                    328:                        panic("intr_establish(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x",
                    329:                            level, ih,
                    330:                            tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
                    331:                            I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
                    332:        }
                    333: #endif
                    334:        /*
                    335:         * This is O(N^2) for long chains, but chains are never long
                    336:         * and we do want to preserve order.
                    337:         */
                    338:        for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next)
                    339:                continue;
                    340:        *p = ih;
                    341:        ih->ih_next = NULL;
                    342:        splx(s);
                    343: }
                    344:
                    345: /*
                    346:  * Like intr_establish, but wires a fast trap vector.  Only one such fast
                    347:  * trap is legal for any interrupt, and it must be a hardware interrupt.
                    348:  * In case some other device wants to share the interrupt, we also register
                    349:  * a callback which will be able to revert this and register a slower, but
                    350:  * shareable trap vector if necessary (for example, to share int 13 between
                    351:  * audioamd and stp).
                    352:  */
                    353: int
                    354: intr_fasttrap(int level, void (*vec)(void), int (*share)(void *), void *cbdata)
                    355: {
                    356:        struct trapvec *tv;
                    357:        u_long hi22, lo10;
                    358: #ifdef DIAGNOSTIC
                    359:        int displ;      /* suspenders, belt, and buttons too */
                    360: #endif
                    361:        int s, i;
                    362:        int instr[3];
                    363:        char *instrp;
                    364:        char *tvp;
                    365:
                    366:        tv = &trapbase[T_L1INT - 1 + level];
                    367:        hi22 = ((u_long)vec) >> 10;
                    368:        lo10 = ((u_long)vec) & 0x3ff;
                    369:        s = splhigh();
                    370:
                    371:        /*
                    372:         * If this interrupt is already being handled, fail; the caller will
                    373:         * either panic or try to register a slow (shareable) trap.
                    374:         */
                    375:        if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL) {
                    376:                splx(s);
                    377:                return (EBUSY);
                    378:        }
                    379:
                    380: #ifdef DIAGNOSTIC
                    381:        displ = (CPU_ISSUN4M)
                    382:                ? &sparc_interrupt4m[0] - &tv->tv_instr[1]
                    383:                : &sparc_interrupt44c[0] - &tv->tv_instr[1];
                    384:
                    385:        /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
                    386:        if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
                    387:            tv->tv_instr[1] != I_BA(0, displ) ||
                    388:            tv->tv_instr[2] != I_RDPSR(I_L0))
                    389:                panic("intr_fasttrap(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x",
                    390:                    level, vec,
                    391:                    tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
                    392:                    I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
                    393: #endif
                    394:
                    395:        instr[0] = I_SETHI(I_L3, hi22);         /* sethi %hi(vec),%l3 */
                    396:        instr[1] = I_JMPLri(I_G0, I_L3, lo10);  /* jmpl %l3+%lo(vec),%g0 */
                    397:        instr[2] = I_RDPSR(I_L0);               /* mov %psr, %l0 */
                    398:
                    399:        fastvec_share[level].cb = share;
                    400:        fastvec_share[level].data = cbdata;
                    401:
                    402:        tvp = (char *)tv->tv_instr;
                    403:        instrp = (char *)instr;
                    404:        for (i = 0; i < sizeof(int) * 3; i++, instrp++, tvp++)
                    405:                pmap_writetext(tvp, *instrp);
                    406:        fastvec |= 1 << level;
                    407:        splx(s);
                    408:
                    409:        return (0);
                    410: }
                    411:
                    412: void
                    413: intr_fastuntrap(int level)
                    414: {
                    415:        struct trapvec *tv;
                    416:        int i, s;
                    417:        int displ;
                    418:        int instr[3];
                    419:        char *instrp;
                    420:        char *tvp;
                    421:
                    422:        tv = &trapbase[T_L1INT - 1 + level];
                    423:
                    424:        /* restore to `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
                    425:        displ = (CPU_ISSUN4M)
                    426:                ? &sparc_interrupt4m[0] - &tv->tv_instr[1]
                    427:                : &sparc_interrupt44c[0] - &tv->tv_instr[1];
                    428:        instr[0] = I_MOVi(I_L3, level);
                    429:        instr[1] = I_BA(0, displ);
                    430:        instr[2] = I_RDPSR(I_L0);
                    431:
                    432:        s = splhigh();
                    433:
                    434: #ifdef DIAGNOSTIC
                    435:        if ((fastvec & (1 << level)) == 0) {
                    436:                splx(s);
                    437:                return;
                    438:        }
                    439: #endif
                    440:
                    441:        tvp = (char *)tv->tv_instr;
                    442:        instrp = (char *)instr;
                    443:        for (i = 0; i < sizeof(int) * 3; i++, instrp++, tvp++)
                    444:                pmap_writetext(tvp, *instrp);
                    445:        fastvec &= ~(1 << level);
                    446:        fastvec_share[level].cb = NULL;
                    447:
                    448:        splx(s);
                    449: }
                    450:
                    451: #ifdef DIAGNOSTIC
                    452: void
                    453: splassert_check(int wantipl, const char *func)
                    454: {
                    455:        int oldipl = (getpsr() & PSR_PIL) >> 8;
                    456:
                    457:        if (oldipl < wantipl) {
                    458:                splassert_fail(wantipl, oldipl, func);
                    459:                /*
                    460:                 * If the splassert_ctl is set to not panic, raise the ipl
                    461:                 * in a feeble attempt to reduce damage.
                    462:                 */
                    463:                setpsr((getpsr() & ~PSR_PIL) | wantipl << 8);
                    464:        }
                    465: }
                    466: #endif
                    467:

CVSweb