1 /*        $NetBSD: intr.c,v 1.37 2025/02/17 11:14:49 jmcneill Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #define __INTR_PRIVATE
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.37 2025/02/17 11:14:49 jmcneill Exp $");
33 
34 #ifdef _KERNEL_OPT
35 #include "opt_interrupt.h"
36 #include "opt_multiprocessor.h"
37 #include "opt_pic.h"
38 #include "opt_ppcarch.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/cpu.h>
43 #include <sys/kernel.h>
44 #include <sys/kmem.h>
45 #include <sys/interrupt.h>
46 
47 #include <powerpc/psl.h>
48 #include <powerpc/pic/picvar.h>
49 
50 #if defined(PIC_I8259) || defined (PIC_PREPIVR)
51 #include <machine/isa_machdep.h>
52 #endif
53 
54 #ifdef MULTIPROCESSOR
55 #include <powerpc/pic/ipivar.h>
56 #endif
57 
58 #ifdef __HAVE_FAST_SOFTINTS
59 #include <powerpc/softint.h>
60 #endif
61 
62 #define MAX_PICS    8         /* 8 PICs ought to be enough for everyone */
63 
64 #define   PIC_VIRQ_LEGAL_P(x) ((u_int)(x) < NVIRQ)
65 
66 #if defined(PPC_IBM4XX) && !defined(PPC_IBM440)
67 /* eieio is implemented as sync */
68 #define REORDER_PROTECT() __asm volatile("sync" ::: "memory")
69 #else
70 #define REORDER_PROTECT() __asm volatile("sync; eieio" ::: "memory")
71 #endif
72 
73 struct pic_ops *pics[MAX_PICS];
74 int num_pics = 0;
75 int max_base = 0;
76 uint8_t   virq_map[NIRQ];
77 imask_t virq_mask = HWIRQ_MASK;
78 static imask_t imask[NIPL];
79 int       primary_pic = 0;
80 
81 static int          fakeintr(void *);
82 static int          mapirq(int);
83 static void         intr_calculatemasks(void);
84 static struct pic_ops *find_pic_by_hwirq(int);
85 
86 static struct intr_source intrsources[NVIRQ];
87 
88 void
pic_init(void)89 pic_init(void)
90 {
91           /* everything is in bss, no reason to zero it. */
92 }
93 
94 int
pic_add(struct pic_ops * pic)95 pic_add(struct pic_ops *pic)
96 {
97 
98           if (num_pics >= MAX_PICS)
99                     return -1;
100 
101           pics[num_pics] = pic;
102           pic->pic_intrbase = max_base;
103           max_base += pic->pic_numintrs;
104           num_pics++;
105 
106           return pic->pic_intrbase;
107 }
108 
109 void
pic_finish_setup(void)110 pic_finish_setup(void)
111 {
112           for (size_t i = 0; i < num_pics; i++) {
113                     struct pic_ops * const pic = pics[i];
114                     if (pic->pic_finish_setup != NULL)
115                               pic->pic_finish_setup(pic);
116           }
117 }
118 
119 static struct pic_ops *
find_pic_by_hwirq(int hwirq)120 find_pic_by_hwirq(int hwirq)
121 {
122           for (u_int base = 0; base < num_pics; base++) {
123                     struct pic_ops * const pic = pics[base];
124                     if (pic->pic_intrbase <= hwirq
125                         && hwirq < pic->pic_intrbase + pic->pic_numintrs) {
126                               return pic;
127                     }
128           }
129           return NULL;
130 }
131 
132 static int
fakeintr(void * arg)133 fakeintr(void *arg)
134 {
135 
136           return 0;
137 }
138 
139 /*
140  * Register an interrupt handler.
141  */
142 void *
intr_establish(int hwirq,int type,int ipl,int (* ih_fun)(void *),void * ih_arg)143 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
144     void *ih_arg)
145 {
146           return intr_establish_xname(hwirq, type, ipl, ih_fun, ih_arg, NULL);
147 }
148 
149 void *
intr_establish_xname(int hwirq,int type,int ipl,int (* ih_fun)(void *),void * ih_arg,const char * xname)150 intr_establish_xname(int hwirq, int type, int ipl, int (*ih_fun)(void *),
151     void *ih_arg, const char *xname)
152 {
153           struct intrhand **p, *q, *ih;
154           struct pic_ops *pic;
155           static struct intrhand fakehand;
156           int maxipl = ipl;
157 
158           if (maxipl == IPL_NONE)
159                     maxipl = IPL_HIGH;
160 
161           if (hwirq >= max_base) {
162                     panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
163                         max_base - 1);
164           }
165 
166           pic = find_pic_by_hwirq(hwirq);
167           if (pic == NULL) {
168                     panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
169           }
170 
171           const int virq = mapirq(hwirq);
172 
173           /* no point in sleeping unless someone can free memory. */
174           ih = kmem_intr_alloc(sizeof(*ih), cold ? KM_NOSLEEP : KM_SLEEP);
175           if (ih == NULL)
176                     panic("intr_establish: can't allocate handler info");
177 
178           if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE)
179                     panic("intr_establish: bogus irq (%d) or type (%d)",
180                         hwirq, type);
181 
182           struct intr_source * const is = &intrsources[virq];
183           const bool cascaded = ih_fun == pic_handle_intr;
184 
185           switch (is->is_type) {
186           case IST_NONE:
187                     is->is_type = type;
188                     is->is_cascaded = cascaded;
189                     break;
190           case IST_EDGE_FALLING:
191           case IST_EDGE_RISING:
192           case IST_LEVEL_LOW:
193           case IST_LEVEL_HIGH:
194                     if (type == is->is_type)
195                               break;
196                     /* FALLTHROUGH */
197           case IST_PULSE:
198                     if (type != IST_NONE) {
199                               panic("intr_establish: can't share %s with %s",
200                                   intr_typename(is->is_type),
201                                   intr_typename(type));
202                     }
203                     if (cascaded != is->is_cascaded) {
204                               panic("intr_establish: can't share cascaded with "
205                                   "non-cascaded interrupt");
206                     }
207                     break;
208           }
209           if (is->is_hand == NULL) {
210                     snprintf(is->is_intrid, sizeof(is->is_intrid), "%s irq %d",
211                         pic->pic_name, is->is_hwirq);
212                     snprintf(is->is_evname, sizeof(is->is_evname), "irq %d",
213                         is->is_hwirq);
214                     evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
215                         pic->pic_name, is->is_evname);
216           }
217 
218           /*
219            * Figure out where to put the handler.
220            * This is O(N^2), but we want to preserve the order, and N is
221            * generally small.
222            */
223           for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
224                     maxipl = uimax(maxipl, q->ih_ipl);
225           }
226 
227           /*
228            * Actually install a fake handler momentarily, since we might be doing
229            * this with interrupts enabled and don't want the real routine called
230            * until masking is set up.
231            */
232           fakehand.ih_ipl = ipl;
233           fakehand.ih_fun = fakeintr;
234           *p = &fakehand;
235 
236           /*
237            * Poke the real handler in now.
238            */
239           ih->ih_fun = ih_fun;
240           ih->ih_arg = ih_arg;
241           ih->ih_next = NULL;
242           ih->ih_ipl = ipl;
243           ih->ih_virq = virq;
244           strlcpy(ih->ih_xname, xname != NULL ? xname : "unknown",
245               sizeof(ih->ih_xname));
246           *p = ih;
247 
248           if (pic->pic_establish_irq != NULL)
249                     pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
250                         is->is_type, maxipl);
251 
252           /*
253            * Remember the highest IPL used by this handler.
254            */
255           is->is_ipl = maxipl;
256 
257           /*
258            * now that the handler is established we're actually ready to
259            * calculate the masks
260            */
261           intr_calculatemasks();
262 
263           return ih;
264 }
265 
266 void
dummy_pic_establish_intr(struct pic_ops * pic,int irq,int type,int pri)267 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
268 {
269 }
270 
271 /*
272  * Deregister an interrupt handler.
273  */
274 void
intr_disestablish(void * arg)275 intr_disestablish(void *arg)
276 {
277           struct intrhand * const ih = arg;
278           const int virq = ih->ih_virq;
279           struct intr_source * const is = &intrsources[virq];
280           struct intrhand **p, **q;
281           int maxipl = IPL_NONE;
282 
283           if (!PIC_VIRQ_LEGAL_P(virq))
284                     panic("intr_disestablish: bogus virq %d", virq);
285 
286           /*
287            * Remove the handler from the chain.
288            * This is O(n^2), too.
289            */
290           for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) {
291                     struct intrhand * const tmp_ih = *p;
292                     if (tmp_ih == ih) {
293                               q = p;
294                     } else {
295                               maxipl = uimax(maxipl, tmp_ih->ih_ipl);
296                     }
297           }
298           if (q)
299                     *q = ih->ih_next;
300           else
301                     panic("intr_disestablish: handler not registered");
302           kmem_intr_free((void *)ih, sizeof(*ih));
303 
304           /*
305            * Reset the IPL for this source now that we've removed a handler.
306            */
307           is->is_ipl = maxipl;
308 
309           intr_calculatemasks();
310 
311           if (is->is_hand == NULL) {
312                     is->is_type = IST_NONE;
313                     evcnt_detach(&is->is_ev);
314                     /*
315                      * Make the virutal IRQ available again.
316                      */
317                     virq_map[virq] = 0;
318                     virq_mask |= PIC_VIRQ_TO_MASK(virq);
319           }
320 }
321 
322 /*
323  * Map max_base irqs into 32 (bits).
324  */
325 static int
mapirq(int hwirq)326 mapirq(int hwirq)
327 {
328           struct pic_ops *pic;
329 
330           if (hwirq >= max_base)
331                     panic("invalid irq %d", hwirq);
332 
333           if ((pic = find_pic_by_hwirq(hwirq)) == NULL)
334                     panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq);
335 
336           if (virq_map[hwirq])
337                     return virq_map[hwirq];
338 
339           if (virq_mask == 0)
340                     panic("virq overflow");
341 
342           const int virq = PIC_VIRQ_MS_PENDING(virq_mask);
343           struct intr_source * const is = intrsources + virq;
344 
345           virq_mask &= ~PIC_VIRQ_TO_MASK(virq);
346 
347           is->is_hwirq = hwirq;
348           is->is_pic = pic;
349           virq_map[hwirq] = virq;
350 #ifdef PIC_DEBUG
351           printf("mapping hwirq %d to virq %d\n", hwirq, virq);
352 #endif
353           return virq;
354 }
355 
356 static const char * const intr_typenames[] = {
357    [IST_NONE]  = "none",
358    [IST_PULSE] = "pulsed",
359    [IST_EDGE_FALLING]  = "falling edge triggered",
360    [IST_EDGE_RISING]  = "rising edge triggered",
361    [IST_LEVEL_LOW] = "low level triggered",
362    [IST_LEVEL_HIGH] = "high level triggered",
363 };
364 
365 const char *
intr_typename(int type)366 intr_typename(int type)
367 {
368           KASSERT((unsigned int) type < __arraycount(intr_typenames));
369           KASSERT(intr_typenames[type] != NULL);
370           return intr_typenames[type];
371 }
372 
373 /*
374  * Recalculate the interrupt masks from scratch.
375  * We could code special registry and deregistry versions of this function that
376  * would be faster, but the code would be nastier, and we don't expect this to
377  * happen very much anyway.
378  */
379 static void
intr_calculatemasks(void)380 intr_calculatemasks(void)
381 {
382           imask_t newmask[NIPL];
383           struct intr_source *is;
384           struct intrhand *ih;
385           int irq;
386 
387           for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) {
388                     newmask[ipl] = 0;
389           }
390 
391           /* First, figure out which ipl each IRQ uses. */
392           for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
393                     for (ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
394                               newmask[ih->ih_ipl] |= PIC_VIRQ_TO_MASK(irq);
395                     }
396           }
397 
398           /*
399            * IPL_NONE is used for hardware interrupts that are never blocked,
400            * and do not block anything else.
401            */
402           newmask[IPL_NONE] = 0;
403 
404           /*
405            * strict hierarchy - all IPLs block everything blocked by any lower
406            * IPL
407            */
408           for (u_int ipl = 1; ipl < NIPL; ipl++) {
409                     newmask[ipl] |= newmask[ipl - 1];
410           }
411 
412 #ifdef PIC_DEBUG
413           for (u_int ipl = 0; ipl < NIPL; ipl++) {
414                     printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]);
415           }
416 #endif
417 
418           /*
419            * Disable all interrupts.
420            */
421           for (u_int base = 0; base < num_pics; base++) {
422                     struct pic_ops * const pic = pics[base];
423                     for (u_int i = 0; i < pic->pic_numintrs; i++) {
424                               pic->pic_disable_irq(pic, i);
425                     }
426           }
427 
428           /*
429            * Now that all interrupts are disabled, update the ipl masks.
430            */
431           for (u_int ipl = 0; ipl < NIPL; ipl++) {
432                     imask[ipl] = newmask[ipl];
433           }
434 
435           /*
436            * Lastly, enable IRQs actually in use.
437            */
438           for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
439                     if (is->is_hand)
440                               pic_enable_irq(is->is_hwirq);
441           }
442 }
443 
444 void
pic_enable_irq(int hwirq)445 pic_enable_irq(int hwirq)
446 {
447           struct pic_ops * const pic = find_pic_by_hwirq(hwirq);
448           if (pic == NULL)
449                     panic("%s: bogus IRQ %d", __func__, hwirq);
450           const int type = intrsources[virq_map[hwirq]].is_type;
451           (*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type);
452 }
453 
454 void
pic_mark_pending(int hwirq)455 pic_mark_pending(int hwirq)
456 {
457           struct cpu_info * const ci = curcpu();
458 
459           const int virq = virq_map[hwirq];
460           if (virq == 0)
461                     printf("IRQ %d maps to 0\n", hwirq);
462 
463           const register_t msr = mfmsr();
464           mtmsr(msr & ~PSL_EE);
465           ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq);
466           mtmsr(msr);
467 }
468 
469 static void
intr_deliver(struct intr_source * is,int virq)470 intr_deliver(struct intr_source *is, int virq)
471 {
472           bool locked = false;
473           for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
474                     KASSERTMSG(ih->ih_fun != NULL,
475                         "%s: irq %d, hwirq %d, is %p ih %p: "
476                          "NULL interrupt handler!\n", __func__,
477                          virq, is->is_hwirq, is, ih);
478                     if (ih->ih_ipl == IPL_VM) {
479                               if (!locked) {
480                                         KERNEL_LOCK(1, NULL);
481                                         locked = true;
482                               }
483                     } else if (locked) {
484                               KERNEL_UNLOCK_ONE(NULL);
485                               locked = false;
486                     }
487                     (*ih->ih_fun)(ih->ih_arg);
488           }
489           if (locked) {
490                     KERNEL_UNLOCK_ONE(NULL);
491           }
492           is->is_ev.ev_count++;
493 }
494 
495 void
pic_do_pending_int(void)496 pic_do_pending_int(void)
497 {
498           struct cpu_info * const ci = curcpu();
499           imask_t vpend;
500 
501           if (ci->ci_iactive)
502                     return;
503 
504           ci->ci_iactive = 1;
505 
506           const register_t emsr = mfmsr();
507           const register_t dmsr = emsr & ~PSL_EE;
508 
509           KASSERT(emsr & PSL_EE);
510           mtmsr(dmsr);
511 
512           const int pcpl = ci->ci_cpl;
513 #ifdef __HAVE_FAST_SOFTINTS
514 again:
515 #endif
516 
517           /* Do now unmasked pendings */
518           while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) {
519                     ci->ci_idepth++;
520                     KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0);
521 
522                     /* Get most significant pending bit */
523                     const int virq = PIC_VIRQ_MS_PENDING(vpend);
524                     ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq);
525 
526                     struct intr_source * const is = &intrsources[virq];
527                     struct pic_ops * const pic = is->is_pic;
528 
529                     if (!is->is_cascaded) {
530                               splraise(is->is_ipl);
531                               mtmsr(emsr);
532                     }
533                     intr_deliver(is, virq);
534                     if (!is->is_cascaded) {
535                               mtmsr(dmsr);
536                               ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
537                     }
538 
539                     pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase,
540                         is->is_type);
541                     ci->ci_idepth--;
542           }
543 
544 #ifdef __HAVE_FAST_SOFTINTS
545           const u_int softints = ci->ci_data.cpu_softints &
546                                          (IPL_SOFTMASK << pcpl);
547 
548           /* make sure there are no bits to screw with the line above */
549           KASSERT((ci->ci_data.cpu_softints & ~IPL_SOFTMASK) == 0);
550 
551           if (__predict_false(softints != 0)) {
552                     ci->ci_cpl = IPL_HIGH;
553                     mtmsr(emsr);
554                     powerpc_softint(ci, pcpl,
555                         (vaddr_t)__builtin_return_address(0));
556                     mtmsr(dmsr);
557                     ci->ci_cpl = pcpl;
558                     if (__predict_false(ci->ci_ipending & ~imask[pcpl]))
559                               goto again;
560           }
561 #endif
562 
563           ci->ci_iactive = 0;
564           mtmsr(emsr);
565 }
566 
567 int
pic_handle_intr(void * cookie)568 pic_handle_intr(void *cookie)
569 {
570           struct pic_ops *pic = cookie;
571           struct cpu_info *ci = curcpu();
572           int picirq;
573 
574           const register_t msr = mfmsr();
575           const int pcpl = ci->ci_cpl;
576 
577           mtmsr(msr & ~PSL_EE);
578 
579           picirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
580           if (picirq == 255) {
581                     mtmsr(msr);
582                     return 0;
583           }
584 
585           do {
586                     const int virq = virq_map[picirq + pic->pic_intrbase];
587 
588                     KASSERT(virq != 0);
589                     KASSERT(picirq < pic->pic_numintrs);
590                     imask_t v_imen = PIC_VIRQ_TO_MASK(virq);
591                     struct intr_source * const is = &intrsources[virq];
592 
593                     if ((imask[pcpl] & v_imen) != 0) {
594                               ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */
595                               pic->pic_disable_irq(pic, picirq);
596                     } else {
597                               /* this interrupt is no longer pending */
598                               ci->ci_ipending &= ~v_imen;
599                               ci->ci_idepth++;
600 
601                               if (!is->is_cascaded) {
602                                         splraise(is->is_ipl);
603                                         mtmsr(msr | PSL_EE);
604                               }
605                               intr_deliver(is, virq);
606                               if (!is->is_cascaded) {
607                                         mtmsr(msr & ~PSL_EE);
608                                         ci->ci_cpl = pcpl;
609                               }
610 
611                               ci->ci_data.cpu_nintr++;
612                               ci->ci_idepth--;
613                     }
614                     pic->pic_ack_irq(pic, picirq);
615           } while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255);
616 
617           mtmsr(msr | PSL_EE);
618           splx(pcpl);         /* Process pendings. */
619           mtmsr(msr);
620 
621           return 0;
622 }
623 
624 void
pic_ext_intr(void)625 pic_ext_intr(void)
626 {
627 
628           KASSERT(pics[primary_pic] != NULL);
629           pic_handle_intr(pics[primary_pic]);
630 
631           return;
632 
633 }
634 
635 int
splraise(int ncpl)636 splraise(int ncpl)
637 {
638           struct cpu_info *ci = curcpu();
639           int ocpl;
640 
641           if (ncpl == ci->ci_cpl)
642                     return ncpl;
643           REORDER_PROTECT();
644           ocpl = ci->ci_cpl;
645           KASSERT(ncpl < NIPL);
646           ci->ci_cpl = uimax(ncpl, ocpl);
647           REORDER_PROTECT();
648           __insn_barrier();
649           return ocpl;
650 }
651 
652 static inline bool
have_pending_intr_p(struct cpu_info * ci,int ncpl)653 have_pending_intr_p(struct cpu_info *ci, int ncpl)
654 {
655           if (ci->ci_ipending & ~imask[ncpl])
656                     return true;
657 #ifdef __HAVE_FAST_SOFTINTS
658           if (ci->ci_data.cpu_softints & (IPL_SOFTMASK << ncpl))
659                     return true;
660 #endif
661           return false;
662 }
663 
664 void
splx(int ncpl)665 splx(int ncpl)
666 {
667           struct cpu_info *ci = curcpu();
668 
669           __insn_barrier();
670           REORDER_PROTECT();
671           ci->ci_cpl = ncpl;
672           if (have_pending_intr_p(ci, ncpl))
673                     pic_do_pending_int();
674 
675           REORDER_PROTECT();
676 }
677 
678 int
spllower(int ncpl)679 spllower(int ncpl)
680 {
681           struct cpu_info *ci = curcpu();
682           int ocpl;
683 
684           __insn_barrier();
685           REORDER_PROTECT();
686           ocpl = ci->ci_cpl;
687           ci->ci_cpl = ncpl;
688           if (have_pending_intr_p(ci, ncpl))
689                     pic_do_pending_int();
690           REORDER_PROTECT();
691           return ocpl;
692 }
693 
694 void
genppc_cpu_configure(void)695 genppc_cpu_configure(void)
696 {
697           aprint_normal("vmmask %x schedmask %x highmask %x\n",
698               (u_int)imask[IPL_VM] & 0x7fffffff,
699               (u_int)imask[IPL_SCHED] & 0x7fffffff,
700               (u_int)imask[IPL_HIGH] & 0x7fffffff);
701 
702           spl0();
703 }
704 
705 #if defined(PIC_PREPIVR) || defined(PIC_I8259)
706 /*
707  * isa_intr_alloc needs to be done here, because it needs direct access to
708  * the various interrupt handler structures.
709  */
710 
711 int
genppc_isa_intr_alloc(isa_chipset_tag_t ic,struct pic_ops * pic,int mask,int type,int * irq_p)712 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
713     int mask, int type, int *irq_p)
714 {
715           int irq, vi;
716           int maybe_irq = -1;
717           int shared_depth = 0;
718           struct intr_source *is;
719 
720           if (pic == NULL)
721                     return 1;
722 
723           for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
724                mask >>= 1, irq++) {
725                     if ((mask & 1) == 0)
726                               continue;
727                     vi = virq_map[irq + pic->pic_intrbase];
728                     if (!vi) {
729                               *irq_p = irq;
730                               return 0;
731                     }
732                     is = &intrsources[vi];
733                     if (is->is_type == IST_NONE) {
734                               *irq_p = irq;
735                               return 0;
736                     }
737                     /* Level interrupts can be shared */
738                     if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
739                               struct intrhand *ih = is->is_hand;
740                               int depth;
741 
742                               if (maybe_irq == -1) {
743                                         maybe_irq = irq;
744                                         continue;
745                               }
746                               for (depth = 0; ih != NULL; ih = ih->ih_next)
747                                         depth++;
748                               if (depth < shared_depth) {
749                                         maybe_irq = irq;
750                                         shared_depth = depth;
751                               }
752                     }
753           }
754           if (maybe_irq != -1) {
755                     *irq_p = maybe_irq;
756                     return 0;
757           }
758           return 1;
759 }
760 #endif
761 
762 static struct intr_source *
intr_get_source(const char * intrid)763 intr_get_source(const char *intrid)
764 {
765           struct intr_source *is;
766           int irq;
767 
768           for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
769                     if (strcmp(intrid, is->is_intrid) == 0)
770                               return is;
771           }
772           return NULL;
773 }
774 
775 static struct intrhand *
intr_get_handler(const char * intrid)776 intr_get_handler(const char *intrid)
777 {
778           struct intr_source *is;
779 
780           is = intr_get_source(intrid);
781           if (is != NULL)
782                     return is->is_hand;
783           return NULL;
784 }
785 
786 uint64_t
interrupt_get_count(const char * intrid,u_int cpu_idx)787 interrupt_get_count(const char *intrid, u_int cpu_idx)
788 {
789           struct intr_source *is;
790 
791           /* XXX interrupt is always generated by CPU 0 */
792           if (cpu_idx != 0)
793                     return 0;
794 
795           is = intr_get_source(intrid);
796           if (is != NULL)
797                     return is->is_ev.ev_count;
798           return 0;
799 }
800 
801 void
interrupt_get_assigned(const char * intrid,kcpuset_t * cpuset)802 interrupt_get_assigned(const char *intrid, kcpuset_t *cpuset)
803 {
804           struct intr_source *is;
805 
806           kcpuset_zero(cpuset);
807 
808           is = intr_get_source(intrid);
809           if (is != NULL)
810                     kcpuset_set(cpuset, 0);       /* XXX */
811 }
812 
813 void
interrupt_get_available(kcpuset_t * cpuset)814 interrupt_get_available(kcpuset_t *cpuset)
815 {
816           CPU_INFO_ITERATOR cii;
817           struct cpu_info *ci;
818 
819           kcpuset_zero(cpuset);
820 
821           mutex_enter(&cpu_lock);
822           for (CPU_INFO_FOREACH(cii, ci)) {
823                     if ((ci->ci_schedstate.spc_flags & SPCF_NOINTR) == 0)
824                               kcpuset_set(cpuset, cpu_index(ci));
825           }
826           mutex_exit(&cpu_lock);
827 }
828 
829 void
interrupt_get_devname(const char * intrid,char * buf,size_t len)830 interrupt_get_devname(const char *intrid, char *buf, size_t len)
831 {
832           struct intrhand *ih;
833 
834           if (len == 0)
835                     return;
836 
837           buf[0] = '\0';
838 
839           for (ih = intr_get_handler(intrid); ih != NULL; ih = ih->ih_next) {
840                     if (buf[0] != '\0')
841                               strlcat(buf, ", ", len);
842                     strlcat(buf, ih->ih_xname, len);
843           }
844 }
845 
846 struct intrids_handler *
interrupt_construct_intrids(const kcpuset_t * cpuset)847 interrupt_construct_intrids(const kcpuset_t *cpuset)
848 {
849           struct intr_source *is;
850           struct intrids_handler *ii_handler;
851           intrid_t *ids;
852           int i, irq, count;
853 
854           if (kcpuset_iszero(cpuset))
855                     return NULL;
856           if (!kcpuset_isset(cpuset, 0))          /* XXX */
857                     return NULL;
858 
859           count = 0;
860           for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
861                     if (is->is_hand != NULL)
862                               count++;
863           }
864 
865           ii_handler = kmem_zalloc(sizeof(int) + sizeof(intrid_t) * count,
866               KM_SLEEP);
867           if (ii_handler == NULL)
868                     return NULL;
869           ii_handler->iih_nids = count;
870           if (count == 0)
871                     return ii_handler;
872 
873           ids = ii_handler->iih_intrids;
874           i = 0;
875           for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
876                     /* Ignore devices attached after counting "count". */
877                     if (i >= count)
878                               break;
879 
880                     if (is->is_hand == NULL)
881                               continue;
882 
883                     strncpy(ids[i], is->is_intrid, sizeof(intrid_t));
884                     i++;
885           }
886 
887           return ii_handler;
888 }
889 
890 void
interrupt_destruct_intrids(struct intrids_handler * ii_handler)891 interrupt_destruct_intrids(struct intrids_handler *ii_handler)
892 {
893           size_t iih_size;
894 
895           if (ii_handler == NULL)
896                     return;
897 
898           iih_size = sizeof(int) + sizeof(intrid_t) * ii_handler->iih_nids;
899           kmem_free(ii_handler, iih_size);
900 }
901 
902 int
interrupt_distribute(void * ich,const kcpuset_t * newset,kcpuset_t * oldset)903 interrupt_distribute(void *ich, const kcpuset_t *newset, kcpuset_t *oldset)
904 {
905           return EOPNOTSUPP;
906 }
907 
908 int
interrupt_distribute_handler(const char * intrid,const kcpuset_t * newset,kcpuset_t * oldset)909 interrupt_distribute_handler(const char *intrid, const kcpuset_t *newset,
910     kcpuset_t *oldset)
911 {
912           return EOPNOTSUPP;
913 }
914 
915 #undef REORDER_PROTECT
916