rmixl_intr.c revision 1.1.2.9 1 /* $NetBSD: rmixl_intr.c,v 1.1.2.9 2010/02/06 02:59:04 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.9 2010/02/06 02:59:04 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 const uint32_t ipl_sr_bits[_IPL_N] = {
108 [IPL_NONE] = _SR_BITS_DFLT,
109 [IPL_SOFTCLOCK] =
110 _SR_BITS_DFLT
111 | MIPS_SOFT_INT_MASK_0,
112 [IPL_SOFTNET] =
113 _SR_BITS_DFLT
114 | MIPS_SOFT_INT_MASK_0
115 | MIPS_SOFT_INT_MASK_1,
116 [IPL_VM] =
117 _SR_BITS_DFLT
118 | MIPS_SOFT_INT_MASK_0
119 | MIPS_SOFT_INT_MASK_1
120 | MIPS_INT_MASK_0,
121 [IPL_SCHED] =
122 MIPS_INT_MASK,
123 };
124
125 /*
126 * 'IRQs' here are indiividual interrupt sources
127 * each has a slot in the Interrupt Redirection Table (IRT)
128 * in the order listed
129 *
130 * NOTE: many irq sources depend on the chip family
131 * XLS1xx vs. XLS2xx vs. XLS3xx vs. XLS6xx
132 * use the right table for the CPU that's running.
133 */
134
135 /*
136 * rmixl_irqnames_xls1xx
137 * - use for XLS1xx, XLS2xx, XLS4xx-Lite
138 */
139 #define NIRQS 32
140 static const char * const rmixl_irqnames_xls1xx[NIRQS] = {
141 "int 0 (watchdog)", /* 0 */
142 "int 1 (timer0)", /* 1 */
143 "int 2 (timer1)", /* 2 */
144 "int 3 (timer2)", /* 3 */
145 "int 4 (timer3)", /* 4 */
146 "int 5 (timer4)", /* 5 */
147 "int 6 (timer5)", /* 6 */
148 "int 7 (timer6)", /* 7 */
149 "int 8 (timer7)", /* 8 */
150 "int 9 (uart0)", /* 9 */
151 "int 10 (uart1)", /* 10 */
152 "int 11 (i2c0)", /* 11 */
153 "int 12 (i2c1)", /* 12 */
154 "int 13 (pcmcia)", /* 13 */
155 "int 14 (gpio_a)", /* 14 */
156 "int 15 (irq15)", /* 15 */
157 "int 16 (bridge_tb)", /* 16 */
158 "int 17 (gmac0)", /* 17 */
159 "int 18 (gmac1)", /* 18 */
160 "int 19 (gmac2)", /* 19 */
161 "int 20 (gmac3)", /* 20 */
162 "int 21 (irq21)", /* 21 */
163 "int 22 (irq22)", /* 22 */
164 "int 23 (irq23)", /* 23 */
165 "int 24 (irq24)", /* 24 */
166 "int 25 (bridge_err)", /* 25 */
167 "int 26 (pcie_link0)", /* 26 */
168 "int 27 (pcie_link1)", /* 27 */
169 "int 28 (irq28)", /* 28 */
170 "int 29 (pcie_err)", /* 29 */
171 "int 30 (gpio_b)", /* 30 */
172 "int 31 (usb)", /* 31 */
173 };
174
175 /*
176 * rmixl_irqnames_xls4xx:
177 * - use for XLS4xx, XLS6xx
178 */
179 static const char * const rmixl_irqnames_xls4xx[NIRQS] = {
180 "int 0 (watchdog)", /* 0 */
181 "int 1 (timer0)", /* 1 */
182 "int 2 (timer1)", /* 2 */
183 "int 3 (timer2)", /* 3 */
184 "int 4 (timer3)", /* 4 */
185 "int 5 (timer4)", /* 5 */
186 "int 6 (timer5)", /* 6 */
187 "int 7 (timer6)", /* 7 */
188 "int 8 (timer7)", /* 8 */
189 "int 9 (uart0)", /* 9 */
190 "int 10 (uart1)", /* 10 */
191 "int 11 (i2c0)", /* 11 */
192 "int 12 (i2c1)", /* 12 */
193 "int 13 (pcmcia)", /* 13 */
194 "int 14 (gpio_a)", /* 14 */
195 "int 15 (irq15)", /* 15 */
196 "int 16 (bridge_tb)", /* 16 */
197 "int 17 (gmac0)", /* 17 */
198 "int 18 (gmac1)", /* 18 */
199 "int 19 (gmac2)", /* 19 */
200 "int 20 (gmac3)", /* 20 */
201 "int 21 (irq21)", /* 21 */
202 "int 22 (irq22)", /* 22 */
203 "int 23 (irq23)", /* 23 */
204 "int 24 (irq24)", /* 24 */
205 "int 25 (bridge_err)", /* 25 */
206 "int 26 (pcie_link0)", /* 26 */
207 "int 27 (pcie_link1)", /* 27 */
208 "int 28 (pcie_link2)", /* 28 */
209 "int 29 (pcie_link3)", /* 29 */
210 "int 30 (gpio_b)", /* 30 */
211 "int 31 (usb)", /* 31 */
212 };
213
214 /*
215 * rmixl_irqnames_generic:
216 * - use for unknown cpu implementation
217 */
218 static const char * const rmixl_irqnames_generic[NIRQS] = {
219 "int 0", /* 0 */
220 "int 1", /* 1 */
221 "int 2", /* 2 */
222 "int 3", /* 3 */
223 "int 4", /* 4 */
224 "int 5", /* 5 */
225 "int 6", /* 6 */
226 "int 7", /* 7 */
227 "int 8", /* 8 */
228 "int 9", /* 9 */
229 "int 10", /* 10 */
230 "int 11", /* 11 */
231 "int 12", /* 12 */
232 "int 13", /* 13 */
233 "int 14", /* 14 */
234 "int 15", /* 15 */
235 "int 16", /* 16 */
236 "int 17", /* 17 */
237 "int 18", /* 18 */
238 "int 19", /* 19 */
239 "int 20", /* 20 */
240 "int 21", /* 21 */
241 "int 22", /* 22 */
242 "int 23", /* 23 */
243 "int 24", /* 24 */
244 "int 25", /* 25 */
245 "int 26", /* 26 */
246 "int 27", /* 27 */
247 "int 28", /* 28 */
248 "int 29", /* 29 */
249 "int 30", /* 30 */
250 "int 31", /* 31 */
251 };
252
253 /*
254 * per-IRQ event stats
255 */
256 struct rmixl_irqtab {
257 struct evcnt irq_count;
258 void *irq_ih;
259 };
260 static struct rmixl_irqtab rmixl_irqtab[NIRQS];
261
262
263 /*
264 * 'vectors' here correspond to IRT Entry vector numbers
265 * - IRT Entry vector# is bit# in EIRR
266 * - note that EIRR[7:0] == CAUSE[15:8]
267 * - we actually only use the first _IPL_N bits
268 * (less than 8)
269 *
270 * each IRT entry gets routed to a vector
271 * (if and when that interrupt is established)
272 * the vectors are shared on a per-IPL basis
273 * which simplifies dispatch
274 *
275 * XXX use of mips64 extended IRQs is TBD
276 */
277 #define NINTRVECS _IPL_N
278
279 /*
280 * translate IPL to vector number
281 */
282 static const int rmixl_iplvec[_IPL_N] = {
283 [IPL_NONE] = -1, /* XXX */
284 [IPL_SOFTCLOCK] = 0,
285 [IPL_SOFTNET] = 1,
286 [IPL_VM] = 2,
287 [IPL_SCHED] = 3,
288 };
289
290 /*
291 * list and ref count manage sharing of each vector
292 */
293 struct rmixl_intrvec {
294 LIST_HEAD(, evbmips_intrhand) iv_list;
295 uint32_t iv_ack;
296 rmixl_intr_trigger_t iv_trigger;
297 rmixl_intr_polarity_t iv_polarity;
298 u_int iv_refcnt;
299 };
300 static struct rmixl_intrvec rmixl_intrvec[NINTRVECS];
301
302 #ifdef DIAGNOSTIC
303 static int evbmips_intr_init_done;
304 #endif
305
306
307 static void rmixl_intr_irt_init(int);
308 static void rmixl_intr_irt_disestablish(int);
309 static void rmixl_intr_irt_establish(int, int, rmixl_intr_trigger_t,
310 rmixl_intr_polarity_t, int);
311
312
313 static inline void
314 pic_irt_print(const char *s, const int n, u_int irq)
315 {
316 #ifdef IOINTR_DEBUG
317 uint32_t c0, c1;
318
319 c0 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC0(irq));
320 c1 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC1(irq));
321 printf("%s:%d: irq %d: c0 %#x, c1 %#x\n", s, n, irq, c0, c1);
322 #endif
323 }
324
325 void
326 evbmips_intr_init(void)
327 {
328 uint32_t r;
329 int i;
330
331 KASSERT(cpu_rmixls(mips_options.mips_cpu));
332
333 #ifdef DIAGNOSTIC
334 if (evbmips_intr_init_done != 0)
335 panic("%s: evbmips_intr_init_done %d",
336 __func__, evbmips_intr_init_done);
337 #endif
338
339 for (i=0; i < NIRQS; i++) {
340 evcnt_attach_dynamic(&rmixl_irqtab[i].irq_count,
341 EVCNT_TYPE_INTR, NULL, "rmixl", rmixl_intr_string(i));
342 rmixl_irqtab[i].irq_ih = NULL;
343 }
344
345 for (i=0; i < NINTRVECS; i++) {
346 LIST_INIT(&rmixl_intrvec[i].iv_list);
347 rmixl_intrvec[i].iv_ack = 0;
348 rmixl_intrvec[i].iv_refcnt = 0;
349 }
350
351 /*
352 * disable watchdog NMI, timers
353 *
354 * XXX
355 * WATCHDOG_ENB is preserved because clearing it causes
356 * hang on the XLS616 (but not on the XLS408)
357 */
358 r = RMIXL_PICREG_READ(RMIXL_PIC_CONTROL);
359 r &= RMIXL_PIC_CONTROL_RESV|RMIXL_PIC_CONTROL_WATCHDOG_ENB;
360 RMIXL_PICREG_WRITE(RMIXL_PIC_CONTROL, r);
361
362 /*
363 * initialize all IRT Entries
364 */
365 for (i=0; i < NIRQS; i++)
366 rmixl_intr_irt_init(i);
367
368 /*
369 * establish IRT entry for mips3 clock interrupt
370 */
371 rmixl_intr_irt_establish(7, IPL_CLOCK, RMIXL_INTR_LEVEL,
372 RMIXL_INTR_HIGH, rmixl_iplvec[IPL_CLOCK]);
373
374 #ifdef DIAGNOSTIC
375 evbmips_intr_init_done = 1;
376 #endif
377 }
378
379 const char *
380 rmixl_intr_string(int irq)
381 {
382 const char *name;
383
384 if (irq < 0 || irq >= NIRQS)
385 panic("%s: irq %d out of range, max %d",
386 __func__, irq, NIRQS - 1);
387
388 switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
389 case MIPS_XLS104:
390 case MIPS_XLS108:
391 case MIPS_XLS204:
392 case MIPS_XLS208:
393 case MIPS_XLS404LITE:
394 case MIPS_XLS408LITE:
395 name = rmixl_irqnames_xls1xx[irq];
396 break;
397 case MIPS_XLS404:
398 case MIPS_XLS408:
399 case MIPS_XLS416:
400 case MIPS_XLS608:
401 case MIPS_XLS616:
402 name = rmixl_irqnames_xls4xx[irq];
403 break;
404 default:
405 name = rmixl_irqnames_generic[irq];
406 break;
407 }
408
409 return name;
410 }
411
412 /*
413 * rmixl_intr_irt_init
414 * - invalidate IRT Entry for irq
415 * - unmask Thread#0 in low word (assume we only have 1 thread)
416 */
417 static void
418 rmixl_intr_irt_init(int irq)
419 {
420 uint32_t threads;
421
422 #if defined(MULTIPROCESSOR) && defined(NOTYET)
423 /*
424 * XXX make sure the threads are ours?
425 */
426 switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
427 case MIPS_XLS104:
428 case MIPS_XLS204:
429 case MIPS_XLS404:
430 case MIPS_XLS404LITE:
431 threads = __BITS(5,4) | __BITS(1,0);
432 break;
433 case MIPS_XLS108:
434 case MIPS_XLS208:
435 case MIPS_XLS408:
436 case MIPS_XLS408LITE:
437 case MIPS_XLS608:
438 threads = __BITS(7,0);
439 break;
440 case MIPS_XLS416:
441 case MIPS_XLS616:
442 threads = __BITS(15,0);
443 break;
444 default:
445 panic("%s: unknown cpu ID %#x\n", __func__,
446 mips_options.mips_cpu_id);
447 }
448 #else
449 threads = 1;
450 #endif
451 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
452 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), threads); /* low word */
453 }
454
455 /*
456 * rmixl_intr_irt_disestablish
457 * - invalidate IRT Entry for irq
458 * - writes to IRTENTRYC1 only; leave IRTENTRYC0 as-is
459 */
460 static void
461 rmixl_intr_irt_disestablish(int irq)
462 {
463 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, 0));
464 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
465 }
466
467 /*
468 * rmixl_intr_irt_establish
469 * - construct and IRT Entry for irq and write to PIC
470 * - writes to IRTENTRYC1 only; assumes IRTENTRYC0 has been initialized
471 */
472 static void
473 rmixl_intr_irt_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
474 rmixl_intr_polarity_t polarity, int vec)
475 {
476 uint32_t irtc1;
477
478 irtc1 = RMIXL_PIC_IRTENTRYC1_VALID;
479 irtc1 |= RMIXL_PIC_IRTENTRYC1_GL; /* local */
480
481 if (trigger == RMIXL_INTR_LEVEL)
482 irtc1 |= RMIXL_PIC_IRTENTRYC1_TRG;
483
484 if ((polarity == RMIXL_INTR_FALLING) || (polarity == RMIXL_INTR_LOW))
485 irtc1 |= RMIXL_PIC_IRTENTRYC1_P;
486
487 irtc1 |= vec;
488
489 /*
490 * write IRT Entry to PIC (high word only)
491 */
492 DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, irtc1));
493 RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1);
494 }
495
496 void *
497 rmixl_intr_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
498 rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg)
499 {
500 struct evbmips_intrhand *ih;
501 struct rmixl_intrvec *ivp;
502 int vec;
503 int s;
504
505 #ifdef DIAGNOSTIC
506 if (evbmips_intr_init_done == 0)
507 panic("%s: called before evbmips_intr_init", __func__);
508 #endif
509
510 /*
511 * check args and assemble an IRT Entry
512 */
513 if (irq < 0 || irq >= NIRQS)
514 panic("%s: irq %d out of range, max %d",
515 __func__, irq, NIRQS - 1);
516 if (ipl <= 0 || ipl >= _IPL_N)
517 panic("%s: ipl %d out of range, min %d, max %d",
518 __func__, ipl, 1, _IPL_N - 1);
519 if (rmixl_irqtab[irq].irq_ih != NULL)
520 panic("%s: irq %d busy", __func__, irq);
521
522 switch (trigger) {
523 case RMIXL_INTR_EDGE:
524 case RMIXL_INTR_LEVEL:
525 break;
526 default:
527 panic("%s: bad trigger %d\n", __func__, trigger);
528 }
529
530 switch (polarity) {
531 case RMIXL_INTR_RISING:
532 case RMIXL_INTR_HIGH:
533 case RMIXL_INTR_FALLING:
534 case RMIXL_INTR_LOW:
535 break;
536 default:
537 panic("%s: bad polarity %d\n", __func__, polarity);
538 }
539
540 /*
541 * ipl determines which vector to use
542 */
543 vec = rmixl_iplvec[ipl];
544 DPRINTF(("%s: irq %d, ipl %d, vec %d\n", __func__, irq, ipl, vec));
545 KASSERT((vec & ~RMIXL_PIC_IRTENTRYC1_INTVEC) == 0);
546
547 s = splhigh();
548
549 ivp = &rmixl_intrvec[vec];
550 if (ivp->iv_refcnt == 0) {
551 ivp->iv_trigger = trigger;
552 ivp->iv_polarity = polarity;
553 } else {
554 if (ivp->iv_trigger != trigger) {
555 #ifdef DIAGNOSTIC
556 printf("%s: vec %d, irqs {", __func__, vec);
557 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
558 printf(" %d", ih->ih_irq);
559 }
560 printf(" } trigger type %d; irq %d wants type %d\n",
561 ivp->iv_trigger, irq, trigger);
562 #endif
563 panic("%s: trigger mismatch at vec %d\n",
564 __func__, vec);
565 }
566 if (ivp->iv_polarity != polarity) {
567 #ifdef DIAGNOSTIC
568 printf("%s: vec %d, irqs {", __func__, vec);
569 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
570 printf(" %d", ih->ih_irq);
571 }
572 printf(" } polarity type %d; irq %d wants type %d\n",
573 ivp->iv_polarity, irq, polarity);
574 #endif
575 panic("%s: polarity mismatch at vec %d\n",
576 __func__, vec);
577 }
578 }
579 ivp->iv_ack |= (1 << irq);
580
581 /*
582 * allocate and initialize an interrupt handle
583 */
584 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
585 if (ih == NULL)
586 return NULL;
587
588 ih->ih_func = func;
589 ih->ih_arg = arg;
590 ih->ih_irq = irq;
591 ih->ih_ipl = ipl;
592
593 /*
594 * mark this irq as established, busy
595 */
596 rmixl_irqtab[irq].irq_ih = ih;
597
598 /*
599 * link this ih into the tables and bump reference count
600 */
601 LIST_INSERT_HEAD(&ivp->iv_list, ih, ih_q);
602 ivp->iv_refcnt++;
603
604 /*
605 * establish IRT Entry
606 */
607 rmixl_intr_irt_establish(irq, ipl, trigger, polarity, vec);
608
609 splx(s);
610
611 return ih;
612 }
613
614 void
615 rmixl_intr_disestablish(void *cookie)
616 {
617 struct evbmips_intrhand *ih = cookie;
618 struct rmixl_intrvec *ivp;
619 int irq;
620 int vec;
621 int s;
622
623 irq = ih->ih_irq;
624 vec = rmixl_iplvec[ih->ih_ipl];
625 ivp = &rmixl_intrvec[vec];
626
627 s = splhigh();
628
629 /*
630 * disable the IRT Entry (high word only)
631 */
632 rmixl_intr_irt_disestablish(irq);
633
634 /*
635 * remove from the table and adjust the reference count
636 */
637 LIST_REMOVE(ih, ih_q);
638 ivp->iv_refcnt--;
639 ivp->iv_ack &= ~(1 << irq);
640
641 /*
642 * this irq now disestablished, not busy
643 */
644 rmixl_irqtab[irq].irq_ih = NULL;
645
646 splx(s);
647
648 free(ih, M_DEVBUF);
649 }
650
651 void
652 evbmips_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
653 {
654 struct evbmips_intrhand *ih;
655 struct rmixl_intrvec *ivp;
656 int vec;
657 uint64_t eirr;
658 #ifdef IOINTR_DEBUG
659 uint64_t eimr;
660
661 printf("%s: status %#x, cause %#x, pc %#x, ipending %#x\n",
662 __func__, status, cause, pc, ipending);
663
664 asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
665 asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr));
666 printf("%s:%d: eirr %#lx, eimr %#lx\n", __func__, __LINE__, eirr, eimr);
667 #endif
668
669 for (vec = NINTRVECS - 1; vec >= 2; vec--) {
670 if ((ipending & (MIPS_SOFT_INT_MASK_0 << vec)) == 0)
671 continue;
672
673 ivp = &rmixl_intrvec[vec];
674
675 eirr = 1ULL << vec;
676 asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr));
677
678 #ifdef IOINTR_DEBUG
679 printf("%s: interrupt at vec %d\n",
680 __func__, vec);
681 if (LIST_EMPTY(&ivp->iv_list))
682 printf("%s: unexpected interrupt at vec %d\n",
683 __func__, vec);
684 #endif
685 LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
686 pic_irt_print(__func__, __LINE__, ih->ih_irq);
687 RMIXL_PICREG_WRITE(RMIXL_PIC_INTRACK,
688 (1 << ih->ih_irq));
689 if ((*ih->ih_func)(ih->ih_arg) != 0) {
690 rmixl_irqtab[ih->ih_irq].irq_count.ev_count++;
691 }
692 }
693
694 cause &= ~(MIPS_SOFT_INT_MASK_0 << vec);
695 }
696
697
698 /* Re-enable anything that we have processed. */
699 _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
700 }
701
702 #ifdef DEBUG
703 int rmixl_intrvec_print(void);
704 int
705 rmixl_intrvec_print(void)
706 {
707 struct evbmips_intrhand *ih;
708 struct rmixl_intrvec *ivp;
709 int vec;
710
711 ivp = &rmixl_intrvec[0];
712 for (vec=0; vec < NINTRVECS ; vec++) {
713 printf("vec %d, irqs {", vec);
714 LIST_FOREACH(ih, &ivp->iv_list, ih_q)
715 printf(" %d", ih->ih_irq);
716 printf(" } trigger type %d\n", ivp->iv_trigger);
717 ivp++;
718 }
719 return 0;
720 }
721 #endif
722