Annotation of sys/arch/mvmeppc/dev/openpic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: openpic.c,v 1.22 2007/05/29 18:10:43 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_extern.h>
! 47:
! 48: #include <ddb/db_var.h>
! 49:
! 50: #include <machine/atomic.h>
! 51: #include <machine/autoconf.h>
! 52: #include <machine/intr.h>
! 53: #include <machine/psl.h>
! 54: #include <machine/pio.h>
! 55:
! 56: #include <mvmeppc/dev/openpicreg.h>
! 57: #include <mvmeppc/dev/ravenvar.h>
! 58: #include <mvmeppc/dev/ravenreg.h>
! 59:
! 60: #define ICU_LEN 32
! 61: #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
! 62: #define IO_ICU1 (isaspace_va + 0x20)
! 63: #define IO_ICU2 (isaspace_va + 0xa0)
! 64: #define IO_ELCR1 (isaspace_va + 0x4d0)
! 65: #define IO_ELCR2 (isaspace_va + 0x4d1)
! 66: #define IRQ_SLAVE 2
! 67: #define ICU_OFFSET 0
! 68: #define PIC_OFFSET 16
! 69:
! 70: #define PIC_SPURIOUS 0xff
! 71:
! 72: unsigned char icu1_val = 0xff;
! 73: unsigned char icu2_val = 0xff;
! 74: unsigned char elcr1_val = 0x00;
! 75: unsigned char elcr2_val = 0x00;
! 76:
! 77: int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
! 78: struct intrhand *intrhand[ICU_LEN];
! 79: int hwirq[ICU_LEN], virq[ICU_LEN];
! 80: unsigned int imen = 0xffffffff;
! 81: int virq_max;
! 82:
! 83: int fakeintr(void *);
! 84: const char *intr_typename(int type);
! 85: void intr_calculatemasks(void);
! 86: static __inline int cntlzw(int x);
! 87: int mapirq(int irq);
! 88: void openpic_enable_irq_mask(int irq_mask);
! 89:
! 90: #define HWIRQ_MAX 27
! 91: #define HWIRQ_MASK 0x0fffffff
! 92:
! 93: static __inline u_int openpic_read(int);
! 94: static __inline void openpic_write(int, u_int);
! 95: void openpic_enable_irq(int, int);
! 96: void openpic_disable_irq(int);
! 97: void openpic_init(void);
! 98: void openpic_set_priority(int, int);
! 99: static __inline int openpic_iack(int);
! 100: static __inline void openpic_eoi(int);
! 101: void openpic_initirq(int, int, int);
! 102:
! 103: void i8259_init(void);
! 104: int i8259_intr(void);
! 105: void i8259_enable_irq(int, int);
! 106: void i8259_disable_irq(int);
! 107: void i8259_eoi(int);
! 108: void *i8259_intr_establish(void *, int, int, int, int (*)(void *), void *,
! 109: char *);
! 110: void i8259_set_irq_mask(void);
! 111:
! 112: struct openpic_softc {
! 113: struct device sc_dev;
! 114: };
! 115:
! 116: int openpic_match(struct device *parent, void *cf, void *aux);
! 117: void openpic_attach(struct device *, struct device *, void *);
! 118: void openpic_do_pending_int(void);
! 119: void ext_intr_openpic(void);
! 120:
! 121: struct cfattach openpic_ca = {
! 122: sizeof(struct openpic_softc), openpic_match, openpic_attach
! 123: };
! 124:
! 125: struct cfdriver openpic_cd = {
! 126: NULL, "openpic", DV_DULL
! 127: };
! 128:
! 129: /*
! 130: * ISA IRQ for PCI IRQ to MPIC IRQ routing.
! 131: * From MVME2600APG tables 5.2 and 5.3
! 132: */
! 133: const struct pci_route {
! 134: int pci;
! 135: int openpic;
! 136: } pci_routes[] = {
! 137: { 10, 2 },
! 138: { 11, 5 },
! 139: { 14, 3 },
! 140: { 15, 4 },
! 141: { 0, 0 }
! 142: };
! 143:
! 144: int
! 145: openpic_match(parent, cf, aux)
! 146: struct device *parent;
! 147: void *cf;
! 148: void *aux;
! 149: {
! 150: /* We must be a child of the raven device */
! 151: if (strcmp(parent->dv_cfdata->cf_driver->cd_name, "raven") != 0)
! 152: return (0);
! 153: /* If there is a raven, then there is a mpic! */
! 154: return 1;
! 155: }
! 156:
! 157: u_int8_t *interrupt_reg;
! 158: typedef void (void_f) (void);
! 159: extern void_f *pending_int_f;
! 160: int abort_switch (void *arg);
! 161: int i8259_dummy(void *arg);
! 162:
! 163: typedef int mac_intr_handle_t;
! 164:
! 165: typedef void *(intr_establish_t)(void *, int, int, int, int (*)(void *),
! 166: void *, char *);
! 167: typedef void (intr_disestablish_t)(void *, void *);
! 168:
! 169: vaddr_t openpic_base;
! 170: extern vaddr_t isaspace_va;
! 171:
! 172: void * openpic_intr_establish(void *, int, int, int, int (*)(void *), void *,
! 173: char *);
! 174: void openpic_intr_disestablish(void *, void *);
! 175: void openpic_collect_preconf_intr(void);
! 176:
! 177: void
! 178: openpic_attach(parent, self, aux)
! 179: struct device *parent, *self;
! 180: void *aux;
! 181: {
! 182: extern intr_establish_t *intr_establish_func;
! 183: extern intr_disestablish_t *intr_disestablish_func;
! 184:
! 185: if ((openpic_base = (vaddr_t)mapiodev(MPCIC_BASE, MPCIC_SIZE)) == NULL) {
! 186: printf(": can't map MPCIC!\n");
! 187: return;
! 188: }
! 189:
! 190: /* the ICU area in isa space already mapped */
! 191:
! 192: printf(": version 0x%x", openpic_read(OPENPIC_FEATURE) & 0xFF);
! 193:
! 194: i8259_init();
! 195: openpic_init();
! 196:
! 197: pending_int_f = openpic_do_pending_int;
! 198: intr_establish_func = i8259_intr_establish;
! 199: intr_disestablish_func = openpic_intr_disestablish;
! 200:
! 201: openpic_collect_preconf_intr();
! 202:
! 203: /*
! 204: * i8259 interrupts are chained to openpic interrupt #0
! 205: */
! 206: openpic_intr_establish(parent, 0x00, IST_LEVEL, IPL_HIGH,
! 207: i8259_dummy, NULL, "8259 Interrupt");
! 208:
! 209: i8259_intr_establish(parent, 0x08, IST_EDGE, IPL_HIGH,
! 210: abort_switch, NULL, "abort button");
! 211:
! 212: printf("\n");
! 213: }
! 214:
! 215: void
! 216: openpic_collect_preconf_intr()
! 217: {
! 218: int i;
! 219:
! 220: for (i = 0; i < ppc_configed_intr_cnt; i++) {
! 221: #ifdef DEBUG
! 222: printf("\n\t%s irq %d level %d fun %x arg %x",
! 223: ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
! 224: ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
! 225: ppc_configed_intr[i].ih_arg);
! 226: #endif
! 227: openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
! 228: IST_LEVEL, ppc_configed_intr[i].ih_level,
! 229: ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
! 230: ppc_configed_intr[i].ih_what);
! 231: }
! 232: }
! 233:
! 234: int
! 235: abort_switch(void *arg)
! 236: {
! 237: #ifdef DDB
! 238: if (db_console)
! 239: Debugger();
! 240: #else
! 241: printf("Abort button pressed, debugger not available.\n");
! 242: #endif
! 243: return 1;
! 244: }
! 245:
! 246: int
! 247: i8259_dummy(void *arg)
! 248: {
! 249: /* All the 8259 handling happens in ext_intr_openpic(), actually. */
! 250: return 1;
! 251: }
! 252:
! 253: int
! 254: fakeintr(arg)
! 255: void *arg;
! 256: {
! 257: return 0;
! 258: }
! 259:
! 260: /*
! 261: * Register an ISA interrupt handler.
! 262: */
! 263: void *
! 264: i8259_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
! 265: void * lcv;
! 266: int irq;
! 267: int type;
! 268: int level;
! 269: int (*ih_fun)(void *);
! 270: void *ih_arg;
! 271: char *what;
! 272: {
! 273: struct intrhand **p, *q, *ih;
! 274: static struct intrhand fakehand;
! 275:
! 276: fakehand.ih_next = NULL;
! 277: fakehand.ih_fun = fakeintr;
! 278:
! 279: #if 0
! 280: printf("i8259_intr_establish, %d, %s", irq, (type == IST_EDGE) ? "EDGE":"LEVEL"));
! 281: #endif
! 282: irq = mapirq(irq + ICU_OFFSET);
! 283:
! 284: /* no point in sleeping unless someone can free memory. */
! 285: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
! 286: if (ih == NULL)
! 287: panic("i8259_intr_establish: can't malloc handler info");
! 288:
! 289: if (!LEGAL_IRQ(irq) || type == IST_NONE)
! 290: panic("i8259_intr_establish: bogus irq or type");
! 291:
! 292: switch (intrtype[irq]) {
! 293: case IST_EDGE:
! 294: case IST_LEVEL:
! 295: if (type == intrtype[irq])
! 296: break;
! 297: case IST_PULSE:
! 298: if (type != IST_NONE)
! 299: panic("intr_establish: can't share %s with %s",
! 300: intr_typename(intrtype[irq]),
! 301: intr_typename(type));
! 302: break;
! 303: }
! 304:
! 305: /*
! 306: * Figure out where to put the handler.
! 307: * This is O(N^2), but we want to preserve the order, and N is
! 308: * generally small.
! 309: */
! 310: for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
! 311: ;
! 312:
! 313: /*
! 314: * Actually install a fake handler momentarily, since we might be doing
! 315: * this with interrupts enabled and don't want the real routine called
! 316: * until masking is set up.
! 317: */
! 318: fakehand.ih_level = level;
! 319: *p = &fakehand;
! 320:
! 321: intr_calculatemasks();
! 322:
! 323: /*
! 324: * Poke the real handler in now.
! 325: */
! 326: ih->ih_fun = ih_fun;
! 327: ih->ih_arg = ih_arg;
! 328: ih->ih_next = NULL;
! 329: ih->ih_level = level;
! 330: ih->ih_irq = irq;
! 331: ih->ih_what = what;
! 332: evcount_attach(&ih->ih_count, what, (void *)&ih->ih_irq, &evcount_intr);
! 333: *p = ih;
! 334:
! 335: return (ih);
! 336: }
! 337:
! 338:
! 339: /*
! 340: * Register a PCI interrupt handler.
! 341: */
! 342: void *
! 343: openpic_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
! 344: void * lcv;
! 345: int irq;
! 346: int type;
! 347: int level;
! 348: int (*ih_fun)(void *);
! 349: void *ih_arg;
! 350: char *what;
! 351: {
! 352: struct intrhand **p, *q, *ih;
! 353: static struct intrhand fakehand;
! 354: const struct pci_route *pr;
! 355:
! 356: fakehand.ih_next = NULL;
! 357: fakehand.ih_fun = fakeintr;
! 358:
! 359: for (pr = pci_routes; pr->pci != 0; pr++)
! 360: if (pr->pci == irq) {
! 361: irq = pr->openpic;
! 362: break;
! 363: }
! 364:
! 365: irq = mapirq(irq + PIC_OFFSET);
! 366:
! 367: /* no point in sleeping unless someone can free memory. */
! 368: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
! 369: if (ih == NULL)
! 370: panic("intr_establish: can't malloc handler info");
! 371:
! 372: if (!LEGAL_IRQ(irq) || type == IST_NONE)
! 373: panic("intr_establish: bogus irq or type");
! 374:
! 375: switch (intrtype[irq]) {
! 376: case IST_EDGE:
! 377: case IST_LEVEL:
! 378: if (type == intrtype[irq])
! 379: break;
! 380: case IST_PULSE:
! 381: if (type != IST_NONE)
! 382: panic("intr_establish: can't share %s with %s",
! 383: intr_typename(intrtype[irq]),
! 384: intr_typename(type));
! 385: break;
! 386: }
! 387:
! 388: /*
! 389: * Figure out where to put the handler.
! 390: * This is O(N^2), but we want to preserve the order, and N is
! 391: * generally small.
! 392: */
! 393: for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
! 394: ;
! 395:
! 396: /*
! 397: * Actually install a fake handler momentarily, since we might be doing
! 398: * this with interrupts enabled and don't want the real routine called
! 399: * until masking is set up.
! 400: */
! 401: fakehand.ih_level = level;
! 402: *p = &fakehand;
! 403:
! 404: intr_calculatemasks();
! 405:
! 406: /*
! 407: * Poke the real handler in now.
! 408: */
! 409: ih->ih_fun = ih_fun;
! 410: ih->ih_arg = ih_arg;
! 411: ih->ih_next = NULL;
! 412: ih->ih_level = level;
! 413: ih->ih_irq = irq;
! 414: ih->ih_what = what;
! 415: evcount_attach(&ih->ih_count, what, (void *)&ih->ih_irq, &evcount_intr);
! 416: *p = ih;
! 417:
! 418: return (ih);
! 419: }
! 420:
! 421: /*
! 422: * Deregister an interrupt handler.
! 423: */
! 424: void
! 425: openpic_intr_disestablish(lcp, arg)
! 426: void *lcp;
! 427: void *arg;
! 428: {
! 429: struct intrhand *ih = arg;
! 430: int irq = ih->ih_irq;
! 431: struct intrhand **p, *q;
! 432:
! 433: if (!LEGAL_IRQ(irq))
! 434: panic("intr_disestablish: bogus irq");
! 435:
! 436: /*
! 437: * Remove the handler from the chain.
! 438: * This is O(n^2), too.
! 439: */
! 440: for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
! 441: ;
! 442: if (q)
! 443: *p = q->ih_next;
! 444: else
! 445: panic("intr_disestablish: handler not registered");
! 446:
! 447: evcount_detach(&ih->ih_count);
! 448: free((void *)ih, M_DEVBUF);
! 449:
! 450: intr_calculatemasks();
! 451:
! 452: if (intrhand[irq] == NULL)
! 453: intrtype[irq] = IST_NONE;
! 454: }
! 455:
! 456: const char *
! 457: intr_typename(type)
! 458: int type;
! 459: {
! 460:
! 461: switch (type) {
! 462: case IST_NONE :
! 463: return ("none");
! 464: case IST_PULSE:
! 465: return ("pulsed");
! 466: case IST_EDGE:
! 467: return ("edge-triggered");
! 468: case IST_LEVEL:
! 469: return ("level-triggered");
! 470: #ifdef DIAGNOSTIC
! 471: default:
! 472: panic("intr_typename: invalid type %d", type);
! 473: #endif
! 474: }
! 475: }
! 476:
! 477: /*
! 478: * Recalculate the interrupt masks from scratch.
! 479: * We could code special registry and deregistry versions of this function that
! 480: * would be faster, but the code would be nastier, and we don't expect this to
! 481: * happen very much anyway.
! 482: */
! 483: void
! 484: intr_calculatemasks()
! 485: {
! 486: int irq, hirq, level, levels;
! 487: struct intrhand *q;
! 488: int irqs;
! 489:
! 490: /* First, figure out which levels each IRQ uses. */
! 491: for (irq = 0; irq < ICU_LEN; irq++) {
! 492: levels = 0;
! 493: for (q = intrhand[irq]; q; q = q->ih_next)
! 494: levels |= 1 << q->ih_level;
! 495: intrlevel[irq] = levels;
! 496: }
! 497:
! 498: /* Then figure out which IRQs use each level. */
! 499: for (level = IPL_NONE; level < IPL_NUM; level++) {
! 500: irqs = 0;
! 501: for (irq = 0; irq < ICU_LEN; irq++)
! 502: if (intrlevel[irq] & (1 << level))
! 503: irqs |= 1 << irq;
! 504: imask[level] = irqs | SINT_MASK;
! 505: }
! 506:
! 507: /*
! 508: * There are tty, network and disk drivers that use free() at interrupt
! 509: * time, so vm > (tty | net | bio).
! 510: *
! 511: * Enforce a hierarchy that gives slow devices a better chance at not
! 512: * dropping data.
! 513: */
! 514: imask[IPL_NET] |= imask[IPL_BIO];
! 515: imask[IPL_TTY] |= imask[IPL_NET];
! 516: imask[IPL_VM] |= imask[IPL_TTY];
! 517: imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK;
! 518:
! 519: /*
! 520: * These are pseudo-levels.
! 521: */
! 522: imask[IPL_NONE] = 0x00000000;
! 523: imask[IPL_HIGH] = 0xffffffff;
! 524:
! 525: /* And eventually calculate the complete masks. */
! 526: for (irq = 0; irq < ICU_LEN; irq++) {
! 527: irqs = 1 << irq;
! 528: for (q = intrhand[irq]; q; q = q->ih_next)
! 529: irqs |= imask[q->ih_level];
! 530: intrmask[irq] = irqs | SINT_MASK;
! 531: }
! 532:
! 533: /* Lastly, determine which IRQs are actually in use. */
! 534: irqs = 0;
! 535: for (irq = 0; irq < ICU_LEN; irq++) {
! 536: hirq = hwirq[irq];
! 537: if (hirq < 0)
! 538: continue;
! 539:
! 540: if (intrhand[irq]) {
! 541: irqs |= 1 << irq;
! 542:
! 543: if (hirq >= PIC_OFFSET)
! 544: openpic_enable_irq(hirq, intrtype[irq]);
! 545: else
! 546: i8259_enable_irq(hirq, intrtype[irq]);
! 547: } else {
! 548: if (hirq >= PIC_OFFSET)
! 549: openpic_disable_irq(hirq);
! 550: else
! 551: i8259_disable_irq(hirq);
! 552: }
! 553: }
! 554:
! 555: /* always enable the chained 8259 interrupt */
! 556: i8259_enable_irq(IRQ_SLAVE, IST_EDGE);
! 557:
! 558: imen = ~irqs;
! 559: i8259_set_irq_mask();
! 560: }
! 561:
! 562: /*
! 563: * Map 64 irqs into 32 (bits).
! 564: */
! 565: int
! 566: mapirq(irq)
! 567: int irq;
! 568: {
! 569: int v;
! 570:
! 571: #ifdef DIAGNOSTIC
! 572: if (irq < 0 || irq >= ICU_LEN)
! 573: panic("invalid irq");
! 574: #endif
! 575:
! 576: virq_max++;
! 577: v = virq_max;
! 578: if (v > HWIRQ_MAX)
! 579: panic("virq overflow");
! 580:
! 581: hwirq[v] = irq;
! 582: virq[irq] = v;
! 583: #ifdef DEBUG
! 584: printf("mapirq %x to %x\n", irq, v);
! 585: #endif
! 586:
! 587: return v;
! 588: }
! 589:
! 590: /*
! 591: * Count leading zeros.
! 592: */
! 593: static __inline int
! 594: cntlzw(x)
! 595: int x;
! 596: {
! 597: int a;
! 598:
! 599: __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
! 600: return a;
! 601: }
! 602:
! 603: void
! 604: openpic_do_pending_int()
! 605: {
! 606: struct intrhand *ih;
! 607: int irq;
! 608: int pcpl;
! 609: int hwpend;
! 610: int s;
! 611: static int processing;
! 612:
! 613: if (processing)
! 614: return;
! 615:
! 616: processing = 1;
! 617: pcpl = splhigh(); /* Turn off all */
! 618: s = ppc_intr_disable();
! 619:
! 620: hwpend = ipending & ~pcpl; /* Do now unmasked pendings */
! 621: imen &= ~hwpend;
! 622: openpic_enable_irq_mask(~imen);
! 623:
! 624: hwpend &= HWIRQ_MASK;
! 625: while (hwpend) {
! 626: irq = 31 - cntlzw(hwpend);
! 627: hwpend &= ~(1L << irq);
! 628: ih = intrhand[irq];
! 629: while (ih) {
! 630: if ((*ih->ih_fun)(ih->ih_arg))
! 631: ih->ih_count.ec_count++;
! 632: ih = ih->ih_next;
! 633: }
! 634: }
! 635:
! 636: do {
! 637: if ((ipending & SINT_CLOCK) & ~pcpl) {
! 638: ipending &= ~SINT_CLOCK;
! 639: softclock();
! 640: }
! 641: if ((ipending & SINT_NET) & ~pcpl) {
! 642: extern int netisr;
! 643: int pisr;
! 644:
! 645: ipending &= ~SINT_NET;
! 646: while ((pisr = netisr) != 0) {
! 647: atomic_clearbits_int(&netisr, pisr);
! 648: softnet(pisr);
! 649: }
! 650: }
! 651: #if 0
! 652: if ((ipending & SINT_TTY) & ~pcpl) {
! 653: ipending &= ~SINT_TTY;
! 654: softtty();
! 655: }
! 656: #endif
! 657: } while (ipending & (SINT_NET|SINT_CLOCK/*|SINT_TTY*/) & ~cpl);
! 658: ipending &= pcpl;
! 659: cpl = pcpl; /* Don't use splx... we are here already! */
! 660:
! 661: #if 0
! 662: i8259_set_irq_mask();
! 663: #endif
! 664:
! 665: ppc_intr_enable(s);
! 666: processing = 0;
! 667: }
! 668:
! 669: u_int
! 670: openpic_read(reg)
! 671: int reg;
! 672: {
! 673: char *addr = (void *)(openpic_base + reg);
! 674:
! 675: return in32rb(addr);
! 676: }
! 677:
! 678: void
! 679: openpic_write(reg, val)
! 680: int reg;
! 681: u_int val;
! 682: {
! 683: char *addr = (void *)(openpic_base + reg);
! 684:
! 685: out32rb(addr, val);
! 686: }
! 687:
! 688: void
! 689: openpic_enable_irq_mask(irq_mask)
! 690: int irq_mask;
! 691: {
! 692: int irq, hirq;
! 693:
! 694: for (irq = 0; irq <= virq_max; irq++) {
! 695: hirq = hwirq[irq];
! 696: if (hirq < 0)
! 697: continue;
! 698:
! 699: if (irq_mask & (1 << irq)) {
! 700: if (hirq >= PIC_OFFSET)
! 701: openpic_enable_irq(hirq, intrtype[irq]);
! 702: else
! 703: i8259_enable_irq(hirq, intrtype[irq]);
! 704: } else {
! 705: if (hirq >= PIC_OFFSET)
! 706: openpic_disable_irq(hirq);
! 707: else
! 708: i8259_disable_irq(hirq);
! 709: }
! 710: }
! 711:
! 712: i8259_set_irq_mask();
! 713: }
! 714:
! 715: void
! 716: openpic_enable_irq(irq, type)
! 717: int irq;
! 718: int type;
! 719: {
! 720: u_int x, isrc;
! 721:
! 722: #ifdef DIAGNOSTIC
! 723: /* skip invalid irqs */
! 724: if (irq < PIC_OFFSET)
! 725: panic("openpic_enable_irq: invalid irq %x", irq);
! 726: #endif
! 727: irq -= PIC_OFFSET;
! 728:
! 729: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
! 730:
! 731: isrc = x & ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL |
! 732: OPENPIC_POLARITY_POSITIVE | OPENPIC_ACTIVITY);
! 733: if (irq == 0)
! 734: isrc |= OPENPIC_POLARITY_POSITIVE;
! 735: if (type == IST_LEVEL)
! 736: isrc |= OPENPIC_SENSE_LEVEL;
! 737: else
! 738: isrc |= OPENPIC_SENSE_EDGE;
! 739:
! 740: /* Ack all pending interrupts if this one is pending. */
! 741: while (x & OPENPIC_ACTIVITY) {
! 742: (void)openpic_iack(0);
! 743: openpic_eoi(0);
! 744: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
! 745: }
! 746:
! 747: if (x != isrc)
! 748: openpic_write(OPENPIC_SRC_VECTOR(irq), isrc);
! 749: }
! 750:
! 751: void
! 752: openpic_disable_irq(irq)
! 753: int irq;
! 754: {
! 755: u_int x;
! 756:
! 757: /* skip invalid irqs */
! 758: if (irq >= PIC_OFFSET)
! 759: irq -= PIC_OFFSET;
! 760:
! 761: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
! 762: x |= OPENPIC_IMASK;
! 763: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
! 764: }
! 765:
! 766: void
! 767: i8259_set_irq_mask(void)
! 768: {
! 769: if (icu2_val != 0xff) {
! 770: /* Turn on the second IC */
! 771: icu1_val &= ~(1 << IRQ_SLAVE);
! 772: } else {
! 773: icu1_val |= (1 << IRQ_SLAVE);
! 774: }
! 775:
! 776: outb(IO_ICU1 + 1, icu1_val);
! 777: outb(IO_ICU2 + 1, icu2_val);
! 778: outb(IO_ELCR1, elcr1_val);
! 779: outb(IO_ELCR2, elcr2_val);
! 780: }
! 781:
! 782: void
! 783: i8259_disable_irq(irq)
! 784: int irq;
! 785: {
! 786: #ifdef DIAGNOSTIC
! 787: /* skip invalid irqs */
! 788: if (irq < 0 || irq >= PIC_OFFSET)
! 789: panic("i8259_disable_irq: invalid irq %x", irq);
! 790: #endif
! 791:
! 792: if (irq < 8) {
! 793: icu1_val |= 1 << irq;
! 794: elcr1_val &= ~(1 << irq);
! 795: } else {
! 796: irq -= 8;
! 797: icu2_val |= 1 << irq;
! 798: elcr2_val &= ~(1 << irq);
! 799: }
! 800: }
! 801:
! 802: void
! 803: i8259_enable_irq(irq, type)
! 804: int irq, type;
! 805: {
! 806: #ifdef DIAGNOSTIC
! 807: /* skip invalid irqs */
! 808: if (irq < 0 || irq >= PIC_OFFSET)
! 809: panic("i8259_enable_irq: invalid irq %x", irq);
! 810: #endif
! 811:
! 812: if (irq < 8) {
! 813: icu1_val &= ~(1 << irq);
! 814: if (type == IST_LEVEL)
! 815: elcr1_val |= (1 << irq);
! 816: else
! 817: elcr1_val &= ~(1 << irq);
! 818: } else {
! 819: irq -= 8;
! 820: icu2_val &= ~(1 << irq);
! 821: if (type == IST_LEVEL)
! 822: elcr2_val |= (1 << irq);
! 823: else
! 824: elcr2_val &= ~(1 << irq);
! 825: }
! 826: }
! 827:
! 828: void
! 829: i8259_eoi(int irq)
! 830: {
! 831: #ifdef DIAGNOSTIC
! 832: /* skip invalid irqs */
! 833: if (irq < 0 || irq >= PIC_OFFSET)
! 834: panic("i8259_eoi: invalid irq %x", irq);
! 835: #endif
! 836:
! 837: if (irq < 8)
! 838: outb(IO_ICU1, 0x60 | irq);
! 839: else {
! 840: outb(IO_ICU2, 0x60 | (irq - 8));
! 841: /*
! 842: * Do not ack on the master unless there are no
! 843: * other interrupts pending on the slave
! 844: * controller!
! 845: */
! 846: outb(IO_ICU2, 0x0b);
! 847: if (inb(IO_ICU2) == 0)
! 848: outb(IO_ICU1, 0x60 | IRQ_SLAVE);
! 849: }
! 850: }
! 851:
! 852: void
! 853: openpic_set_priority(cpu, pri)
! 854: int cpu, pri;
! 855: {
! 856: u_int x;
! 857:
! 858: x = openpic_read(OPENPIC_CPU_PRIORITY(cpu));
! 859: x &= ~OPENPIC_CPU_PRIORITY_MASK;
! 860: x |= pri;
! 861: openpic_write(OPENPIC_CPU_PRIORITY(cpu), x);
! 862: }
! 863:
! 864: int
! 865: openpic_iack(cpu)
! 866: int cpu;
! 867: {
! 868: return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
! 869: }
! 870:
! 871: void
! 872: openpic_eoi(cpu)
! 873: int cpu;
! 874: {
! 875: openpic_write(OPENPIC_EOI(cpu), 0);
! 876: openpic_read(OPENPIC_EOI(cpu));
! 877: }
! 878:
! 879: void
! 880: i8259_init(void)
! 881: {
! 882: /* initialize 8259's */
! 883: outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
! 884: outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */
! 885: outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
! 886: outb(IO_ICU1+1, 1); /* 8086 mode */
! 887: outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
! 888: /* init interrupt controller 2 */
! 889: outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
! 890: outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */
! 891: outb(IO_ICU2+1, IRQ_SLAVE);
! 892: outb(IO_ICU2+1, 1); /* 8086 mode */
! 893: outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
! 894: }
! 895:
! 896: int
! 897: i8259_intr(void)
! 898: {
! 899: int irq;
! 900:
! 901: /*
! 902: * Perform an interrupt acknowledge cycle on controller 1
! 903: */
! 904: outb(IO_ICU1, 0x0c);
! 905: irq = inb(IO_ICU1) & 7;
! 906:
! 907: if (irq == IRQ_SLAVE) {
! 908: /*
! 909: * Interrupt is cascaded so perform interrupt
! 910: * acknowledge on controller 2
! 911: */
! 912: outb(IO_ICU2, 0x0c);
! 913: irq = (inb(IO_ICU2) & 7) + 8;
! 914: if (irq == 15) {
! 915: outb(IO_ICU2, 0x0b);
! 916: if ((inb(IO_ICU2) & 0x80) == 0) {
! 917: #ifdef DIAGNOSTIC
! 918: printf("spurious interrupt on ICU2\n");
! 919: #endif
! 920: return PIC_SPURIOUS;
! 921: }
! 922: }
! 923: } else if (irq == 7) {
! 924: /*
! 925: * This may be a spurious interrupt
! 926: *
! 927: * Read the interrupt status register. If the most
! 928: * significant bit is not set then there is no valid
! 929: * interrupt
! 930: */
! 931: outb(IO_ICU1, 0x0b);
! 932: if ((inb(IO_ICU1) & 0x80) == 0) {
! 933: #ifdef DIAGNOSTIC
! 934: printf("spurious interrupt on ICU1\n");
! 935: #endif
! 936: return PIC_SPURIOUS;
! 937: }
! 938: }
! 939:
! 940: return (ICU_OFFSET + irq);
! 941: }
! 942:
! 943: void
! 944: ext_intr_openpic()
! 945: {
! 946: int irq, realirq;
! 947: int r_imen;
! 948: int pcpl, ocpl;
! 949: struct intrhand *ih;
! 950:
! 951: pcpl = cpl;
! 952:
! 953: realirq = openpic_iack(0);
! 954:
! 955: while (realirq != PIC_SPURIOUS) {
! 956: if (realirq == 0x00) {
! 957: /*
! 958: * Interrupt from the PCI/ISA bridge. PCI interrupts
! 959: * are shadowed on the ISA PIC for compatibility with
! 960: * MVME1600, so simply handle the ISA PIC.
! 961: */
! 962: realirq = i8259_intr();
! 963: openpic_eoi(0);
! 964: if (realirq == PIC_SPURIOUS)
! 965: break;
! 966: } else {
! 967: realirq += PIC_OFFSET;
! 968: }
! 969:
! 970: irq = virq[realirq];
! 971:
! 972: /* XXX check range */
! 973:
! 974: r_imen = 1 << irq;
! 975:
! 976: if ((pcpl & r_imen) != 0) {
! 977: ipending |= r_imen; /* Masked! Mark this as pending */
! 978: if (realirq >= PIC_OFFSET) {
! 979: openpic_disable_irq(realirq);
! 980: openpic_eoi(0);
! 981: } else {
! 982: i8259_disable_irq(realirq);
! 983: i8259_set_irq_mask();
! 984: i8259_eoi(realirq);
! 985: }
! 986: } else {
! 987: if (realirq >= PIC_OFFSET) {
! 988: openpic_disable_irq(realirq);
! 989: } else {
! 990: i8259_disable_irq(realirq);
! 991: i8259_set_irq_mask();
! 992: }
! 993:
! 994: ocpl = splraise(intrmask[irq]);
! 995:
! 996: ih = intrhand[irq];
! 997: while (ih) {
! 998: if ((*ih->ih_fun)(ih->ih_arg))
! 999: ih->ih_count.ec_count++;
! 1000: ih = ih->ih_next;
! 1001: }
! 1002:
! 1003: uvmexp.intrs++;
! 1004: __asm__ volatile("":::"memory");
! 1005: cpl = ocpl;
! 1006: __asm__ volatile("":::"memory");
! 1007:
! 1008: if (realirq >= PIC_OFFSET) {
! 1009: openpic_eoi(0);
! 1010: openpic_enable_irq(realirq, intrtype[irq]);
! 1011: } else {
! 1012: i8259_eoi(realirq);
! 1013: i8259_enable_irq(realirq, intrtype[irq]);
! 1014: i8259_set_irq_mask();
! 1015: }
! 1016: }
! 1017:
! 1018: realirq = openpic_iack(0);
! 1019: }
! 1020: ppc_intr_enable(1);
! 1021:
! 1022: splx(pcpl); /* Process pendings. */
! 1023: }
! 1024:
! 1025: void
! 1026: openpic_initirq(int irq, int pol, int sense)
! 1027: {
! 1028: u_int x;
! 1029:
! 1030: x = (irq & OPENPIC_VECTOR_MASK);
! 1031: x |= OPENPIC_IMASK;
! 1032: x |= (pol ? OPENPIC_POLARITY_POSITIVE : OPENPIC_POLARITY_NEGATIVE);
! 1033: x |= (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE);
! 1034: x |= 8 << OPENPIC_PRIORITY_SHIFT;
! 1035: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
! 1036: }
! 1037:
! 1038: void
! 1039: openpic_init()
! 1040: {
! 1041: int irq;
! 1042: u_int x;
! 1043:
! 1044: /* disable all interrupts and init hwirq[] */
! 1045: for (irq = 0; irq < ICU_LEN; irq++) {
! 1046: hwirq[irq] = -1;
! 1047: intrtype[irq] = IST_NONE;
! 1048: intrmask[irq] = 0;
! 1049: intrlevel[irq] = 0;
! 1050: intrhand[irq] = NULL;
! 1051: openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
! 1052: }
! 1053: openpic_set_priority(0, 15);
! 1054:
! 1055: /* we don't need 8259 pass through mode */
! 1056: x = openpic_read(OPENPIC_CONFIG);
! 1057: x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
! 1058: openpic_write(OPENPIC_CONFIG, x);
! 1059:
! 1060: /* send all interrupts to cpu 0 */
! 1061: for (irq = 0; irq < ICU_LEN; irq++)
! 1062: openpic_write(OPENPIC_SRC_DEST(irq), CPU(0));
! 1063:
! 1064: /* special case for intr src 0 */
! 1065: openpic_initirq(0, 1, 0);
! 1066: for (irq = 1; irq < ICU_LEN; irq++) {
! 1067: openpic_initirq(irq, 0, 1);
! 1068: }
! 1069:
! 1070: /* XXX set spurious intr vector */
! 1071: #if 0
! 1072: openpic_write(OPENPIC_SPURIOUS_VECTOR, 0xFF);
! 1073: #endif
! 1074:
! 1075: /* unmask interrupts for cpu 0 */
! 1076: openpic_set_priority(0, 0);
! 1077:
! 1078: /* clear all pending interrunts */ /* < ICU_LEN ? */
! 1079: for (irq = 0; irq < PIC_OFFSET; irq++) {
! 1080: openpic_iack(0);
! 1081: openpic_eoi(0);
! 1082: }
! 1083:
! 1084: for (irq = 0; irq < PIC_OFFSET; irq++) { /* < ICU_LEN ? */
! 1085: i8259_disable_irq(irq);
! 1086: openpic_disable_irq(irq);
! 1087: }
! 1088:
! 1089: i8259_set_irq_mask();
! 1090:
! 1091: install_extint(ext_intr_openpic);
! 1092: }
CVSweb