1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * William Jolitz.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34 /*-
35 * Copyright (c) 2002 Benno Rice.
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 * form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
59 */
60
61 #include "opt_isa.h"
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/queue.h>
67 #include <sys/bus.h>
68 #include <sys/cpuset.h>
69 #include <sys/interrupt.h>
70 #include <sys/ktr.h>
71 #include <sys/lock.h>
72 #include <sys/malloc.h>
73 #include <sys/mutex.h>
74 #include <sys/pcpu.h>
75 #include <sys/smp.h>
76 #include <sys/syslog.h>
77 #include <sys/vmmeter.h>
78 #include <sys/proc.h>
79
80 #include <machine/frame.h>
81 #include <machine/intr_machdep.h>
82 #include <machine/md_var.h>
83 #include <machine/smp.h>
84 #include <machine/trap.h>
85
86 #include "pic_if.h"
87
88 static MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
89
90 struct powerpc_intr {
91 struct intr_event *event;
92 long *cntp;
93 void *priv; /* PIC-private data */
94 device_t pic;
95 u_int irq;
96 u_int intline;
97 u_int vector;
98 u_int cntindex;
99 int fwcode;
100 int ipi;
101 int pi_domain;
102 enum intr_trigger trig;
103 enum intr_polarity pol;
104 cpuset_t pi_cpuset;
105 };
106
107 struct pic {
108 device_t dev;
109 uint32_t node;
110 u_int irqs;
111 u_int ipis;
112 int base;
113 };
114
115 static u_int intrcnt_index = 0;
116 static struct mtx intr_table_lock;
117 static struct powerpc_intr **powerpc_intrs;
118 static struct pic piclist[MAX_PICS];
119 static u_int nvectors; /* Allocated vectors */
120 static u_int npics; /* PICs registered */
121 #ifdef DEV_ISA
122 static u_int nirqs = 16; /* Allocated IRQS (ISA pre-allocated). */
123 #else
124 static u_int nirqs = 0; /* Allocated IRQs. */
125 #endif
126 static u_int stray_count;
127
128 #define INTRNAME_LEN (MAXCOMLEN + 1)
129 u_long *intrcnt;
130 char *intrnames;
131 size_t sintrcnt = sizeof(intrcnt);
132 size_t sintrnames = sizeof(intrnames);
133 int nintrcnt;
134
135 /*
136 * Just to start
137 */
138 #ifdef __powerpc64__
139 u_int num_io_irqs = 768;
140 #else
141 u_int num_io_irqs = 256;
142 #endif
143
144 device_t root_pic;
145
146 #ifdef SMP
147 static void *ipi_cookie;
148 #endif
149
150 static int powerpc_setup_intr_int(const char *name, u_int irq, driver_filter_t
151 filter, driver_intr_t handler, void *arg, enum intr_type flags, void
152 **cookiep, int domain, bool ipi);
153
154 static void
intrcnt_setname(const char * name,int index)155 intrcnt_setname(const char *name, int index)
156 {
157
158 snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s",
159 INTRNAME_LEN - 1, name);
160 }
161
162 MTX_SYSINIT(intr_table_lock, &intr_table_lock, "intr sources lock", MTX_DEF);
163
164 static void
intr_init_sources(void * arg __unused)165 intr_init_sources(void *arg __unused)
166 {
167
168 powerpc_intrs = mallocarray(num_io_irqs, sizeof(*powerpc_intrs),
169 M_INTR, M_WAITOK | M_ZERO);
170 nintrcnt = 1 + num_io_irqs * 2 + mp_ncpus * 2;
171 #ifdef COUNT_IPIS
172 if (mp_ncpus > 1)
173 nintrcnt += 8 * mp_ncpus;
174 #endif
175 intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTR, M_WAITOK |
176 M_ZERO);
177 intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTR, M_WAITOK |
178 M_ZERO);
179 sintrcnt = nintrcnt * sizeof(u_long);
180 sintrnames = nintrcnt * INTRNAME_LEN;
181
182 intrcnt_setname("???", 0);
183 intrcnt_index = 1;
184 }
185 /*
186 * This needs to happen before SI_SUB_CPU
187 */
188 SYSINIT(intr_init_sources, SI_SUB_KLD, SI_ORDER_ANY, intr_init_sources, NULL);
189
190 #ifdef SMP
191 static void
smp_intr_init(void * dummy __unused)192 smp_intr_init(void *dummy __unused)
193 {
194 struct powerpc_intr *i;
195 int vector;
196
197 for (vector = 0; vector < nvectors; vector++) {
198 i = powerpc_intrs[vector];
199 if (i != NULL && i->event != NULL && i->pic == root_pic)
200 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
201 }
202 }
203 SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL);
204 #endif
205
206 void
intrcnt_add(const char * name,u_long ** countp)207 intrcnt_add(const char *name, u_long **countp)
208 {
209 int idx;
210
211 idx = atomic_fetchadd_int(&intrcnt_index, 1);
212 KASSERT(idx < nintrcnt, ("intrcnt_add: Interrupt counter index %d/%d"
213 "reached nintrcnt : %d", intrcnt_index, idx, nintrcnt));
214 *countp = &intrcnt[idx];
215 intrcnt_setname(name, idx);
216 }
217
218 static struct powerpc_intr *
intr_lookup(u_int irq)219 intr_lookup(u_int irq)
220 {
221 char intrname[16];
222 struct powerpc_intr *i, *iscan;
223 int vector;
224
225 mtx_lock(&intr_table_lock);
226 for (vector = 0; vector < nvectors; vector++) {
227 i = powerpc_intrs[vector];
228 if (i != NULL && i->irq == irq) {
229 mtx_unlock(&intr_table_lock);
230 return (i);
231 }
232 }
233
234 i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
235 if (i == NULL) {
236 mtx_unlock(&intr_table_lock);
237 return (NULL);
238 }
239
240 i->event = NULL;
241 i->cntp = NULL;
242 i->priv = NULL;
243 i->trig = INTR_TRIGGER_CONFORM;
244 i->pol = INTR_POLARITY_CONFORM;
245 i->irq = irq;
246 i->pic = NULL;
247 i->vector = -1;
248 i->fwcode = 0;
249 i->ipi = 0;
250
251 #ifdef SMP
252 i->pi_cpuset = all_cpus;
253 #else
254 CPU_SETOF(0, &i->pi_cpuset);
255 #endif
256
257 for (vector = 0; vector < num_io_irqs && vector <= nvectors;
258 vector++) {
259 iscan = powerpc_intrs[vector];
260 if (iscan != NULL && iscan->irq == irq)
261 break;
262 if (iscan == NULL && i->vector == -1)
263 i->vector = vector;
264 iscan = NULL;
265 }
266
267 if (iscan == NULL && i->vector != -1) {
268 powerpc_intrs[i->vector] = i;
269 i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1);
270 i->cntp = &intrcnt[i->cntindex];
271 sprintf(intrname, "irq%u:", i->irq);
272 intrcnt_setname(intrname, i->cntindex);
273 nvectors++;
274 }
275 mtx_unlock(&intr_table_lock);
276
277 if (iscan != NULL || i->vector == -1) {
278 free(i, M_INTR);
279 i = iscan;
280 }
281
282 return (i);
283 }
284
285 static int
powerpc_map_irq(struct powerpc_intr * i)286 powerpc_map_irq(struct powerpc_intr *i)
287 {
288 struct pic *p;
289 u_int cnt;
290 int idx;
291
292 for (idx = 0; idx < npics; idx++) {
293 p = &piclist[idx];
294 cnt = p->irqs + p->ipis;
295 if (i->irq >= p->base && i->irq < p->base + cnt)
296 break;
297 }
298 if (idx == npics)
299 return (EINVAL);
300
301 i->intline = i->irq - p->base;
302 i->pic = p->dev;
303
304 /* Try a best guess if that failed */
305 if (i->pic == NULL)
306 i->pic = root_pic;
307
308 return (0);
309 }
310
311 static void
powerpc_intr_eoi(void * arg)312 powerpc_intr_eoi(void *arg)
313 {
314 struct powerpc_intr *i = arg;
315
316 PIC_EOI(i->pic, i->intline, i->priv);
317 }
318
319 static void
powerpc_intr_pre_ithread(void * arg)320 powerpc_intr_pre_ithread(void *arg)
321 {
322 struct powerpc_intr *i = arg;
323
324 PIC_MASK(i->pic, i->intline, i->priv);
325 PIC_EOI(i->pic, i->intline, i->priv);
326 }
327
328 static void
powerpc_intr_post_ithread(void * arg)329 powerpc_intr_post_ithread(void *arg)
330 {
331 struct powerpc_intr *i = arg;
332
333 PIC_UNMASK(i->pic, i->intline, i->priv);
334 }
335
336 static int
powerpc_assign_intr_cpu(void * arg,int cpu)337 powerpc_assign_intr_cpu(void *arg, int cpu)
338 {
339 #ifdef SMP
340 struct powerpc_intr *i = arg;
341
342 if (cpu == NOCPU)
343 i->pi_cpuset = all_cpus;
344 else
345 CPU_SETOF(cpu, &i->pi_cpuset);
346
347 if (!cold && i->pic != NULL && i->pic == root_pic)
348 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
349
350 return (0);
351 #else
352 return (EOPNOTSUPP);
353 #endif
354 }
355
356 u_int
powerpc_register_pic(device_t dev,uint32_t node,u_int irqs,u_int ipis,u_int atpic)357 powerpc_register_pic(device_t dev, uint32_t node, u_int irqs, u_int ipis,
358 u_int atpic)
359 {
360 struct pic *p;
361 u_int irq;
362 int idx;
363
364 mtx_lock(&intr_table_lock);
365
366 /* XXX see powerpc_get_irq(). */
367 for (idx = 0; idx < npics; idx++) {
368 p = &piclist[idx];
369 if (p->node != node)
370 continue;
371 if (node != 0 || p->dev == dev)
372 break;
373 }
374 p = &piclist[idx];
375
376 p->dev = dev;
377 p->node = node;
378 p->irqs = irqs;
379 p->ipis = ipis;
380 if (idx == npics) {
381 #ifdef DEV_ISA
382 p->base = (atpic) ? 0 : nirqs;
383 #else
384 p->base = nirqs;
385 #endif
386 irq = p->base + irqs + ipis;
387 nirqs = MAX(nirqs, irq);
388 npics++;
389 }
390
391 KASSERT(npics < MAX_PICS,
392 ("Number of PICs exceeds maximum (%d)", MAX_PICS));
393
394 mtx_unlock(&intr_table_lock);
395
396 return (p->base);
397 }
398
399 u_int
powerpc_get_irq(uint32_t node,u_int pin)400 powerpc_get_irq(uint32_t node, u_int pin)
401 {
402 int idx;
403
404 if (node == 0)
405 return (pin);
406
407 mtx_lock(&intr_table_lock);
408 for (idx = 0; idx < npics; idx++) {
409 if (piclist[idx].node == node) {
410 mtx_unlock(&intr_table_lock);
411 return (piclist[idx].base + pin);
412 }
413 }
414
415 /*
416 * XXX we should never encounter an unregistered PIC, but that
417 * can only be done when we properly support bus enumeration
418 * using multiple passes. Until then, fake an entry and give it
419 * some adhoc maximum number of IRQs and IPIs.
420 */
421 piclist[idx].dev = NULL;
422 piclist[idx].node = node;
423 piclist[idx].irqs = 124;
424 piclist[idx].ipis = 4;
425 piclist[idx].base = nirqs;
426 nirqs += (1 << 25);
427 npics++;
428
429 KASSERT(npics < MAX_PICS,
430 ("Number of PICs exceeds maximum (%d)", MAX_PICS));
431
432 mtx_unlock(&intr_table_lock);
433
434 return (piclist[idx].base + pin);
435 }
436
437 int
powerpc_enable_intr(void)438 powerpc_enable_intr(void)
439 {
440 struct powerpc_intr *i;
441 int error, vector;
442 #ifdef SMP
443 int n;
444 #endif
445
446 if (npics == 0)
447 panic("no PIC detected\n");
448
449 if (root_pic == NULL)
450 root_pic = piclist[0].dev;
451
452 KASSERT(root_pic != NULL, ("no root PIC!"));
453
454 #ifdef SMP
455 /* Install an IPI handler. */
456 if (mp_ncpus > 1) {
457 for (n = 0; n < npics; n++) {
458 if (piclist[n].dev != root_pic)
459 continue;
460
461 KASSERT(piclist[n].ipis != 0,
462 ("%s: SMP root PIC does not supply any IPIs",
463 __func__));
464 error = powerpc_setup_intr_int("IPI",
465 MAP_IRQ(piclist[n].node, piclist[n].irqs),
466 powerpc_ipi_handler, NULL, NULL,
467 INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie,
468 0 /* domain XXX */, true);
469 if (error) {
470 printf("unable to setup IPI handler\n");
471 return (error);
472 }
473 }
474 }
475 #endif
476
477 for (vector = 0; vector < nvectors; vector++) {
478 i = powerpc_intrs[vector];
479 if (i == NULL)
480 continue;
481
482 error = powerpc_map_irq(i);
483 if (error)
484 continue;
485
486 if (i->trig == INTR_TRIGGER_INVALID)
487 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode,
488 &i->trig, &i->pol);
489 if (i->trig != INTR_TRIGGER_CONFORM ||
490 i->pol != INTR_POLARITY_CONFORM)
491 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
492
493 if (i->event != NULL)
494 PIC_ENABLE(i->pic, i->intline, vector, &i->priv);
495 }
496
497 return (0);
498 }
499
500 int
powerpc_setup_intr(const char * name,u_int irq,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,void ** cookiep,int domain)501 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
502 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep,
503 int domain)
504 {
505
506 return (powerpc_setup_intr_int(name, irq, filter, handler, arg, flags,
507 cookiep, domain, false));
508 }
509
510
511 static int
powerpc_setup_intr_int(const char * name,u_int irq,driver_filter_t filter,driver_intr_t handler,void * arg,enum intr_type flags,void ** cookiep,int domain,bool ipi)512 powerpc_setup_intr_int(const char *name, u_int irq, driver_filter_t filter,
513 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep,
514 int domain, bool ipi)
515 {
516 struct powerpc_intr *i;
517 int error, enable = 0;
518
519 i = intr_lookup(irq);
520 if (i == NULL)
521 return (ENOMEM);
522
523 if (i->event == NULL) {
524 error = intr_event_create(&i->event, (void *)i, 0, irq,
525 powerpc_intr_pre_ithread, powerpc_intr_post_ithread,
526 (ipi ? NULL : powerpc_intr_eoi), powerpc_assign_intr_cpu,
527 "irq%u:", irq);
528 if (error)
529 return (error);
530
531 enable = 1;
532 }
533 i->ipi = ipi;
534
535 error = intr_event_add_handler(i->event, name, filter, handler, arg,
536 intr_priority(flags), flags, cookiep);
537 if (error)
538 return (error);
539 i->pi_domain = domain;
540 if (strcmp(name, "IPI") != 0) {
541 CPU_ZERO(&i->pi_cpuset);
542 CPU_COPY(&cpuset_domain[domain], &i->pi_cpuset);
543 }
544 mtx_lock(&intr_table_lock);
545 intrcnt_setname(i->event->ie_fullname, i->cntindex);
546 mtx_unlock(&intr_table_lock);
547
548 if (!cold) {
549 error = powerpc_map_irq(i);
550
551 if (!error) {
552 if (i->trig == INTR_TRIGGER_INVALID)
553 PIC_TRANSLATE_CODE(i->pic, i->intline,
554 i->fwcode, &i->trig, &i->pol);
555
556 if (i->trig != INTR_TRIGGER_CONFORM ||
557 i->pol != INTR_POLARITY_CONFORM)
558 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
559
560 if (i->pic == root_pic)
561 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv);
562
563 if (enable)
564 PIC_ENABLE(i->pic, i->intline, i->vector,
565 &i->priv);
566 }
567 }
568 return (error);
569 }
570
571 int
powerpc_teardown_intr(void * cookie)572 powerpc_teardown_intr(void *cookie)
573 {
574
575 return (intr_event_remove_handler(cookie));
576 }
577
578 #ifdef SMP
579 int
powerpc_bind_intr(u_int irq,u_char cpu)580 powerpc_bind_intr(u_int irq, u_char cpu)
581 {
582 struct powerpc_intr *i;
583
584 i = intr_lookup(irq);
585 if (i == NULL)
586 return (ENOMEM);
587
588 return (intr_event_bind(i->event, cpu));
589 }
590 #endif
591
592 int
powerpc_fw_config_intr(int irq,int sense_code)593 powerpc_fw_config_intr(int irq, int sense_code)
594 {
595 struct powerpc_intr *i;
596
597 i = intr_lookup(irq);
598 if (i == NULL)
599 return (ENOMEM);
600
601 i->trig = INTR_TRIGGER_INVALID;
602 i->pol = INTR_POLARITY_CONFORM;
603 i->fwcode = sense_code;
604
605 if (!cold && i->pic != NULL) {
606 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig,
607 &i->pol);
608 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
609 }
610
611 return (0);
612 }
613
614 int
powerpc_config_intr(int irq,enum intr_trigger trig,enum intr_polarity pol)615 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
616 {
617 struct powerpc_intr *i;
618
619 i = intr_lookup(irq);
620 if (i == NULL)
621 return (ENOMEM);
622
623 i->trig = trig;
624 i->pol = pol;
625
626 if (!cold && i->pic != NULL)
627 PIC_CONFIG(i->pic, i->intline, trig, pol);
628
629 return (0);
630 }
631
632 void
powerpc_dispatch_intr(u_int vector,struct trapframe * tf)633 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
634 {
635 struct powerpc_intr *i;
636 struct intr_event *ie;
637
638 i = powerpc_intrs[vector];
639 if (i == NULL)
640 goto stray;
641
642 (*i->cntp)++;
643
644 ie = i->event;
645 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
646
647 /*
648 * IPIs are magical and need to be EOI'ed before filtering.
649 * This prevents races in IPI handling.
650 */
651 if (i->ipi)
652 PIC_EOI(i->pic, i->intline, i->priv);
653
654 if (intr_event_handle(ie, tf) != 0) {
655 goto stray;
656 }
657 return;
658
659 stray:
660 stray_count++;
661 if (stray_count <= INTR_STRAY_LOG_MAX) {
662 printf("stray irq %d\n", i ? i->irq : -1);
663 if (stray_count >= INTR_STRAY_LOG_MAX) {
664 printf("got %d stray interrupts, not logging anymore\n",
665 INTR_STRAY_LOG_MAX);
666 }
667 }
668 if (i != NULL)
669 PIC_MASK(i->pic, i->intline, i->priv);
670 }
671
672 void
powerpc_intr_mask(u_int irq)673 powerpc_intr_mask(u_int irq)
674 {
675 struct powerpc_intr *i;
676
677 i = intr_lookup(irq);
678 if (i == NULL || i->pic == NULL)
679 return;
680
681 PIC_MASK(i->pic, i->intline, i->priv);
682 }
683
684 void
powerpc_intr_unmask(u_int irq)685 powerpc_intr_unmask(u_int irq)
686 {
687 struct powerpc_intr *i;
688
689 i = intr_lookup(irq);
690 if (i == NULL || i->pic == NULL)
691 return;
692
693 PIC_UNMASK(i->pic, i->intline, i->priv);
694 }
695