xref: /netbsd-src/sys/arch/mips/rmi/rmixl_intr.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: rmixl_intr.c,v 1.2 2009/12/14 00:46:07 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.2 2009/12/14 00:46:07 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 *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 (irq29)",	/* 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 *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_xls4xx:
216  * - use for unknown cpu implementation
217  */
218 static const char *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(mycpu));
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(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 	RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0);	/* high word */
421 	RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), 1);	/* low  word */
422 }
423 
424 /*
425  * rmixl_intr_irt_disestablish
426  * - invalidate IRT Entry for irq
427  * - writes to IRTENTRYC1 only; leave IRTENTRYC0 as-is
428  */
429 static void
430 rmixl_intr_irt_disestablish(int irq)
431 {
432 	DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, 0));
433 	RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0);	/* high word */
434 }
435 
436 /*
437  * rmixl_intr_irt_establish
438  * - construct and IRT Entry for irq and write to PIC
439  * - writes to IRTENTRYC1 only; assumes IRTENTRYC0 has been initialized
440  */
441 static void
442 rmixl_intr_irt_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
443 	rmixl_intr_polarity_t polarity, int vec)
444 {
445 	uint32_t irtc1;
446 
447 	irtc1  = RMIXL_PIC_IRTENTRYC1_VALID;
448 	irtc1 |= RMIXL_PIC_IRTENTRYC1_GL;	/* local */
449 
450 	if (trigger == RMIXL_INTR_LEVEL)
451 		irtc1 |= RMIXL_PIC_IRTENTRYC1_TRG;
452 
453 	if ((polarity == RMIXL_INTR_FALLING) || (polarity == RMIXL_INTR_LOW))
454 		irtc1 |= RMIXL_PIC_IRTENTRYC1_P;
455 
456 	irtc1 |= vec;
457 
458 	/*
459 	 * write IRT Entry to PIC (high word only)
460 	 */
461 	DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, irtc1));
462 	RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1);
463 }
464 
465 void *
466 rmixl_intr_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
467 	rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg)
468 {
469 	struct evbmips_intrhand *ih;
470 	struct rmixl_intrvec *ivp;
471 	int vec;
472 	int s;
473 
474 #ifdef DIAGNOSTIC
475 	if (evbmips_intr_init_done == 0)
476 		panic("%s: called before evbmips_intr_init", __func__);
477 #endif
478 
479 	/*
480 	 * check args and assemble an IRT Entry
481 	 */
482 	if (irq < 0 || irq >= NIRQS)
483 		panic("%s: irq %d out of range, max %d",
484 			__func__, irq, NIRQS - 1);
485 	if (ipl <= 0 || ipl >= _IPL_N)
486 		panic("%s: ipl %d out of range, min %d, max %d",
487 			__func__, ipl, 1, _IPL_N - 1);
488 	if (rmixl_irqtab[irq].irq_ih != NULL)
489 		panic("%s: irq %d busy", __func__, irq);
490 
491 	switch (trigger) {
492 	case RMIXL_INTR_EDGE:
493 	case RMIXL_INTR_LEVEL:
494 		break;
495 	default:
496 		panic("%s: bad trigger %d\n", __func__, trigger);
497 	}
498 
499 	switch (polarity) {
500 	case RMIXL_INTR_RISING:
501 	case RMIXL_INTR_HIGH:
502 	case RMIXL_INTR_FALLING:
503 	case RMIXL_INTR_LOW:
504 		break;
505 	default:
506 		panic("%s: bad polarity %d\n", __func__, polarity);
507 	}
508 
509 	/*
510 	 * ipl determines which vector to use
511 	 */
512 	vec = rmixl_iplvec[ipl];
513 	DPRINTF(("%s: irq %d, ipl %d, vec %d\n", __func__, irq, ipl, vec));
514 	KASSERT((vec & ~RMIXL_PIC_IRTENTRYC1_INTVEC) == 0);
515 
516 	s = splhigh();
517 
518 	ivp = &rmixl_intrvec[vec];
519 	if (ivp->iv_refcnt == 0) {
520 		ivp->iv_trigger = trigger;
521 		ivp->iv_polarity = polarity;
522 	} else {
523 		if (ivp->iv_trigger != trigger) {
524 #ifdef DIAGNOSTIC
525 			printf("%s: vec %d, irqs {", __func__, vec);
526 			LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
527 				printf(" %d", ih->ih_irq);
528 			}
529 			printf(" } trigger type %d; irq %d wants type %d\n",
530 				ivp->iv_trigger, irq, trigger);
531 #endif
532 			panic("%s: trigger mismatch at vec %d\n",
533 				__func__, vec);
534 		}
535 		if (ivp->iv_polarity != polarity) {
536 #ifdef DIAGNOSTIC
537 			printf("%s: vec %d, irqs {", __func__, vec);
538 			LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
539 				printf(" %d", ih->ih_irq);
540 			}
541 			printf(" } polarity type %d; irq %d wants type %d\n",
542 				ivp->iv_polarity, irq, polarity);
543 #endif
544 			panic("%s: polarity mismatch at vec %d\n",
545 				__func__, vec);
546 		}
547 	}
548 	ivp->iv_ack |= (1 << irq);
549 
550 	/*
551 	 * allocate and initialize an interrupt handle
552 	 */
553 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
554 	if (ih == NULL)
555 		return NULL;
556 
557 	ih->ih_func = func;
558 	ih->ih_arg = arg;
559 	ih->ih_irq = irq;
560 	ih->ih_ipl = ipl;
561 
562 	/*
563 	 * mark this irq as established, busy
564 	 */
565 	rmixl_irqtab[irq].irq_ih = ih;
566 
567 	/*
568 	 * link this ih into the tables and bump reference count
569 	 */
570 	LIST_INSERT_HEAD(&ivp->iv_list, ih, ih_q);
571 	ivp->iv_refcnt++;
572 
573 	/*
574 	 * establish IRT Entry
575 	 */
576 	rmixl_intr_irt_establish(irq, ipl, trigger, polarity, vec);
577 
578 	splx(s);
579 
580 	return ih;
581 }
582 
583 void
584 rmixl_intr_disestablish(void *cookie)
585 {
586 	struct evbmips_intrhand *ih = cookie;
587 	struct rmixl_intrvec *ivp;
588 	int irq;
589 	int vec;
590 	int s;
591 
592 	irq = ih->ih_irq;
593 	vec = rmixl_iplvec[ih->ih_ipl];
594 	ivp = &rmixl_intrvec[vec];
595 
596 	s = splhigh();
597 
598 	/*
599 	 * disable the IRT Entry (high word only)
600 	 */
601 	rmixl_intr_irt_disestablish(irq);
602 
603 	/*
604 	 * remove from the table and adjust the reference count
605 	 */
606 	LIST_REMOVE(ih, ih_q);
607 	ivp->iv_refcnt--;
608 	ivp->iv_ack &= ~(1 << irq);
609 
610 	/*
611 	 * this irq now disestablished, not busy
612 	 */
613 	rmixl_irqtab[irq].irq_ih = NULL;
614 
615 	splx(s);
616 
617 	free(ih, M_DEVBUF);
618 }
619 
620 static inline void
621 pci_int_status(const char *s, const int n)
622 {
623 #ifdef IOINTR_DEBUG
624 	uint32_t r;
625 	r = RMIXL_IOREG_READ(RMIXL_IO_DEV_PCIE_LE + 0xa0);
626 	printf("%s:%d: PCIE_LINK0_INT_STATUS0 %#x\n", s, n, r);
627 #endif
628 }
629 
630 void
631 evbmips_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
632 {
633 	struct evbmips_intrhand *ih;
634 	struct rmixl_intrvec *ivp;
635 	int vec;
636 	uint64_t eirr;
637 #ifdef IOINTR_DEBUG
638 	uint64_t eimr;
639 
640 	printf("%s: status %#x, cause %#x, pc %#x, ipending %#x\n",
641 		__func__, status, cause, pc, ipending);
642 
643 	asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
644 	asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr));
645 	printf("%s:%d: eirr %#lx, eimr %#lx\n", __func__, __LINE__, eirr, eimr);
646 	pci_int_status(__func__, __LINE__);
647 #endif
648 
649 	for (vec = NINTRVECS - 1; vec >= 2; vec--) {
650 		if ((ipending & (MIPS_SOFT_INT_MASK_0 << vec)) == 0)
651 			continue;
652 
653 		ivp = &rmixl_intrvec[vec];
654 
655 		eirr = 1ULL << vec;
656 		asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr));
657 
658 #ifdef IOINTR_DEBUG
659 		printf("%s: interrupt at vec %d\n",
660 			__func__, vec);
661 		if (LIST_EMPTY(&ivp->iv_list))
662 			printf("%s: unexpected interrupt at vec %d\n",
663 				__func__, vec);
664 #endif
665 		LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
666 			pic_irt_print(__func__, __LINE__, ih->ih_irq);
667 			RMIXL_PICREG_WRITE(RMIXL_PIC_INTRACK,
668 				(1 << ih->ih_irq));
669 			if ((*ih->ih_func)(ih->ih_arg) != 0) {
670 				rmixl_irqtab[ih->ih_irq].irq_count.ev_count++;
671 			}
672 		}
673 
674 		pci_int_status(__func__, __LINE__);
675 
676 		cause &= ~(MIPS_SOFT_INT_MASK_0 << vec);
677 	}
678 
679 
680 	/* Re-enable anything that we have processed. */
681 	_splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
682 }
683 
684 #ifdef DEBUG
685 int rmixl_intrvec_print(void);
686 int
687 rmixl_intrvec_print(void)
688 {
689 	struct evbmips_intrhand *ih;
690 	struct rmixl_intrvec *ivp;
691 	int vec;
692 
693 	ivp = &rmixl_intrvec[0];
694 	for (vec=0; vec < NINTRVECS ; vec++) {
695 		printf("vec %d, irqs {", vec);
696 		LIST_FOREACH(ih, &ivp->iv_list, ih_q)
697 			printf(" %d", ih->ih_irq);
698 		printf(" } trigger type %d\n", ivp->iv_trigger);
699 		ivp++;
700 	}
701 	return 0;
702 }
703 #endif
704