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