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