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