Home | History | Annotate | Line # | Download | only in cobalt
      1  1.11  thorpej /*	$NetBSD: interrupt.c,v 1.11 2020/11/21 15:26:53 thorpej Exp $	*/
      2   1.1  tsutsui 
      3   1.3  tsutsui /*-
      4   1.3  tsutsui  * Copyright (c) 2006 Izumi Tsutsui.  All rights reserved.
      5   1.1  tsutsui  *
      6   1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
      7   1.1  tsutsui  * modification, are permitted provided that the following conditions
      8   1.1  tsutsui  * are met:
      9   1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     10   1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
     11   1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     13   1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     14   1.1  tsutsui  *
     15   1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16   1.1  tsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17   1.1  tsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18   1.1  tsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19   1.1  tsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20   1.1  tsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21   1.1  tsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22   1.1  tsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23   1.1  tsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24   1.1  tsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25   1.1  tsutsui  */
     26   1.1  tsutsui 
     27   1.1  tsutsui /*-
     28   1.1  tsutsui  * Copyright (c) 2001 The NetBSD Foundation, Inc.
     29   1.1  tsutsui  * All rights reserved.
     30   1.1  tsutsui  *
     31   1.1  tsutsui  * This code is derived from software contributed to The NetBSD Foundation
     32   1.1  tsutsui  * by Jason R. Thorpe.
     33   1.1  tsutsui  *
     34   1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
     35   1.1  tsutsui  * modification, are permitted provided that the following conditions
     36   1.1  tsutsui  * are met:
     37   1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     38   1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
     39   1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     40   1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     41   1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     42   1.1  tsutsui  *
     43   1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     44   1.1  tsutsui  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     45   1.1  tsutsui  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     46   1.1  tsutsui  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     47   1.1  tsutsui  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     48   1.1  tsutsui  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     49   1.1  tsutsui  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     50   1.1  tsutsui  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     51   1.1  tsutsui  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     52   1.1  tsutsui  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     53   1.1  tsutsui  * POSSIBILITY OF SUCH DAMAGE.
     54   1.1  tsutsui  */
     55   1.1  tsutsui 
     56   1.1  tsutsui /*
     57   1.1  tsutsui  * Copyright (c) 2000 Soren S. Jorvang.  All rights reserved.
     58   1.1  tsutsui  *
     59   1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
     60   1.1  tsutsui  * modification, are permitted provided that the following conditions
     61   1.1  tsutsui  * are met:
     62   1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     63   1.1  tsutsui  *    notice, this list of conditions, and the following disclaimer.
     64   1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     65   1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     66   1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     67   1.1  tsutsui  *
     68   1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     69   1.1  tsutsui  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     70   1.1  tsutsui  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     71   1.1  tsutsui  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     72   1.1  tsutsui  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     73   1.1  tsutsui  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     74   1.1  tsutsui  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     75   1.1  tsutsui  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     76   1.1  tsutsui  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     77   1.1  tsutsui  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     78   1.1  tsutsui  * SUCH DAMAGE.
     79   1.1  tsutsui  */
     80   1.1  tsutsui 
     81   1.1  tsutsui #include <sys/cdefs.h>
     82  1.11  thorpej __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.11 2020/11/21 15:26:53 thorpej Exp $");
     83   1.6     matt 
     84   1.6     matt #define __INTR_PRIVATE
     85   1.1  tsutsui 
     86   1.1  tsutsui #include <sys/param.h>
     87  1.11  thorpej #include <sys/kmem.h>
     88   1.1  tsutsui #include <sys/cpu.h>
     89   1.1  tsutsui #include <sys/intr.h>
     90   1.1  tsutsui 
     91   1.1  tsutsui #include <mips/mips3_clock.h>
     92   1.7   dyoung #include <sys/bus.h>
     93   1.1  tsutsui 
     94   1.1  tsutsui #include <dev/ic/i8259reg.h>
     95   1.1  tsutsui #include <dev/isa/isareg.h>
     96   1.1  tsutsui 
     97   1.1  tsutsui #include <cobalt/dev/gtreg.h>
     98   1.1  tsutsui 
     99   1.1  tsutsui #define ICU_LEVEL	4
    100   1.1  tsutsui #define IRQ_SLAVE	2
    101   1.1  tsutsui 
    102   1.1  tsutsui #define IO_ELCR		0x4d0
    103   1.1  tsutsui #define IO_ELCRSIZE	2
    104   1.1  tsutsui #define ELCR0		0
    105   1.1  tsutsui #define ELCR1		1
    106   1.1  tsutsui 
    107   1.1  tsutsui #define ICU1_READ(reg)		\
    108   1.1  tsutsui     bus_space_read_1(icu_bst, icu1_bsh, (reg))
    109   1.1  tsutsui #define ICU1_WRITE(reg, val)	\
    110   1.1  tsutsui     bus_space_write_1(icu_bst, icu1_bsh, (reg), (val))
    111   1.1  tsutsui #define ICU2_READ(reg)		\
    112   1.1  tsutsui     bus_space_read_1(icu_bst, icu2_bsh, (reg))
    113   1.1  tsutsui #define ICU2_WRITE(reg, val)	\
    114   1.1  tsutsui     bus_space_write_1(icu_bst, icu2_bsh, (reg), (val))
    115   1.1  tsutsui #define ELCR_READ(reg)		\
    116   1.1  tsutsui     bus_space_read_1(icu_bst, elcr_bsh, (reg))
    117   1.1  tsutsui #define ELCR_WRITE(reg, val)	\
    118   1.1  tsutsui     bus_space_write_1(icu_bst, elcr_bsh, (reg), (val))
    119   1.1  tsutsui 
    120   1.1  tsutsui static u_int icu_imask, icu_elcr;
    121   1.1  tsutsui static bus_space_tag_t icu_bst;
    122   1.1  tsutsui static bus_space_handle_t icu1_bsh, icu2_bsh, elcr_bsh;
    123   1.1  tsutsui 
    124   1.1  tsutsui struct icu_intrhead {
    125   1.1  tsutsui 	LIST_HEAD(, cobalt_intrhand) intr_q;
    126   1.1  tsutsui 	int intr_type;
    127   1.1  tsutsui 	struct evcnt intr_evcnt;
    128   1.1  tsutsui 	char intr_evname[32];
    129   1.1  tsutsui };
    130   1.1  tsutsui static struct icu_intrhead icu_intrtab[NICU_INT];
    131   1.1  tsutsui 
    132   1.1  tsutsui struct cpu_intrhead {
    133   1.1  tsutsui 	struct cobalt_intrhand intr_ih;
    134   1.1  tsutsui 	struct evcnt intr_evcnt;
    135   1.1  tsutsui 	char intr_evname[32];
    136   1.1  tsutsui };
    137   1.1  tsutsui static struct cpu_intrhead cpu_intrtab[NCPU_INT];
    138   1.1  tsutsui 
    139   1.1  tsutsui static int	icu_intr(void *);
    140   1.1  tsutsui static void	icu_set(void);
    141   1.1  tsutsui 
    142   1.6     matt static const struct ipl_sr_map cobalt_ipl_sr_map = {
    143   1.6     matt     .sr_bits = {
    144   1.6     matt 	[IPL_NONE] =		MIPS_INT_MASK_0,
    145   1.6     matt 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0 | MIPS_INT_MASK_0,
    146   1.6     matt 	[IPL_SOFTBIO] =		MIPS_SOFT_INT_MASK_0 | MIPS_INT_MASK_0,
    147   1.6     matt 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
    148   1.6     matt 	[IPL_SOFTSERIAL] =	MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
    149   1.6     matt 	[IPL_VM] =		MIPS_INT_MASK ^ MIPS_INT_MASK_5,
    150   1.6     matt 	[IPL_SCHED] =		MIPS_INT_MASK,
    151   1.6     matt 	[IPL_DDB] =		MIPS_INT_MASK,
    152   1.6     matt 	[IPL_HIGH] =		MIPS_INT_MASK,
    153   1.6     matt     },
    154   1.6     matt };
    155   1.6     matt 
    156   1.1  tsutsui void
    157   1.1  tsutsui intr_init(void)
    158   1.1  tsutsui {
    159   1.1  tsutsui 	int i;
    160   1.1  tsutsui 
    161   1.6     matt 	ipl_sr_map = cobalt_ipl_sr_map;
    162   1.1  tsutsui 	/*
    163   1.1  tsutsui 	 * Initialize CPU interrupts.
    164   1.1  tsutsui 	 */
    165   1.1  tsutsui 	for (i = 0; i < NCPU_INT; i++) {
    166   1.1  tsutsui 		snprintf(cpu_intrtab[i].intr_evname,
    167   1.1  tsutsui 		    sizeof(cpu_intrtab[i].intr_evname), "int %d", i);
    168   1.1  tsutsui 		evcnt_attach_dynamic(&cpu_intrtab[i].intr_evcnt,
    169   1.1  tsutsui 		    EVCNT_TYPE_INTR, NULL, "mips", cpu_intrtab[i].intr_evname);
    170   1.1  tsutsui 	}
    171   1.1  tsutsui 
    172   1.8    skrll 	extern struct mips_bus_space cobalt_bs;
    173   1.8    skrll 
    174   1.1  tsutsui 	/*
    175   1.1  tsutsui 	 * Initialize ICU interrupts.
    176   1.1  tsutsui 	 */
    177   1.9     maya 	icu_bst = &cobalt_bs;
    178   1.1  tsutsui 	bus_space_map(icu_bst, PCIB_BASE + IO_ICU1, IO_ICUSIZE, 0, &icu1_bsh);
    179   1.1  tsutsui 	bus_space_map(icu_bst, PCIB_BASE + IO_ICU2, IO_ICUSIZE, 0, &icu2_bsh);
    180   1.1  tsutsui 	bus_space_map(icu_bst, PCIB_BASE + IO_ELCR, IO_ELCRSIZE, 0, &elcr_bsh);
    181   1.1  tsutsui 
    182   1.1  tsutsui 	/* All interrupts default to "masked off". */
    183   1.1  tsutsui 	icu_imask = 0xffff;
    184   1.1  tsutsui 
    185   1.1  tsutsui 	/* All interrupts default to edge-triggered. */
    186   1.1  tsutsui 	icu_elcr = 0;
    187   1.1  tsutsui 
    188   1.1  tsutsui 	/* Initialize master PIC */
    189   1.1  tsutsui 
    190   1.1  tsutsui 	/* reset; program device, four bytes */
    191   1.1  tsutsui 	ICU1_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
    192   1.1  tsutsui 	/* starting at this vector index */
    193   1.1  tsutsui 	ICU1_WRITE(PIC_ICW2, 0);			/* XXX */
    194   1.1  tsutsui 	/* slave on line 2 */
    195   1.1  tsutsui 	ICU1_WRITE(PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE));
    196   1.1  tsutsui 	/* special fully nested mode, 8086 mode */
    197   1.1  tsutsui 	ICU1_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
    198   1.1  tsutsui 	/* mask all interrupts */
    199   1.1  tsutsui 	ICU1_WRITE(PIC_OCW1, icu_imask & 0xff);
    200   1.1  tsutsui 	/* special mask mode */
    201   1.1  tsutsui 	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    202   1.1  tsutsui 	/* read IRR by default */
    203   1.1  tsutsui 	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
    204   1.1  tsutsui 
    205   1.1  tsutsui 	/* Initialize slave PIC */
    206   1.1  tsutsui 
    207   1.1  tsutsui 	/* reset; program device, four bytes */
    208   1.1  tsutsui 	ICU2_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
    209   1.1  tsutsui 	/* starting at this vector index */
    210   1.1  tsutsui 	ICU2_WRITE(PIC_ICW2, 8);			/* XXX */
    211   1.1  tsutsui 	/* slave connected to line 2 of master */
    212   1.1  tsutsui 	ICU2_WRITE(PIC_ICW3, ICW3_SIC(IRQ_SLAVE));
    213   1.1  tsutsui 	/* special fully nested mode, 8086 mode */
    214   1.1  tsutsui 	ICU2_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
    215   1.1  tsutsui 	/* mask all interrupts */
    216   1.1  tsutsui 	ICU1_WRITE(PIC_OCW1, (icu_imask >> 8) & 0xff);
    217   1.1  tsutsui 	/* special mask mode */
    218   1.1  tsutsui 	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
    219   1.1  tsutsui 	/* read IRR by default */
    220   1.1  tsutsui 	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
    221   1.1  tsutsui 
    222   1.1  tsutsui 	/* default to edge-triggered */
    223   1.1  tsutsui 	ELCR_WRITE(ELCR0, icu_elcr & 0xff);
    224   1.1  tsutsui 	ELCR_WRITE(ELCR1, (icu_elcr >> 8) & 0xff);
    225   1.1  tsutsui 
    226   1.1  tsutsui 	wbflush();
    227   1.1  tsutsui 
    228   1.1  tsutsui 	/* Initialize our interrupt table. */
    229   1.1  tsutsui 	for (i = 0; i < NICU_INT; i++) {
    230   1.1  tsutsui 		LIST_INIT(&icu_intrtab[i].intr_q);
    231   1.1  tsutsui 		snprintf(icu_intrtab[i].intr_evname,
    232   1.1  tsutsui 		    sizeof(icu_intrtab[i].intr_evname), "irq %d", i);
    233   1.1  tsutsui 		evcnt_attach_dynamic(&icu_intrtab[i].intr_evcnt,
    234   1.1  tsutsui 		    EVCNT_TYPE_INTR, &cpu_intrtab[ICU_LEVEL].intr_evcnt,
    235   1.1  tsutsui 		    "icu", icu_intrtab[i].intr_evname);
    236   1.1  tsutsui 		icu_intrtab[i].intr_type = IST_NONE;
    237   1.1  tsutsui 	}
    238   1.1  tsutsui 
    239   1.1  tsutsui 	cpu_intr_establish(ICU_LEVEL, IPL_NONE, icu_intr, NULL);
    240   1.1  tsutsui }
    241   1.1  tsutsui 
    242   1.1  tsutsui void *
    243   1.1  tsutsui icu_intr_establish(int irq, int type, int ipl, int (*func)(void *), void *arg)
    244   1.1  tsutsui {
    245   1.1  tsutsui 	struct cobalt_intrhand *ih;
    246   1.1  tsutsui 	int s;
    247   1.1  tsutsui 
    248   1.1  tsutsui 	if (irq >= NICU_INT || irq == IRQ_SLAVE || type == IST_NONE)
    249   1.1  tsutsui 		panic("%s: bad irq or type", __func__);
    250   1.1  tsutsui 
    251   1.1  tsutsui 	switch (icu_intrtab[irq].intr_type) {
    252   1.1  tsutsui 	case IST_NONE:
    253   1.1  tsutsui 		icu_intrtab[irq].intr_type = type;
    254   1.1  tsutsui 		break;
    255   1.1  tsutsui 
    256   1.1  tsutsui 	case IST_EDGE:
    257   1.1  tsutsui 	case IST_LEVEL:
    258   1.1  tsutsui 		if (type == icu_intrtab[irq].intr_type)
    259   1.1  tsutsui 			break;
    260   1.1  tsutsui 		/* FALLTHROUGH */
    261   1.1  tsutsui 	case IST_PULSE:
    262   1.1  tsutsui 		/*
    263   1.1  tsutsui 		 * We can't share interrupts in this case.
    264   1.1  tsutsui 		 */
    265   1.1  tsutsui 		return NULL;
    266   1.1  tsutsui 	}
    267   1.1  tsutsui 
    268  1.11  thorpej 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
    269   1.1  tsutsui 	ih->ih_func = func;
    270   1.1  tsutsui 	ih->ih_arg = arg;
    271   1.1  tsutsui 	ih->ih_irq = irq;
    272   1.1  tsutsui 	ih->ih_cookie_type = COBALT_COOKIE_TYPE_ICU;
    273   1.1  tsutsui 
    274   1.1  tsutsui 	s = splhigh();
    275   1.1  tsutsui 
    276   1.1  tsutsui 	/* Insert the handler into the table. */
    277   1.1  tsutsui 	LIST_INSERT_HEAD(&icu_intrtab[irq].intr_q, ih, ih_q);
    278   1.1  tsutsui 
    279   1.1  tsutsui 	/* Enable it, set trigger mode. */
    280   1.1  tsutsui 	icu_imask &= ~(1U << irq);
    281   1.1  tsutsui 	if (icu_intrtab[irq].intr_type == IST_LEVEL)
    282   1.1  tsutsui 		icu_elcr |= (1U << irq);
    283   1.1  tsutsui 	else
    284   1.1  tsutsui 		icu_elcr &= ~(1U << irq);
    285   1.1  tsutsui 
    286   1.1  tsutsui 	icu_set();
    287   1.1  tsutsui 
    288   1.1  tsutsui 	splx(s);
    289   1.1  tsutsui 
    290   1.1  tsutsui 	return ih;
    291   1.1  tsutsui }
    292   1.1  tsutsui 
    293   1.1  tsutsui void
    294   1.1  tsutsui icu_intr_disestablish(void *cookie)
    295   1.1  tsutsui {
    296   1.1  tsutsui 	struct cobalt_intrhand *ih = cookie;
    297   1.1  tsutsui 	int s;
    298   1.1  tsutsui 
    299   1.1  tsutsui 	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_ICU) {
    300   1.1  tsutsui 		s = splhigh();
    301   1.1  tsutsui 
    302   1.1  tsutsui 		LIST_REMOVE(ih, ih_q);
    303   1.1  tsutsui 
    304   1.1  tsutsui 		if (LIST_FIRST(&icu_intrtab[ih->ih_irq].intr_q) == NULL) {
    305   1.1  tsutsui 			icu_imask |= (1U << ih->ih_irq);
    306   1.1  tsutsui 			icu_set();
    307   1.1  tsutsui 		}
    308   1.1  tsutsui 		splx(s);
    309  1.11  thorpej 		kmem_free(ih, sizeof(*ih));
    310   1.1  tsutsui 	}
    311   1.1  tsutsui }
    312   1.1  tsutsui 
    313   1.1  tsutsui void
    314   1.1  tsutsui icu_set(void)
    315   1.1  tsutsui {
    316   1.1  tsutsui 
    317   1.1  tsutsui 	if ((icu_imask & 0xff00) != 0xff00)
    318   1.1  tsutsui 		icu_imask &= ~(1U << IRQ_SLAVE);
    319   1.1  tsutsui 	else
    320   1.1  tsutsui 		icu_imask |= (1U << IRQ_SLAVE);
    321   1.1  tsutsui 
    322   1.1  tsutsui 	ICU1_WRITE(PIC_OCW1, icu_imask);
    323   1.1  tsutsui 	ICU2_WRITE(PIC_OCW1, icu_imask >> 8);
    324   1.1  tsutsui 
    325   1.1  tsutsui 	ELCR_WRITE(ELCR0, icu_elcr);
    326   1.1  tsutsui 	ELCR_WRITE(ELCR1, icu_elcr >> 8);
    327   1.1  tsutsui }
    328   1.1  tsutsui 
    329   1.1  tsutsui int
    330   1.1  tsutsui icu_intr(void *arg)
    331   1.1  tsutsui {
    332   1.1  tsutsui 	struct cobalt_intrhand *ih;
    333   1.1  tsutsui 	int irq, handled;
    334   1.1  tsutsui 
    335   1.1  tsutsui 	handled = 0;
    336   1.1  tsutsui 
    337   1.1  tsutsui 	for (;;) {
    338   1.1  tsutsui 		/* check requested irq */
    339   1.1  tsutsui 		ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_POLL);
    340   1.1  tsutsui 		irq = ICU1_READ(PIC_OCW3);
    341   1.1  tsutsui 		if ((irq & OCW3_POLL_PENDING) == 0)
    342   1.1  tsutsui 			return handled;
    343   1.1  tsutsui 
    344   1.1  tsutsui 		irq = OCW3_POLL_IRQ(irq);
    345   1.1  tsutsui 		if (irq == IRQ_SLAVE) {
    346   1.1  tsutsui 			ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_POLL);
    347   1.1  tsutsui 			irq = OCW3_POLL_IRQ(ICU2_READ(PIC_OCW3)) + 8;
    348   1.1  tsutsui 		}
    349   1.1  tsutsui 
    350   1.1  tsutsui 		icu_intrtab[irq].intr_evcnt.ev_count++;
    351   1.1  tsutsui 		LIST_FOREACH(ih, &icu_intrtab[irq].intr_q, ih_q) {
    352   1.1  tsutsui 			if (__predict_false(ih->ih_func == NULL))
    353   1.1  tsutsui 				printf("%s: spurious interrupt (irq = %d)\n",
    354   1.1  tsutsui 				    __func__, irq);
    355   1.1  tsutsui 			else if (__predict_true((*ih->ih_func)(ih->ih_arg))) {
    356   1.1  tsutsui 				handled = 1;
    357   1.1  tsutsui 			}
    358   1.1  tsutsui 		}
    359   1.1  tsutsui 
    360   1.1  tsutsui 		/* issue EOI to ack */
    361   1.1  tsutsui 		if (irq >= 8) {
    362   1.1  tsutsui 			ICU2_WRITE(PIC_OCW2,
    363   1.1  tsutsui 			    OCW2_SELECT | OCW2_SL | OCW2_EOI |
    364   1.1  tsutsui 			    OCW2_ILS(irq - 8));
    365   1.1  tsutsui 			irq = IRQ_SLAVE;
    366   1.1  tsutsui 		}
    367   1.1  tsutsui 		ICU1_WRITE(PIC_OCW2,
    368   1.1  tsutsui 		    OCW2_SELECT | OCW2_SL | OCW2_EOI | OCW2_ILS(irq));
    369   1.1  tsutsui 	}
    370   1.1  tsutsui }
    371   1.1  tsutsui 
    372   1.1  tsutsui void *
    373   1.1  tsutsui cpu_intr_establish(int level, int ipl, int (*func)(void *), void *arg)
    374   1.1  tsutsui {
    375   1.1  tsutsui 	struct cobalt_intrhand *ih;
    376   1.1  tsutsui 
    377   1.1  tsutsui 	if (level < 0 || level >= NCPU_INT)
    378   1.1  tsutsui 		panic("invalid interrupt level");
    379   1.1  tsutsui 
    380   1.1  tsutsui 	ih = &cpu_intrtab[level].intr_ih;
    381   1.1  tsutsui 
    382   1.1  tsutsui 	if (ih->ih_func != NULL)
    383   1.1  tsutsui 		panic("cannot share CPU interrupts");
    384   1.1  tsutsui 
    385   1.1  tsutsui 	ih->ih_cookie_type = COBALT_COOKIE_TYPE_CPU;
    386   1.1  tsutsui 	ih->ih_func = func;
    387   1.1  tsutsui 	ih->ih_arg = arg;
    388   1.1  tsutsui 	ih->ih_irq = NICU_INT + level;
    389   1.1  tsutsui 
    390   1.1  tsutsui 	return ih;
    391   1.1  tsutsui }
    392   1.1  tsutsui 
    393   1.1  tsutsui void
    394   1.1  tsutsui cpu_intr_disestablish(void *cookie)
    395   1.1  tsutsui {
    396   1.1  tsutsui 	struct cobalt_intrhand *ih = cookie;
    397   1.1  tsutsui 
    398   1.1  tsutsui 	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_CPU) {
    399   1.1  tsutsui 		ih->ih_func = NULL;
    400   1.1  tsutsui 		ih->ih_arg = NULL;
    401   1.1  tsutsui 		ih->ih_cookie_type = 0;
    402   1.1  tsutsui 	}
    403   1.1  tsutsui }
    404   1.1  tsutsui 
    405   1.6     matt static void inline
    406   1.6     matt intr_handle(struct cpu_intrhead *intr)
    407   1.6     matt {
    408   1.6     matt 	struct cobalt_intrhand * const ih = &intr->intr_ih;
    409   1.6     matt 	if (__predict_true(ih->ih_func != NULL)
    410   1.6     matt 	    && __predict_true((*ih->ih_func)(ih->ih_arg))) {
    411   1.6     matt 		intr->intr_evcnt.ev_count++;
    412   1.6     matt 	}
    413   1.6     matt }
    414   1.6     matt 
    415   1.1  tsutsui void
    416   1.6     matt cpu_intr(int ppl, vaddr_t pc, uint32_t status)
    417   1.1  tsutsui {
    418   1.6     matt 	uint32_t pending;
    419   1.6     matt 	int ipl;
    420   1.1  tsutsui 
    421   1.6     matt 	curcpu()->ci_data.cpu_nintr++;
    422   1.1  tsutsui 
    423   1.6     matt 	while (ppl < (ipl = splintr(&pending))) {
    424   1.6     matt 		splx(ipl);
    425   1.6     matt 		if (pending & MIPS_INT_MASK_5) {
    426   1.6     matt 			struct clockframe cf;
    427   1.6     matt 			/* call the common MIPS3 clock interrupt handler */
    428   1.6     matt 			cf.pc = pc;
    429   1.6     matt 			cf.sr = status;
    430   1.6     matt 			cf.intr = (curcpu()->ci_idepth > 1);
    431   1.6     matt 			mips3_clockintr(&cf);
    432   1.6     matt 		}
    433   1.1  tsutsui 
    434   1.6     matt 		if (__predict_false(pending & MIPS_INT_MASK_0)) {
    435   1.6     matt 			/* GT64x11 timer0 */
    436   1.6     matt 			volatile uint32_t *irq_src =
    437   1.6     matt 			    (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_INTR_CAUSE);
    438   1.6     matt 
    439   1.6     matt 			if (__predict_true((*irq_src & T0EXP) != 0)) {
    440   1.6     matt 				/* GT64x11 timer is no longer used for hardclock(9) */
    441   1.6     matt 				*irq_src = 0;
    442   1.6     matt 			}
    443   1.1  tsutsui 		}
    444   1.1  tsutsui 
    445   1.6     matt 		if (pending & MIPS_INT_MASK_3) {
    446   1.6     matt 			/* 16650 serial */
    447   1.6     matt 			intr_handle(&cpu_intrtab[3]);
    448   1.1  tsutsui 		}
    449   1.1  tsutsui 
    450   1.6     matt 		if (pending & MIPS_INT_MASK_1) {
    451   1.6     matt 			/* tulip primary */
    452   1.6     matt 			intr_handle(&cpu_intrtab[1]);
    453   1.1  tsutsui 		}
    454   1.6     matt 
    455   1.6     matt 		if (pending & MIPS_INT_MASK_2) {
    456   1.6     matt 			/* tulip secondary */
    457   1.6     matt 			intr_handle(&cpu_intrtab[2]);
    458   1.1  tsutsui 		}
    459   1.1  tsutsui 
    460   1.6     matt 		if (pending & MIPS_INT_MASK_4) {
    461   1.6     matt 			/* ICU interrupts */
    462   1.6     matt 			intr_handle(&cpu_intrtab[4]);
    463   1.1  tsutsui 		}
    464   1.6     matt 		(void)splhigh();
    465   1.1  tsutsui 	}
    466   1.1  tsutsui }
    467