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