Home | History | Annotate | Line # | Download | only in alchemy
au_icu.c revision 1.2.4.2
      1  1.2.4.2  gehenna /*	$NetBSD: au_icu.c,v 1.2.4.2 2002/08/31 13:45:13 gehenna Exp $	*/
      2  1.2.4.2  gehenna 
      3  1.2.4.2  gehenna /*-
      4  1.2.4.2  gehenna  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  1.2.4.2  gehenna  * All rights reserved.
      6  1.2.4.2  gehenna  *
      7  1.2.4.2  gehenna  * This code is derived from software contributed to The NetBSD Foundation
      8  1.2.4.2  gehenna  * by Jason R. Thorpe.
      9  1.2.4.2  gehenna  *
     10  1.2.4.2  gehenna  * Redistribution and use in source and binary forms, with or without
     11  1.2.4.2  gehenna  * modification, are permitted provided that the following conditions
     12  1.2.4.2  gehenna  * are met:
     13  1.2.4.2  gehenna  * 1. Redistributions of source code must retain the above copyright
     14  1.2.4.2  gehenna  *    notice, this list of conditions and the following disclaimer.
     15  1.2.4.2  gehenna  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.2.4.2  gehenna  *    notice, this list of conditions and the following disclaimer in the
     17  1.2.4.2  gehenna  *    documentation and/or other materials provided with the distribution.
     18  1.2.4.2  gehenna  * 3. All advertising materials mentioning features or use of this software
     19  1.2.4.2  gehenna  *    must display the following acknowledgement:
     20  1.2.4.2  gehenna  *	This product includes software developed by the NetBSD
     21  1.2.4.2  gehenna  *	Foundation, Inc. and its contributors.
     22  1.2.4.2  gehenna  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.2.4.2  gehenna  *    contributors may be used to endorse or promote products derived
     24  1.2.4.2  gehenna  *    from this software without specific prior written permission.
     25  1.2.4.2  gehenna  *
     26  1.2.4.2  gehenna  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.2.4.2  gehenna  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.2.4.2  gehenna  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.2.4.2  gehenna  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.2.4.2  gehenna  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.2.4.2  gehenna  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.2.4.2  gehenna  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.2.4.2  gehenna  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.2.4.2  gehenna  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.2.4.2  gehenna  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.2.4.2  gehenna  * POSSIBILITY OF SUCH DAMAGE.
     37  1.2.4.2  gehenna  */
     38  1.2.4.2  gehenna 
     39  1.2.4.2  gehenna /*
     40  1.2.4.2  gehenna  * Interrupt support for the Alchemy Semiconductor Au1x00 CPUs.
     41  1.2.4.2  gehenna  *
     42  1.2.4.2  gehenna  * The Alchemy Semiconductor Au1x00's interrupts are wired to two internal
     43  1.2.4.2  gehenna  * interrupt controllers.
     44  1.2.4.2  gehenna  */
     45  1.2.4.2  gehenna 
     46  1.2.4.2  gehenna #include "opt_ddb.h"
     47  1.2.4.2  gehenna 
     48  1.2.4.2  gehenna #include <sys/param.h>
     49  1.2.4.2  gehenna #include <sys/queue.h>
     50  1.2.4.2  gehenna #include <sys/malloc.h>
     51  1.2.4.2  gehenna #include <sys/systm.h>
     52  1.2.4.2  gehenna #include <sys/device.h>
     53  1.2.4.2  gehenna #include <sys/kernel.h>
     54  1.2.4.2  gehenna 
     55  1.2.4.2  gehenna #include <machine/bus.h>
     56  1.2.4.2  gehenna #include <machine/intr.h>
     57  1.2.4.2  gehenna 
     58  1.2.4.2  gehenna #include <mips/locore.h>
     59  1.2.4.2  gehenna #include <mips/alchemy/include/aureg.h>
     60  1.2.4.2  gehenna #include <mips/alchemy/include/auvar.h>
     61  1.2.4.2  gehenna 
     62  1.2.4.2  gehenna #define	REGVAL(x)	*((__volatile u_int32_t *)(MIPS_PHYS_TO_KSEG1((x))))
     63  1.2.4.2  gehenna 
     64  1.2.4.2  gehenna /*
     65  1.2.4.2  gehenna  * This is a mask of bits to clear in the SR when we go to a
     66  1.2.4.2  gehenna  * given hardware interrupt priority level.
     67  1.2.4.2  gehenna  */
     68  1.2.4.2  gehenna 
     69  1.2.4.2  gehenna const u_int32_t ipl_sr_bits[_IPL_N] = {
     70  1.2.4.2  gehenna 	0,					/*  0: IPL_NONE */
     71  1.2.4.2  gehenna 
     72  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/*  1: IPL_SOFT */
     73  1.2.4.2  gehenna 
     74  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/*  2: IPL_SOFTCLOCK */
     75  1.2.4.2  gehenna 
     76  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/*  3: IPL_SOFTNET */
     77  1.2.4.2  gehenna 
     78  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/*  4: IPL_SOFTSERIAL */
     79  1.2.4.2  gehenna 
     80  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0|
     81  1.2.4.2  gehenna 		MIPS_SOFT_INT_MASK_1|
     82  1.2.4.2  gehenna 		MIPS_INT_MASK_0,		/*  5: IPL_BIO */
     83  1.2.4.2  gehenna 
     84  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0|
     85  1.2.4.2  gehenna 		MIPS_SOFT_INT_MASK_1|
     86  1.2.4.2  gehenna 		MIPS_INT_MASK_0,		/*  6: IPL_NET */
     87  1.2.4.2  gehenna 
     88  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0|
     89  1.2.4.2  gehenna 		MIPS_SOFT_INT_MASK_1|
     90  1.2.4.2  gehenna 		MIPS_INT_MASK_0,		/*  7: IPL_{SERIAL,TTY} */
     91  1.2.4.2  gehenna 
     92  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0|
     93  1.2.4.2  gehenna 		MIPS_SOFT_INT_MASK_1|
     94  1.2.4.2  gehenna 		MIPS_INT_MASK_0|
     95  1.2.4.2  gehenna 		MIPS_INT_MASK_1|
     96  1.2.4.2  gehenna 		MIPS_INT_MASK_2|
     97  1.2.4.2  gehenna 		MIPS_INT_MASK_3|
     98  1.2.4.2  gehenna 		MIPS_INT_MASK_4|
     99  1.2.4.2  gehenna 		MIPS_INT_MASK_5,		/*  8: IPL_{CLOCK,HIGH} */
    100  1.2.4.2  gehenna };
    101  1.2.4.2  gehenna 
    102  1.2.4.2  gehenna /*
    103  1.2.4.2  gehenna  * This is a mask of bits to clear in the SR when we go to a
    104  1.2.4.2  gehenna  * given software interrupt priority level.
    105  1.2.4.2  gehenna  * Hardware ipls are port/board specific.
    106  1.2.4.2  gehenna  */
    107  1.2.4.2  gehenna const u_int32_t ipl_si_to_sr[_IPL_NSOFT] = {
    108  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
    109  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
    110  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTNET */
    111  1.2.4.2  gehenna 	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTSERIAL */
    112  1.2.4.2  gehenna };
    113  1.2.4.2  gehenna 
    114  1.2.4.2  gehenna #define	NIRQS		64
    115  1.2.4.2  gehenna 
    116  1.2.4.2  gehenna const char *au1000_intrnames[NIRQS] = {
    117  1.2.4.2  gehenna 	"uart0",
    118  1.2.4.2  gehenna 	"uart1",
    119  1.2.4.2  gehenna 	"uart2",
    120  1.2.4.2  gehenna 	"uart3",
    121  1.2.4.2  gehenna 	"ssi0",
    122  1.2.4.2  gehenna 	"ssi1",
    123  1.2.4.2  gehenna 	"dma0",
    124  1.2.4.2  gehenna 	"dma1",
    125  1.2.4.2  gehenna 	"dma2",
    126  1.2.4.2  gehenna 	"dma3",
    127  1.2.4.2  gehenna 	"dma4",
    128  1.2.4.2  gehenna 	"dma5",
    129  1.2.4.2  gehenna 	"dma6",
    130  1.2.4.2  gehenna 	"dma7",
    131  1.2.4.2  gehenna 	"pc0",
    132  1.2.4.2  gehenna 	"pc0 match1",
    133  1.2.4.2  gehenna 	"pc0 match2",
    134  1.2.4.2  gehenna 	"pc0 match3",
    135  1.2.4.2  gehenna 	"pc1",
    136  1.2.4.2  gehenna 	"pc1 match1",
    137  1.2.4.2  gehenna 	"pc1 match2",
    138  1.2.4.2  gehenna 	"pc1 match3",
    139  1.2.4.2  gehenna 	"irda tx",
    140  1.2.4.2  gehenna 	"irda rx",
    141  1.2.4.2  gehenna 	"usb intr",
    142  1.2.4.2  gehenna 	"usb suspend",
    143  1.2.4.2  gehenna 	"usb host",
    144  1.2.4.2  gehenna 	"ac97",
    145  1.2.4.2  gehenna 	"mac0",
    146  1.2.4.2  gehenna 	"mac1",
    147  1.2.4.2  gehenna 	"i2s",
    148  1.2.4.2  gehenna 	"ac97 cmd",
    149  1.2.4.2  gehenna 
    150  1.2.4.2  gehenna 	"gpio 0",
    151  1.2.4.2  gehenna 	"gpio 1",
    152  1.2.4.2  gehenna 	"gpio 2",
    153  1.2.4.2  gehenna 	"gpio 3",
    154  1.2.4.2  gehenna 	"gpio 4",
    155  1.2.4.2  gehenna 	"gpio 5",
    156  1.2.4.2  gehenna 	"gpio 6",
    157  1.2.4.2  gehenna 	"gpio 7",
    158  1.2.4.2  gehenna 	"gpio 8",
    159  1.2.4.2  gehenna 	"gpio 9",
    160  1.2.4.2  gehenna 	"gpio 10",
    161  1.2.4.2  gehenna 	"gpio 11",
    162  1.2.4.2  gehenna 	"gpio 12",
    163  1.2.4.2  gehenna 	"gpio 13",
    164  1.2.4.2  gehenna 	"gpio 14",
    165  1.2.4.2  gehenna 	"gpio 15",
    166  1.2.4.2  gehenna 	"gpio 16",
    167  1.2.4.2  gehenna 	"gpio 17",
    168  1.2.4.2  gehenna 	"gpio 18",
    169  1.2.4.2  gehenna 	"gpio 19",
    170  1.2.4.2  gehenna 	"gpio 20",
    171  1.2.4.2  gehenna 	"gpio 21",
    172  1.2.4.2  gehenna 	"gpio 22",
    173  1.2.4.2  gehenna 	"gpio 23",
    174  1.2.4.2  gehenna 	"gpio 24",
    175  1.2.4.2  gehenna 	"gpio 25",
    176  1.2.4.2  gehenna 	"gpio 26",
    177  1.2.4.2  gehenna 	"gpio 27",
    178  1.2.4.2  gehenna 	"gpio 28",
    179  1.2.4.2  gehenna 	"gpio 29",
    180  1.2.4.2  gehenna 	"gpio 30",
    181  1.2.4.2  gehenna 	"gpio 31",
    182  1.2.4.2  gehenna };
    183  1.2.4.2  gehenna 
    184  1.2.4.2  gehenna struct au1000_intrhead {
    185  1.2.4.2  gehenna 	struct evcnt intr_count;
    186  1.2.4.2  gehenna 	int intr_refcnt;
    187  1.2.4.2  gehenna };
    188  1.2.4.2  gehenna struct au1000_intrhead au1000_intrtab[NIRQS];
    189  1.2.4.2  gehenna 
    190  1.2.4.2  gehenna #define	NINTRS			4	/* MIPS INT0 - INT3 */
    191  1.2.4.2  gehenna 
    192  1.2.4.2  gehenna struct au1000_cpuintr {
    193  1.2.4.2  gehenna 	LIST_HEAD(, evbmips_intrhand) cintr_list;
    194  1.2.4.2  gehenna 	struct evcnt cintr_count;
    195  1.2.4.2  gehenna };
    196  1.2.4.2  gehenna 
    197  1.2.4.2  gehenna struct au1000_cpuintr au1000_cpuintrs[NINTRS];
    198  1.2.4.2  gehenna const char *au1000_cpuintrnames[NINTRS] = {
    199  1.2.4.2  gehenna 	"icu 0, req 0",
    200  1.2.4.2  gehenna 	"icu 0, req 1",
    201  1.2.4.2  gehenna 	"icu 1, req 0",
    202  1.2.4.2  gehenna 	"icu 1, req 1",
    203  1.2.4.2  gehenna };
    204  1.2.4.2  gehenna 
    205  1.2.4.2  gehenna void
    206  1.2.4.2  gehenna au_intr_init(void)
    207  1.2.4.2  gehenna {
    208  1.2.4.2  gehenna 	int i;
    209  1.2.4.2  gehenna 
    210  1.2.4.2  gehenna 	for (i = 0; i < NINTRS; i++) {
    211  1.2.4.2  gehenna 		LIST_INIT(&au1000_cpuintrs[i].cintr_list);
    212  1.2.4.2  gehenna 		evcnt_attach_dynamic(&au1000_cpuintrs[i].cintr_count,
    213  1.2.4.2  gehenna 		    EVCNT_TYPE_INTR, NULL, "mips", au1000_cpuintrnames[i]);
    214  1.2.4.2  gehenna 	}
    215  1.2.4.2  gehenna 
    216  1.2.4.2  gehenna 	evcnt_attach_static(&mips_int5_evcnt);
    217  1.2.4.2  gehenna 
    218  1.2.4.2  gehenna 	for (i = 0; i < NIRQS; i++) {
    219  1.2.4.2  gehenna 		/* XXX steering - use an irqmap array? */
    220  1.2.4.2  gehenna 
    221  1.2.4.2  gehenna 		au1000_intrtab[i].intr_refcnt = 0;
    222  1.2.4.2  gehenna 		evcnt_attach_dynamic(&au1000_intrtab[i].intr_count,
    223  1.2.4.2  gehenna 		    EVCNT_TYPE_INTR, NULL, "au1000", au1000_intrnames[i]);
    224  1.2.4.2  gehenna 	}
    225  1.2.4.2  gehenna }
    226  1.2.4.2  gehenna 
    227  1.2.4.2  gehenna void *
    228  1.2.4.2  gehenna au_intr_establish(int irq, int req, int level, int type,
    229  1.2.4.2  gehenna     int (*func)(void *), void *arg)
    230  1.2.4.2  gehenna {
    231  1.2.4.2  gehenna 	struct evbmips_intrhand *ih;
    232  1.2.4.2  gehenna 	uint32_t icu_base;
    233  1.2.4.2  gehenna 	int cpu_intr, s;
    234  1.2.4.2  gehenna 
    235  1.2.4.2  gehenna 	if (irq >= NIRQS)
    236  1.2.4.2  gehenna 		panic("au_intr_establish: bogus IRQ %d\n", irq);
    237  1.2.4.2  gehenna 	if (req > 1)
    238  1.2.4.2  gehenna 		panic("au_intr_establish: bogus request %d\n", req);
    239  1.2.4.2  gehenna 
    240  1.2.4.2  gehenna 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    241  1.2.4.2  gehenna 	if (ih == NULL)
    242  1.2.4.2  gehenna 		return (NULL);
    243  1.2.4.2  gehenna 
    244  1.2.4.2  gehenna 	ih->ih_func = func;
    245  1.2.4.2  gehenna 	ih->ih_arg = arg;
    246  1.2.4.2  gehenna 	ih->ih_irq = irq;
    247  1.2.4.2  gehenna 
    248  1.2.4.2  gehenna 	s = splhigh();
    249  1.2.4.2  gehenna 
    250  1.2.4.2  gehenna 	/*
    251  1.2.4.2  gehenna 	 * First, link it into the tables.
    252  1.2.4.2  gehenna 	 * XXX do we want a separate list (really, should only be one item, not
    253  1.2.4.2  gehenna 	 *     a list anyway) per irq, not per cpu interrupt?
    254  1.2.4.2  gehenna 	 */
    255  1.2.4.2  gehenna 	cpu_intr = (irq < 32 ? 0 : 2);
    256  1.2.4.2  gehenna 	LIST_INSERT_HEAD(&au1000_cpuintrs[cpu_intr].cintr_list, ih, ih_q);
    257  1.2.4.2  gehenna 
    258  1.2.4.2  gehenna 	/*
    259  1.2.4.2  gehenna 	 * Now enable it.
    260  1.2.4.2  gehenna 	 */
    261  1.2.4.2  gehenna 	if (au1000_intrtab[irq].intr_refcnt++ == 0) {
    262  1.2.4.2  gehenna 		icu_base = (irq < 32) ? IC0_BASE : IC1_BASE;
    263  1.2.4.2  gehenna 
    264  1.2.4.2  gehenna 		irq &= 31;	/* throw away high bit if set */
    265  1.2.4.2  gehenna 		irq = 1 << irq;	/* only used as a mask from here on */
    266  1.2.4.2  gehenna 
    267  1.2.4.2  gehenna 		/* XXX Only high-level interrupts for now */
    268  1.2.4.2  gehenna 		switch (type) {
    269  1.2.4.2  gehenna 		case IST_NONE:
    270  1.2.4.2  gehenna 		case IST_PULSE:
    271  1.2.4.2  gehenna 		case IST_EDGE:
    272  1.2.4.2  gehenna 			panic("unsupported irq type %d", type);
    273  1.2.4.2  gehenna 		case IST_LEVEL:
    274  1.2.4.2  gehenna 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    275  1.2.4.2  gehenna 			REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    276  1.2.4.2  gehenna 			REGVAL(icu_base + IC_CONFIG0_SET) = irq;
    277  1.2.4.2  gehenna 		}
    278  1.2.4.2  gehenna 
    279  1.2.4.2  gehenna 		/* XXX handle GPIO interrupts - not done at all yet */
    280  1.2.4.2  gehenna 		if (cpu_intr & 0x1)
    281  1.2.4.2  gehenna 			REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
    282  1.2.4.2  gehenna 		else
    283  1.2.4.2  gehenna 			REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
    284  1.2.4.2  gehenna 
    285  1.2.4.2  gehenna 		/* Associate interrupt with peripheral */
    286  1.2.4.2  gehenna 		REGVAL(icu_base + IC_SOURCE_SET) = irq;
    287  1.2.4.2  gehenna 
    288  1.2.4.2  gehenna 		/* Actually enable the interrupt */
    289  1.2.4.2  gehenna 		REGVAL(icu_base + IC_MASK_SET) = irq;
    290  1.2.4.2  gehenna 
    291  1.2.4.2  gehenna 		/* And allow the interrupt to interrupt idle */
    292  1.2.4.2  gehenna 		REGVAL(icu_base + IC_WAKEUP_SET) = irq;
    293  1.2.4.2  gehenna 	}
    294  1.2.4.2  gehenna 	splx(s);
    295  1.2.4.2  gehenna 
    296  1.2.4.2  gehenna 	return (ih);
    297  1.2.4.2  gehenna }
    298  1.2.4.2  gehenna 
    299  1.2.4.2  gehenna void
    300  1.2.4.2  gehenna au_intr_disestablish(void *cookie)
    301  1.2.4.2  gehenna {
    302  1.2.4.2  gehenna 	struct evbmips_intrhand *ih = cookie;
    303  1.2.4.2  gehenna 	uint32_t icu_base;
    304  1.2.4.2  gehenna 	int irq, s;
    305  1.2.4.2  gehenna 
    306  1.2.4.2  gehenna 	irq = ih->ih_irq;
    307  1.2.4.2  gehenna 
    308  1.2.4.2  gehenna 	s = splhigh();
    309  1.2.4.2  gehenna 
    310  1.2.4.2  gehenna 	/*
    311  1.2.4.2  gehenna 	 * First, remove it from the table.
    312  1.2.4.2  gehenna 	 */
    313  1.2.4.2  gehenna 	LIST_REMOVE(ih, ih_q);
    314  1.2.4.2  gehenna 
    315  1.2.4.2  gehenna 	/*
    316  1.2.4.2  gehenna 	 * Now, disable it, if there is nothing remaining on the
    317  1.2.4.2  gehenna 	 * list.
    318  1.2.4.2  gehenna 	 */
    319  1.2.4.2  gehenna 	if (au1000_intrtab[irq].intr_refcnt-- == 1) {
    320  1.2.4.2  gehenna 		icu_base = (irq < 32) ? IC0_BASE : IC1_BASE;
    321  1.2.4.2  gehenna 
    322  1.2.4.2  gehenna 		irq &= 31;	/* throw away high bit if set */
    323  1.2.4.2  gehenna 		irq = 1 << irq;	/* only used as a mask from here on */
    324  1.2.4.2  gehenna 
    325  1.2.4.2  gehenna 		REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
    326  1.2.4.2  gehenna 		REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    327  1.2.4.2  gehenna 		REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    328  1.2.4.2  gehenna 
    329  1.2.4.2  gehenna 		/* XXX disable with MASK_CLEAR and WAKEUP_CLEAR */
    330  1.2.4.2  gehenna 	}
    331  1.2.4.2  gehenna 
    332  1.2.4.2  gehenna 	splx(s);
    333  1.2.4.2  gehenna 
    334  1.2.4.2  gehenna 	free(ih, M_DEVBUF);
    335  1.2.4.2  gehenna }
    336  1.2.4.2  gehenna 
    337  1.2.4.2  gehenna void
    338  1.2.4.2  gehenna au_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending)
    339  1.2.4.2  gehenna {
    340  1.2.4.2  gehenna 	struct evbmips_intrhand *ih;
    341  1.2.4.2  gehenna 	int level;
    342  1.2.4.2  gehenna 	u_int32_t icu_base, irqmask;
    343  1.2.4.2  gehenna 
    344  1.2.4.2  gehenna 	for (level = 3; level >= 0; level--) {
    345  1.2.4.2  gehenna 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    346  1.2.4.2  gehenna 			continue;
    347  1.2.4.2  gehenna 
    348  1.2.4.2  gehenna 		/*
    349  1.2.4.2  gehenna 		 * XXX	the following may well be slow to execute.
    350  1.2.4.2  gehenna 		 *	investigate and possibly speed up.
    351  1.2.4.2  gehenna 		 *
    352  1.2.4.2  gehenna 		 * is something like:
    353  1.2.4.2  gehenna 		 *
    354  1.2.4.2  gehenna 		 *    irqmask = REGVAL(
    355  1.2.4.2  gehenna 		 *	 (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
    356  1.2.4.2  gehenna 		 *	 (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
    357  1.2.4.2  gehenna 		 *
    358  1.2.4.2  gehenna 		 * be any better?
    359  1.2.4.2  gehenna 		 *
    360  1.2.4.2  gehenna 		 */
    361  1.2.4.2  gehenna 		switch (level) {
    362  1.2.4.2  gehenna 		case 0:
    363  1.2.4.2  gehenna 			icu_base = IC0_BASE;
    364  1.2.4.2  gehenna 			irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
    365  1.2.4.2  gehenna 			break;
    366  1.2.4.2  gehenna 		case 1:
    367  1.2.4.2  gehenna 			icu_base = IC0_BASE;
    368  1.2.4.2  gehenna 			irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
    369  1.2.4.2  gehenna 			break;
    370  1.2.4.2  gehenna 		case 2:
    371  1.2.4.2  gehenna 			icu_base = IC1_BASE;
    372  1.2.4.2  gehenna 			irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
    373  1.2.4.2  gehenna 			break;
    374  1.2.4.2  gehenna 		case 3:
    375  1.2.4.2  gehenna 			icu_base = IC1_BASE;
    376  1.2.4.2  gehenna 			irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
    377  1.2.4.2  gehenna 			break;
    378  1.2.4.2  gehenna 		}
    379  1.2.4.2  gehenna 		au1000_cpuintrs[level].cintr_count.ev_count++;
    380  1.2.4.2  gehenna 		LIST_FOREACH(ih, &au1000_cpuintrs[level].cintr_list, ih_q) {
    381  1.2.4.2  gehenna 			/* XXX should check is see if interrupt is masked? */
    382  1.2.4.2  gehenna 			if (1 << ih->ih_irq & irqmask) {
    383  1.2.4.2  gehenna 				au1000_intrtab[ih->ih_irq].intr_count.ev_count++;
    384  1.2.4.2  gehenna 				(*ih->ih_func)(ih->ih_arg);
    385  1.2.4.2  gehenna 
    386  1.2.4.2  gehenna 				REGVAL(icu_base + IC_MASK_CLEAR) = 1 << ih->ih_irq;
    387  1.2.4.2  gehenna 				REGVAL(icu_base + IC_MASK_SET) = 1 << ih->ih_irq;
    388  1.2.4.2  gehenna 			}
    389  1.2.4.2  gehenna 		}
    390  1.2.4.2  gehenna 		cause &= ~(MIPS_INT_MASK_0 << level);
    391  1.2.4.2  gehenna 	}
    392  1.2.4.2  gehenna 
    393  1.2.4.2  gehenna 	/* Re-enable anything that we have processed. */
    394  1.2.4.2  gehenna 	_splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
    395  1.2.4.2  gehenna }
    396