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