Home | History | Annotate | Line # | Download | only in alchemy
au_icu.c revision 1.13
      1  1.13  gdamore /*	$NetBSD: au_icu.c,v 1.13 2006/02/06 23:23:53 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.13  gdamore __KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.13 2006/02/06 23:23:53 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.12    perry #define	REGVAL(x)	*((volatile u_int32_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.1   simonb const u_int32_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.6  tsutsui const u_int32_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.13  gdamore struct au_cpuintr {
    159   1.1   simonb 	LIST_HEAD(, evbmips_intrhand) cintr_list;
    160   1.1   simonb 	struct evcnt cintr_count;
    161   1.1   simonb };
    162   1.1   simonb 
    163  1.13  gdamore struct au_cpuintr au_cpuintrs[NINTRS];
    164  1.13  gdamore const char *au_cpuintrnames[NINTRS] = {
    165   1.1   simonb 	"icu 0, req 0",
    166   1.1   simonb 	"icu 0, req 1",
    167   1.1   simonb 	"icu 1, req 0",
    168   1.1   simonb 	"icu 1, req 1",
    169   1.1   simonb };
    170   1.1   simonb 
    171  1.13  gdamore static bus_addr_t ic0_base, ic1_base;
    172  1.13  gdamore 
    173   1.1   simonb void
    174   1.1   simonb au_intr_init(void)
    175   1.1   simonb {
    176  1.13  gdamore 	int			i;
    177  1.13  gdamore 	struct au_chipdep	*chip;
    178   1.1   simonb 
    179   1.1   simonb 	for (i = 0; i < NINTRS; i++) {
    180  1.13  gdamore 		LIST_INIT(&au_cpuintrs[i].cintr_list);
    181  1.13  gdamore 		evcnt_attach_dynamic(&au_cpuintrs[i].cintr_count,
    182  1.13  gdamore 		    EVCNT_TYPE_INTR, NULL, "mips", au_cpuintrnames[i]);
    183   1.1   simonb 	}
    184   1.1   simonb 
    185  1.13  gdamore 	chip = au_chipdep();
    186  1.13  gdamore 	KASSERT(chip != NULL);
    187  1.13  gdamore 
    188  1.13  gdamore 	ic0_base = chip->icus[0];
    189  1.13  gdamore 	ic1_base = chip->icus[1];
    190  1.13  gdamore 
    191   1.1   simonb 	for (i = 0; i < NIRQS; i++) {
    192  1.13  gdamore 		au_icu_intrtab[i].intr_refcnt = 0;
    193  1.13  gdamore 		evcnt_attach_dynamic(&au_icu_intrtab[i].intr_count,
    194  1.13  gdamore 		    EVCNT_TYPE_INTR, NULL, chip->name, chip->irqnames[i]);
    195   1.1   simonb 	}
    196   1.1   simonb }
    197   1.1   simonb 
    198   1.1   simonb void *
    199   1.1   simonb au_intr_establish(int irq, int req, int level, int type,
    200   1.1   simonb     int (*func)(void *), void *arg)
    201   1.1   simonb {
    202  1.13  gdamore 	struct evbmips_intrhand	*ih;
    203  1.13  gdamore 	uint32_t		icu_base;
    204  1.13  gdamore 	int			cpu_int, s;
    205  1.13  gdamore 	struct au_chipdep	*chip;
    206  1.13  gdamore 
    207  1.13  gdamore 	chip = au_chipdep();
    208  1.13  gdamore 	KASSERT(chip != NULL);
    209   1.1   simonb 
    210   1.1   simonb 	if (irq >= NIRQS)
    211   1.3   provos 		panic("au_intr_establish: bogus IRQ %d", irq);
    212   1.1   simonb 	if (req > 1)
    213   1.3   provos 		panic("au_intr_establish: bogus request %d", req);
    214   1.1   simonb 
    215   1.1   simonb 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    216   1.1   simonb 	if (ih == NULL)
    217   1.1   simonb 		return (NULL);
    218   1.1   simonb 
    219   1.1   simonb 	ih->ih_func = func;
    220   1.1   simonb 	ih->ih_arg = arg;
    221   1.1   simonb 	ih->ih_irq = irq;
    222   1.1   simonb 
    223   1.1   simonb 	s = splhigh();
    224   1.1   simonb 
    225   1.1   simonb 	/*
    226   1.1   simonb 	 * First, link it into the tables.
    227   1.1   simonb 	 * XXX do we want a separate list (really, should only be one item, not
    228   1.9      wiz 	 *     a list anyway) per irq, not per CPU interrupt?
    229   1.1   simonb 	 */
    230  1.10       he 	cpu_int = (irq < 32 ? 0 : 2);
    231  1.13  gdamore 	LIST_INSERT_HEAD(&au_cpuintrs[cpu_int].cintr_list, ih, ih_q);
    232   1.1   simonb 
    233   1.1   simonb 	/*
    234   1.1   simonb 	 * Now enable it.
    235   1.1   simonb 	 */
    236  1.13  gdamore 	if (au_icu_intrtab[irq].intr_refcnt++ == 0) {
    237  1.13  gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    238   1.1   simonb 
    239   1.1   simonb 		irq &= 31;	/* throw away high bit if set */
    240   1.1   simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    241   1.1   simonb 
    242  1.13  gdamore 		/* XXX Only level interrupts for now */
    243   1.1   simonb 		switch (type) {
    244   1.1   simonb 		case IST_NONE:
    245   1.1   simonb 		case IST_PULSE:
    246   1.1   simonb 		case IST_EDGE:
    247   1.1   simonb 			panic("unsupported irq type %d", type);
    248   1.5  hpeyerl 			/* NOTREACHED */
    249   1.1   simonb 		case IST_LEVEL:
    250   1.5  hpeyerl 		case IST_LEVEL_HIGH:
    251   1.1   simonb 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    252   1.1   simonb 			REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    253   1.1   simonb 			REGVAL(icu_base + IC_CONFIG0_SET) = irq;
    254   1.5  hpeyerl 			break;
    255   1.5  hpeyerl 		case IST_LEVEL_LOW:
    256   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
    257   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG1_SET) = irq;
    258   1.5  hpeyerl 			REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    259   1.5  hpeyerl 			break;
    260   1.1   simonb 		}
    261   1.1   simonb 
    262   1.1   simonb 		/* XXX handle GPIO interrupts - not done at all yet */
    263  1.10       he 		if (cpu_int & 0x1)
    264   1.1   simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
    265   1.1   simonb 		else
    266   1.1   simonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
    267   1.1   simonb 
    268   1.1   simonb 		/* Associate interrupt with peripheral */
    269   1.1   simonb 		REGVAL(icu_base + IC_SOURCE_SET) = irq;
    270   1.1   simonb 
    271   1.1   simonb 		/* Actually enable the interrupt */
    272   1.1   simonb 		REGVAL(icu_base + IC_MASK_SET) = irq;
    273   1.1   simonb 
    274   1.1   simonb 		/* And allow the interrupt to interrupt idle */
    275   1.1   simonb 		REGVAL(icu_base + IC_WAKEUP_SET) = irq;
    276   1.1   simonb 	}
    277   1.1   simonb 	splx(s);
    278   1.1   simonb 
    279   1.1   simonb 	return (ih);
    280   1.1   simonb }
    281   1.1   simonb 
    282   1.1   simonb void
    283   1.1   simonb au_intr_disestablish(void *cookie)
    284   1.1   simonb {
    285   1.1   simonb 	struct evbmips_intrhand *ih = cookie;
    286   1.1   simonb 	uint32_t icu_base;
    287   1.1   simonb 	int irq, s;
    288   1.1   simonb 
    289   1.1   simonb 	irq = ih->ih_irq;
    290   1.1   simonb 
    291   1.1   simonb 	s = splhigh();
    292   1.1   simonb 
    293   1.1   simonb 	/*
    294   1.1   simonb 	 * First, remove it from the table.
    295   1.1   simonb 	 */
    296   1.1   simonb 	LIST_REMOVE(ih, ih_q);
    297   1.1   simonb 
    298   1.1   simonb 	/*
    299   1.1   simonb 	 * Now, disable it, if there is nothing remaining on the
    300   1.1   simonb 	 * list.
    301   1.1   simonb 	 */
    302  1.13  gdamore 	if (au_icu_intrtab[irq].intr_refcnt-- == 1) {
    303  1.13  gdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
    304   1.1   simonb 
    305   1.1   simonb 		irq &= 31;	/* throw away high bit if set */
    306   1.1   simonb 		irq = 1 << irq;	/* only used as a mask from here on */
    307   1.1   simonb 
    308   1.1   simonb 		REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
    309   1.1   simonb 		REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
    310   1.1   simonb 		REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
    311   1.1   simonb 
    312   1.1   simonb 		/* XXX disable with MASK_CLEAR and WAKEUP_CLEAR */
    313   1.1   simonb 	}
    314   1.1   simonb 
    315   1.1   simonb 	splx(s);
    316   1.1   simonb 
    317   1.1   simonb 	free(ih, M_DEVBUF);
    318   1.1   simonb }
    319   1.1   simonb 
    320   1.1   simonb void
    321   1.1   simonb au_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending)
    322   1.1   simonb {
    323   1.1   simonb 	struct evbmips_intrhand *ih;
    324   1.1   simonb 	int level;
    325   1.8   simonb 	u_int32_t icu_base = 0, irqmask = 0;	/* Both XXX gcc */
    326   1.1   simonb 
    327   1.1   simonb 	for (level = 3; level >= 0; level--) {
    328   1.1   simonb 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
    329   1.1   simonb 			continue;
    330   1.1   simonb 
    331   1.1   simonb 		/*
    332   1.1   simonb 		 * XXX	the following may well be slow to execute.
    333   1.1   simonb 		 *	investigate and possibly speed up.
    334   1.1   simonb 		 *
    335   1.1   simonb 		 * is something like:
    336   1.1   simonb 		 *
    337   1.1   simonb 		 *    irqmask = REGVAL(
    338   1.1   simonb 		 *	 (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
    339   1.1   simonb 		 *	 (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
    340   1.1   simonb 		 *
    341   1.1   simonb 		 * be any better?
    342   1.1   simonb 		 *
    343   1.1   simonb 		 */
    344   1.1   simonb 		switch (level) {
    345   1.1   simonb 		case 0:
    346  1.13  gdamore 			icu_base = ic0_base;
    347   1.1   simonb 			irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
    348   1.1   simonb 			break;
    349   1.1   simonb 		case 1:
    350  1.13  gdamore 			icu_base = ic0_base;
    351   1.1   simonb 			irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
    352   1.1   simonb 			break;
    353   1.1   simonb 		case 2:
    354  1.13  gdamore 			icu_base = ic1_base;
    355   1.1   simonb 			irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
    356   1.1   simonb 			break;
    357   1.1   simonb 		case 3:
    358  1.13  gdamore 			icu_base = ic1_base;
    359   1.1   simonb 			irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
    360   1.1   simonb 			break;
    361   1.1   simonb 		}
    362  1.13  gdamore 		au_cpuintrs[level].cintr_count.ev_count++;
    363  1.13  gdamore 		LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
    364   1.1   simonb 			/* XXX should check is see if interrupt is masked? */
    365   1.1   simonb 			if (1 << ih->ih_irq & irqmask) {
    366  1.13  gdamore 				au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
    367   1.1   simonb 				(*ih->ih_func)(ih->ih_arg);
    368   1.1   simonb 
    369   1.1   simonb 				REGVAL(icu_base + IC_MASK_CLEAR) = 1 << ih->ih_irq;
    370   1.1   simonb 				REGVAL(icu_base + IC_MASK_SET) = 1 << ih->ih_irq;
    371   1.1   simonb 			}
    372   1.1   simonb 		}
    373   1.1   simonb 		cause &= ~(MIPS_INT_MASK_0 << level);
    374   1.1   simonb 	}
    375   1.1   simonb 
    376   1.1   simonb 	/* Re-enable anything that we have processed. */
    377   1.1   simonb 	_splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
    378   1.1   simonb }
    379