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