1 /* $OpenBSD: macintr.c,v 1.47 2014/07/12 18:44:42 tedu Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org> 5 * Copyright (c) 1995 Per Fogelstrom 6 * Copyright (c) 1993, 1994 Charles M. Hannum. 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * William Jolitz and Don Ahn. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)isa.c 7.2 (Berkeley) 5/12/91 38 */ 39 40 #include <sys/param.h> 41 #include <sys/device.h> 42 #include <sys/systm.h> 43 #include <sys/malloc.h> 44 45 #include <uvm/uvm_extern.h> 46 #include <ddb/db_var.h> 47 48 #include <machine/atomic.h> 49 #include <machine/autoconf.h> 50 #include <machine/intr.h> 51 #include <machine/psl.h> 52 #include <machine/pio.h> 53 54 #include <dev/ofw/openfirm.h> 55 56 #define ICU_LEN 64 57 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) 58 59 int macintr_ienable_l[IPL_NUM], macintr_ienable_h[IPL_NUM]; 60 int macintr_pri_share[IPL_NUM]; 61 62 struct intrq macintr_handler[ICU_LEN]; 63 64 void macintr_calc_mask(void); 65 void macintr_eoi(int irq); 66 int macintr_read_irq(void); 67 static void macintr_do_pending_int(void); 68 69 extern u_int32_t *heathrow_FCR; 70 71 #define INT_STATE_REG0 (interrupt_reg + 0x20) 72 #define INT_ENABLE_REG0 (interrupt_reg + 0x24) 73 #define INT_CLEAR_REG0 (interrupt_reg + 0x28) 74 #define INT_LEVEL_REG0 (interrupt_reg + 0x2c) 75 #define INT_STATE_REG1 (INT_STATE_REG0 - 0x10) 76 #define INT_ENABLE_REG1 (INT_ENABLE_REG0 - 0x10) 77 #define INT_CLEAR_REG1 (INT_CLEAR_REG0 - 0x10) 78 #define INT_LEVEL_REG1 (INT_LEVEL_REG0 - 0x10) 79 80 struct macintr_softc { 81 struct device sc_dev; 82 }; 83 84 int macintr_match(struct device *parent, void *cf, void *aux); 85 void macintr_attach(struct device *, struct device *, void *); 86 void mac_do_pending_int(void); 87 void mac_ext_intr(void); 88 void macintr_collect_preconf_intr(void); 89 void macintr_setipl(int ipl); 90 91 struct cfattach macintr_ca = { 92 sizeof(struct macintr_softc), 93 macintr_match, 94 macintr_attach 95 }; 96 97 struct cfdriver macintr_cd = { 98 NULL, "macintr", DV_DULL 99 }; 100 101 int 102 macintr_match(struct device *parent, void *cf, void *aux) 103 { 104 struct confargs *ca = aux; 105 char type[40]; 106 107 /* 108 * Match entry according to "present" openfirmware entry. 109 */ 110 if (strcmp(ca->ca_name, "interrupt-controller") == 0 ) { 111 OF_getprop(ca->ca_node, "device_type", type, sizeof(type)); 112 if (strcmp(type, "interrupt-controller") == 0) 113 return 1; 114 } 115 116 /* 117 * Check name for legacy interrupt controller, this is 118 * faked to allow old firmware which does not have an entry 119 * to attach to this device. 120 */ 121 if (strcmp(ca->ca_name, "legacy-interrupt-controller") == 0 ) 122 return 1; 123 return 0; 124 } 125 126 u_int8_t *interrupt_reg; 127 typedef void (void_f) (void); 128 extern void_f *pending_int_f; 129 int macintr_prog_button (void *arg); 130 131 intr_establish_t macintr_establish; 132 intr_disestablish_t macintr_disestablish; 133 extern intr_establish_t *mac_intr_establish_func; 134 extern intr_disestablish_t *mac_intr_disestablish_func; 135 136 ppc_splraise_t macintr_splraise; 137 ppc_spllower_t macintr_spllower; 138 ppc_splx_t macintr_splx; 139 140 141 int 142 macintr_splraise(int newcpl) 143 { 144 struct cpu_info *ci = curcpu(); 145 newcpl = macintr_pri_share[newcpl]; 146 int ocpl = ci->ci_cpl; 147 if (ocpl > newcpl) 148 newcpl = ocpl; 149 150 macintr_setipl(newcpl); 151 152 return ocpl; 153 } 154 155 int 156 macintr_spllower(int newcpl) 157 { 158 struct cpu_info *ci = curcpu(); 159 int ocpl = ci->ci_cpl; 160 161 macintr_splx(newcpl); 162 163 return ocpl; 164 } 165 166 void 167 macintr_splx(int newcpl) 168 { 169 struct cpu_info *ci = curcpu(); 170 171 macintr_setipl(newcpl); 172 if (ci->ci_ipending & ppc_smask[newcpl]) 173 macintr_do_pending_int(); 174 } 175 176 void 177 macintr_attach(struct device *parent, struct device *self, void *aux) 178 { 179 struct cpu_info *ci = curcpu(); 180 struct confargs *ca = aux; 181 extern intr_establish_t *intr_establish_func; 182 extern intr_disestablish_t *intr_disestablish_func; 183 struct intrq *iq; 184 int i; 185 186 interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */ 187 188 for (i = 0; i < ICU_LEN; i++) { 189 iq = &macintr_handler[i]; 190 TAILQ_INIT(&iq->iq_list); 191 } 192 ppc_smask_init(); 193 194 install_extint(mac_ext_intr); 195 pending_int_f = macintr_do_pending_int; 196 intr_establish_func = macintr_establish; 197 intr_disestablish_func = macintr_disestablish; 198 mac_intr_establish_func = macintr_establish; 199 mac_intr_disestablish_func = macintr_disestablish; 200 201 ppc_intr_func.raise = macintr_splraise; 202 ppc_intr_func.lower = macintr_spllower; 203 ppc_intr_func.x = macintr_splx; 204 205 ci->ci_iactive = 0; 206 207 macintr_collect_preconf_intr(); 208 209 mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH, 210 macintr_prog_button, (void *)0x14, "progbutton"); 211 212 ppc_intr_enable(1); 213 printf("\n"); 214 } 215 216 void 217 macintr_collect_preconf_intr() 218 { 219 int i; 220 for (i = 0; i < ppc_configed_intr_cnt; i++) { 221 #ifdef DEBUG 222 printf("\n\t%s irq %d level %d fun %p arg %p", 223 ppc_configed_intr[i].ih_what, 224 ppc_configed_intr[i].ih_irq, 225 ppc_configed_intr[i].ih_level, 226 ppc_configed_intr[i].ih_fun, 227 ppc_configed_intr[i].ih_arg 228 ); 229 #endif 230 macintr_establish(NULL, 231 ppc_configed_intr[i].ih_irq, 232 IST_LEVEL, 233 ppc_configed_intr[i].ih_level, 234 ppc_configed_intr[i].ih_fun, 235 ppc_configed_intr[i].ih_arg, 236 ppc_configed_intr[i].ih_what); 237 } 238 } 239 240 241 /* 242 * programmer_button function to fix args to Debugger. 243 * deal with any enables/disables, if necessary. 244 */ 245 int 246 macintr_prog_button (void *arg) 247 { 248 #ifdef DDB 249 if (db_console) 250 Debugger(); 251 #else 252 printf("programmer button pressed, debugger not available\n"); 253 #endif 254 return 1; 255 } 256 257 void 258 macintr_setipl(int ipl) 259 { 260 struct cpu_info *ci = curcpu(); 261 int s; 262 s = ppc_intr_disable(); 263 ci->ci_cpl = ipl; 264 if (heathrow_FCR) 265 out32rb(INT_ENABLE_REG1, 266 macintr_ienable_h[macintr_pri_share[ipl]]); 267 268 out32rb(INT_ENABLE_REG0, macintr_ienable_l[macintr_pri_share[ipl]]); 269 ppc_intr_enable(s); 270 } 271 272 /* 273 * Register an interrupt handler. 274 */ 275 void * 276 macintr_establish(void * lcv, int irq, int type, int level, 277 int (*ih_fun)(void *), void *ih_arg, const char *name) 278 { 279 struct cpu_info *ci = curcpu(); 280 struct intrq *iq; 281 struct intrhand *ih; 282 int s; 283 284 #if 0 285 printf("macintr_establish, hI %d L %d %s", irq, level, ppc_intr_typename(type)); 286 #endif 287 288 /* no point in sleeping unless someone can free memory. */ 289 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 290 if (ih == NULL) 291 panic("intr_establish: can't malloc handler info"); 292 293 if (!LEGAL_IRQ(irq) || type == IST_NONE) 294 panic("intr_establish: bogus irq or type"); 295 296 iq = &macintr_handler[irq]; 297 switch (iq->iq_ist) { 298 case IST_NONE: 299 iq->iq_ist = type; 300 break; 301 case IST_EDGE: 302 intr_shared_edge = 1; 303 /* FALLTHROUGH */ 304 case IST_LEVEL: 305 if (type == iq->iq_ist) 306 break; 307 case IST_PULSE: 308 if (type != IST_NONE) 309 panic("intr_establish: can't share %s with %s", 310 ppc_intr_typename(iq->iq_ist), 311 ppc_intr_typename(type)); 312 break; 313 } 314 315 ih->ih_fun = ih_fun; 316 ih->ih_arg = ih_arg; 317 ih->ih_level = level; 318 ih->ih_irq = irq; 319 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 320 321 /* 322 * Append handler to end of list 323 */ 324 s = ppc_intr_disable(); 325 326 TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); 327 macintr_calc_mask(); 328 329 macintr_setipl(ci->ci_cpl); 330 ppc_intr_enable(s); 331 332 return (ih); 333 } 334 335 /* 336 * Deregister an interrupt handler. 337 */ 338 void 339 macintr_disestablish(void *lcp, void *arg) 340 { 341 struct cpu_info *ci = curcpu(); 342 struct intrhand *ih = arg; 343 int irq = ih->ih_irq; 344 int s; 345 struct intrq *iq; 346 347 if (!LEGAL_IRQ(irq)) 348 panic("intr_disestablish: bogus irq"); 349 350 /* 351 * Remove the handler from the chain. 352 */ 353 354 iq = &macintr_handler[irq]; 355 s = ppc_intr_disable(); 356 357 TAILQ_REMOVE(&iq->iq_list, ih, ih_list); 358 macintr_calc_mask(); 359 360 macintr_setipl(ci->ci_cpl); 361 ppc_intr_enable(s); 362 363 evcount_detach(&ih->ih_count); 364 free((void *)ih, M_DEVBUF, 0); 365 366 if (TAILQ_EMPTY(&iq->iq_list)) 367 iq->iq_ist = IST_NONE; 368 } 369 370 /* 371 * Recalculate the interrupt masks from scratch. 372 * We could code special registry and deregistry versions of this function that 373 * would be faster, but the code would be nastier, and we don't expect this to 374 * happen very much anyway. 375 */ 376 void 377 macintr_calc_mask() 378 { 379 int irq; 380 struct intrhand *ih; 381 int i; 382 383 for (i = IPL_NONE; i < IPL_NUM; i++) { 384 macintr_pri_share[i] = i; 385 } 386 387 for (irq = 0; irq < ICU_LEN; irq++) { 388 int maxipl = IPL_NONE; 389 int minipl = IPL_HIGH; 390 struct intrq *iq = &macintr_handler[irq]; 391 392 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { 393 if (ih->ih_level > maxipl) 394 maxipl = ih->ih_level; 395 if (ih->ih_level < minipl) 396 minipl = ih->ih_level; 397 } 398 399 iq->iq_ipl = maxipl; 400 401 if (maxipl == IPL_NONE) { 402 minipl = IPL_NONE; /* Interrupt not enabled */ 403 } else { 404 for (i = minipl; i < maxipl; i++) 405 macintr_pri_share[i] = 406 macintr_pri_share[maxipl]; 407 } 408 409 /* Enable interrupts at lower levels */ 410 411 if (irq < 32) { 412 for (i = IPL_NONE; i < minipl; i++) 413 macintr_ienable_l[i] |= (1 << irq); 414 for (; i <= IPL_HIGH; i++) 415 macintr_ienable_l[i] &= ~(1 << irq); 416 } else { 417 for (i = IPL_NONE; i < minipl; i++) 418 macintr_ienable_h[i] |= (1 << (irq-32)); 419 for (; i <= IPL_HIGH; i++) 420 macintr_ienable_h[i] &= ~(1 << (irq-32)); 421 } 422 } 423 424 #if 0 425 for (i = 0; i < IPL_NUM; i++) 426 printf("imask[%d] %x %x\n", i, macintr_ienable_l[i], 427 macintr_ienable_h[i]); 428 #endif 429 } 430 431 /* 432 * external interrupt handler 433 */ 434 void 435 mac_ext_intr() 436 { 437 int irq = 0; 438 int pcpl, ret; 439 struct cpu_info *ci = curcpu(); 440 struct intrq *iq; 441 struct intrhand *ih; 442 443 pcpl = ci->ci_cpl; /* Turn off all */ 444 445 irq = macintr_read_irq(); 446 while (irq != 255) { 447 iq = &macintr_handler[irq]; 448 macintr_setipl(iq->iq_ipl); 449 450 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { 451 ppc_intr_enable(1); 452 ret = ((*ih->ih_fun)(ih->ih_arg)); 453 if (ret) { 454 ih->ih_count.ec_count++; 455 if (intr_shared_edge == 0 && ret == 1) 456 break; 457 } 458 (void)ppc_intr_disable(); 459 } 460 macintr_eoi(irq); 461 macintr_setipl(pcpl); 462 463 uvmexp.intrs++; 464 465 irq = macintr_read_irq(); 466 } 467 468 ppc_intr_enable(1); 469 splx(pcpl); /* Process pendings. */ 470 } 471 472 void 473 macintr_do_pending_int() 474 { 475 struct cpu_info *ci = curcpu(); 476 int pcpl = ci->ci_cpl; /* XXX */ 477 int s; 478 s = ppc_intr_disable(); 479 if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { 480 ppc_intr_enable(s); 481 return; 482 } 483 atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 484 485 do { 486 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && 487 (pcpl < IPL_SOFTCLOCK)) { 488 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); 489 softintr_dispatch(SI_SOFTCLOCK); 490 } 491 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && 492 (pcpl < IPL_SOFTNET)) { 493 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); 494 softintr_dispatch(SI_SOFTNET); 495 } 496 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && 497 (pcpl < IPL_SOFTTTY)) { 498 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); 499 softintr_dispatch(SI_SOFTTTY); 500 } 501 502 } while (ci->ci_ipending & ppc_smask[pcpl]); 503 macintr_setipl(pcpl); 504 ppc_intr_enable(s); 505 506 atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 507 } 508 509 void 510 macintr_eoi(int irq) 511 { 512 u_int32_t state0, state1; 513 514 if (irq < 32) { 515 state0 = 1 << irq; 516 out32rb(INT_CLEAR_REG0, state0); 517 } else { 518 if (heathrow_FCR) { /* has heathrow? */ 519 state1 = 1 << (irq - 32); 520 out32rb(INT_CLEAR_REG1, state1); 521 } 522 } 523 } 524 525 int 526 macintr_read_irq() 527 { 528 struct cpu_info *ci = curcpu(); 529 u_int32_t state0, state1, irq_mask; 530 int ipl, irq; 531 532 state0 = in32rb(INT_STATE_REG0); 533 534 if (heathrow_FCR) /* has heathrow? */ 535 state1 = in32rb(INT_STATE_REG1); 536 else 537 state1 = 0; 538 539 for (ipl = IPL_HIGH; ipl >= ci->ci_cpl; ipl --) { 540 irq_mask = state0 & macintr_ienable_l[ipl]; 541 if (irq_mask) { 542 irq = ffs(irq_mask) - 1; 543 return irq; 544 } 545 irq_mask = state1 & macintr_ienable_h[ipl]; 546 if (irq_mask) { 547 irq = ffs(irq_mask) + 31; 548 return irq; 549 } 550 } 551 return 255; 552 } 553