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