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