xref: /netbsd/sys/arch/sparc/sparc/intr.c (revision 0849ceb0)
1 /*	$NetBSD: intr.c,v 1.127 2021/01/24 07:36:54 mrg 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. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)intr.c	8.3 (Berkeley) 11/11/93
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.127 2021/01/24 07:36:54 mrg Exp $");
45 
46 #include "opt_multiprocessor.h"
47 #include "opt_sparc_arch.h"
48 #include "sx.h"
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/kmem.h>
54 #include <sys/cpu.h>
55 #include <sys/intr.h>
56 #include <sys/atomic.h>
57 
58 #include <uvm/uvm_extern.h>
59 
60 #include <dev/cons.h>
61 
62 #include <machine/ctlreg.h>
63 #include <machine/instr.h>
64 #include <machine/trap.h>
65 #include <machine/promlib.h>
66 #include <machine/locore.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 #if NSX > 0
76 #include <sys/bus.h>
77 #include <sparc/dev/sxvar.h>
78 #endif
79 
80 #if defined(MULTIPROCESSOR)
81 static int intr_biglock_wrapper(void *);
82 
83 void *xcall_cookie;
84 #endif
85 
86 void	strayintr(struct clockframe *);
87 #ifdef DIAGNOSTIC
88 void	bogusintr(struct clockframe *);
89 #endif
90 
91 /*
92  * Stray interrupt handler.  Clear it if possible.
93  * If not, and if we get 10 interrupts in 10 seconds, panic.
94  * XXXSMP: We are holding the kernel lock at entry & exit.
95  */
96 void
strayintr(struct clockframe * fp)97 strayintr(struct clockframe *fp)
98 {
99 	static int straytime, nstray;
100 	char bits[64];
101 	int timesince;
102 
103 #if defined(MULTIPROCESSOR)
104 	/*
105 	 * XXX
106 	 *
107 	 * Don't whine about zs interrupts on MP.  We sometimes get
108 	 * stray interrupts when polled kernel output on cpu>0 eats
109 	 * the interrupt and cpu0 sees it.
110 	 */
111 #define ZS_INTR_IPL	12
112 	if (fp->ipl == ZS_INTR_IPL)
113 		return;
114 #endif
115 
116 	snprintb(bits, sizeof(bits), PSR_BITS, fp->psr);
117 	printf("stray interrupt cpu%d ipl 0x%x pc=0x%x npc=0x%x psr=%s\n",
118 	    cpu_number(), fp->ipl, fp->pc, fp->npc, bits);
119 
120 	timesince = time_uptime - straytime;
121 	if (timesince <= 10) {
122 		if (++nstray > 10)
123 			panic("crazy interrupts");
124 	} else {
125 		straytime = time_uptime;
126 		nstray = 1;
127 	}
128 }
129 
130 
131 #ifdef DIAGNOSTIC
132 /*
133  * Bogus interrupt for which neither hard nor soft interrupt bit in
134  * the IPR was set.
135  */
136 void
bogusintr(struct clockframe * fp)137 bogusintr(struct clockframe *fp)
138 {
139 	char bits[64];
140 
141 #if defined(MULTIPROCESSOR)
142 	/*
143 	 * XXX as above.
144 	 */
145 	if (fp->ipl == ZS_INTR_IPL)
146 		return;
147 #endif
148 
149 	snprintb(bits, sizeof(bits), PSR_BITS, fp->psr);
150 	printf("cpu%d: bogus interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n",
151 	    cpu_number(), fp->ipl, fp->pc, fp->npc, bits);
152 }
153 #endif /* DIAGNOSTIC */
154 
155 /*
156  * Get module ID of interrupt target.
157  */
158 u_int
getitr(void)159 getitr(void)
160 {
161 #if defined(MULTIPROCESSOR)
162 	u_int v;
163 
164 	if (!CPU_ISSUN4M || sparc_ncpus <= 1)
165 		return (0);
166 
167 	v = *((u_int *)ICR_ITR);
168 	return (v + 8);
169 #else
170 	return (0);
171 #endif
172 }
173 
174 /*
175  * Set interrupt target.
176  * Return previous value.
177  */
178 u_int
setitr(u_int mid)179 setitr(u_int mid)
180 {
181 #if defined(MULTIPROCESSOR)
182 	u_int v;
183 
184 	if (!CPU_ISSUN4M || sparc_ncpus <= 1)
185 		return (0);
186 
187 	v = *((u_int *)ICR_ITR);
188 	*((u_int *)ICR_ITR) = CPU_MID2CPUNO(mid);
189 	return (v + 8);
190 #else
191 	return (0);
192 #endif
193 }
194 
195 #if (defined(SUN4M) && !defined(MSIIEP)) || defined(SUN4D)
196 void	nmi_hard(void);
197 void	nmi_soft(struct trapframe *);
198 
199 int	(*memerr_handler)(void);
200 int	(*sbuserr_handler)(void);
201 int	(*vmeerr_handler)(void);
202 int	(*moduleerr_handler)(void);
203 
204 #if defined(MULTIPROCESSOR)
205 static volatile u_int	nmi_hard_wait = 0;
206 int			drop_into_rom_on_fatal = 1;
207 #endif
208 
209 void
nmi_hard(void)210 nmi_hard(void)
211 {
212 	/*
213 	 * A level 15 hard interrupt.
214 	 */
215 	int fatal = 0;
216 	uint32_t si;
217 	char bits[64];
218 	u_int afsr, afva;
219 
220 	/* Tally */
221 	cpuinfo.ci_intrcnt[15].ev_count++;
222 	cpuinfo.ci_data.cpu_nintr++;
223 
224 	afsr = afva = 0;
225 	if ((*cpuinfo.get_asyncflt)(&afsr, &afva) == 0) {
226 		snprintb(bits, sizeof(bits), AFSR_BITS, afsr);
227 		printf("Async registers (mid %d): afsr=%s; afva=0x%x%x\n",
228 			cpuinfo.mid, bits,
229 			(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
230 	}
231 
232 #if defined(MULTIPROCESSOR)
233 	/*
234 	 * Increase nmi_hard_wait.  If we aren't the master, loop while this
235 	 * variable is non-zero.  If we are the master, loop while this
236 	 * variable is less than the number of cpus.
237 	 */
238 	atomic_inc_uint(&nmi_hard_wait);
239 
240 	if (cpuinfo.master == 0) {
241 		while (nmi_hard_wait)
242 			;
243 		return;
244 	} else {
245 		int n = 100000;
246 
247 		while (nmi_hard_wait < sparc_ncpus) {
248 			DELAY(1);
249 			if (n-- > 0)
250 				continue;
251 			printf("nmi_hard: SMP botch.\n");
252 			break;
253 		}
254 	}
255 #endif
256 
257 	/*
258 	 * Examine pending system interrupts.
259 	 */
260 	si = *((uint32_t *)ICR_SI_PEND);
261 	snprintb(bits, sizeof(bits), SINTR_BITS, si);
262 	printf("cpu%d: NMI: system interrupts: %s\n", cpu_number(), bits);
263 
264 #if NSX > 0
265 	sx_dump();
266 #endif
267 
268 	if ((si & SINTR_M) != 0) {
269 		/* ECC memory error */
270 		if (memerr_handler != NULL)
271 			fatal |= (*memerr_handler)();
272 	}
273 	if ((si & SINTR_I) != 0) {
274 		/* MBus/SBus async error */
275 		if (sbuserr_handler != NULL)
276 			fatal |= (*sbuserr_handler)();
277 	}
278 	if ((si & SINTR_V) != 0) {
279 		/* VME async error */
280 		if (vmeerr_handler != NULL)
281 			fatal |= (*vmeerr_handler)();
282 	}
283 	if ((si & SINTR_ME) != 0) {
284 		/* Module async error */
285 		if (moduleerr_handler != NULL)
286 			fatal |= (*moduleerr_handler)();
287 	}
288 
289 #if defined(MULTIPROCESSOR)
290 	/*
291 	 * Tell everyone else we've finished dealing with the hard NMI.
292 	 */
293 	nmi_hard_wait = 0;
294 	if (fatal && drop_into_rom_on_fatal) {
295 		prom_abort();
296 		return;
297 	}
298 #endif
299 
300 	if (fatal)
301 		panic("nmi");
302 }
303 
304 /*
305  * Non-maskable soft interrupt level 15 handler
306  */
307 void
nmi_soft(struct trapframe * tf)308 nmi_soft(struct trapframe *tf)
309 {
310 
311 	/* Tally */
312 	cpuinfo.ci_sintrcnt[15].ev_count++;
313 	cpuinfo.ci_data.cpu_nintr++;
314 
315 	if (cpuinfo.mailbox) {
316 		/* Check PROM messages */
317 		uint8_t msg = *(uint8_t *)cpuinfo.mailbox;
318 		switch (msg) {
319 		case OPENPROM_MBX_STOP:
320 		case OPENPROM_MBX_WD:
321 			/* In case there's an xcall in progress (unlikely) */
322 			spl0();
323 #ifdef MULTIPROCESSOR
324 			cpu_ready_mask &= ~(1 << cpu_number());
325 #endif
326 			prom_cpustop(0);
327 			break;
328 		case OPENPROM_MBX_ABORT:
329 		case OPENPROM_MBX_BPT:
330 			prom_cpuidle(0);
331 			/*
332 			 * We emerge here after someone does a
333 			 * prom_resumecpu(ournode).
334 			 */
335 			return;
336 		default:
337 			break;
338 		}
339 	}
340 
341 #if defined(MULTIPROCESSOR)
342 	switch (cpuinfo.msg_lev15.tag) {
343 	case XPMSG15_PAUSECPU:
344 		/* XXX - assumes DDB is the only user of mp_pause_cpu() */
345 		cpuinfo.flags |= CPUFLG_PAUSED;
346 #if defined(DDB)
347 		/* trap(T_DBPAUSE) */
348 		__asm("ta 0x8b");
349 #else
350 		while (cpuinfo.flags & CPUFLG_PAUSED)
351 			/* spin */;
352 #endif /* DDB */
353 	}
354 	cpuinfo.msg_lev15.tag = 0;
355 #endif /* MULTIPROCESSOR */
356 }
357 
358 #if defined(MULTIPROCESSOR)
359 /*
360  * Respond to an xcall() request from another CPU.
361  *
362  * This is also called directly from xcall() if we notice an
363  * incoming message while we're waiting to grab the xpmsg_lock.
364  * We pass the address of xcallintr() itself to indicate that
365  * this is not a real interrupt.
366  */
367 void
xcallintr(void * v)368 xcallintr(void *v)
369 {
370 
371 	kpreempt_disable();
372 
373 	/* Tally */
374 	if (v != xcallintr)
375 		cpuinfo.ci_sintrcnt[13].ev_count++;
376 
377 	/*
378 	 * This happens when the remote CPU is slow at responding and the
379 	 * caller gave up, and has given up the mutex.
380 	 */
381 	if (mutex_owned(&xpmsg_mutex) == 0) {
382 		cpuinfo.ci_xpmsg_mutex_not_held.ev_count++;
383 #ifdef DEBUG
384 		printf("%s: cpu%d mutex not held\n", __func__, cpu_number());
385 #endif
386 		cpuinfo.msg.complete = 1;
387 		kpreempt_enable();
388 		return;
389 	}
390 
391 	if (cpuinfo.msg.complete != 0) {
392 		cpuinfo.ci_xpmsg_bogus.ev_count++;
393 #ifdef DEBUG
394 		volatile struct xpmsg_func *p = &cpuinfo.msg.u.xpmsg_func;
395 		printf("%s: bogus message %08x %08x %08x %08x\n", __func__,
396 		    cpuinfo.msg.tag, (uint32_t)p->func, p->arg0, p->arg1);
397 #endif
398 		kpreempt_enable();
399 		return;
400 	}
401 
402 	/* notyet - cpuinfo.msg.received = 1; */
403 	switch (cpuinfo.msg.tag) {
404 	case XPMSG_FUNC:
405 	    {
406 		volatile struct xpmsg_func *p = &cpuinfo.msg.u.xpmsg_func;
407 
408 		if (p->func)
409 			(*p->func)(p->arg0, p->arg1, p->arg2);
410 		break;
411 	    }
412 	}
413 	cpuinfo.msg.tag = 0;
414 	cpuinfo.msg.complete = 1;
415 
416 	kpreempt_enable();
417 }
418 #endif /* MULTIPROCESSOR */
419 #endif /* SUN4M || SUN4D */
420 
421 
422 #ifdef MSIIEP
423 /*
424  * It's easier to make this separate so that not to further obscure
425  * SUN4M case with more ifdefs.  There's no common functionality
426  * anyway.
427  */
428 
429 #include <sparc/sparc/msiiepreg.h>
430 
431 void	nmi_hard_msiiep(void);
432 void	nmi_soft_msiiep(void);
433 
434 
435 void
nmi_hard_msiiep(void)436 nmi_hard_msiiep(void)
437 {
438 	uint32_t si;
439 	char bits[128];
440 	int fatal = 0;
441 
442 	si = mspcic_read_4(pcic_sys_ipr);
443 	snprintb(bits, sizeof(bits), MSIIEP_SYS_IPR_BITS, si);
444 	printf("NMI: system interrupts: %s\n", bits);
445 
446 
447 	if (si & MSIIEP_SYS_IPR_MEM_FAULT) {
448 		uint32_t afsr, afar, mfsr, mfar;
449 
450 		afar = *(volatile uint32_t *)MSIIEP_AFAR;
451 		afsr = *(volatile uint32_t *)MSIIEP_AFSR;
452 
453 		mfar = *(volatile uint32_t *)MSIIEP_MFAR;
454 		mfsr = *(volatile uint32_t *)MSIIEP_MFSR;
455 
456 		if (afsr & MSIIEP_AFSR_ERR) {
457 			snprintb(bits, sizeof(bits), MSIIEP_AFSR_BITS, afsr);
458 			printf("async fault: afsr=%s; afar=%08x\n", bits, afar);
459 		}
460 
461 		if (mfsr & MSIIEP_MFSR_ERR) {
462 			snprintb(bits, sizeof(bits), MSIIEP_MFSR_BITS, mfsr);
463 			printf("mem fault: mfsr=%s; mfar=%08x\n", bits, mfar);
464 		}
465 
466 		fatal = 0;
467 	}
468 
469 	if (si & MSIIEP_SYS_IPR_SERR) {	/* XXX */
470 		printf("serr#\n");
471 		fatal = 0;
472 	}
473 
474 	if (si & MSIIEP_SYS_IPR_DMA_ERR) {
475 		printf("dma: %08x\n",
476 		       mspcic_read_stream_4(pcic_iotlb_err_addr));
477 		fatal = 0;
478 	}
479 
480 	if (si & MSIIEP_SYS_IPR_PIO_ERR) {
481 		printf("pio: addr=%08x, cmd=%x stat=%04x\n",
482 		       mspcic_read_stream_4(pcic_pio_err_addr),
483 		       mspcic_read_stream_1(pcic_pio_err_cmd),
484 		       mspcic_read_stream_2(pcic_stat));
485 		fatal = 0;
486 	}
487 
488 	if (fatal)
489 		panic("nmi");
490 
491 	/* Clear the NMI if it was PCIC related */
492 	mspcic_write_1(pcic_sys_ipr_clr, MSIIEP_SYS_IPR_CLR_ALL);
493 }
494 
495 
496 void
nmi_soft_msiiep(void)497 nmi_soft_msiiep(void)
498 {
499 
500 	panic("soft nmi");
501 }
502 
503 #endif /* MSIIEP */
504 
505 
506 /*
507  * Level 15 interrupts are special, and not vectored here.
508  * Only `prewired' interrupts appear here; boot-time configured devices
509  * are attached via intr_establish() below.
510  */
511 struct intrhand *intrhand[15] = {
512 	NULL,			/*  0 = error */
513 	NULL,			/*  1 = software level 1 + Sbus */
514 	NULL,	 		/*  2 = Sbus level 2 (4m: Sbus L1) */
515 	NULL,			/*  3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/
516 	NULL,			/*  4 = software level 4 (tty softint) (scsi) */
517 	NULL,			/*  5 = Ethernet + Sbus level 4 (4m: Sbus L3) */
518 	NULL,			/*  6 = software level 6 (not used) (4m: enet)*/
519 	NULL,			/*  7 = video + Sbus level 5 */
520 	NULL,			/*  8 = Sbus level 6 */
521 	NULL,			/*  9 = Sbus level 7 */
522 	NULL, 			/* 10 = counter 0 = clock */
523 	NULL,			/* 11 = floppy */
524 	NULL,			/* 12 = zs hardware interrupt */
525 	NULL,			/* 13 = audio chip */
526 	NULL, 			/* 14 = counter 1 = profiling timer */
527 };
528 
529 /*
530  * Soft interrupts use a separate set of handler chains.
531  * This is necessary since soft interrupt handlers do not return a value
532  * and therefore cannot be mixed with hardware interrupt handlers on a
533  * shared handler chain.
534  */
535 struct intrhand *sintrhand[15] = { NULL };
536 
537 static void
ih_insert(struct intrhand ** head,struct intrhand * ih)538 ih_insert(struct intrhand **head, struct intrhand *ih)
539 {
540 	struct intrhand **p, *q;
541 	/*
542 	 * This is O(N^2) for long chains, but chains are never long
543 	 * and we do want to preserve order.
544 	 */
545 	for (p = head; (q = *p) != NULL; p = &q->ih_next)
546 		continue;
547 	*p = ih;
548 	ih->ih_next = NULL;
549 }
550 
551 static void
ih_remove(struct intrhand ** head,struct intrhand * ih)552 ih_remove(struct intrhand **head, struct intrhand *ih)
553 {
554 	struct intrhand **p, *q;
555 
556 	for (p = head; (q = *p) != ih; p = &q->ih_next)
557 		continue;
558 	if (q == NULL)
559 		panic("intr_remove: intrhand %p fun %p arg %p",
560 			ih, ih->ih_fun, ih->ih_arg);
561 
562 	*p = q->ih_next;
563 	q->ih_next = NULL;
564 }
565 
566 static int fastvec;		/* marks fast vectors (see below) */
567 
568 #ifdef DIAGNOSTIC
569 static void
check_tv(int level)570 check_tv(int level)
571 {
572 	struct trapvec *tv;
573 	int displ;
574 
575 	/* double check for legal hardware interrupt */
576 	tv = &trapbase[T_L1INT - 1 + level];
577 	displ = (CPU_ISSUN4M || CPU_ISSUN4D)
578 		? &sparc_interrupt4m[0] - &tv->tv_instr[1]
579 		: &sparc_interrupt44c[0] - &tv->tv_instr[1];
580 
581 	/* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */
582 	if (tv->tv_instr[0] != I_MOVi(I_L3, level) ||
583 	    tv->tv_instr[1] != I_BA(0, displ) ||
584 	    tv->tv_instr[2] != I_RDPSR(I_L0))
585 		panic("intr_establish(%d)\n0x%x 0x%x 0x%x != 0x%x 0x%x 0x%x",
586 		    level,
587 		    tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2],
588 		    I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0));
589 }
590 #endif
591 
592 /*
593  * Wire a fast trap vector.  Only one such fast trap is legal for any
594  * interrupt, and it must be a hardware interrupt.
595  */
596 static void
inst_fasttrap(int level,void (* vec)(void))597 inst_fasttrap(int level, void (*vec)(void))
598 {
599 	struct trapvec *tv;
600 	u_long hi22, lo10;
601 	int s;
602 
603 	if (CPU_ISSUN4 || CPU_ISSUN4C) {
604 		/* Can't wire to softintr slots */
605 		if (level == 1 || level == 4 || level == 6)
606 			return;
607 	}
608 
609 #ifdef DIAGNOSTIC
610 	check_tv(level);
611 #endif
612 
613 	tv = &trapbase[T_L1INT - 1 + level];
614 	hi22 = ((u_long)vec) >> 10;
615 	lo10 = ((u_long)vec) & 0x3ff;
616 	s = splhigh();
617 
618 	/* kernel text is write protected -- let us in for a moment */
619 	pmap_kprotect((vaddr_t)tv & -PAGE_SIZE, PAGE_SIZE,
620 	    VM_PROT_READ|VM_PROT_WRITE);
621 	cpuinfo.cache_flush_all();
622 	tv->tv_instr[0] = I_SETHI(I_L3, hi22);	/* sethi %hi(vec),%l3 */
623 	tv->tv_instr[1] = I_JMPLri(I_G0, I_L3, lo10);/* jmpl %l3+%lo(vec),%g0 */
624 	tv->tv_instr[2] = I_RDPSR(I_L0);	/* mov %psr, %l0 */
625 	pmap_kprotect((vaddr_t)tv & -PAGE_SIZE, PAGE_SIZE, VM_PROT_READ);
626 	cpuinfo.cache_flush_all();
627 	fastvec |= 1 << level;
628 	splx(s);
629 }
630 
631 /*
632  * Uninstall a fast trap handler.
633  */
634 static void
uninst_fasttrap(int level)635 uninst_fasttrap(int level)
636 {
637 	struct trapvec *tv;
638 	int displ;	/* suspenders, belt, and buttons too */
639 	int s;
640 
641 	tv = &trapbase[T_L1INT - 1 + level];
642 	s = splhigh();
643 	displ = (CPU_ISSUN4M || CPU_ISSUN4D)
644 		? &sparc_interrupt4m[0] - &tv->tv_instr[1]
645 		: &sparc_interrupt44c[0] - &tv->tv_instr[1];
646 
647 	/* kernel text is write protected -- let us in for a moment */
648 	pmap_kprotect((vaddr_t)tv & -PAGE_SIZE, PAGE_SIZE,
649 	    VM_PROT_READ|VM_PROT_WRITE);
650 	cpuinfo.cache_flush_all();
651 	tv->tv_instr[0] = I_MOVi(I_L3, level);
652 	tv->tv_instr[1] = I_BA(0, displ);
653 	tv->tv_instr[2] = I_RDPSR(I_L0);
654 	pmap_kprotect((vaddr_t)tv & -PAGE_SIZE, PAGE_SIZE, VM_PROT_READ);
655 	cpuinfo.cache_flush_all();
656 	fastvec &= ~(1 << level);
657 	splx(s);
658 }
659 
660 /*
661  * Attach an interrupt handler to the vector chain for the given level.
662  * This is not possible if it has been taken away as a fast vector.
663  */
664 void
intr_establish(int level,int classipl,struct intrhand * ih,void (* vec)(void),bool maybe_mpsafe)665 intr_establish(int level, int classipl,
666 	       struct intrhand *ih, void (*vec)(void),
667 	       bool maybe_mpsafe)
668 {
669 	int s = splhigh();
670 #ifdef MULTIPROCESSOR
671 	bool mpsafe;
672 #endif /* MULTIPROCESSOR */
673 	if (classipl == 0)
674 		classipl = level;
675 
676 #ifdef MULTIPROCESSOR
677 	mpsafe = (classipl != IPL_VM) || maybe_mpsafe;
678 #endif
679 
680 #ifdef DIAGNOSTIC
681 	if (CPU_ISSUN4C) {
682 		/*
683 		 * Check reserved softintr slots on SUN4C only.
684 		 * No check for SUN4, as 4/300's have
685 		 * esp0 at level 4 and le0 at level 6.
686 		 */
687 		if (level == 1 || level == 4 || level == 6)
688 			panic("intr_establish: reserved softintr level");
689 	}
690 #endif
691 
692 	/*
693 	 * If a `fast vector' is currently tied to this level, we must
694 	 * first undo that.
695 	 */
696 	if (fastvec & (1 << level)) {
697 		printf("intr_establish: untie fast vector at level %d\n",
698 		    level);
699 		uninst_fasttrap(level);
700 	} else if (vec != NULL &&
701 		   intrhand[level] == NULL && sintrhand[level] == NULL) {
702 		inst_fasttrap(level, vec);
703 	}
704 
705 	/* A requested IPL cannot exceed its device class level */
706 	if (classipl < level)
707 		panic("intr_establish: class lvl (%d) < pil (%d)\n",
708 			classipl, level);
709 
710 	/* pre-shift to PIL field in %psr */
711 	ih->ih_classipl = (classipl << 8) & PSR_PIL;
712 
713 #ifdef MULTIPROCESSOR
714 	if (!mpsafe) {
715 		ih->ih_realfun = ih->ih_fun;
716 		ih->ih_realarg = ih->ih_arg;
717 		ih->ih_fun = intr_biglock_wrapper;
718 		ih->ih_arg = ih;
719 	}
720 #endif /* MULTIPROCESSOR */
721 
722 	ih_insert(&intrhand[level], ih);
723 	splx(s);
724 }
725 
726 void
intr_disestablish(int level,struct intrhand * ih)727 intr_disestablish(int level, struct intrhand *ih)
728 {
729 
730 	ih_remove(&intrhand[level], ih);
731 }
732 
733 /*
734  * This is a softintr cookie.  NB that sic_pilreq MUST be the
735  * first element in the struct, because the softintr_schedule()
736  * macro in intr.h casts cookies to int * to get it.  On a
737  * sun4m, sic_pilreq is an actual processor interrupt level that
738  * is passed to raise(), and on a sun4 or sun4c sic_pilreq is a
739  * bit to set in the interrupt enable register with ienab_bis().
740  */
741 struct softintr_cookie {
742 	int sic_pilreq;		/* CPU-specific bits; MUST be first! */
743 	int sic_pil;		/* Actual machine PIL that is used */
744 	struct intrhand sic_hand;
745 };
746 
747 /*
748  * softintr_init(): initialise the MI softintr system.
749  */
750 void
sparc_softintr_init(void)751 sparc_softintr_init(void)
752 {
753 
754 #if defined(MULTIPROCESSOR) && (defined(SUN4M) || defined(SUN4D))
755 	/* Establish a standard soft interrupt handler for cross calls */
756 	xcall_cookie = sparc_softintr_establish(13, xcallintr, NULL);
757 #endif
758 }
759 
760 /*
761  * softintr_establish(): MI interface.  establish a func(arg) as a
762  * software interrupt.
763  */
764 void *
sparc_softintr_establish(int level,void (* fun)(void *),void * arg)765 sparc_softintr_establish(int level, void (*fun)(void *), void *arg)
766 {
767 	struct softintr_cookie *sic;
768 	struct intrhand *ih;
769 	int pilreq;
770 	int pil;
771 #ifdef MULTIPROCESSOR
772 	bool mpsafe = (level != IPL_VM);
773 #endif /* MULTIPROCESSOR */
774 
775 	/*
776 	 * On a sun4m, the processor interrupt level is stored
777 	 * in the softintr cookie to be passed to raise().
778 	 *
779 	 * On a sun4 or sun4c the appropriate bit to set
780 	 * in the interrupt enable register is stored in
781 	 * the softintr cookie to be passed to ienab_bis().
782 	 */
783 	pil = pilreq = level;
784 	if (CPU_ISSUN4 || CPU_ISSUN4C) {
785 		/* Select the most suitable of three available softint levels */
786 		if (level >= 1 && level < 4) {
787 			pil = 1;
788 			pilreq = IE_L1;
789 		} else if (level >= 4 && level < 6) {
790 			pil = 4;
791 			pilreq = IE_L4;
792 		} else {
793 			pil = 6;
794 			pilreq = IE_L6;
795 		}
796 	}
797 
798 	sic = kmem_alloc(sizeof(*sic), KM_SLEEP);
799 	sic->sic_pil = pil;
800 	sic->sic_pilreq = pilreq;
801 	ih = &sic->sic_hand;
802 #ifdef MULTIPROCESSOR
803 	if (!mpsafe) {
804 		ih->ih_realfun = (int (*)(void *))fun;
805 		ih->ih_realarg = arg;
806 		ih->ih_fun = intr_biglock_wrapper;
807 		ih->ih_arg = ih;
808 	} else
809 #endif /* MULTIPROCESSOR */
810 	{
811 		ih->ih_fun = (int (*)(void *))fun;
812 		ih->ih_arg = arg;
813 	}
814 
815 	/*
816 	 * Always run the handler at the requested level, which might
817 	 * be higher than the hardware can provide.
818 	 *
819 	 * pre-shift to PIL field in %psr
820 	 */
821 	ih->ih_classipl = (level << 8) & PSR_PIL;
822 
823 	if (fastvec & (1 << pil)) {
824 		printf("softintr_establish: untie fast vector at level %d\n",
825 		    pil);
826 		uninst_fasttrap(level);
827 	}
828 
829 	ih_insert(&sintrhand[pil], ih);
830 	return (void *)sic;
831 }
832 
833 /*
834  * softintr_disestablish(): MI interface.  disestablish the specified
835  * software interrupt.
836  */
837 void
sparc_softintr_disestablish(void * cookie)838 sparc_softintr_disestablish(void *cookie)
839 {
840 	struct softintr_cookie *sic = cookie;
841 
842 	ih_remove(&sintrhand[sic->sic_pil], &sic->sic_hand);
843 	kmem_free(sic, sizeof(*sic));
844 }
845 
846 #if 0
847 void
848 sparc_softintr_schedule(void *cookie)
849 {
850 	struct softintr_cookie *sic = cookie;
851 	if (CPU_ISSUN4M || CPU_ISSUN4D) {
852 #if defined(SUN4M) || defined(SUN4D)
853 		raise(0, sic->sic_pilreq);
854 #endif
855 	} else {
856 #if defined(SUN4) || defined(SUN4C)
857 		ienab_bis(sic->sic_pilreq);
858 #endif
859 	}
860 }
861 #endif
862 
863 #ifdef MULTIPROCESSOR
864 
865 /*
866  * intr_biglock_wrapper: grab biglock and call a real interrupt handler.
867  */
868 
869 static int
intr_biglock_wrapper(void * vp)870 intr_biglock_wrapper(void *vp)
871 {
872 	struct intrhand *ih = vp;
873 	int ret;
874 
875 	KERNEL_LOCK(1, NULL);
876 
877 	ret = (*ih->ih_realfun)(ih->ih_realarg);
878 
879 	KERNEL_UNLOCK_ONE(NULL);
880 
881 	return ret;
882 }
883 #endif /* MULTIPROCESSOR */
884 
885 bool
cpu_intr_p(void)886 cpu_intr_p(void)
887 {
888 
889 	/*
890 	 * cpuinfo is the same VA on every CPU.  Even if preempted it will
891 	 * give the correct answer.
892 	 */
893 	return cpuinfo.ci_idepth != 0;
894 }
895