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