Home | History | Annotate | Line # | Download | only in rmi
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