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