Annotation of sys/arch/macppc/dev/macintr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: macintr.c,v 1.33 2007/05/29 18:10:42 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. 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: }
CVSweb