Annotation of sys/arch/alpha/alpha/interrupt.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: interrupt.c,v 1.24 2007/06/17 10:01:25 miod Exp $ */
2: /* $NetBSD: interrupt.c,v 1.46 2000/06/03 20:47:36 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
42: * All rights reserved.
43: *
44: * Authors: Keith Bostic, Chris G. Demetriou
45: *
46: * Permission to use, copy, modify and distribute this software and
47: * its documentation is hereby granted, provided that both the copyright
48: * notice and this permission notice appear in all copies of the
49: * software, derivative works or modified versions, and any portions
50: * thereof, and that both notices appear in supporting documentation.
51: *
52: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
53: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
54: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
55: *
56: * Carnegie Mellon requests users of this software to return to
57: *
58: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
59: * School of Computer Science
60: * Carnegie Mellon University
61: * Pittsburgh PA 15213-3890
62: *
63: * any improvements or extensions that they make and grant Carnegie the
64: * rights to redistribute these changes.
65: */
66: /*
67: * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center.
68: * Redistribute and modify at will, leaving only this additional copyright
69: * notice.
70: */
71:
72: #include <sys/param.h>
73: #include <sys/systm.h>
74: #include <sys/proc.h>
75: #include <sys/vmmeter.h>
76: #include <sys/sched.h>
77: #include <sys/kernel.h>
78: #include <sys/systm.h>
79: #include <sys/device.h>
80: #include <sys/mbuf.h>
81: #include <sys/socket.h>
82: #include <sys/evcount.h>
83:
84: #include <uvm/uvm_extern.h>
85:
86: #include <machine/atomic.h>
87: #include <machine/autoconf.h>
88: #include <machine/cpu.h>
89: #include <machine/reg.h>
90: #include <machine/rpb.h>
91: #include <machine/frame.h>
92: #include <machine/cpuconf.h>
93:
94: #if defined(MULTIPROCESSOR)
95: #include <sys/device.h>
96: #endif
97:
98: #include <net/netisr.h>
99: #include <net/if.h>
100:
101: #ifdef INET
102: #include <netinet/in.h>
103: #include <netinet/if_ether.h>
104: #include <netinet/ip_var.h>
105: #endif
106:
107: #ifdef INET6
108: #ifndef INET
109: #include <netinet/in.h>
110: #endif
111: #include <netinet/ip6.h>
112: #include <netinet6/ip6_var.h>
113: #endif
114:
115: #include "ppp.h"
116: #include "bridge.h"
117:
118: #include "apecs.h"
119: #include "cia.h"
120: #include "lca.h"
121: #include "tcasic.h"
122:
123: static u_int schedclk2;
124:
125: extern struct evcount clk_count;
126:
127: struct scbvec scb_iovectab[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)];
128:
129: void netintr(void);
130:
131: void scb_stray(void *, u_long);
132:
133: void
134: scb_init(void)
135: {
136: u_long i;
137:
138: for (i = 0; i < SCB_NIOVECS; i++) {
139: scb_iovectab[i].scb_func = scb_stray;
140: scb_iovectab[i].scb_arg = NULL;
141: }
142: }
143:
144: void
145: scb_stray(void *arg, u_long vec)
146: {
147:
148: printf("WARNING: stray interrupt, vector 0x%lx\n", vec);
149: }
150:
151: void
152: scb_set(u_long vec, void (*func)(void *, u_long), void *arg)
153: {
154: u_long idx;
155: int s;
156:
157: s = splhigh();
158:
159: if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
160: (vec & (SCB_VECSIZE - 1)) != 0)
161: panic("scb_set: bad vector 0x%lx", vec);
162:
163: idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
164:
165: if (scb_iovectab[idx].scb_func != scb_stray)
166: panic("scb_set: vector 0x%lx already occupied", vec);
167:
168: scb_iovectab[idx].scb_func = func;
169: scb_iovectab[idx].scb_arg = arg;
170:
171: splx(s);
172: }
173:
174: u_long
175: scb_alloc(void (*func)(void *, u_long), void *arg)
176: {
177: u_long vec, idx;
178: int s;
179:
180: s = splhigh();
181:
182: /*
183: * Allocate "downwards", to avoid bumping into
184: * interrupts which are likely to be at the lower
185: * vector numbers.
186: */
187: for (vec = SCB_SIZE - SCB_VECSIZE;
188: vec >= SCB_IOVECBASE; vec -= SCB_VECSIZE) {
189: idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
190: if (scb_iovectab[idx].scb_func == scb_stray) {
191: scb_iovectab[idx].scb_func = func;
192: scb_iovectab[idx].scb_arg = arg;
193: splx(s);
194: return (vec);
195: }
196: }
197:
198: splx(s);
199:
200: return (SCB_ALLOC_FAILED);
201: }
202:
203: void
204: scb_free(u_long vec)
205: {
206: u_long idx;
207: int s;
208:
209: s = splhigh();
210:
211: if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
212: (vec & (SCB_VECSIZE - 1)) != 0)
213: panic("scb_free: bad vector 0x%lx", vec);
214:
215: idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
216:
217: if (scb_iovectab[idx].scb_func == scb_stray)
218: panic("scb_free: vector 0x%lx is empty", vec);
219:
220: scb_iovectab[idx].scb_func = scb_stray;
221: scb_iovectab[idx].scb_arg = (void *) vec;
222:
223: splx(s);
224: }
225:
226: void
227: interrupt(unsigned long a0, unsigned long a1, unsigned long a2,
228: struct trapframe *framep)
229: {
230: struct proc *p;
231: struct cpu_info *ci = curcpu();
232: extern int schedhz;
233:
234: switch (a0) {
235: case ALPHA_INTR_XPROC: /* interprocessor interrupt */
236: #if defined(MULTIPROCESSOR)
237: {
238: u_long pending_ipis, bit;
239:
240: #if 0
241: printf("CPU %lu got IPI\n", cpu_id);
242: #endif
243:
244: #ifdef DIAGNOSTIC
245: if (ci->ci_dev == NULL) {
246: /* XXX panic? */
247: printf("WARNING: no device for ID %lu\n", ci->ci_cpuid);
248: return;
249: }
250: #endif
251:
252: pending_ipis = atomic_loadlatch_ulong(&ci->ci_ipis, 0);
253: for (bit = 0; bit < ALPHA_NIPIS; bit++)
254: if (pending_ipis & (1UL << bit))
255: (*ipifuncs[bit])();
256:
257: /*
258: * Handle inter-console messages if we're the primary
259: * CPU.
260: */
261: if (ci->ci_cpuid == hwrpb->rpb_primary_cpu_id &&
262: hwrpb->rpb_txrdy != 0)
263: cpu_iccb_receive();
264: }
265: #else
266: printf("WARNING: received interprocessor interrupt!\n");
267: #endif /* MULTIPROCESSOR */
268: break;
269:
270: case ALPHA_INTR_CLOCK: /* clock interrupt */
271: #if defined(MULTIPROCESSOR)
272: /* XXX XXX XXX */
273: if (CPU_IS_PRIMARY(ci) == 0)
274: return;
275: #endif
276: uvmexp.intrs++;
277: clk_count.ec_count++;
278: if (platform.clockintr) {
279: /*
280: * Call hardclock(). This will also call
281: * statclock(). On the primary CPU, it
282: * will also deal with time-of-day stuff.
283: */
284: (*platform.clockintr)((struct clockframe *)framep);
285:
286: /*
287: * If it's time to call the scheduler clock,
288: * do so.
289: */
290: if ((++schedclk2 & 0x3f) == 0 &&
291: (p = ci->ci_curproc) != NULL && schedhz != 0)
292: schedclock(p);
293: }
294: break;
295:
296: case ALPHA_INTR_ERROR: /* Machine Check or Correctable Error */
297: a0 = alpha_pal_rdmces();
298: if (platform.mcheck_handler)
299: (*platform.mcheck_handler)(a0, framep, a1, a2);
300: else
301: machine_check(a0, framep, a1, a2);
302: break;
303:
304: case ALPHA_INTR_DEVICE: /* I/O device interrupt */
305: {
306: struct scbvec *scb;
307:
308: KDASSERT(a1 >= SCB_IOVECBASE && a1 < SCB_SIZE);
309:
310: #if defined(MULTIPROCESSOR)
311: /* XXX XXX XXX */
312: if (CPU_IS_PRIMARY(ci) == 0)
313: return;
314: #endif
315: uvmexp.intrs++;
316:
317: scb = &scb_iovectab[SCB_VECTOIDX(a1 - SCB_IOVECBASE)];
318: (*scb->scb_func)(scb->scb_arg, a1);
319: break;
320: }
321:
322: case ALPHA_INTR_PERF: /* performance counter interrupt */
323: printf("WARNING: received performance counter interrupt!\n");
324: break;
325:
326: case ALPHA_INTR_PASSIVE:
327: #if 0
328: printf("WARNING: received passive release interrupt vec "
329: "0x%lx\n", a1);
330: #endif
331: break;
332:
333: default:
334: printf("unexpected interrupt: type 0x%lx vec 0x%lx "
335: "a2 0x%lx"
336: #if defined(MULTIPROCESSOR)
337: " cpu %lu"
338: #endif
339: "\n", a0, a1, a2
340: #if defined(MULTIPROCESSOR)
341: , ci->ci_cpuid
342: #endif
343: );
344: panic("interrupt");
345: /* NOTREACHED */
346: }
347: }
348:
349: void
350: machine_check(unsigned long mces, struct trapframe *framep,
351: unsigned long vector, unsigned long param)
352: {
353: const char *type;
354: struct mchkinfo *mcp;
355:
356: mcp = &curcpu()->ci_mcinfo;
357: /* Make sure it's an error we know about. */
358: if ((mces & (ALPHA_MCES_MIP|ALPHA_MCES_SCE|ALPHA_MCES_PCE)) == 0) {
359: type = "fatal machine check or error (unknown type)";
360: goto fatal;
361: }
362:
363: /* Machine checks. */
364: if (mces & ALPHA_MCES_MIP) {
365: /* If we weren't expecting it, then we punt. */
366: if (!mcp->mc_expected) {
367: type = "unexpected machine check";
368: goto fatal;
369: }
370: mcp->mc_expected = 0;
371: mcp->mc_received = 1;
372: }
373:
374: /* System correctable errors. */
375: if (mces & ALPHA_MCES_SCE)
376: printf("Warning: received system correctable error.\n");
377:
378: /* Processor correctable errors. */
379: if (mces & ALPHA_MCES_PCE)
380: printf("Warning: received processor correctable error.\n");
381:
382: /* Clear pending machine checks and correctable errors */
383: alpha_pal_wrmces(mces);
384: return;
385:
386: fatal:
387: /* Clear pending machine checks and correctable errors */
388: alpha_pal_wrmces(mces);
389:
390: printf("\n");
391: printf("%s:\n", type);
392: printf("\n");
393: printf(" mces = 0x%lx\n", mces);
394: printf(" vector = 0x%lx\n", vector);
395: printf(" param = 0x%lx\n", param);
396: printf(" pc = 0x%lx\n", framep->tf_regs[FRAME_PC]);
397: printf(" ra = 0x%lx\n", framep->tf_regs[FRAME_RA]);
398: printf(" curproc = %p\n", curproc);
399: if (curproc != NULL)
400: printf(" pid = %d, comm = %s\n", curproc->p_pid,
401: curproc->p_comm);
402: printf("\n");
403: panic("machine check");
404: }
405:
406: #if NAPECS > 0 || NCIA > 0 || NLCA > 0 || NTCASIC > 0
407:
408: int
409: badaddr(void *addr, size_t size)
410: {
411: return(badaddr_read(addr, size, NULL));
412: }
413:
414: int
415: badaddr_read(void *addr, size_t size, void *rptr)
416: {
417: struct mchkinfo *mcp = &curcpu()->ci_mcinfo;
418: long rcpt;
419: int rv;
420:
421: /* Get rid of any stale machine checks that have been waiting. */
422: alpha_pal_draina();
423:
424: /* Tell the trap code to expect a machine check. */
425: mcp->mc_received = 0;
426: mcp->mc_expected = 1;
427:
428: /* Read from the test address, and make sure the read happens. */
429: alpha_mb();
430: switch (size) {
431: case sizeof (u_int8_t):
432: rcpt = *(volatile u_int8_t *)addr;
433: break;
434:
435: case sizeof (u_int16_t):
436: rcpt = *(volatile u_int16_t *)addr;
437: break;
438:
439: case sizeof (u_int32_t):
440: rcpt = *(volatile u_int32_t *)addr;
441: break;
442:
443: case sizeof (u_int64_t):
444: rcpt = *(volatile u_int64_t *)addr;
445: break;
446:
447: default:
448: panic("badaddr: invalid size (%ld)", size);
449: }
450: alpha_mb();
451: alpha_mb(); /* MAGIC ON SOME SYSTEMS */
452:
453: /* Make sure we took the machine check, if we caused one. */
454: alpha_pal_draina();
455:
456: /* disallow further machine checks */
457: mcp->mc_expected = 0;
458:
459: rv = mcp->mc_received;
460: mcp->mc_received = 0;
461:
462: /*
463: * And copy back read results (if no fault occurred).
464: */
465: if (rptr && rv == 0) {
466: switch (size) {
467: case sizeof (u_int8_t):
468: *(volatile u_int8_t *)rptr = rcpt;
469: break;
470:
471: case sizeof (u_int16_t):
472: *(volatile u_int16_t *)rptr = rcpt;
473: break;
474:
475: case sizeof (u_int32_t):
476: *(volatile u_int32_t *)rptr = rcpt;
477: break;
478:
479: case sizeof (u_int64_t):
480: *(volatile u_int64_t *)rptr = rcpt;
481: break;
482: }
483: }
484: /* Return non-zero (i.e. true) if it's a bad address. */
485: return (rv);
486: }
487:
488: #endif /* NAPECS > 0 || NCIA > 0 || NLCA > 0 || NTCASIC > 0 */
489:
490: int netisr;
491:
492: void
493: netintr()
494: {
495: int n;
496:
497: while ((n = netisr) != 0) {
498: atomic_clearbits_int(&netisr, n);
499:
500: #define DONETISR(bit, fn) \
501: do { \
502: if (n & (1 << (bit))) \
503: fn(); \
504: } while (0)
505:
506: #include <net/netisr_dispatch.h>
507:
508: #undef DONETISR
509: }
510: }
511:
512: struct alpha_soft_intr alpha_soft_intrs[SI_NSOFT];
513:
514: /* XXX For legacy software interrupts. */
515: struct alpha_soft_intrhand *softnet_intrhand, *softclock_intrhand;
516:
517: /*
518: * softintr_init:
519: *
520: * Initialize the software interrupt system.
521: */
522: void
523: softintr_init()
524: {
525: struct alpha_soft_intr *asi;
526: int i;
527:
528: for (i = 0; i < SI_NSOFT; i++) {
529: asi = &alpha_soft_intrs[i];
530: TAILQ_INIT(&asi->softintr_q);
531: simple_lock_init(&asi->softintr_slock);
532: asi->softintr_siq = i;
533: }
534:
535: /* XXX Establish legacy software interrupt handlers. */
536: softnet_intrhand = softintr_establish(IPL_SOFTNET,
537: (void (*)(void *))netintr, NULL);
538: softclock_intrhand = softintr_establish(IPL_SOFTCLOCK,
539: (void (*)(void *))softclock, NULL);
540: }
541:
542: /*
543: * softintr_dispatch:
544: *
545: * Process pending software interrupts.
546: */
547: void
548: softintr_dispatch()
549: {
550: struct alpha_soft_intr *asi;
551: struct alpha_soft_intrhand *sih;
552: u_int64_t n, i;
553:
554: while ((n = atomic_loadlatch_ulong(&ssir, 0)) != 0) {
555: for (i = 0; i < SI_NSOFT; i++) {
556: if ((n & (1 << i)) == 0)
557: continue;
558:
559: asi = &alpha_soft_intrs[i];
560:
561: for (;;) {
562: (void) alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
563: simple_lock(&asi->softintr_slock);
564:
565: sih = TAILQ_FIRST(&asi->softintr_q);
566: if (sih != NULL) {
567: TAILQ_REMOVE(&asi->softintr_q, sih,
568: sih_q);
569: sih->sih_pending = 0;
570: }
571:
572: simple_unlock(&asi->softintr_slock);
573: (void) alpha_pal_swpipl(ALPHA_PSL_IPL_SOFT);
574:
575: if (sih == NULL)
576: break;
577:
578: uvmexp.softs++;
579: (*sih->sih_fn)(sih->sih_arg);
580: }
581: }
582: }
583: }
584:
585: static int
586: ipl2si(int ipl)
587: {
588: int si;
589:
590: switch (ipl) {
591: case IPL_TTY: /* XXX */
592: case IPL_SOFTSERIAL:
593: si = SI_SOFTSERIAL;
594: break;
595: case IPL_SOFTNET:
596: si = SI_SOFTNET;
597: break;
598: case IPL_SOFTCLOCK:
599: si = SI_SOFTCLOCK;
600: break;
601: case IPL_SOFT:
602: si = SI_SOFT;
603: break;
604: default:
605: panic("ipl2si: %d", ipl);
606: }
607: return si;
608: }
609:
610: /*
611: * softintr_establish: [interface]
612: *
613: * Register a software interrupt handler.
614: */
615: void *
616: softintr_establish(int ipl, void (*func)(void *), void *arg)
617: {
618: struct alpha_soft_intr *asi;
619: struct alpha_soft_intrhand *sih;
620: int si;
621:
622: si = ipl2si(ipl);
623: asi = &alpha_soft_intrs[si];
624:
625: sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
626: if (__predict_true(sih != NULL)) {
627: sih->sih_intrhead = asi;
628: sih->sih_fn = func;
629: sih->sih_arg = arg;
630: sih->sih_pending = 0;
631: }
632: return (sih);
633: }
634:
635: /*
636: * softintr_disestablish: [interface]
637: *
638: * Unregister a software interrupt handler.
639: */
640: void
641: softintr_disestablish(void *arg)
642: {
643: struct alpha_soft_intrhand *sih = arg;
644: struct alpha_soft_intr *asi = sih->sih_intrhead;
645: int s;
646:
647: s = splhigh();
648: simple_lock(&asi->softintr_slock);
649: if (sih->sih_pending) {
650: TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
651: sih->sih_pending = 0;
652: }
653: simple_unlock(&asi->softintr_slock);
654: splx(s);
655:
656: free(sih, M_DEVBUF);
657: }
658:
659: int
660: _splraise(int s)
661: {
662: int cur = alpha_pal_rdps() & ALPHA_PSL_IPL_MASK;
663: return (s > cur ? alpha_pal_swpipl(s) : cur);
664: }
665:
666: #ifdef DIAGNOSTIC
667: void
668: splassert_check(int wantipl, const char *func)
669: {
670: int curipl = alpha_pal_rdps() & ALPHA_PSL_IPL_MASK;
671:
672: /*
673: * Tell soft interrupts apart from regular levels.
674: */
675: if (wantipl < 0)
676: wantipl = IPL_SOFTINT;
677:
678: /*
679: * Depending on the system, hardware interrupts may occur either
680: * at level 3 or level 4. Avoid false positives in the former case.
681: */
682: if (curipl == ALPHA_PSL_IPL_IO - 1)
683: curipl = ALPHA_PSL_IPL_IO;
684:
685: if (curipl < wantipl) {
686: splassert_fail(wantipl, curipl, func);
687: /*
688: * If splassert_ctl is set to not panic, raise the ipl
689: * in a feeble attempt to reduce damage.
690: */
691: alpha_pal_swpipl(wantipl);
692: }
693: }
694: #endif
CVSweb