|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992,1993 NeXT Computer, Inc. ! 27: * ! 28: * Interrupt handling routines. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 5 July 1993 ? at NeXT ! 33: * Removed software interrupt support. ! 34: * Changed lower_ipl() to never raise masked_ipl. ! 35: * 20 May 1993 Curtis Galloway at NeXT ! 36: * Added checking for phantom interrupts. ! 37: * 26 August 1992 ? at NeXT ! 38: * Major rev for driverkit support. ! 39: * 22 August 1992 ? at NeXT ! 40: * Added software interrupts. Made all data structures static. ! 41: * 20 Aug 1992 Joe Pasqua ! 42: * Added intr_enable_irq/disable_irq routines based on the enableMask. ! 43: * 24 June 1992 ? at NeXT ! 44: * Rewritten to implement 'soft spls'. ! 45: * 1 June 1992 ? at NeXT ! 46: * Created. ! 47: */ ! 48: ! 49: #import <mach/mach_types.h> ! 50: ! 51: #import <machdep/i386/intr_exported.h> ! 52: #import <machdep/i386/intr_internal.h> ! 53: #import <machdep/i386/intr_inline.h> ! 54: #import <machdep/i386/cpu_inline.h> ! 55: ! 56: static intr_dispatch_t dispatch_table[INTR_NIRQ]; ! 57: static intr_irq_mask_t ipl_mask[INTR_NIPL]; ! 58: static intr_dispatch_t *defer_table[INTR_NIPL]; ! 59: ! 60: static int current_ipl, masked_ipl; ! 61: static intr_irq_mask_t current_irq_mask, disabled_irq_mask; ! 62: static intr_irq_mask_t current_elcr; ! 63: ! 64: /* ! 65: * Send an EOI (end of interrupt) to both PICs. ! 66: */ ! 67: static inline ! 68: void ! 69: send_eoi( ! 70: void ! 71: ) ! 72: { ! 73: send_eoi_command((intr_ocw2_t) { ! 74: 0, /* no level */ ! 75: 0, /* must be */ ! 76: TRUE, /* EOI */ ! 77: FALSE, /* non-specific */ ! 78: FALSE /* no rotation */ ! 79: }); ! 80: } ! 81: ! 82: static inline ! 83: void ! 84: set_elcr( ! 85: intr_irq_mask_t mask ! 86: ) ! 87: { ! 88: union { ! 89: intr_irq_mask_t full; ! 90: struct { ! 91: unsigned short ! 92: half :8, ! 93: :8; ! 94: } master; ! 95: struct { ! 96: unsigned short ! 97: :8, ! 98: half :8; ! 99: } slave; ! 100: } new_mask; ! 101: ! 102: new_mask.full.mask = mask.mask; ! 103: ! 104: if (new_mask.full.mask != current_elcr.mask) { ! 105: current_elcr = new_mask.full; ! 106: ! 107: set_master_elcr((intr_elcr_t) { ! 108: new_mask.master.half }); ! 109: ! 110: set_slave_elcr((intr_elcr_t) { ! 111: new_mask.slave.half }); ! 112: } ! 113: } ! 114: ! 115: /* ! 116: * Set the interrupt masks of both PICs ! 117: * according to the irq mask. ! 118: */ ! 119: static inline ! 120: void ! 121: set_irq_mask( ! 122: intr_irq_mask_t mask ! 123: ) ! 124: { ! 125: union { ! 126: intr_irq_mask_t full; ! 127: struct { ! 128: unsigned short ! 129: half :8, ! 130: :8; ! 131: } master; ! 132: struct { ! 133: unsigned short ! 134: :8, ! 135: half :8; ! 136: } slave; ! 137: } new_mask; ! 138: ! 139: new_mask.full.mask = mask.mask | disabled_irq_mask.mask; ! 140: ! 141: if (new_mask.full.mask != current_irq_mask.mask) { ! 142: current_irq_mask = new_mask.full; ! 143: ! 144: set_master_mask((intr_ocw1_t) { ! 145: new_mask.master.half }); ! 146: ! 147: set_slave_mask((intr_ocw1_t) { ! 148: new_mask.slave.half }); ! 149: } ! 150: } ! 151: ! 152: /* ! 153: * Set the irq mask according to ! 154: * the ipl. ! 155: */ ! 156: static inline ! 157: int ! 158: set_masked_ipl( ! 159: int ipl ! 160: ) ! 161: { ! 162: int old_ipl = masked_ipl; ! 163: ! 164: if (ipl != masked_ipl) { ! 165: set_irq_mask(ipl_mask[ipl]); ! 166: masked_ipl = ipl; ! 167: } ! 168: ! 169: return (old_ipl); ! 170: } ! 171: ! 172: /* ! 173: * Set the 'soft' ipl. ! 174: */ ! 175: static inline ! 176: int ! 177: set_ipl( ! 178: int ipl ! 179: ) ! 180: { ! 181: int old_ipl = current_ipl; ! 182: ! 183: current_ipl = ipl; ! 184: ! 185: return (old_ipl); ! 186: } ! 187: ! 188: /* ! 189: * Clear the interrupt flag, and ! 190: * return the original state of ! 191: * the flag. ! 192: */ ! 193: boolean_t ! 194: intr_disbl( ! 195: void ! 196: ) ! 197: { ! 198: unsigned int efl; ! 199: ! 200: efl = eflags(); ! 201: ! 202: cli(); ! 203: ! 204: return ((efl & EFL_IF) != 0); ! 205: } ! 206: ! 207: /* ! 208: * Set or clear the interrupt ! 209: * flag, and return the original ! 210: * state of the flag. ! 211: */ ! 212: boolean_t ! 213: intr_enbl( ! 214: boolean_t enable ! 215: ) ! 216: { ! 217: unsigned int efl; ! 218: ! 219: efl = eflags(); ! 220: ! 221: if (enable) sti(); else cli(); ! 222: ! 223: return ((efl & EFL_IF) != 0); ! 224: } ! 225: ! 226: static inline ! 227: void ! 228: lower_masked_ipl( ! 229: int ipl ! 230: ) ! 231: { ! 232: if (ipl < masked_ipl) ! 233: (void) set_masked_ipl(ipl); ! 234: } ! 235: ! 236: static ! 237: void ! 238: lower_ipl( ! 239: int ipl, ! 240: int old_ipl ! 241: ) ! 242: { ! 243: intr_dispatch_t **d, *i; ! 244: ! 245: for (d = &defer_table[old_ipl]; d > &defer_table[ipl]; d--) ! 246: if (i = *d) { ! 247: *d = 0; ! 248: ! 249: (void) set_ipl(i->ipl); ! 250: ! 251: sti(); ! 252: (*i->routine)(i->which, 0, ipl); ! 253: cli(); ! 254: } ! 255: ! 256: (void) set_ipl(ipl); ! 257: ! 258: lower_masked_ipl(ipl); ! 259: } ! 260: ! 261: /* ! 262: * External 'well known' routines. ! 263: */ ! 264: ! 265: inline ! 266: int ! 267: splx( ! 268: int ipl ! 269: ) ! 270: { ! 271: int old_ipl; ! 272: ! 273: cli(); ! 274: ! 275: old_ipl = set_ipl(ipl); ! 276: if (ipl < old_ipl) ! 277: lower_ipl(ipl, old_ipl); ! 278: ! 279: sti(); ! 280: ! 281: return (old_ipl); ! 282: } ! 283: ! 284: #define DEFINE_SPL(name, ipl) \ ! 285: int spl##name( \ ! 286: void \ ! 287: ) \ ! 288: { \ ! 289: return (splx(ipl)); \ ! 290: } ! 291: ! 292: #define DEFINE_SPLNOP(name) \ ! 293: int spl##name( \ ! 294: void \ ! 295: ) \ ! 296: { \ ! 297: return (current_ipl); \ ! 298: } ! 299: ! 300: DEFINE_SPL(0, INTR_IPL0) ! 301: ! 302: DEFINE_SPL(1, INTR_IPL1) ! 303: DEFINE_SPLNOP(tty) ! 304: ! 305: DEFINE_SPL(2, INTR_IPL2) ! 306: ! 307: DEFINE_SPL(3, INTR_IPL3) ! 308: DEFINE_SPLNOP(net) ! 309: DEFINE_SPLNOP(vm) ! 310: DEFINE_SPLNOP(imp) ! 311: DEFINE_SPLNOP(bio) ! 312: DEFINE_SPL(device, INTR_IPL3) ! 313: ! 314: DEFINE_SPL(4, INTR_IPL4) ! 315: ! 316: DEFINE_SPL(5, INTR_IPL5) ! 317: ! 318: DEFINE_SPL(6, INTR_IPL6) ! 319: DEFINE_SPL(dma, INTR_IPL6) ! 320: DEFINE_SPL(usclock, INTR_IPL6) ! 321: DEFINE_SPL(sched, INTR_IPL6) ! 322: DEFINE_SPL(clock, INTR_IPL6) ! 323: ! 324: DEFINE_SPL(7, INTR_IPL7) ! 325: DEFINE_SPL(high, INTR_IPL7) ! 326: ! 327: int ! 328: spln( ! 329: int ipl ! 330: ) ! 331: { ! 332: return (splx(ipl)); ! 333: } ! 334: ! 335: int ! 336: ipltospl( ! 337: int ipl ! 338: ) ! 339: { ! 340: return (ipl); ! 341: } ! 342: ! 343: /* ! 344: * Return the current ipl. ! 345: */ ! 346: int ! 347: curipl( ! 348: void ! 349: ) ! 350: { ! 351: return (current_ipl); ! 352: } ! 353: ! 354: /* ! 355: * Initialization templates. ! 356: */ ! 357: ! 358: #define MASTER_ICW1 ((intr_icw1_t) { \ ! 359: TRUE, /* IC4 needed */ \ ! 360: FALSE, /* cascaded */ \ ! 361: 0, /* not used */ \ ! 362: INTR_ICW1_EDGE_TRIG, \ ! 363: 1 /* must be */ \ ! 364: }) ! 365: #define MASTER_ICW2 ((intr_icw2_t) { \ ! 366: INTR_VECT_OFF /* index in IDT */ \ ! 367: }) ! 368: #define MASTER_ICW3 ((intr_icw3m_t) { \ ! 369: INTR_MASK_SLAVE /* slave inputs */ \ ! 370: }) ! 371: #define MASTER_ICW4 ((intr_icw4_t) { \ ! 372: INTR_ICW4_8086_MODE, \ ! 373: FALSE, /* no auto EOI */ \ ! 374: INTR_ICW4_NONBUF, \ ! 375: FALSE /* no SFN mode */ \ ! 376: }) ! 377: ! 378: #define SLAVE_ICW1 ((intr_icw1_t) { \ ! 379: TRUE, /* IC4 needed */ \ ! 380: FALSE, /* cascaded */ \ ! 381: 0, /* not used */ \ ! 382: INTR_ICW1_EDGE_TRIG, \ ! 383: 1 /* must be */ \ ! 384: }) ! 385: #define SLAVE_ICW2 ((intr_icw2_t) { \ ! 386: INTR_VECT_OFF + 8 /* index in IDT */ \ ! 387: }) ! 388: #define SLAVE_ICW3 ((intr_icw3s_t) { \ ! 389: INTR_SLAVE_IRQ /* slave id */ \ ! 390: }) ! 391: #define SLAVE_ICW4 ((intr_icw4_t) { \ ! 392: INTR_ICW4_8086_MODE, \ ! 393: FALSE, /* no auto EOI */ \ ! 394: INTR_ICW4_NONBUF, \ ! 395: FALSE /* no SFN mode */ \ ! 396: }) ! 397: ! 398: /* ! 399: * Called early during system ! 400: * initialization. Sets up the ! 401: * PICs, sets the ipl to IPLHI, ! 402: * and masks all irqs. ! 403: */ ! 404: void ! 405: intr_initialize( ! 406: void ! 407: ) ! 408: { ! 409: intr_irq_mask_t *m; ! 410: int i, mask; ! 411: ! 412: cli(); ! 413: ! 414: initialize_master( MASTER_ICW1, ! 415: MASTER_ICW2, ! 416: MASTER_ICW3, ! 417: MASTER_ICW4); ! 418: ! 419: initialize_slave( SLAVE_ICW1, ! 420: SLAVE_ICW2, ! 421: SLAVE_ICW3, ! 422: SLAVE_ICW4); ! 423: ! 424: mask = INTR_MASK_ALL; ! 425: for (i = 0, m = ipl_mask; i++ < INTR_NIPL; m++) ! 426: m->mask = mask; ! 427: ! 428: disabled_irq_mask.mask = INTR_MASK_NONE; ! 429: ! 430: set_masked_ipl(INTR_IPLHI); ! 431: ! 432: set_ipl(INTR_IPLHI); ! 433: ! 434: sti(); ! 435: } ! 436: ! 437: /* ! 438: * Register an ISR for an irq at ! 439: * the ipl. Returns TRUE on success, ! 440: * FALSE on failure. Failure includes ! 441: * trying to overwrite an existing ISR. ! 442: */ ! 443: boolean_t ! 444: intr_register_irq( ! 445: int irq, ! 446: intr_handler_t routine, ! 447: unsigned int which, ! 448: int ipl ! 449: ) ! 450: { ! 451: intr_irq_mask_t *m; ! 452: int i, mask; ! 453: boolean_t e; ! 454: ! 455: if (irq < 0 || irq >= INTR_NIRQ || irq == INTR_SLAVE_IRQ) ! 456: return (FALSE); ! 457: ! 458: if (ipl < 0 || ipl >= INTR_NIPL) ! 459: return (FALSE); ! 460: ! 461: if (dispatch_table[irq].routine) ! 462: return (FALSE); ! 463: ! 464: e = intr_disbl(); ! 465: ! 466: dispatch_table[irq].which = which; ! 467: dispatch_table[irq].routine = routine; ! 468: dispatch_table[irq].ipl = ipl; ! 469: ! 470: mask = INTR_MASK_IRQ(irq); ! 471: for (i = 0, m = ipl_mask; i < INTR_NIPL; i++, m++) { ! 472: if (i < ipl) ! 473: m->mask &= ~mask; ! 474: else ! 475: m->mask |= mask; ! 476: } ! 477: ! 478: disabled_irq_mask.mask |= mask; ! 479: ! 480: set_irq_mask(ipl_mask[masked_ipl]); ! 481: ! 482: (void) intr_enbl(e); ! 483: ! 484: return (TRUE); ! 485: } ! 486: ! 487: boolean_t ! 488: intr_unregister_irq( ! 489: int irq ! 490: ) ! 491: { ! 492: intr_irq_mask_t *m; ! 493: int i, mask; ! 494: boolean_t e; ! 495: ! 496: if (irq < 0 || irq >= INTR_NIRQ || irq == INTR_SLAVE_IRQ) ! 497: return (FALSE); ! 498: ! 499: if (!dispatch_table[irq].routine) ! 500: return (FALSE); ! 501: ! 502: e = intr_disbl(); ! 503: ! 504: dispatch_table[irq].which = 0; ! 505: dispatch_table[irq].routine = 0; ! 506: dispatch_table[irq].ipl = 0; ! 507: ! 508: mask = INTR_MASK_IRQ(irq); ! 509: for (i = 0, m = ipl_mask; i < INTR_NIPL; i++, m++) { ! 510: m->mask |= mask; ! 511: } ! 512: ! 513: set_irq_mask(ipl_mask[masked_ipl]); ! 514: ! 515: (void) intr_enbl(e); ! 516: ! 517: (void) intr_change_mode(irq, FALSE); ! 518: ! 519: return (TRUE); ! 520: } ! 521: ! 522: boolean_t ! 523: intr_enable_irq( ! 524: int irq ! 525: ) ! 526: { ! 527: boolean_t e; ! 528: ! 529: if (irq < 0 || irq >= INTR_NIRQ || irq == INTR_SLAVE_IRQ) ! 530: return (FALSE); ! 531: ! 532: e = intr_disbl(); ! 533: ! 534: disabled_irq_mask.mask &= ~INTR_MASK_IRQ(irq); ! 535: set_irq_mask(ipl_mask[masked_ipl]); ! 536: ! 537: (void) intr_enbl(e); ! 538: ! 539: return (TRUE); ! 540: } ! 541: ! 542: boolean_t ! 543: intr_disable_irq( ! 544: int irq ! 545: ) ! 546: { ! 547: boolean_t e; ! 548: ! 549: if (irq < 0 || irq >= INTR_NIRQ || irq == INTR_SLAVE_IRQ) ! 550: return (FALSE); ! 551: ! 552: e = intr_disbl(); ! 553: ! 554: disabled_irq_mask.mask |= INTR_MASK_IRQ(irq); ! 555: set_irq_mask(ipl_mask[masked_ipl]); ! 556: ! 557: (void) intr_enbl(e); ! 558: ! 559: return (TRUE); ! 560: } ! 561: ! 562: boolean_t ! 563: intr_change_ipl( ! 564: int irq, ! 565: int ipl ! 566: ) ! 567: { ! 568: intr_irq_mask_t *m; ! 569: int i, mask; ! 570: boolean_t e; ! 571: ! 572: if (irq < 0 || irq >= INTR_NIRQ || irq == INTR_SLAVE_IRQ) ! 573: return (FALSE); ! 574: ! 575: if (ipl < 0 || ipl >= INTR_NIPL) ! 576: return (FALSE); ! 577: ! 578: if (dispatch_table[irq].routine == 0) ! 579: return (FALSE); ! 580: ! 581: e = intr_disbl(); ! 582: ! 583: dispatch_table[irq].ipl = ipl; ! 584: ! 585: mask = INTR_MASK_IRQ(irq); ! 586: for (i = 0, m = ipl_mask; i < INTR_NIPL; i++, m++) { ! 587: if (i < ipl) ! 588: m->mask &= ~mask; ! 589: else ! 590: m->mask |= mask; ! 591: } ! 592: ! 593: set_irq_mask(ipl_mask[masked_ipl]); ! 594: ! 595: (void) intr_enbl(e); ! 596: ! 597: return (TRUE); ! 598: } ! 599: ! 600: boolean_t ! 601: intr_change_mode( ! 602: int irq, ! 603: boolean_t level_trig ! 604: ) ! 605: { ! 606: intr_irq_mask_t reg; ! 607: boolean_t e; ! 608: #define _T_ TRUE ! 609: #define _F_ FALSE ! 610: static boolean_t valid_irq[INTR_NIRQ] = { ! 611: _F_, _F_, _F_, _T_, _T_, _T_, _T_, _T_, ! 612: _F_, _T_, _T_, _T_, _T_, _F_, _T_, _T_ ! 613: }; ! 614: #undef _T_ ! 615: #undef _F_ ! 616: ! 617: if (!eisa_present()) ! 618: return (FALSE); ! 619: ! 620: if (irq < 0 || irq >= INTR_NIRQ || !valid_irq[irq]) ! 621: return (FALSE); ! 622: ! 623: e = intr_disbl(); ! 624: ! 625: reg = current_elcr; ! 626: ! 627: if (level_trig) ! 628: reg.mask |= INTR_MASK_IRQ(irq); ! 629: else ! 630: reg.mask &= ~INTR_MASK_IRQ(irq); ! 631: ! 632: set_elcr(reg); ! 633: ! 634: (void) intr_enbl(e); ! 635: ! 636: return (TRUE); ! 637: } ! 638: ! 639: struct { ! 640: unsigned int intr; ! 641: unsigned int defer; ! 642: unsigned int phantom; ! 643: } intr_cnt; ! 644: ! 645: /* ! 646: * The system interrupt handler. ! 647: */ ! 648: void ! 649: intr_handler( ! 650: void *_state ! 651: ) ! 652: { ! 653: thread_saved_state_t *state = (thread_saved_state_t *)_state; ! 654: int irq = state->trapno - INTR_VECT_OFF; ! 655: intr_dispatch_t *i = &dispatch_table[irq]; ! 656: int old_masked_ipl; ! 657: ! 658: intr_cnt.intr++; ! 659: ! 660: /* ! 661: * Check for phantom interrupt. ! 662: */ ! 663: if (((irq == INTR_MASTER_PHANTOM_IRQ && ! 664: (get_master_isr() & INTR_PHANTOM_IRQ_MASK) == 0)) || ! 665: ((irq == INTR_SLAVE_PHANTOM_IRQ && ! 666: (get_slave_isr() & INTR_PHANTOM_IRQ_MASK) == 0)) ) { ! 667: intr_cnt.phantom++; ! 668: return; ! 669: } ! 670: ! 671: /* ! 672: * Mask this interrupt before ! 673: * acknowledging so that level ! 674: * triggered inputs work. ! 675: */ ! 676: old_masked_ipl = set_masked_ipl(i->ipl); ! 677: ! 678: /* ! 679: * Acknowledge by sending ! 680: * an EOI command to the PICs. ! 681: */ ! 682: send_eoi(); ! 683: ! 684: /* ! 685: * Leave this interrupt ! 686: * disabled if it isn't ! 687: * currently registered. ! 688: * N.B.: This should never ! 689: * happen. ! 690: */ ! 691: if (i->routine == 0) ! 692: printf("intr: dropped IRQ %d\n", irq); ! 693: else ! 694: /* ! 695: * If this interrupt isn't ! 696: * disallowed via spl(), ! 697: * handle it now. ! 698: */ ! 699: if (current_ipl < i->ipl) { ! 700: int old_ipl = set_ipl(i->ipl); ! 701: ! 702: sti(); (*i->routine)(i->which, state, old_ipl); cli(); ! 703: ! 704: (void) set_ipl(old_ipl); ! 705: (void) set_masked_ipl(old_masked_ipl); ! 706: } ! 707: /* ! 708: * Otherwise, leave it masked ! 709: * and defer it until later. ! 710: */ ! 711: else { ! 712: intr_cnt.defer++; ! 713: ! 714: defer_table[i->ipl] = i; ! 715: } ! 716: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.