1 /* $OpenBSD: macintr.c,v 1.43 2011/08/29 20:21:44 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] = i; 409 } 410 411 /* Enable interrupts at lower levels */ 412 413 if (irq < 32) { 414 for (i = IPL_NONE; i < minipl; i++) 415 macintr_ienable_l[i] |= (1 << irq); 416 for (; i <= IPL_HIGH; i++) 417 macintr_ienable_l[i] &= ~(1 << irq); 418 } else { 419 for (i = IPL_NONE; i < minipl; i++) 420 macintr_ienable_h[i] |= (1 << (irq-32)); 421 for (; i <= IPL_HIGH; i++) 422 macintr_ienable_h[i] &= ~(1 << (irq-32)); 423 } 424 } 425 426 #if 0 427 for (i = 0; i < IPL_NUM; i++) 428 printf("imask[%d] %x %x\n", i, macintr_ienable_l[i], 429 macintr_ienable_h[i]); 430 #endif 431 } 432 433 /* 434 * external interrupt handler 435 */ 436 void 437 mac_ext_intr() 438 { 439 int irq = 0; 440 int pcpl, ret; 441 struct cpu_info *ci = curcpu(); 442 struct intrq *iq; 443 struct intrhand *ih; 444 445 pcpl = ci->ci_cpl; /* Turn off all */ 446 447 irq = macintr_read_irq(); 448 while (irq != 255) { 449 iq = &macintr_handler[irq]; 450 macintr_setipl(iq->iq_ipl); 451 452 TAILQ_FOREACH(ih, &iq->iq_list, ih_list) { 453 ppc_intr_enable(1); 454 ret = ((*ih->ih_fun)(ih->ih_arg)); 455 if (ret) { 456 ih->ih_count.ec_count++; 457 if (intr_shared_edge == 0 && ret == 1) 458 break; 459 } 460 (void)ppc_intr_disable(); 461 } 462 macintr_eoi(irq); 463 macintr_setipl(pcpl); 464 465 uvmexp.intrs++; 466 467 irq = macintr_read_irq(); 468 } 469 470 ppc_intr_enable(1); 471 splx(pcpl); /* Process pendings. */ 472 } 473 474 void 475 macintr_do_pending_int() 476 { 477 struct cpu_info *ci = curcpu(); 478 int pcpl = ci->ci_cpl; /* XXX */ 479 int s; 480 s = ppc_intr_disable(); 481 if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) { 482 ppc_intr_enable(s); 483 return; 484 } 485 atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 486 487 do { 488 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) && 489 (pcpl < IPL_SOFTCLOCK)) { 490 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK); 491 softintr_dispatch(SI_SOFTCLOCK); 492 } 493 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) && 494 (pcpl < IPL_SOFTNET)) { 495 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET); 496 softintr_dispatch(SI_SOFTNET); 497 } 498 if((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) && 499 (pcpl < IPL_SOFTTTY)) { 500 ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY); 501 softintr_dispatch(SI_SOFTTTY); 502 } 503 504 } while (ci->ci_ipending & ppc_smask[pcpl]); 505 macintr_setipl(pcpl); 506 ppc_intr_enable(s); 507 508 atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT); 509 } 510 511 void 512 macintr_eoi(int irq) 513 { 514 u_int32_t state0, state1; 515 516 if (irq < 32) { 517 state0 = 1 << irq; 518 out32rb(INT_CLEAR_REG0, state0); 519 } else { 520 if (heathrow_FCR) { /* has heathrow? */ 521 state1 = 1 << (irq - 32); 522 out32rb(INT_CLEAR_REG1, state1); 523 } 524 } 525 } 526 527 int 528 macintr_read_irq() 529 { 530 struct cpu_info *ci = curcpu(); 531 u_int32_t state0, state1, irq_mask; 532 int ipl, irq; 533 534 state0 = in32rb(INT_STATE_REG0); 535 536 if (heathrow_FCR) /* has heathrow? */ 537 state1 = in32rb(INT_STATE_REG1); 538 else 539 state1 = 0; 540 541 for (ipl = IPL_HIGH; ipl >= ci->ci_cpl; ipl --) { 542 irq_mask = state0 & macintr_ienable_l[ipl]; 543 if (irq_mask) { 544 irq = ffs(irq_mask) - 1; 545 return irq; 546 } 547 irq_mask = state1 & macintr_ienable_h[ipl]; 548 if (irq_mask) { 549 irq = ffs(irq_mask) + 31; 550 return irq; 551 } 552 } 553 return 255; 554 } 555