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