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