|
|
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.