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