xref: /netbsd/sys/arch/sparc/sparc/intr.c (revision c4a72b64)
1 /*	$NetBSD: intr.c,v 1.61 2002/12/06 16:04:12 pk Exp $ */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)intr.c	8.3 (Berkeley) 11/11/93
45  */
46 
47 #include "opt_multiprocessor.h"
48 #include "opt_sparc_arch.h"
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/malloc.h>
54 
55 #include <uvm/uvm_extern.h>
56 
57 #include <dev/cons.h>
58 
59 #include <net/netisr.h>
60 
61 #include <machine/cpu.h>
62 #include <machine/ctlreg.h>
63 #include <machine/instr.h>
64 #include <machine/intr.h>
65 #include <machine/trap.h>
66 #include <machine/promlib.h>
67 
68 #include <sparc/sparc/asm.h>
69 #include <sparc/sparc/cpuvar.h>
70 
71 #if defined(MULTIPROCESSOR) && defined(DDB)
72 #include <machine/db_machdep.h>
73 #endif
74 
75 void *softnet_cookie;
76 
77 void	strayintr __P((struct clockframe *));
78 #ifdef DIAGNOSTIC
79 void	bogusintr __P((struct clockframe *));
80 #endif
81 void	softnet __P((void *));
82 
83 /*
84  * Stray interrupt handler.  Clear it if possible.
85  * If not, and if we get 10 interrupts in 10 seconds, panic.
86  * XXXSMP: We are holding the kernel lock at entry & exit.
87  */
88 void
89 strayintr(fp)
90 	struct clockframe *fp;
91 {
92 	static int straytime, nstray;
93 	char bits[64];
94 	int timesince;
95 
96 	printf("stray interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n",
97 		fp->ipl, fp->pc, fp->npc, bitmask_snprintf(fp->psr,
98 		       PSR_BITS, bits, sizeof(bits)));
99 
100 	timesince = time.tv_sec - straytime;
101 	if (timesince <= 10) {
102 		if (++nstray > 10)
103 			panic("crazy interrupts");
104 	} else {
105 		straytime = time.tv_sec;
106 		nstray = 1;
107 	}
108 }
109 
110 
111 #ifdef DIAGNOSTIC
112 /*
113  * Bogus interrupt for which neither hard nor soft interrupt bit in
114  * the IPR was set.
115  */
116 void
117 bogusintr(fp)
118 	struct clockframe *fp;
119 {
120 	char bits[64];
121 
122 	printf("bogus interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n",
123 		fp->ipl, fp->pc, fp->npc, bitmask_snprintf(fp->psr,
124 		       PSR_BITS, bits, sizeof(bits)));
125 }
126 #endif /* DIAGNOSTIC */
127 
128 
129 /*
130  * Process software network interrupts.
131  */
132 void
133 softnet(fp)
134 	void *fp;
135 {
136 	int n, s;
137 
138 	s = splhigh();
139 	n = netisr;
140 	netisr = 0;
141 	splx(s);
142 
143 	if (n == 0)
144 		return;
145 
146 #define DONETISR(bit, fn) do {		\
147 	if (n & (1 << bit))		\
148 		fn();			\
149 	} while (0)
150 
151 #include <net/netisr_dispatch.h>
152 
153 #undef DONETISR
154 }
155 
156 #if defined(SUN4M)
157 void	nmi_hard __P((void));
158 void	nmi_soft __P((struct trapframe *));
159 
160 int	(*memerr_handler) __P((void));
161 int	(*sbuserr_handler) __P((void));
162 int	(*vmeerr_handler) __P((void));
163 int	(*moduleerr_handler) __P((void));
164 
165 #if defined(MULTIPROCESSOR)
166 volatile int nmi_hard_wait = 0;
167 struct simplelock nmihard_lock = SIMPLELOCK_INITIALIZER;
168 #endif
169 
170 void
171 nmi_hard()
172 {
173 	/*
174 	 * A level 15 hard interrupt.
175 	 */
176 	int fatal = 0;
177 	u_int32_t si;
178 	char bits[64];
179 	u_int afsr, afva;
180 
181 	afsr = afva = 0;
182 	if ((*cpuinfo.get_asyncflt)(&afsr, &afva) == 0) {
183 		printf("Async registers (mid %d): afsr=%s; afva=0x%x%x\n",
184 			cpuinfo.mid,
185 			bitmask_snprintf(afsr, AFSR_BITS, bits, sizeof(bits)),
186 			(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
187 	}
188 
189 #if defined(MULTIPROCESSOR)
190 	/*
191 	 * Increase nmi_hard_wait.  If we aren't the master, loop while this
192 	 * variable is non-zero.  If we are the master, loop while this
193 	 * variable is less than the number of cpus.
194 	 */
195 	simple_lock(&nmihard_lock);
196 	nmi_hard_wait++;
197 	simple_unlock(&nmihard_lock);
198 
199 	if (cpuinfo.master == 0) {
200 		while (nmi_hard_wait)
201 			;
202 		return;
203 	} else {
204 		int n = 0;
205 
206 		while (nmi_hard_wait < ncpu)
207 			if (n++ > 100000)
208 				panic("nmi_hard: SMP botch.");
209 	}
210 #endif
211 
212 	/*
213 	 * Examine pending system interrupts.
214 	 */
215 	si = *((u_int32_t *)ICR_SI_PEND);
216 	printf("cpu%d: NMI: system interrupts: %s\n", cpu_number(),
217 		bitmask_snprintf(si, SINTR_BITS, bits, sizeof(bits)));
218 
219 	if ((si & SINTR_M) != 0) {
220 		/* ECC memory error */
221 		if (memerr_handler != NULL)
222 			fatal |= (*memerr_handler)();
223 	}
224 	if ((si & SINTR_I) != 0) {
225 		/* MBus/SBus async error */
226 		if (sbuserr_handler != NULL)
227 			fatal |= (*sbuserr_handler)();
228 	}
229 	if ((si & SINTR_V) != 0) {
230 		/* VME async error */
231 		if (vmeerr_handler != NULL)
232 			fatal |= (*vmeerr_handler)();
233 	}
234 	if ((si & SINTR_ME) != 0) {
235 		/* Module async error */
236 		if (moduleerr_handler != NULL)
237 			fatal |= (*moduleerr_handler)();
238 	}
239 
240 #if defined(MULTIPROCESSOR)
241 	/*
242 	 * Tell everyone else we've finished dealing with the hard NMI.
243 	 */
244 	simple_lock(&nmihard_lock);
245 	nmi_hard_wait = 0;
246 	simple_unlock(&nmihard_lock);
247 #endif
248 
249 	if (fatal)
250 		panic("nmi");
251 }
252 
253 void
254 nmi_soft(tf)
255 	struct trapframe *tf;
256 {
257 
258 #ifdef MULTIPROCESSOR
259 	switch (cpuinfo.msg.tag) {
260 	case XPMSG_SAVEFPU:
261 		savefpstate(cpuinfo.fpproc->p_md.md_fpstate);
262 		cpuinfo.fpproc->p_md.md_fpumid = -1;
263 		cpuinfo.fpproc = NULL;
264 		break;
265 	case XPMSG_PAUSECPU:
266 	    {
267 #if defined(DDB)
268 		db_regs_t regs;
269 
270 		regs.db_tf = *tf;
271 		regs.db_fr = *(struct frame *)tf->tf_out[6];
272 		cpuinfo.ci_ddb_regs = &regs;
273 #endif
274 		cpuinfo.flags |= CPUFLG_PAUSED|CPUFLG_GOTMSG;
275 		while (cpuinfo.flags & CPUFLG_PAUSED)
276 			cpuinfo.cache_flush((caddr_t)&cpuinfo.flags,
277 			    sizeof(cpuinfo.flags));
278 #if defined(DDB)
279 		cpuinfo.ci_ddb_regs = 0;
280 #endif
281 		return;
282 	    }
283 	case XPMSG_FUNC:
284 	    {
285 		struct xpmsg_func *p = &cpuinfo.msg.u.xpmsg_func;
286 
287 		p->retval = (*p->func)(p->arg0, p->arg1, p->arg2, p->arg3);
288 		break;
289 	    }
290 	case XPMSG_VCACHE_FLUSH_PAGE:
291 	    {
292 		struct xpmsg_flush_page *p = &cpuinfo.msg.u.xpmsg_flush_page;
293 		int ctx = getcontext();
294 
295 		setcontext(p->ctx);
296 		cpuinfo.sp_vcache_flush_page(p->va);
297 		setcontext(ctx);
298 		break;
299 	    }
300 	case XPMSG_VCACHE_FLUSH_SEGMENT:
301 	    {
302 		struct xpmsg_flush_segment *p = &cpuinfo.msg.u.xpmsg_flush_segment;
303 		int ctx = getcontext();
304 
305 		setcontext(p->ctx);
306 		cpuinfo.sp_vcache_flush_segment(p->vr, p->vs);
307 		setcontext(ctx);
308 		break;
309 	    }
310 	case XPMSG_VCACHE_FLUSH_REGION:
311 	    {
312 		struct xpmsg_flush_region *p = &cpuinfo.msg.u.xpmsg_flush_region;
313 		int ctx = getcontext();
314 
315 		setcontext(p->ctx);
316 		cpuinfo.sp_vcache_flush_region(p->vr);
317 		setcontext(ctx);
318 		break;
319 	    }
320 	case XPMSG_VCACHE_FLUSH_CONTEXT:
321 	    {
322 		struct xpmsg_flush_context *p = &cpuinfo.msg.u.xpmsg_flush_context;
323 		int ctx = getcontext();
324 
325 		setcontext(p->ctx);
326 		cpuinfo.sp_vcache_flush_context();
327 		setcontext(ctx);
328 		break;
329 	    }
330 	case XPMSG_VCACHE_FLUSH_RANGE:
331 	    {
332 		struct xpmsg_flush_range *p = &cpuinfo.msg.u.xpmsg_flush_range;
333 		int ctx = getcontext();
334 
335 		setcontext(p->ctx);
336 		cpuinfo.sp_cache_flush(p->va, p->size);
337 		setcontext(ctx);
338 		break;
339 	    }
340 	case XPMSG_DEMAP_TLB_PAGE:
341 	    {
342 		struct xpmsg_flush_page *p = &cpuinfo.msg.u.xpmsg_flush_page;
343 		int ctx = getcontext();
344 
345 		setcontext(p->ctx);
346 		tlb_flush_page_real(p->va);
347 		setcontext(ctx);
348 		break;
349 	    }
350 	case XPMSG_DEMAP_TLB_SEGMENT:
351 	    {
352 		struct xpmsg_flush_segment *p = &cpuinfo.msg.u.xpmsg_flush_segment;
353 		int ctx = getcontext();
354 
355 		setcontext(p->ctx);
356 		tlb_flush_segment_real(p->vr, p->vs);
357 		setcontext(ctx);
358 		break;
359 	    }
360 	case XPMSG_DEMAP_TLB_REGION:
361 	    {
362 		struct xpmsg_flush_region *p = &cpuinfo.msg.u.xpmsg_flush_region;
363 		int ctx = getcontext();
364 
365 		setcontext(p->ctx);
366 		tlb_flush_region_real(p->vr);
367 		setcontext(ctx);
368 		break;
369 	    }
370 	case XPMSG_DEMAP_TLB_CONTEXT:
371 	    {
372 		struct xpmsg_flush_context *p = &cpuinfo.msg.u.xpmsg_flush_context;
373 		int ctx = getcontext();
374 
375 		setcontext(p->ctx);
376 		tlb_flush_context_real();
377 		setcontext(ctx);
378 		break;
379 	    }
380 	case XPMSG_DEMAP_TLB_ALL:
381 		tlb_flush_all_real();
382 		break;
383 	}
384 	cpuinfo.flags |= CPUFLG_GOTMSG;
385 #endif
386 }
387 #endif
388 
389 /*
390  * Level 15 interrupts are special, and not vectored here.
391  * Only `prewired' interrupts appear here; boot-time configured devices
392  * are attached via intr_establish() below.
393  */
394 struct intrhand *intrhand[15] = {
395 	NULL,			/*  0 = error */
396 	NULL,			/*  1 = software level 1 + Sbus */
397 	NULL,	 		/*  2 = Sbus level 2 (4m: Sbus L1) */
398 	NULL,			/*  3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/
399 	NULL,			/*  4 = software level 4 (tty softint) (scsi) */
400 	NULL,			/*  5 = Ethernet + Sbus level 4 (4m: Sbus L3) */
401 	NULL,			/*  6 = software level 6 (not used) (4m: enet)*/
402 	NULL,			/*  7 = video + Sbus level 5 */
403 	NULL,			/*  8 = Sbus level 6 */
404 	NULL,			/*  9 = Sbus level 7 */
405 	NULL, 			/* 10 = counter 0 = clock */
406 	NULL,			/* 11 = floppy */
407 	NULL,			/* 12 = zs hardware interrupt */
408 	NULL,			/* 13 = audio chip */
409 	NULL, 			/* 14 = counter 1 = profiling timer */
410 };
411 
412 static int fastvec;		/* marks fast vectors (see below) */
413 #ifdef DIAGNOSTIC
414 extern int sparc_interrupt4m[];
415 extern int sparc_interrupt44c[];
416 #endif
417 
418 /*
419  * Attach an interrupt handler to the vector chain for the given level.
420  * This is not possible if it has been taken away as a fast vector.
421  */
422 void
423 intr_establish(level, classipl, ih)
424 	int level;
425 	int classipl;
426 	struct intrhand *ih;
427 {
428 	struct intrhand **p, *q;
429 #ifdef DIAGNOSTIC
430 	struct trapvec *tv;
431 	int displ;
432 #endif
433 	int s;
434 
435 	s = splhigh();
436 	if (fastvec & (1 << level))
437 		panic("intr_establish: level %d interrupt tied to fast vector",
438 		    level);
439 #ifdef DIAGNOSTIC
440 	/* double check for legal hardware interrupt */
441 	if ((level != 1 && level != 4 && level != 6) || CPU_ISSUN4M) {
442 		tv = &trapbase[T_L1INT - 1 + level];
443 		displ = (CPU_ISSUN4M)
444 			? &sparc_interrupt4m[0] - &tv->tv_instr[1]
445 			: &sparc_interrupt44c[0] - &tv->tv_instr[1];
446 
447 		/* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
448 		if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
449 		    tv->tv_instr[1] != I_BA(0, displ) ||
450 		    tv->tv_instr[2] != I_RDPSR(I_L0))
451 			panic("intr_establish(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x",
452 			    level, ih,
453 			    tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
454 			    I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
455 	}
456 #endif
457 
458 	if (classipl == 0)
459 		classipl = level;
460 
461 	/* A requested IPL cannot exceed its device class level */
462 	if (classipl < level)
463 		panic("intr_establish: class lvl (%d) < pil (%d)\n",
464 			classipl, level);
465 
466 	/* pre-shift to PIL field in %psr */
467 	ih->ih_classipl = (classipl << 8) & PSR_PIL;
468 
469 	/*
470 	 * This is O(N^2) for long chains, but chains are never long
471 	 * and we do want to preserve order.
472 	 */
473 	for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next)
474 		continue;
475 	*p = ih;
476 	ih->ih_next = NULL;
477 	splx(s);
478 }
479 
480 void
481 intr_disestablish(level, ih)
482 	int level;
483 	struct intrhand *ih;
484 {
485 	struct intrhand **p, *q;
486 
487 	for (p = &intrhand[level]; (q = *p) != ih; p = &q->ih_next)
488 		continue;
489 	if (q == NULL)
490 		panic("intr_disestablish: level %d intrhand %p fun %p arg %p",
491 		    level, ih, ih->ih_fun, ih->ih_arg);
492 
493 	*p = q->ih_next;
494 	q->ih_next = NULL;
495 }
496 
497 /*
498  * Like intr_establish, but wires a fast trap vector.  Only one such fast
499  * trap is legal for any interrupt, and it must be a hardware interrupt.
500  */
501 void
502 intr_fasttrap(level, vec)
503 	int level;
504 	void (*vec) __P((void));
505 {
506 	struct trapvec *tv;
507 	u_long hi22, lo10;
508 #ifdef DIAGNOSTIC
509 	int displ;	/* suspenders, belt, and buttons too */
510 #endif
511 	int s;
512 
513 	tv = &trapbase[T_L1INT - 1 + level];
514 	hi22 = ((u_long)vec) >> 10;
515 	lo10 = ((u_long)vec) & 0x3ff;
516 	s = splhigh();
517 	if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL)
518 		panic("intr_fasttrap: already handling level %d interrupts",
519 		    level);
520 #ifdef DIAGNOSTIC
521 	displ = (CPU_ISSUN4M)
522 		? &sparc_interrupt4m[0] - &tv->tv_instr[1]
523 		: &sparc_interrupt44c[0] - &tv->tv_instr[1];
524 
525 	/* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
526 	if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
527 	    tv->tv_instr[1] != I_BA(0, displ) ||
528 	    tv->tv_instr[2] != I_RDPSR(I_L0))
529 		panic("intr_fasttrap(%d, %p)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x",
530 		    level, vec,
531 		    tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
532 		    I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
533 #endif
534 	/* kernel text is write protected -- let us in for a moment */
535 	pmap_changeprot(pmap_kernel(), (vaddr_t)tv,
536 	    VM_PROT_READ|VM_PROT_WRITE, 1);
537 	cpuinfo.cache_flush_all();
538 	tv->tv_instr[0] = I_SETHI(I_L3, hi22);	/* sethi %hi(vec),%l3 */
539 	tv->tv_instr[1] = I_JMPLri(I_G0, I_L3, lo10);/* jmpl %l3+%lo(vec),%g0 */
540 	tv->tv_instr[2] = I_RDPSR(I_L0);	/* mov %psr, %l0 */
541 	pmap_changeprot(pmap_kernel(), (vaddr_t)tv, VM_PROT_READ, 1);
542 	cpuinfo.cache_flush_all();
543 	fastvec |= 1 << level;
544 	splx(s);
545 }
546 
547 /*
548  * softintr_init(): initialise the MI softintr system.
549  */
550 void
551 softintr_init()
552 {
553 
554 	softnet_cookie = softintr_establish(IPL_SOFTNET, softnet, NULL);
555 }
556 
557 /*
558  * softintr_establish(): MI interface.  establish a func(arg) as a
559  * software interrupt.
560  */
561 void *
562 softintr_establish(level, fun, arg)
563 	int level;
564 	void (*fun) __P((void *));
565 	void *arg;
566 {
567 	struct intrhand *ih;
568 
569 	ih = malloc(sizeof(*ih), M_DEVBUF, 0);
570 	bzero(ih, sizeof(*ih));
571 	ih->ih_fun = (int (*) __P((void *)))fun;
572 	ih->ih_arg = arg;
573 	ih->ih_next = 0;
574 	intr_establish(1, level, ih);
575 	return (void *)ih;
576 }
577 
578 /*
579  * softintr_disestablish(): MI interface.  disestablish the specified
580  * software interrupt.
581  */
582 void
583 softintr_disestablish(cookie)
584 	void *cookie;
585 {
586 
587 	intr_disestablish(1, cookie);
588 	free(cookie, M_DEVBUF);
589 }
590 
591 #ifdef MULTIPROCESSOR
592 /*
593  * Called by interrupt stubs, etc., to lock/unlock the kernel.
594  */
595 void
596 intr_lock_kernel()
597 {
598 
599 	KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
600 }
601 
602 void
603 intr_unlock_kernel()
604 {
605 
606 	KERNEL_UNLOCK();
607 }
608 #endif
609