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