1 /* $OpenBSD: macintr.c,v 1.35 2008/11/21 17:35:52 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1995 Per Fogelstrom 5 * Copyright (c) 1993, 1994 Charles M. Hannum. 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz and Don Ahn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)isa.c 7.2 (Berkeley) 5/12/91 37 */ 38 39 #include <sys/param.h> 40 #include <sys/device.h> 41 #include <sys/ioctl.h> 42 #include <sys/mbuf.h> 43 #include <sys/socket.h> 44 #include <sys/systm.h> 45 46 #include <uvm/uvm.h> 47 #include <ddb/db_var.h> 48 49 #include <machine/atomic.h> 50 #include <machine/autoconf.h> 51 #include <machine/intr.h> 52 #include <machine/psl.h> 53 #include <machine/pio.h> 54 #include <machine/powerpc.h> 55 56 #include <dev/ofw/openfirm.h> 57 58 #define ICU_LEN 64 59 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN)) 60 61 int m_intrtype[ICU_LEN], m_intrmask[ICU_LEN], m_intrlevel[ICU_LEN]; 62 struct intrhand *m_intrhand[ICU_LEN]; 63 int m_hwirq[ICU_LEN], m_virq[64]; 64 unsigned int imen_m = 0xffffffff; 65 int m_virq_max = 0; 66 67 static int fakeintr(void *); 68 static char *intr_typename(int type); 69 static void intr_calculatemasks(void); 70 static void enable_irq(int x); 71 static __inline int cntlzw(int x); 72 static int mapirq(int irq); 73 static int read_irq(void); 74 static void mac_intr_do_pending_int(void); 75 76 extern u_int32_t *heathrow_FCR; 77 78 #define HWIRQ_MAX 27 79 #define HWIRQ_MASK 0x0fffffff 80 81 #define INT_STATE_REG0 (interrupt_reg + 0x20) 82 #define INT_ENABLE_REG0 (interrupt_reg + 0x24) 83 #define INT_CLEAR_REG0 (interrupt_reg + 0x28) 84 #define INT_LEVEL_REG0 (interrupt_reg + 0x2c) 85 #define INT_STATE_REG1 (INT_STATE_REG0 - 0x10) 86 #define INT_ENABLE_REG1 (INT_ENABLE_REG0 - 0x10) 87 #define INT_CLEAR_REG1 (INT_CLEAR_REG0 - 0x10) 88 #define INT_LEVEL_REG1 (INT_LEVEL_REG0 - 0x10) 89 90 struct macintr_softc { 91 struct device sc_dev; 92 }; 93 94 int macintr_match(struct device *parent, void *cf, void *aux); 95 void macintr_attach(struct device *, struct device *, void *); 96 void mac_do_pending_int(void); 97 void mac_ext_intr(void); 98 99 struct cfattach macintr_ca = { 100 sizeof(struct macintr_softc), 101 macintr_match, 102 macintr_attach 103 }; 104 105 struct cfdriver macintr_cd = { 106 NULL, "macintr", DV_DULL 107 }; 108 109 int 110 macintr_match(struct device *parent, void *cf, void *aux) 111 { 112 struct confargs *ca = aux; 113 char type[40]; 114 115 /* 116 * Match entry according to "present" openfirmware entry. 117 */ 118 if (strcmp(ca->ca_name, "interrupt-controller") == 0 ) { 119 OF_getprop(ca->ca_node, "device_type", type, sizeof(type)); 120 if (strcmp(type, "interrupt-controller") == 0) 121 return 1; 122 } 123 124 /* 125 * Check name for legacy interrupt controller, this is 126 * faked to allow old firmware which does not have an entry 127 * to attach to this device. 128 */ 129 if (strcmp(ca->ca_name, "legacy-interrupt-controller") == 0 ) 130 return 1; 131 return 0; 132 } 133 134 u_int8_t *interrupt_reg; 135 typedef void (void_f) (void); 136 extern void_f *pending_int_f; 137 int macintr_prog_button (void *arg); 138 139 intr_establish_t macintr_establish; 140 intr_disestablish_t macintr_disestablish; 141 extern intr_establish_t *mac_intr_establish_func; 142 extern intr_disestablish_t *mac_intr_disestablish_func; 143 void macintr_collect_preconf_intr(void); 144 145 void 146 macintr_attach(struct device *parent, struct device *self, void *aux) 147 { 148 struct confargs *ca = aux; 149 extern intr_establish_t *intr_establish_func; 150 extern intr_disestablish_t *intr_disestablish_func; 151 152 interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */ 153 154 install_extint(mac_ext_intr); 155 pending_int_f = mac_intr_do_pending_int; 156 intr_establish_func = macintr_establish; 157 intr_disestablish_func = macintr_disestablish; 158 mac_intr_establish_func = macintr_establish; 159 mac_intr_disestablish_func = macintr_disestablish; 160 161 macintr_collect_preconf_intr(); 162 163 mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH, 164 macintr_prog_button, (void *)0x14, "progbutton"); 165 166 ppc_intr_enable(1); 167 168 printf("\n"); 169 } 170 171 void 172 macintr_collect_preconf_intr() 173 { 174 int i; 175 for (i = 0; i < ppc_configed_intr_cnt; i++) { 176 #ifdef DEBUG 177 printf("\n\t%s irq %d level %d fun %p arg %p", 178 ppc_configed_intr[i].ih_what, 179 ppc_configed_intr[i].ih_irq, 180 ppc_configed_intr[i].ih_level, 181 ppc_configed_intr[i].ih_fun, 182 ppc_configed_intr[i].ih_arg 183 ); 184 #endif 185 macintr_establish(NULL, 186 ppc_configed_intr[i].ih_irq, 187 IST_LEVEL, 188 ppc_configed_intr[i].ih_level, 189 ppc_configed_intr[i].ih_fun, 190 ppc_configed_intr[i].ih_arg, 191 ppc_configed_intr[i].ih_what); 192 } 193 } 194 195 196 /* 197 * programmer_button function to fix args to Debugger. 198 * deal with any enables/disables, if necessary. 199 */ 200 int 201 macintr_prog_button (void *arg) 202 { 203 #ifdef DDB 204 if (db_console) 205 Debugger(); 206 #else 207 printf("programmer button pressed, debugger not available\n"); 208 #endif 209 return 1; 210 } 211 212 static int 213 fakeintr(void *arg) 214 { 215 216 return 0; 217 } 218 219 /* 220 * Register an interrupt handler. 221 */ 222 void * 223 macintr_establish(void * lcv, int irq, int type, int level, 224 int (*ih_fun)(void *), void *ih_arg, char *name) 225 { 226 struct intrhand **p, *q, *ih; 227 static struct intrhand fakehand; 228 229 fakehand.ih_next = NULL; 230 fakehand.ih_fun = fakeintr; 231 232 #if 0 233 printf("macintr_establish, hI %d L %d ", irq, type); 234 printf("addr reg0 %x\n", INT_STATE_REG0); 235 #endif 236 irq = mapirq(irq); 237 #if 0 238 printf("vI %d ", irq); 239 #endif 240 241 /* no point in sleeping unless someone can free memory. */ 242 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 243 if (ih == NULL) 244 panic("intr_establish: can't malloc handler info"); 245 246 if (!LEGAL_IRQ(irq) || type == IST_NONE) 247 panic("intr_establish: bogus irq or type"); 248 249 switch (m_intrtype[irq]) { 250 case IST_NONE: 251 m_intrtype[irq] = type; 252 break; 253 case IST_EDGE: 254 case IST_LEVEL: 255 if (type == m_intrtype[irq]) 256 break; 257 case IST_PULSE: 258 if (type != IST_NONE) 259 panic("intr_establish: can't share %s with %s", 260 intr_typename(m_intrtype[irq]), 261 intr_typename(type)); 262 break; 263 } 264 265 /* 266 * Figure out where to put the handler. 267 * This is O(N^2), but we want to preserve the order, and N is 268 * generally small. 269 */ 270 for (p = &m_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) 271 ; 272 273 /* 274 * Actually install a fake handler momentarily, since we might be doing 275 * this with interrupts enabled and DON'T WANt the real routine called 276 * until masking is set up. 277 */ 278 fakehand.ih_level = level; 279 *p = &fakehand; 280 281 intr_calculatemasks(); 282 283 /* 284 * Poke the real handler in now. 285 */ 286 ih->ih_fun = ih_fun; 287 ih->ih_arg = ih_arg; 288 ih->ih_next = NULL; 289 ih->ih_level = level; 290 ih->ih_irq = irq; 291 evcount_attach(&ih->ih_count, name, (void *)&m_hwirq[irq], 292 &evcount_intr); 293 *p = ih; 294 295 return (ih); 296 } 297 298 /* 299 * Deregister an interrupt handler. 300 */ 301 void 302 macintr_disestablish(void *lcp, void *arg) 303 { 304 struct intrhand *ih = arg; 305 int irq = ih->ih_irq; 306 struct intrhand **p, *q; 307 308 if (!LEGAL_IRQ(irq)) 309 panic("intr_disestablish: bogus irq"); 310 311 /* 312 * Remove the handler from the chain. 313 * This is O(n^2), too. 314 */ 315 for (p = &m_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next) 316 ; 317 if (q) 318 *p = q->ih_next; 319 else 320 panic("intr_disestablish: handler not registered"); 321 322 evcount_detach(&ih->ih_count); 323 free((void *)ih, M_DEVBUF); 324 325 intr_calculatemasks(); 326 327 if (m_intrhand[irq] == NULL) 328 m_intrtype[irq] = IST_NONE; 329 } 330 331 332 static char * 333 intr_typename(int type) 334 { 335 switch (type) { 336 case IST_NONE : 337 return ("none"); 338 case IST_PULSE: 339 return ("pulsed"); 340 case IST_EDGE: 341 return ("edge-triggered"); 342 case IST_LEVEL: 343 return ("level-triggered"); 344 default: 345 panic("intr_typename: invalid type %d", type); 346 #if 1 /* XXX */ 347 return ("unknown"); 348 #endif 349 } 350 } 351 /* 352 * Recalculate the interrupt masks from scratch. 353 * We could code special registry and deregistry versions of this function that 354 * would be faster, but the code would be nastier, and we don't expect this to 355 * happen very much anyway. 356 */ 357 static void 358 intr_calculatemasks() 359 { 360 int irq, level; 361 struct intrhand *q; 362 363 /* First, figure out which levels each IRQ uses. */ 364 for (irq = 0; irq < ICU_LEN; irq++) { 365 register int levels = 0; 366 for (q = m_intrhand[irq]; q; q = q->ih_next) 367 levels |= 1 << q->ih_level; 368 m_intrlevel[irq] = levels; 369 } 370 371 /* Then figure out which IRQs use each level. */ 372 for (level = IPL_NONE; level < IPL_NUM; level++) { 373 register int irqs = 0; 374 for (irq = 0; irq < ICU_LEN; irq++) 375 if (m_intrlevel[irq] & (1 << level)) 376 irqs |= 1 << irq; 377 imask[level] = irqs | SINT_MASK; 378 } 379 380 /* 381 * There are tty, network and disk drivers that use free() at interrupt 382 * time, so vm > (tty | net | bio). 383 * 384 * Enforce a hierarchy that gives slow devices a better chance at not 385 * dropping data. 386 */ 387 imask[IPL_NET] |= imask[IPL_BIO]; 388 imask[IPL_TTY] |= imask[IPL_NET]; 389 imask[IPL_VM] |= imask[IPL_TTY]; 390 imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK; 391 392 /* 393 * These are pseudo-levels. 394 */ 395 imask[IPL_NONE] = 0x00000000; 396 imask[IPL_HIGH] = 0xffffffff; 397 398 /* And eventually calculate the complete masks. */ 399 for (irq = 0; irq < ICU_LEN; irq++) { 400 register int irqs = 1 << irq; 401 for (q = m_intrhand[irq]; q; q = q->ih_next) 402 irqs |= imask[q->ih_level]; 403 m_intrmask[irq] = irqs | SINT_MASK; 404 } 405 406 /* Lastly, determine which IRQs are actually in use. */ 407 { 408 register int irqs = 0; 409 for (irq = 0; irq < ICU_LEN; irq++) { 410 if (m_intrhand[irq]) 411 irqs |= 1 << irq; 412 } 413 imen_m = ~irqs; 414 enable_irq(~imen_m); 415 } 416 } 417 static void 418 enable_irq(int x) 419 { 420 int state0, state1, v; 421 int irq; 422 423 x &= HWIRQ_MASK; /* XXX Higher bits are software interrupts. */ 424 425 state0 = state1 = 0; 426 while (x) { 427 v = 31 - cntlzw(x); 428 irq = m_hwirq[v]; 429 if (irq < 32) 430 state0 |= 1 << irq; 431 else 432 state1 |= 1 << (irq - 32); 433 434 x &= ~(1 << v); 435 } 436 437 if (heathrow_FCR) 438 out32rb(INT_ENABLE_REG1, state1); 439 440 out32rb(INT_ENABLE_REG0, state0); 441 } 442 443 int m_virq_inited = 0; 444 445 /* 446 * Map 64 irqs into 32 (bits). 447 */ 448 static int 449 mapirq(int irq) 450 { 451 int v; 452 int i; 453 454 if (m_virq_inited == 0) { 455 m_virq_max = 0; 456 for (i = 0; i < ICU_LEN; i++) { 457 m_virq[i] = 0; 458 } 459 m_virq_inited = 1; 460 } 461 462 /* irq in table already? */ 463 if (m_virq[irq] != 0) 464 return m_virq[irq]; 465 466 if (irq < 0 || irq >= 64) 467 panic("invalid irq %d", irq); 468 m_virq_max++; 469 v = m_virq_max; 470 if (v > HWIRQ_MAX) 471 panic("virq overflow"); 472 473 m_hwirq[v] = irq; 474 m_virq[irq] = v; 475 #if 0 476 printf("\nmapirq %x to %x\n", irq, v); 477 #endif 478 479 return v; 480 } 481 482 /* 483 * Count leading zeros. 484 */ 485 static __inline int 486 cntlzw(int x) 487 { 488 int a; 489 490 __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x)); 491 492 return a; 493 } 494 495 /* 496 * external interrupt handler 497 */ 498 void 499 mac_ext_intr() 500 { 501 int irq = 0; 502 int o_imen, r_imen; 503 int pcpl; 504 struct cpu_info *ci = curcpu(); 505 struct intrhand *ih; 506 volatile unsigned long int_state; 507 508 pcpl = ci->ci_cpl; /* Turn off all */ 509 510 int_state = read_irq(); 511 if (int_state == 0) 512 goto out; 513 514 start: 515 irq = 31 - cntlzw(int_state); 516 517 o_imen = imen_m; 518 r_imen = 1 << irq; 519 520 if ((ci->ci_cpl & r_imen) != 0) { 521 /* Masked! Mark this as pending. */ 522 ci->ci_ipending |= r_imen; 523 imen_m |= r_imen; 524 enable_irq(~imen_m); 525 } else { 526 splraise(m_intrmask[irq]); 527 528 ih = m_intrhand[irq]; 529 while (ih) { 530 if ((*ih->ih_fun)(ih->ih_arg)) 531 ih->ih_count.ec_count++; 532 ih = ih->ih_next; 533 } 534 535 uvmexp.intrs++; 536 } 537 int_state &= ~r_imen; 538 if (int_state) 539 goto start; 540 541 out: 542 splx(pcpl); /* Process pendings. */ 543 } 544 545 void 546 mac_intr_do_pending_int() 547 { 548 struct cpu_info *ci = curcpu(); 549 struct intrhand *ih; 550 int irq; 551 int pcpl; 552 int hwpend; 553 int s; 554 555 if (ci->ci_iactive) 556 return; 557 558 ci->ci_iactive = 1; 559 pcpl = splhigh(); /* Turn off all */ 560 s = ppc_intr_disable(); 561 562 hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */ 563 imen_m &= ~hwpend; 564 enable_irq(~imen_m); 565 hwpend &= HWIRQ_MASK; 566 while (hwpend) { 567 irq = 31 - cntlzw(hwpend); 568 hwpend &= ~(1L << irq); 569 ih = m_intrhand[irq]; 570 while(ih) { 571 if ((*ih->ih_fun)(ih->ih_arg)) 572 ih->ih_count.ec_count++; 573 ih = ih->ih_next; 574 } 575 } 576 577 /*out32rb(INT_ENABLE_REG, ~imen_m);*/ 578 579 do { 580 if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) { 581 ci->ci_ipending &= ~SINT_CLOCK; 582 softclock(); 583 } 584 if((ci->ci_ipending & SINT_NET) & ~pcpl) { 585 extern int netisr; 586 int pisr; 587 588 ci->ci_ipending &= ~SINT_NET; 589 while ((pisr = netisr) != 0) { 590 atomic_clearbits_int(&netisr, pisr); 591 softnet(pisr); 592 } 593 } 594 if((ci->ci_ipending & SINT_TTY) & ~pcpl) { 595 ci->ci_ipending &= ~SINT_TTY; 596 softtty(); 597 } 598 } while ((ci->ci_ipending & SINT_MASK) & ~pcpl); 599 ci->ci_ipending &= pcpl; 600 ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */ 601 ppc_intr_enable(s); 602 ci->ci_iactive = 0; 603 } 604 605 static int 606 read_irq() 607 { 608 int rv = 0; 609 int state0, state1, p; 610 int state0save, state1save; 611 612 state0 = in32rb(INT_STATE_REG0); 613 if (state0) 614 out32rb(INT_CLEAR_REG0, state0); 615 state0save = state0; 616 while (state0) { 617 p = 31 - cntlzw(state0); 618 rv |= 1 << m_virq[p]; 619 state0 &= ~(1 << p); 620 } 621 622 if (heathrow_FCR) /* has heathrow? */ 623 state1 = in32rb(INT_STATE_REG1); 624 else 625 state1 = 0; 626 627 if (state1) 628 out32rb(INT_CLEAR_REG1, state1); 629 state1save = state1; 630 while (state1) { 631 p = 31 - cntlzw(state1); 632 rv |= 1 << m_virq[p + 32]; 633 state1 &= ~(1 << p); 634 } 635 #if 0 636 printf("mac_intr int_stat 0:%x 1:%x\n", state0save, state1save); 637 #endif 638 639 /* 1 << 0 is invalid. */ 640 return rv & ~1; 641 } 642