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