rmixl_intr.c revision 1.1.2.13 1 /* $NetBSD: rmixl_intr.c,v 1.1.2.13 2010/02/23 20:24:37 matt Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
9 * conditions 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
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * 3. The names of the authors may not be used to endorse or promote
17 * products derived from this software without specific prior
18 * written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 */
33 /*-
34 * Copyright (c) 2001 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Jason R. Thorpe.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
50 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 * POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 /*
63 * Platform-specific interrupt support for the RMI XLP, XLR, XLS
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: rmixl_intr.c,v 1.1.2.13 2010/02/23 20:24:37 matt Exp $");
68
69 #include "opt_ddb.h"
70
71 #include <sys/param.h>
72 #include <sys/queue.h>
73 #include <sys/malloc.h>
74 #include <sys/systm.h>
75 #include <sys/device.h>
76 #include <sys/kernel.h>
77
78 #include <machine/bus.h>
79 #include <machine/intr.h>
80
81 #include <mips/cpu.h>
82 #include <mips/locore.h>
83
84 #include <mips/rmi/rmixlreg.h>
85 #include <mips/rmi/rmixlvar.h>
86
87 #include <dev/pci/pcireg.h>
88 #include <dev/pci/pcivar.h>
89
90 #ifdef IOINTR_DEBUG
91 int iointr_debug = IOINTR_DEBUG;
92 # define DPRINTF(x) do { if (iointr_debug) printf x ; } while(0)
93 #else
94 # define DPRINTF(x)
95 #endif
96
97 #define RMIXL_PICREG_READ(off) \
98 RMIXL_IOREG_READ(RMIXL_IO_DEV_PIC + (off))
99 #define RMIXL_PICREG_WRITE(off, val) \
100 RMIXL_IOREG_WRITE(RMIXL_IO_DEV_PIC + (off), (val))
101 /*
102 * This is a mask of bits to clear in the SR when we go to a
103 * given hardware interrupt priority level.
104 * _SR_BITS_DFLT bits are to be always clear (disabled)
105 */
106 #define _SR_BITS_DFLT (MIPS_INT_MASK_2|MIPS_INT_MASK_3|MIPS_INT_MASK_4)
107 static const struct ipl_sr_map rmixl_ipl_sr_map = {
108 .sr_bits = {
109 [IPL_NONE] = _SR_BITS_DFLT,
110 [IPL_SOFTCLOCK] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK_0,
111 [IPL_SOFTNET] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK,
112 [IPL_VM] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
113 [IPL_SCHED] = MIPS_INT_MASK,
114 [IPL_HIGH] = MIPS_INT_MASK,
115 },
116 };
117
118 /*
119 * 'IRQs' here are indiividual interrupt sources
120 * each has a slot in the Interrupt Redirection Table (IRT)
121 * in the order listed
122 *
123 * NOTE: many irq sources depend on the chip family
124 * XLS1xx vs. XLS2xx vs. XLS3xx vs. XLS6xx
125 * use the right table for the CPU that's running.
126 */
127
128 /*
129 * rmixl_irqnames_xls1xx
130 * - use for XLS1xx, XLS2xx, XLS4xx-Lite
131 */
132 #define NIRQS 32
133 static const char * const rmixl_irqnames_xls1xx[NIRQS] = {
134 "int 0 (watchdog)", /* 0 */
135 "int 1 (timer0)", /* 1 */
136 "int 2 (timer1)", /* 2 */
137 "int 3 (timer2)", /* 3 */
138 "int 4 (timer3)", /* 4 */
139 "int 5 (timer4)", /* 5 */
140 "int 6 (timer5)", /* 6 */
141 "int 7 (timer6)", /* 7 */
142 "int 8 (timer7)", /* 8 */
143 "int 9 (uart0)", /* 9 */
144 "int 10 (uart1)", /* 10 */
145 "int 11 (i2c0)", /* 11 */
146 "int 12 (i2c1)", /* 12 */
147 "int 13 (pcmcia)", /* 13 */
148 "int 14 (gpio_a)", /* 14 */
149 "int 15 (irq15)", /* 15 */
150 "int 16 (bridge_tb)", /* 16 */
151 "int 17 (gmac0)", /* 17 */
152 "int 18 (gmac1)", /* 18 */
153 "int 19 (gmac2)", /* 19 */
154 "int 20 (gmac3)", /* 20 */
155 "int 21 (irq21)", /* 21 */
156 "int 22 (irq22)", /* 22 */
157 "int 23 (irq23)", /* 23 */
158 "int 24 (irq24)", /* 24 */
159 "int 25 (bridge_err)", /* 25 */
160 "int 26 (pcie_link0)", /* 26 */
161 "int 27 (pcie_link1)", /* 27 */
162 "int 28 (irq28)", /* 28 */
163 "int 29 (pcie_err)", /* 29 */
164 "int 30 (gpio_b)", /* 30 */
165 "int 31 (usb)", /* 31 */
166 };
167
168 /*
169 * rmixl_irqnames_xls4xx:
170 * - use for XLS4xx, XLS6xx
171 */
172 static const char * const rmixl_irqnames_xls4xx[NIRQS] = {
173 "int 0 (watchdog)", /* 0 */
174 "int 1 (timer0)", /* 1 */
175 "int 2 (timer1)", /* 2 */
176 "int 3 (timer2)", /* 3 */
177 "int 4 (timer3)", /* 4 */
178 "int 5 (timer4)", /* 5 */
179 "int 6 (timer5)", /* 6 */
180 "int 7 (timer6)", /* 7 */
181 "int 8 (timer7)", /* 8 */
182 "int 9 (uart0)", /* 9 */
183 "int 10 (uart1)", /* 10 */
184 "int 11 (i2c0)", /* 11 */
185 "int 12 (i2c1)", /* 12 */
186 "int 13 (pcmcia)", /* 13 */
187 "int 14 (gpio_a)", /* 14 */
188 "int 15 (irq15)", /* 15 */
189 "int 16 (bridge_tb)", /* 16 */
190 "int 17 (gmac0)", /* 17 */
191 "int 18 (gmac1)", /* 18 */
192 "int 19 (gmac2)", /* 19 */
193 "int 20 (gmac3)", /* 20 */
194 "int 21 (irq21)", /* 21 */
195 "int 22 (irq22)", /* 22 */
196 "int 23 (irq23)", /* 23 */
197 "int 24 (irq24)", /* 24 */
198 "int 25 (bridge_err)", /* 25 */
199 "int 26 (pcie_link0)", /* 26 */
200 "int 27 (pcie_link1)", /* 27 */
201 "int 28 (pcie_link2)", /* 28 */
202 "int 29 (pcie_link3)", /* 29 */
203 "int 30 (gpio_b)", /* 30 */
204 "int 31 (usb)", /* 31 */
205 };
206
207 /*
208 * rmixl_irqnames_generic:
209 * - use for unknown cpu implementation
210 */
211 static const char * const rmixl_irqnames_generic[NIRQS] = {
212 "int 0", /* 0 */
213 "int 1", /* 1 */
214 "int 2", /* 2 */
215 "int 3", /* 3 */
216 "int 4", /* 4 */
217 "int 5", /* 5 */
218 "int 6", /* 6 */
219 "int 7", /* 7 */
220 "int 8", /* 8 */
221 "int 9", /* 9 */
222 "int 10", /* 10 */
223 "int 11", /* 11 */
224 "int 12", /* 12 */
225 "int 13", /* 13 */
226 "int 14", /* 14 */
227 "int 15", /* 15 */
228 "int 16", /* 16 */
229 "int 17", /* 17 */
230 "int 18", /* 18 */
231 "int 19", /* 19 */
232 "int 20", /* 20 */
233 "int 21", /* 21 */
234 "int 22", /* 22 */
235 "int 23", /* 23 */
236 "int 24", /* 24 */
237 "int 25", /* 25 */
238 "int 26", /* 26 */
239 "int 27", /* 27 */
240 "int 28", /* 28 */
241 "int 29", /* 29 */
242 "int 30", /* 30 */
243 "int 31", /* 31 */
244 };
245
246 /*
247 * per-IRQ event stats
248 */
249 struct rmixl_irqtab {
250 struct evcnt irq_count;
251 void *irq_ih;
252 };
253 static struct rmixl_irqtab rmixl_irqtab[NIRQS];
254
255
256 /*
257 * 'vectors' here correspond to IRT Entry vector numbers
258 * - IRT Entry vector# is bit# in EIRR
259 * - note that EIRR[7:0] == CAUSE[15:8]
260 * - we actually only use the first _IPL_N bits
261 * (less than 8)
262 *
263 * each IRT entry gets routed to a vector
264 * (if and when that interrupt is established)
265 * the vectors are shared on a per-IPL basis
266 * which simplifies dispatch
267 *
268 * XXX use of mips64 extended IRQs is TBD
269 */
270 #define NINTRVECS _IPL_N
271
272 /*
273 * translate IPL to vector number
274 */
275 static const int rmixl_iplvec[_IPL_N] = {
276 [IPL_NONE] = -1, /* XXX */
277 [IPL_SOFTCLOCK] = 0,
278 [IPL_SOFTNET] = 1,
279 [IPL_VM] = 2,
280 [IPL_SCHED] = 3,
281 };
282
283 /*
284 * list and ref count manage sharing of each vector
285 */
286 struct rmixl_intrvec {
287 LIST_HEAD(, evbmips_intrhand) iv_list;
288 uint32_t iv_ack;
289 rmixl_intr_trigger_t iv_trigger;
290 rmixl_intr_polarity_t iv_polarity;
291 u_int iv_refcnt;
292 };
293 static struct rmixl_intrvec rmixl_intrvec[NINTRVECS];
294
295 #ifdef DIAGNOSTIC
296 static int evbmips_intr_init_done;
297 #endif
298
299
300 static void rmixl_intr_irt_init(int);
301 static void rmixl_intr_irt_disestablish(int);
302 static void rmixl_intr_irt_establish(int, int, rmixl_intr_trigger_t,
303 rmixl_intr_polarity_t, int);
304
305
306 static inline void
307 pic_irt_print(const char *s, const int n, u_int irq)
308 {
309 #ifdef IOINTR_DEBUG
310 uint32_t c0, c1;
311
312 c0 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC0(irq));
313 c1 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC1(irq));
314 printf("%s:%d: irq %d: c0 %#x, c1 %#x\n", s, n, irq, c0, c1);
315 #endif
316 }
317
318 void
319 evbmips_intr_init(void)
320 {
321 uint32_t r;
322 int i;
323
324 KASSERT(cpu_rmixls(mips_options.mips_cpu));
325 ipl_sr_map = rmixl_ipl_sr_map;
326
327 #ifdef DIAGNOSTIC
328 if (evbmips_intr_init_done != 0)
329 panic("%s: evbmips_intr_init_done %d",
330 __func__, evbmips_intr_init_done);
331 #endif
332
333 for (i=0; i < NIRQS; i++) {
334 evcnt_attach_dynamic(&rmixl_irqtab[i].irq_count,
335 EVCNT_TYPE_INTR, NULL, "rmixl", rmixl_intr_string(i));
336 rmixl_irqtab[i].irq_ih = NULL;
337 }
338
339 for (i=0; i < NINTRVECS; i++) {
340 LIST_INIT(&rmixl_intrvec[i].iv_list);
341 rmixl_intrvec[i].iv_ack = 0;
342 rmixl_intrvec[i].iv_refcnt = 0;
343 }
344
345 /*
346 * disable watchdog NMI, timers
347 *
348 * XXX
349 * WATCHDOG_ENB is preserved because clearing it causes
350 * hang on the XLS616 (but not on the XLS408)
351 */
352 r = RMIXL_PICREG_READ(RMIXL_PIC_CONTROL);
353 r &= RMIXL_PIC_CONTROL_RESV|RMIXL_PIC_CONTROL_WATCHDOG_ENB;
354 RMIXL_PICREG_WRITE(RMIXL_PIC_CONTROL, r);
355
356 /*
357 * initialize all IRT Entries
358 */
359 for (i=0; i < NIRQS; i++)
360 rmixl_intr_irt_init(i);
361
362 /*
363 * establish IRT entry for mips3 clock interrupt
364 */
365 rmixl_intr_irt_establish(7, IPL_CLOCK, RMIXL_INTR_LEVEL,
366 RMIXL_INTR_HIGH, rmixl_iplvec[IPL_CLOCK]);
367
368 #ifdef DIAGNOSTIC
369 evbmips_intr_init_done = 1;
370 #endif
371 }
372
373 const char *
374 rmixl_intr_string(int irq)
375 {
376 const char *name;
377
378 if (irq < 0 || irq >= NIRQS)
379 panic("%s: irq %d out of range, max %d",
380 __func__, irq, NIRQS - 1);
381
382 switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
383 case MIPS_XLS104:
384 case MIPS_XLS108:
385 case MIPS_XLS204:
386 case MIPS_XLS208:
387 case MIPS_XLS404LITE:
388 case MIPS_XLS408LITE:
389 name = rmixl_irqnames_xls1xx[irq];
390 break;
391 case MIPS_XLS404:
392 case MIPS_XLS408:
393 case MIPS_XLS416:
394 case MIPS_XLS608:
395 case MIPS_XLS616:
396 name = rmixl_irqnames_xls4xx[irq];
397 break;
398 default:
399 name = rmixl_irqnames_generic[irq];
400 break;
401 }
402
403 return name;
404 }
405
406 /*
407 * rmixl_intr_irt_init
408 * - invalidate IRT Entry for irq
409 * - unmask Thread#0 in low word (assume we only have 1 thread)
410 */
411 static void
412 rmixl_intr_irt_init(int irq)
413 {
414 uint32_t threads;
415
416 #if defined(MULTIPROCESSOR) && defined(NOTYET)
417 /*
418 * XXX make sure the threads are ours?
419 */
420 switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
421 case MIPS_XLS104:
422 case MIPS_XLS204:
423 case MIPS_XLS404:
424 case MIPS_XLS404LITE:
425 threads = __BITS(5,4) | __BITS(1,0);
426 break;
427 case MIPS_XLS108:
428 case MIPS_XLS208:
429 case MIPS_XLS408:
430 case MIPS_XLS408LITE:
431 case MIPS_XLS608:
432 threads = __BITS(7,0);
433 break;
434 case MIPS_XLS416:
435 case MIPS_XLS616:
436 threads = __BITS(15,0);
437 break;
438 default:
439 panic("%s: unknown cpu ID %#x\n", __func__,
440 mips_options.mips_cpu_id);
441 }
442 #else
443 threads = 1;
444 #endif
445 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
446 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), threads); /* low word */
447 }
448
449 /*
450 * rmixl_intr_irt_disestablish
451 * - invalidate IRT Entry for irq
452 * - writes to IRTENTRYC1 only; leave IRTENTRYC0 as-is
453 */
454 static void
455 rmixl_intr_irt_disestablish(int irq)
456 {
457 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, 0));
458 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
459 }
460
461 /*
462 * rmixl_intr_irt_establish
463 * - construct and IRT Entry for irq and write to PIC
464 * - writes to IRTENTRYC1 only; assumes IRTENTRYC0 has been initialized
465 */
466 static void
467 rmixl_intr_irt_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
468 rmixl_intr_polarity_t polarity, int vec)
469 {
470 uint32_t irtc1;
471
472 irtc1 = RMIXL_PIC_IRTENTRYC1_VALID;
473 irtc1 |= RMIXL_PIC_IRTENTRYC1_GL; /* local */
474
475 if (trigger == RMIXL_INTR_LEVEL)
476 irtc1 |= RMIXL_PIC_IRTENTRYC1_TRG;
477
478 if ((polarity == RMIXL_INTR_FALLING) || (polarity == RMIXL_INTR_LOW))
479 irtc1 |= RMIXL_PIC_IRTENTRYC1_P;
480
481 irtc1 |= vec;
482
483 /*
484 * write IRT Entry to PIC (high word only)
485 */
486 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, irtc1));
487 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1);
488 }
489
490 void *
491 rmixl_intr_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
492 rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg)
493 {
494 struct evbmips_intrhand *ih;
495 struct rmixl_intrvec *ivp;
496 int vec;
497 int s;
498
499 #ifdef DIAGNOSTIC
500 if (evbmips_intr_init_done == 0)
501 panic("%s: called before evbmips_intr_init", __func__);
502 #endif
503
504 /*
505 * check args and assemble an IRT Entry
506 */
507 if (irq < 0 || irq >= NIRQS)
508 panic("%s: irq %d out of range, max %d",
509 __func__, irq, NIRQS - 1);
510 if (ipl <= 0 || ipl >= _IPL_N)
511 panic("%s: ipl %d out of range, min %d, max %d",
512 __func__, ipl, 1, _IPL_N - 1);
513 if (rmixl_irqtab[irq].irq_ih != NULL)
514 panic("%s: irq %d busy", __func__, irq);
515
516 switch (trigger) {
517 case RMIXL_INTR_EDGE:
518 case RMIXL_INTR_LEVEL:
519 break;
520 default:
521 panic("%s: bad trigger %d\n", __func__, trigger);
522 }
523
524 switch (polarity) {
525 case RMIXL_INTR_RISING:
526 case RMIXL_INTR_HIGH:
527 case RMIXL_INTR_FALLING:
528 case RMIXL_INTR_LOW:
529 break;
530 default:
531 panic("%s: bad polarity %d\n", __func__, polarity);
532 }
533
534 /*
535 * ipl determines which vector to use
536 */
537 vec = rmixl_iplvec[ipl];
538 DPRINTF(("%s: irq %d, ipl %d, vec %d\n", __func__, irq, ipl, vec));
539 KASSERT((vec & ~RMIXL_PIC_IRTENTRYC1_INTVEC) == 0);
540
541 s = splhigh();
542
543 ivp = &rmixl_intrvec[vec];
544 if (ivp->iv_refcnt == 0) {
545 ivp->iv_trigger = trigger;
546 ivp->iv_polarity = polarity;
547 } else {
548 if (ivp->iv_trigger != trigger) {
549 #ifdef DIAGNOSTIC
550 printf("%s: vec %d, irqs {", __func__, vec);
551 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
552 printf(" %d", ih->ih_irq);
553 }
554 printf(" } trigger type %d; irq %d wants type %d\n",
555 ivp->iv_trigger, irq, trigger);
556 #endif
557 panic("%s: trigger mismatch at vec %d\n",
558 __func__, vec);
559 }
560 if (ivp->iv_polarity != polarity) {
561 #ifdef DIAGNOSTIC
562 printf("%s: vec %d, irqs {", __func__, vec);
563 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
564 printf(" %d", ih->ih_irq);
565 }
566 printf(" } polarity type %d; irq %d wants type %d\n",
567 ivp->iv_polarity, irq, polarity);
568 #endif
569 panic("%s: polarity mismatch at vec %d\n",
570 __func__, vec);
571 }
572 }
573 ivp->iv_ack |= (1 << irq);
574
575 /*
576 * allocate and initialize an interrupt handle
577 */
578 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
579 if (ih == NULL)
580 goto out;
581
582 ih->ih_func = func;
583 ih->ih_arg = arg;
584 ih->ih_irq = irq;
585 ih->ih_ipl = ipl;
586
587 /*
588 * mark this irq as established, busy
589 */
590 rmixl_irqtab[irq].irq_ih = ih;
591
592 /*
593 * link this ih into the tables and bump reference count
594 */
595 LIST_INSERT_HEAD(&ivp->iv_list, ih, ih_q);
596 ivp->iv_refcnt++;
597
598 /*
599 * establish IRT Entry
600 */
601 rmixl_intr_irt_establish(irq, ipl, trigger, polarity, vec);
602
603 out:
604 splx(s);
605
606 return ih;
607 }
608
609 void
610 rmixl_intr_disestablish(void *cookie)
611 {
612 struct evbmips_intrhand *ih = cookie;
613 struct rmixl_intrvec *ivp;
614 int irq;
615 int vec;
616 int s;
617
618 irq = ih->ih_irq;
619 vec = rmixl_iplvec[ih->ih_ipl];
620 ivp = &rmixl_intrvec[vec];
621
622 s = splhigh();
623
624 /*
625 * disable the IRT Entry (high word only)
626 */
627 rmixl_intr_irt_disestablish(irq);
628
629 /*
630 * remove from the table and adjust the reference count
631 */
632 LIST_REMOVE(ih, ih_q);
633 ivp->iv_refcnt--;
634 ivp->iv_ack &= ~(1 << irq);
635
636 /*
637 * this irq now disestablished, not busy
638 */
639 rmixl_irqtab[irq].irq_ih = NULL;
640
641 splx(s);
642
643 free(ih, M_DEVBUF);
644 }
645
646 void
647 evbmips_iointr(int ipl, vaddr_t pc, uint32_t ipending)
648 {
649 struct evbmips_intrhand *ih;
650 struct rmixl_intrvec *ivp;
651 int vec;
652 uint64_t eirr;
653 #ifdef IOINTR_DEBUG
654 uint64_t eimr;
655
656 printf("%s: ipl %d, pc %#x, ipending %#x\n",
657 __func__, ipl, pc, ipending);
658
659 asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
660 asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr));
661 printf("%s:%d: eirr %#lx, eimr %#lx\n", __func__, __LINE__, eirr, eimr);
662 #endif
663
664 for (vec = NINTRVECS - 1; vec >= 2; vec--) {
665 if ((ipending & (MIPS_SOFT_INT_MASK_0 << vec)) == 0)
666 continue;
667
668 ivp = &rmixl_intrvec[vec];
669
670 asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
671 eirr &= 3;
672 eirr |= 1ULL << vec;
673 asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr));
674
675 #ifdef IOINTR_DEBUG
676 printf("%s: interrupt at vec %d\n",
677 __func__, vec);
678 if (LIST_EMPTY(&ivp->iv_list))
679 printf("%s: unexpected interrupt at vec %d\n",
680 __func__, vec);
681 #endif
682 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
683 pic_irt_print(__func__, __LINE__, ih->ih_irq);
684 RMIXL_PICREG_WRITE(RMIXL_PIC_INTRACK,
685 (1 << ih->ih_irq));
686 if ((*ih->ih_func)(ih->ih_arg) != 0) {
687 rmixl_irqtab[ih->ih_irq].irq_count.ev_count++;
688 }
689 }
690 }
691 }
692
693 #ifdef DEBUG
694 int rmixl_intrvec_print(void);
695 int
696 rmixl_intrvec_print(void)
697 {
698 struct evbmips_intrhand *ih;
699 struct rmixl_intrvec *ivp;
700 int vec;
701
702 ivp = &rmixl_intrvec[0];
703 for (vec=0; vec < NINTRVECS ; vec++) {
704 printf("vec %d, irqs {", vec);
705 LIST_FOREACH(ih, &ivp->iv_list, ih_q)
706 printf(" %d", ih->ih_irq);
707 printf(" } trigger type %d\n", ivp->iv_trigger);
708 ivp++;
709 }
710 return 0;
711 }
712 #endif
713