1 /* $OpenBSD: openpic.c,v 1.90 2022/07/24 00:28:09 cheloha Exp $ */
2
3 /*-
4 * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org>
5 * Copyright (c) 1995 Per Fogelstrom
6 * Copyright (c) 1993, 1994 Charles M. Hannum.
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * William Jolitz and Don Ahn.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)isa.c 7.2 (Berkeley) 5/12/91
38 */
39
40 #include "hpb.h"
41
42 #include <sys/param.h>
43 #include <sys/device.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/atomic.h>
47
48 #include <uvm/uvm_extern.h>
49
50 #include <machine/autoconf.h>
51 #include <machine/intr.h>
52 #include <machine/psl.h>
53 #include <machine/pio.h>
54 #include <dev/ofw/openfirm.h>
55
56 #include <macppc/dev/openpicreg.h>
57
58 #ifdef OPENPIC_DEBUG
59 #define DPRINTF(x...) do { printf(x); } while(0)
60 #else
61 #define DPRINTF(x...)
62 #endif
63
64 #define ICU_LEN 128
65 int openpic_numirq = ICU_LEN;
66 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
67
68 int openpic_pri_share[IPL_NUM];
69
70 struct intrq openpic_handler[ICU_LEN];
71
72 struct openpic_softc {
73 struct device sc_dev;
74 };
75
76 vaddr_t openpic_base;
77 int openpic_big_endian;
78 struct evcount openpic_spurious;
79 int openpic_spurious_irq = 255;
80
81 int openpic_match(struct device *parent, void *cf, void *aux);
82 void openpic_attach(struct device *, struct device *, void *);
83
84 int openpic_splraise(int);
85 int openpic_spllower(int);
86 void openpic_splx(int);
87
88 u_int openpic_read(int reg);
89 void openpic_write(int reg, u_int val);
90
91 void openpic_acknowledge_irq(int, int);
92 void openpic_enable_irq(int, int, int);
93 void openpic_disable_irq(int, int);
94
95 void openpic_calc_mask(void);
96 void openpic_set_priority(int, int);
97 void *openpic_intr_establish(void *, int, int, int, int (*)(void *), void *,
98 const char *);
99 void openpic_intr_disestablish(void *, void *);
100 void openpic_collect_preconf_intr(void);
101 void openpic_ext_intr(void);
102 int openpic_ext_intr_handler(struct intrhand *, int *);
103
104 /* Generic IRQ management routines. */
105 void openpic_gen_acknowledge_irq(int, int);
106 void openpic_gen_enable_irq(int, int, int);
107 void openpic_gen_disable_irq(int, int);
108
109 #if NHPB > 0
110 /* CPC945 IRQ management routines. */
111 void openpic_cpc945_acknowledge_irq(int, int);
112 void openpic_cpc945_enable_irq(int, int, int);
113 void openpic_cpc945_disable_irq(int, int);
114 #endif /* NHPB */
115
116 struct openpic_ops {
117 void (*acknowledge_irq)(int, int);
118 void (*enable_irq)(int, int, int);
119 void (*disable_irq)(int, int);
120 } openpic_ops = {
121 openpic_gen_acknowledge_irq,
122 openpic_gen_enable_irq,
123 openpic_gen_disable_irq
124 };
125
126 #ifdef MULTIPROCESSOR
127 void openpic_ipi_ddb(void);
128
129 /* IRQ vector used for inter-processor interrupts. */
130 #define IPI_VECTOR_NOP 64
131 #define IPI_VECTOR_DDB 65
132
133 static struct evcount ipi_count;
134
135 static int ipi_irq = IPI_VECTOR_NOP;
136
137 intr_send_ipi_t openpic_send_ipi;
138 #endif /* MULTIPROCESSOR */
139
140 const struct cfattach openpic_ca = {
141 sizeof(struct openpic_softc), openpic_match, openpic_attach
142 };
143
144 struct cfdriver openpic_cd = {
145 NULL, "openpic", DV_DULL
146 };
147
148 u_int
openpic_read(int reg)149 openpic_read(int reg)
150 {
151 char *addr = (void *)(openpic_base + reg);
152
153 membar_sync();
154 if (openpic_big_endian)
155 return in32(addr);
156 else
157 return in32rb(addr);
158 }
159
160 void
openpic_write(int reg,u_int val)161 openpic_write(int reg, u_int val)
162 {
163 char *addr = (void *)(openpic_base + reg);
164
165 if (openpic_big_endian)
166 out32(addr, val);
167 else
168 out32rb(addr, val);
169 membar_sync();
170 }
171
172 static inline int
openpic_read_irq(int cpu)173 openpic_read_irq(int cpu)
174 {
175 return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
176 }
177
178 static inline void
openpic_eoi(int cpu)179 openpic_eoi(int cpu)
180 {
181 openpic_write(OPENPIC_EOI(cpu), 0);
182 }
183
184 int
openpic_match(struct device * parent,void * cf,void * aux)185 openpic_match(struct device *parent, void *cf, void *aux)
186 {
187 char type[40];
188 int pirq;
189 struct confargs *ca = aux;
190
191 bzero (type, sizeof(type));
192
193 if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq))
194 == sizeof(pirq))
195 return 0; /* XXX */
196
197 if (strcmp(ca->ca_name, "interrupt-controller") != 0 &&
198 strcmp(ca->ca_name, "mpic") != 0)
199 return 0;
200
201 OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
202 if (strcmp(type, "open-pic") != 0)
203 return 0;
204
205 if (ca->ca_nreg < 8)
206 return 0;
207
208 return 1;
209 }
210
211 void
openpic_attach(struct device * parent,struct device * self,void * aux)212 openpic_attach(struct device *parent, struct device *self, void *aux)
213 {
214 struct cpu_info *ci = curcpu();
215 struct confargs *ca = aux;
216 struct intrq *iq;
217 uint32_t reg = 0;
218 int i, irq;
219 u_int x;
220
221 if (OF_getprop(ca->ca_node, "big-endian", ®, sizeof reg) == 0)
222 openpic_big_endian = 1;
223
224 openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
225 ca->ca_reg[0], 0x40000);
226
227 /* Reset the PIC */
228 x = openpic_read(OPENPIC_CONFIG) | OPENPIC_CONFIG_RESET;
229 openpic_write(OPENPIC_CONFIG, x);
230
231 while (openpic_read(OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET)
232 delay(100);
233
234 /* openpic may support more than 128 interrupts but driver doesn't */
235 openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1;
236
237 printf(": version 0x%x feature %x %s",
238 openpic_read(OPENPIC_VENDOR_ID),
239 openpic_read(OPENPIC_FEATURE),
240 openpic_big_endian ? "BE" : "LE" );
241
242 openpic_set_priority(ci->ci_cpuid, 15);
243
244 /* disable all interrupts */
245 for (irq = 0; irq < openpic_numirq; irq++)
246 openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
247
248 for (i = 0; i < openpic_numirq; i++) {
249 iq = &openpic_handler[i];
250 TAILQ_INIT(&iq->iq_list);
251 }
252
253 /* we don't need 8259 pass through mode */
254 x = openpic_read(OPENPIC_CONFIG);
255 x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
256 openpic_write(OPENPIC_CONFIG, x);
257
258 /* initialize all vectors to something sane */
259 for (irq = 0; irq < ICU_LEN; irq++) {
260 x = irq;
261 x |= OPENPIC_IMASK;
262 x |= OPENPIC_POLARITY_NEGATIVE;
263 x |= OPENPIC_SENSE_LEVEL;
264 x |= 8 << OPENPIC_PRIORITY_SHIFT;
265 openpic_write(OPENPIC_SRC_VECTOR(irq), x);
266 }
267
268 /* send all interrupts to cpu 0 */
269 for (irq = 0; irq < openpic_numirq; irq++)
270 openpic_write(OPENPIC_IDEST(irq), 1 << 0);
271
272 /* clear all pending interrupts */
273 for (irq = 0; irq < ICU_LEN; irq++) {
274 openpic_read_irq(ci->ci_cpuid);
275 openpic_eoi(ci->ci_cpuid);
276 }
277
278 #ifdef MULTIPROCESSOR
279 /* Set up inter-processor interrupts. */
280 /* IPI0 - NOP */
281 x = IPI_VECTOR_NOP;
282 x |= 15 << OPENPIC_PRIORITY_SHIFT;
283 openpic_write(OPENPIC_IPI_VECTOR(0), x);
284 /* IPI1 - DDB */
285 x = IPI_VECTOR_DDB;
286 x |= 15 << OPENPIC_PRIORITY_SHIFT;
287 openpic_write(OPENPIC_IPI_VECTOR(1), x);
288
289 evcount_attach(&ipi_count, "ipi", &ipi_irq);
290 #endif
291
292 /* clear all pending interrupts */
293 for (irq = 0; irq < ICU_LEN; irq++) {
294 openpic_read_irq(0);
295 openpic_eoi(0);
296 }
297
298 #if 0
299 openpic_write(OPENPIC_SPURIOUS_VECTOR, 255);
300 #endif
301
302 #if NHPB > 0
303 /* Only U4 systems have a big-endian MPIC. */
304 if (openpic_big_endian) {
305 openpic_ops.acknowledge_irq = openpic_cpc945_acknowledge_irq;
306 openpic_ops.enable_irq = openpic_cpc945_enable_irq;
307 openpic_ops.disable_irq = openpic_cpc945_disable_irq;
308 }
309 #endif
310
311 install_extint(openpic_ext_intr);
312
313 openpic_set_priority(ci->ci_cpuid, 0);
314
315 intr_establish_func = openpic_intr_establish;
316 intr_disestablish_func = openpic_intr_disestablish;
317 #ifdef MULTIPROCESSOR
318 intr_send_ipi_func = openpic_send_ipi;
319 #endif
320
321 ppc_smask_init();
322
323 openpic_collect_preconf_intr();
324
325 evcount_attach(&openpic_spurious, "spurious", &openpic_spurious_irq);
326
327 ppc_intr_func.raise = openpic_splraise;
328 ppc_intr_func.lower = openpic_spllower;
329 ppc_intr_func.x = openpic_splx;
330
331 openpic_set_priority(0, ci->ci_cpl);
332
333 ppc_intr_enable(1);
334
335 printf("\n");
336 }
337
338 /* Must be called with interrupt disable. */
339 static inline void
openpic_setipl(int newcpl)340 openpic_setipl(int newcpl)
341 {
342 struct cpu_info *ci = curcpu();
343
344 ci->ci_cpl = newcpl;
345 openpic_set_priority(ci->ci_cpuid, newcpl);
346 }
347
348 int
openpic_splraise(int newcpl)349 openpic_splraise(int newcpl)
350 {
351 struct cpu_info *ci = curcpu();
352 int ocpl = ci->ci_cpl;
353 int s;
354
355 newcpl = openpic_pri_share[newcpl];
356 if (ocpl > newcpl)
357 newcpl = ocpl;
358
359 s = ppc_intr_disable();
360 openpic_setipl(newcpl);
361 ppc_intr_enable(s);
362
363 return ocpl;
364 }
365
366 int
openpic_spllower(int newcpl)367 openpic_spllower(int newcpl)
368 {
369 struct cpu_info *ci = curcpu();
370 int ocpl = ci->ci_cpl;
371
372 openpic_splx(newcpl);
373
374 return ocpl;
375 }
376
377 void
openpic_splx(int newcpl)378 openpic_splx(int newcpl)
379 {
380 struct cpu_info *ci = curcpu();
381 int intr, s;
382
383 intr = ppc_intr_disable();
384 openpic_setipl(newcpl);
385 if (ci->ci_dec_deferred && newcpl < IPL_CLOCK) {
386 ppc_mtdec(0);
387 ppc_mtdec(UINT32_MAX); /* raise DEC exception */
388 }
389 if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) {
390 s = splsofttty();
391 dosoftint(newcpl);
392 openpic_setipl(s); /* no-overhead splx */
393 }
394 ppc_intr_enable(intr);
395 }
396
397 void
openpic_collect_preconf_intr(void)398 openpic_collect_preconf_intr(void)
399 {
400 int i;
401 for (i = 0; i < ppc_configed_intr_cnt; i++) {
402 DPRINTF("\n\t%s irq %d level %d fun %p arg %p",
403 ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
404 ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
405 ppc_configed_intr[i].ih_arg);
406 openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
407 IST_LEVEL, ppc_configed_intr[i].ih_level,
408 ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
409 ppc_configed_intr[i].ih_what);
410 }
411 }
412
413 /*
414 * Register an interrupt handler.
415 */
416 void *
openpic_intr_establish(void * lcv,int irq,int type,int level,int (* ih_fun)(void *),void * ih_arg,const char * name)417 openpic_intr_establish(void *lcv, int irq, int type, int level,
418 int (*ih_fun)(void *), void *ih_arg, const char *name)
419 {
420 struct intrhand *ih;
421 struct intrq *iq;
422 int s, flags;
423
424 if (!LEGAL_IRQ(irq) || type == IST_NONE) {
425 printf("%s: bogus irq %d or type %d", __func__, irq, type);
426 return (NULL);
427 }
428
429 /* no point in sleeping unless someone can free memory. */
430 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
431 if (ih == NULL)
432 panic("%s: can't malloc handler info", __func__);
433
434 iq = &openpic_handler[irq];
435 switch (iq->iq_ist) {
436 case IST_NONE:
437 iq->iq_ist = type;
438 break;
439 case IST_EDGE:
440 intr_shared_edge = 1;
441 /* FALLTHROUGH */
442 case IST_LEVEL:
443 if (type == iq->iq_ist)
444 break;
445 case IST_PULSE:
446 if (type != IST_NONE)
447 panic("intr_establish: can't share %s with %s",
448 ppc_intr_typename(iq->iq_ist),
449 ppc_intr_typename(type));
450 break;
451 }
452
453 flags = level & IPL_MPSAFE;
454 level &= ~IPL_MPSAFE;
455
456 KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE);
457
458 ih->ih_fun = ih_fun;
459 ih->ih_arg = ih_arg;
460 ih->ih_level = level;
461 ih->ih_flags = flags;
462 ih->ih_irq = irq;
463
464 evcount_attach(&ih->ih_count, name, &ih->ih_irq);
465
466 /*
467 * Append handler to end of list
468 */
469 s = ppc_intr_disable();
470
471 TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
472 openpic_calc_mask();
473
474 ppc_intr_enable(s);
475
476 return (ih);
477 }
478
479 /*
480 * Deregister an interrupt handler.
481 */
482 void
openpic_intr_disestablish(void * lcp,void * arg)483 openpic_intr_disestablish(void *lcp, void *arg)
484 {
485 struct intrhand *ih = arg;
486 int irq = ih->ih_irq;
487 struct intrq *iq;
488 int s;
489
490 if (!LEGAL_IRQ(irq)) {
491 printf("%s: bogus irq %d", __func__, irq);
492 return;
493 }
494 iq = &openpic_handler[irq];
495
496 /*
497 * Remove the handler from the chain.
498 */
499 s = ppc_intr_disable();
500
501 TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
502 openpic_calc_mask();
503
504 ppc_intr_enable(s);
505
506 evcount_detach(&ih->ih_count);
507 free(ih, M_DEVBUF, sizeof *ih);
508
509 if (TAILQ_EMPTY(&iq->iq_list))
510 iq->iq_ist = IST_NONE;
511 }
512
513 /*
514 * Recalculate the interrupt masks from scratch.
515 * We could code special registry and deregistry versions of this function that
516 * would be faster, but the code would be nastier, and we don't expect this to
517 * happen very much anyway.
518 */
519
520 void
openpic_calc_mask(void)521 openpic_calc_mask(void)
522 {
523 struct cpu_info *ci = curcpu();
524 int irq;
525 struct intrhand *ih;
526 int i;
527
528 /* disable all openpic interrupts */
529 openpic_set_priority(ci->ci_cpuid, 15);
530
531 for (i = IPL_NONE; i < IPL_NUM; i++) {
532 openpic_pri_share[i] = i;
533 }
534
535 for (irq = 0; irq < openpic_numirq; irq++) {
536 int maxipl = IPL_NONE;
537 int minipl = IPL_HIGH;
538 struct intrq *iq = &openpic_handler[irq];
539
540 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
541 if (ih->ih_level > maxipl)
542 maxipl = ih->ih_level;
543 if (ih->ih_level < minipl)
544 minipl = ih->ih_level;
545 }
546
547 if (maxipl == IPL_NONE) {
548 minipl = IPL_NONE; /* Interrupt not enabled */
549
550 openpic_disable_irq(irq, iq->iq_ist);
551 } else {
552 for (i = minipl; i <= maxipl; i++) {
553 openpic_pri_share[i] = maxipl;
554 }
555 openpic_enable_irq(irq, iq->iq_ist, maxipl);
556 }
557
558 iq->iq_ipl = maxipl;
559 }
560
561 /* restore interrupts */
562 openpic_set_priority(ci->ci_cpuid, ci->ci_cpl);
563 }
564
565 void
openpic_gen_acknowledge_irq(int irq,int cpuid)566 openpic_gen_acknowledge_irq(int irq, int cpuid)
567 {
568 openpic_eoi(cpuid);
569 }
570
571 void
openpic_gen_enable_irq(int irq,int ist,int pri)572 openpic_gen_enable_irq(int irq, int ist, int pri)
573 {
574 u_int x;
575
576 x = irq;
577
578 if (ist == IST_LEVEL)
579 x |= OPENPIC_SENSE_LEVEL;
580 else
581 x |= OPENPIC_SENSE_EDGE;
582 x |= OPENPIC_POLARITY_NEGATIVE;
583 x |= pri << OPENPIC_PRIORITY_SHIFT;
584 openpic_write(OPENPIC_SRC_VECTOR(irq), x);
585 }
586
587 void
openpic_gen_disable_irq(int irq,int ist)588 openpic_gen_disable_irq(int irq, int ist)
589 {
590 u_int x;
591
592 x = openpic_read(OPENPIC_SRC_VECTOR(irq));
593 x |= OPENPIC_IMASK;
594 openpic_write(OPENPIC_SRC_VECTOR(irq), x);
595 }
596
597 void
openpic_set_priority(int cpu,int pri)598 openpic_set_priority(int cpu, int pri)
599 {
600 openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
601 }
602
603 int openpic_irqnest[PPC_MAXPROCS];
604 int openpic_irqloop[PPC_MAXPROCS];
605
606 void
openpic_ext_intr(void)607 openpic_ext_intr(void)
608 {
609 struct cpu_info *ci = curcpu();
610 int irq, pcpl, ret;
611 int maxipl = IPL_NONE;
612 struct intrhand *ih;
613 struct intrq *iq;
614 int spurious;
615
616 pcpl = ci->ci_cpl;
617
618 openpic_irqloop[ci->ci_cpuid] = 0;
619 irq = openpic_read_irq(ci->ci_cpuid);
620 openpic_irqnest[ci->ci_cpuid]++;
621
622 while (irq != 255) {
623 openpic_irqloop[ci->ci_cpuid]++;
624 #ifdef OPENPIC_DEBUG
625 if (openpic_irqloop[ci->ci_cpuid] > 20 ||
626 openpic_irqnest[ci->ci_cpuid] > 3) {
627 printf("irqloop %d irqnest %d\n",
628 openpic_irqloop[ci->ci_cpuid],
629 openpic_irqnest[ci->ci_cpuid]);
630 }
631 #endif
632 if (openpic_irqloop[ci->ci_cpuid] > 20) {
633 DPRINTF("irqloop %d irqnest %d: returning\n",
634 openpic_irqloop[ci->ci_cpuid],
635 openpic_irqnest[ci->ci_cpuid]);
636 openpic_irqnest[ci->ci_cpuid]--;
637 return;
638 }
639 #ifdef MULTIPROCESSOR
640 if (irq == IPI_VECTOR_NOP || irq == IPI_VECTOR_DDB) {
641 ipi_count.ec_count++;
642 openpic_eoi(ci->ci_cpuid);
643 if (irq == IPI_VECTOR_DDB)
644 openpic_ipi_ddb();
645 irq = openpic_read_irq(ci->ci_cpuid);
646 continue;
647 }
648 #endif
649 iq = &openpic_handler[irq];
650
651 #ifdef OPENPIC_DEBUG
652 if (iq->iq_ipl <= pcpl)
653 printf("invalid interrupt %d lvl %d at %d hw %d\n",
654 irq, iq->iq_ipl, pcpl,
655 openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid)));
656 #endif
657
658 if (iq->iq_ipl > maxipl)
659 maxipl = iq->iq_ipl;
660 openpic_splraise(iq->iq_ipl);
661 openpic_acknowledge_irq(irq, ci->ci_cpuid);
662
663 spurious = 1;
664 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
665 ppc_intr_enable(1);
666 ret = openpic_ext_intr_handler(ih, &spurious);
667 (void)ppc_intr_disable();
668 if (intr_shared_edge == 00 && ret == 1)
669 break;
670 }
671 if (spurious) {
672 openpic_spurious.ec_count++;
673 DPRINTF("spurious intr %d\n", irq);
674 }
675
676 uvmexp.intrs++;
677 openpic_setipl(pcpl);
678
679 irq = openpic_read_irq(ci->ci_cpuid);
680 }
681
682 openpic_splx(pcpl); /* Process pendings. */
683 openpic_irqnest[ci->ci_cpuid]--;
684 }
685
686 int
openpic_ext_intr_handler(struct intrhand * ih,int * spurious)687 openpic_ext_intr_handler(struct intrhand *ih, int *spurious)
688 {
689 int ret;
690 #ifdef MULTIPROCESSOR
691 int need_lock;
692
693 if (ih->ih_flags & IPL_MPSAFE)
694 need_lock = 0;
695 else
696 need_lock = 1;
697
698 if (need_lock)
699 KERNEL_LOCK();
700 #endif
701 ret = (*ih->ih_fun)(ih->ih_arg);
702 if (ret) {
703 ih->ih_count.ec_count++;
704 *spurious = 0;
705 }
706
707 #ifdef MULTIPROCESSOR
708 if (need_lock)
709 KERNEL_UNLOCK();
710 #endif
711
712 return (ret);
713 }
714
715 void
openpic_acknowledge_irq(int irq,int cpuid)716 openpic_acknowledge_irq(int irq, int cpuid)
717 {
718 (openpic_ops.acknowledge_irq)(irq, cpuid);
719 }
720
721 void
openpic_enable_irq(int irq,int ist,int pri)722 openpic_enable_irq(int irq, int ist, int pri)
723 {
724 (openpic_ops.enable_irq)(irq, ist, pri);
725 }
726
727 void
openpic_disable_irq(int irq,int ist)728 openpic_disable_irq(int irq, int ist)
729 {
730 (openpic_ops.disable_irq)(irq, ist);
731 }
732
733 #ifdef MULTIPROCESSOR
734 void
openpic_send_ipi(struct cpu_info * ci,int id)735 openpic_send_ipi(struct cpu_info *ci, int id)
736 {
737 switch (id) {
738 case PPC_IPI_NOP:
739 id = 0;
740 break;
741 case PPC_IPI_DDB:
742 id = 1;
743 break;
744 default:
745 panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id);
746 }
747
748 openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
749 }
750
751 void
openpic_ipi_ddb(void)752 openpic_ipi_ddb(void)
753 {
754 #ifdef DDB
755 db_enter();
756 #endif
757 }
758 #endif /* MULTIPROCESSOR */
759
760 #if NHPB > 0
761 extern int hpb_enable_irq(int, int);
762 extern int hpb_disable_irq(int, int);
763 extern void hpb_eoi(int);
764
765 void
openpic_cpc945_acknowledge_irq(int irq,int cpuid)766 openpic_cpc945_acknowledge_irq(int irq, int cpuid)
767 {
768 hpb_eoi(irq);
769 openpic_gen_acknowledge_irq(irq, cpuid);
770 }
771
772 void
openpic_cpc945_enable_irq(int irq,int ist,int pri)773 openpic_cpc945_enable_irq(int irq, int ist, int pri)
774 {
775 if (hpb_enable_irq(irq, ist)) {
776 u_int x = irq;
777
778 x |= OPENPIC_SENSE_EDGE;
779 x |= OPENPIC_POLARITY_POSITIVE;
780 x |= pri << OPENPIC_PRIORITY_SHIFT;
781 openpic_write(OPENPIC_SRC_VECTOR(irq), x);
782
783 hpb_eoi(irq);
784 } else
785 openpic_gen_enable_irq(irq, ist, pri);
786 }
787
788 void
openpic_cpc945_disable_irq(int irq,int ist)789 openpic_cpc945_disable_irq(int irq, int ist)
790 {
791 hpb_disable_irq(irq, ist);
792 openpic_gen_disable_irq(irq, ist);
793 }
794 #endif /* NHPB */
795
796