2 * Copyright (c) 1991 The Regents of the University of California.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. 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.
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
36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
40 * This file contains an aggregated module marked:
41 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
42 * All rights reserved.
43 * See the notice for details.
46 #include "opt_auto_eoi.h"
50 #include <sys/param.h>
52 #include <machine/lock.h>
54 #include <sys/systm.h>
55 #include <sys/syslog.h>
56 #include <sys/malloc.h>
57 #include <sys/errno.h>
58 #include <sys/interrupt.h>
59 #include <machine/ipl.h>
60 #include <machine/md_var.h>
61 #include <machine/segments.h>
65 #include <machine/smp.h>
66 #include <machine/smptests.h> /** FAST_HI */
69 #include <pc98/pc98/pc98.h>
70 #include <pc98/pc98/pc98_machdep.h>
71 #include <pc98/pc98/epsonio.h>
73 #include <i386/isa/isa.h>
75 #include <i386/isa/icu.h>
78 #include <isa/isavar.h>
80 #include <i386/isa/intr_machdep.h>
81 #include <sys/interrupt.h>
83 #include <machine/clock.h>
88 #include <i386/isa/mca_machdep.h>
91 /* XXX should be in suitable include files */
93 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
96 #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
102 * This is to accommodate "mixed-mode" programming for
103 * motherboards that don't connect the 8254 to the IO APIC.
108 #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
110 u_long *intr_countp[ICU_LEN];
111 inthand2_t *intr_handler[ICU_LEN];
112 u_int intr_mask[ICU_LEN];
113 static u_int* intr_mptr[ICU_LEN];
114 void *intr_unit[ICU_LEN];
116 static inthand_t *fastintr[ICU_LEN] = {
117 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
118 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
119 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
120 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
121 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
122 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
123 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
124 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
126 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
127 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
128 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
129 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
133 static inthand_t *slowintr[ICU_LEN] = {
134 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
135 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
136 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
137 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
139 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
140 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
144 static inthand2_t isa_strayintr;
147 #define NMI_PARITY 0x04
148 #define NMI_EPARITY 0x02
150 #define NMI_PARITY (1 << 7)
151 #define NMI_IOCHAN (1 << 6)
152 #define ENMI_WATCHDOG (1 << 7)
153 #define ENMI_BUSTIMER (1 << 6)
154 #define ENMI_IOSTATUS (1 << 5)
158 * Handle a NMI, possibly a machine check.
159 * return true to panic system, false to ignore.
166 int port = inb(0x33);
167 if (epson_machine_id == 0x20)
168 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
169 if (port & NMI_PARITY) {
170 panic("BASE RAM parity error, likely hardware failure.");
171 } else if (port & NMI_EPARITY) {
172 panic("EXTENDED RAM parity error, likely hardware failure.");
174 printf("\nNMI Resume ??\n");
178 int isa_port = inb(0x61);
179 int eisa_port = inb(0x461);
182 if (MCA_system && mca_bus_nmi())
186 if (isa_port & NMI_PARITY)
187 panic("RAM parity error, likely hardware failure.");
189 if (isa_port & NMI_IOCHAN)
190 panic("I/O channel check, likely hardware failure.");
193 * On a real EISA machine, this will never happen. However it can
194 * happen on ISA machines which implement XT style floating point
195 * error handling (very rare). Save them from a meaningless panic.
197 if (eisa_port == 0xff)
200 if (eisa_port & ENMI_WATCHDOG)
201 panic("EISA watchdog timer expired, likely hardware failure.");
203 if (eisa_port & ENMI_BUSTIMER)
204 panic("EISA bus timeout, likely hardware failure.");
206 if (eisa_port & ENMI_IOSTATUS)
207 panic("EISA I/O port status error.");
209 printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
215 * Fill in default interrupt table (in case of spuruious interrupt
216 * during configuration of kernel, setup interrupt control unit
224 for (i = 0; i < ICU_LEN; i++)
225 icu_unset(i, (inthand2_t *)NULL);
227 /* initialize 8259's */
230 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
233 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
235 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
236 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
239 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
241 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
245 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
247 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
250 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
251 outb(IO_ICU1, 0x0a); /* default to IRR on read */
253 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
258 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
261 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
263 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
264 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
266 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
269 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
271 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
274 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
275 outb(IO_ICU2, 0x0a); /* default to IRR on read */
279 * Caught a stray interrupt, notify
282 isa_strayintr(vcookiep)
285 int intr = (void **)vcookiep - &intr_unit[0];
287 /* DON'T BOTHER FOR NOW! */
288 /* for some reason, we get bursts of intr #7, even if not enabled! */
290 * Well the reason you got bursts of intr #7 is because someone
291 * raised an interrupt line and dropped it before the 8259 could
292 * prioritize it. This is documented in the intel data book. This
293 * means you have BAD hardware! I have changed this so that only
294 * the first 5 get logged, then it quits logging them, and puts
295 * out a special message. rgrimes 3/25/1993
298 * XXX TODO print a different message for #7 if it is for a
299 * glitch. Glitches can be distinguished from real #7's by
300 * testing that the in-service bit is _not_ set. The test
301 * must be done before sending an EOI so it can't be done if
302 * we are using AUTO_EOI_1.
304 if (intrcnt[1 + intr] <= 5)
305 log(LOG_ERR, "stray irq %d\n", intr);
306 if (intrcnt[1 + intr] == 5)
308 "too many stray irq %d's; not logging any more\n", intr);
313 * Return a bitmap of the current interrupt requests. This is 8259-specific
314 * and is only suitable for use at probe time.
324 return ((irr2 << 8) | irr1);
329 update_intr_masks(void)
334 for (intr=0; intr < ICU_LEN; intr ++) {
336 /* no 8259 SLAVE to ignore */
338 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
340 maskptr = intr_mptr[intr];
343 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
345 if (mask != intr_mask[intr]) {
347 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
348 intr, intr_mask[intr], mask, maskptr);
350 intr_mask[intr]=mask;
359 update_intrname(int intr, char *name)
363 int name_index, off, strayintr;
366 * Initialise strings for bitbucket and stray interrupt counters.
367 * These have statically allocated indices 0 and 1 through ICU_LEN.
369 if (intrnames[0] == '\0') {
370 off = sprintf(intrnames, "???") + 1;
371 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
372 off += sprintf(intrnames + off, "stray irq%d",
378 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
382 * Search for `buf' in `intrnames'. In the usual case when it is
383 * not found, append it to the end if there is enough space (the \0
384 * terminator for the previous string, if any, becomes a separator).
386 for (cp = intrnames, name_index = 0;
387 cp != eintrnames && name_index < NR_INTRNAMES;
388 cp += strlen(cp) + 1, name_index++) {
390 if (strlen(buf) >= eintrnames - cp)
395 if (strcmp(cp, buf) == 0)
400 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
404 intr_countp[intr] = &intrcnt[name_index];
408 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
411 int select; /* the select register is 8 bits */
413 u_int32_t value; /* the window register is 32 bits */
416 u_int mask = (maskptr ? *maskptr : 0);
419 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
421 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
423 if (intr_handler[intr] != isa_strayintr)
428 intr_handler[intr] = handler;
429 intr_mptr[intr] = maskptr;
430 intr_mask[intr] = mask | SWI_CLOCK_MASK | (1 << intr);
431 intr_unit[intr] = arg;
433 if (flags & INTR_FAST) {
434 vector = TPR_FAST_INTS + intr;
435 setidt(vector, fastintr[intr],
436 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
439 vector = TPR_SLOW_INTS + intr;
440 #ifdef APIC_INTR_REORDER
441 #ifdef APIC_INTR_HIGHPRI_CLOCK
442 /* XXX: Hack (kludge?) for more accurate clock. */
443 if (intr == apic_8254_intr || intr == 8) {
444 vector = TPR_FAST_INTS + intr;
448 setidt(vector, slowintr[intr],
449 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
451 #ifdef APIC_INTR_REORDER
452 set_lapic_isrloc(intr, vector);
455 * Reprogram the vector in the IO APIC.
457 if (int_to_apicintpin[intr].ioapic >= 0) {
458 select = int_to_apicintpin[intr].redirindex;
459 value = io_apic_read(int_to_apicintpin[intr].ioapic,
460 select) & ~IOART_INTVEC;
461 io_apic_write(int_to_apicintpin[intr].ioapic,
462 select, value | vector);
465 setidt(ICU_OFFSET + intr,
466 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
467 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
476 icu_unset(intr, handler)
482 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
488 intr_countp[intr] = &intrcnt[1 + intr];
489 intr_handler[intr] = isa_strayintr;
490 intr_mptr[intr] = NULL;
491 intr_mask[intr] = HWI_MASK | SWI_MASK;
492 intr_unit[intr] = &intr_unit[intr];
494 /* XXX how do I re-create dvp here? */
495 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
496 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
498 #ifdef APIC_INTR_REORDER
499 set_lapic_isrloc(intr, ICU_OFFSET + intr);
501 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
502 GSEL(GCODE_SEL, SEL_KPL));
509 /* The following notice applies beyond this point in the file */
512 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
513 * All rights reserved.
515 * Redistribution and use in source and binary forms, with or without
516 * modification, are permitted provided that the following conditions
518 * 1. Redistributions of source code must retain the above copyright
519 * notice unmodified, this list of conditions, and the following
521 * 2. Redistributions in binary form must reproduce the above copyright
522 * notice, this list of conditions and the following disclaimer in the
523 * documentation and/or other materials provided with the distribution.
525 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
526 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
527 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
528 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
529 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
530 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
531 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
532 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
533 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
534 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
540 typedef struct intrec {
551 static intrec *intreclist_head[ICU_LEN];
554 * The interrupt multiplexer calls each of the handlers in turn. The
555 * ipl is initially quite low. It is raised as necessary for each call
556 * and lowered after the call. Thus out of order handling is possible
557 * even for interrupts of the same type. This is probably no more
558 * harmful than out of order handling in general (not harmful except
559 * for real time response which we don't support anyway).
567 for (p = arg; p != NULL; p = p->next) {
568 oldspl = splq(p->mask);
569 p->handler(p->argument);
575 find_idesc(unsigned *maskptr, int irq)
577 intrec *p = intreclist_head[irq];
579 while (p && p->maskptr != maskptr)
586 find_pred(intrec *idesc, int irq)
588 intrec **pp = &intreclist_head[irq];
601 * Both the low level handler and the shared interrupt multiplexer
602 * block out further interrupts as set in the handlers "mask", while
603 * the handler is running. In fact *maskptr should be used for this
604 * purpose, but since this requires one more pointer dereference on
605 * each interrupt, we rather bother update "mask" whenever *maskptr
606 * changes. The function "update_masks" should be called **after**
607 * all manipulation of the linked list of interrupt handlers hung
608 * off of intrdec_head[irq] is complete, since the chain of handlers
609 * will both determine the *maskptr values and the instances of mask
610 * that are fixed. This function should be called with the irq for
611 * which a new handler has been add blocked, since the masks may not
612 * yet know about the use of this irq for a device of a certain class.
616 update_mux_masks(void)
619 for (irq = 0; irq < ICU_LEN; irq++) {
620 intrec *idesc = intreclist_head[irq];
621 while (idesc != NULL) {
622 if (idesc->maskptr != NULL) {
623 /* our copy of *maskptr may be stale, refresh */
624 idesc->mask = *idesc->maskptr;
632 update_masks(intrmask_t *maskptr, int irq)
634 intrmask_t mask = 1 << irq;
639 if (find_idesc(maskptr, irq) == NULL) {
640 /* no reference to this maskptr was found in this irq's chain */
641 if ((*maskptr & mask) == 0)
643 /* the irq was included in the classes mask, remove it */
646 /* a reference to this maskptr was found in this irq's chain */
647 if ((*maskptr & mask) != 0)
649 /* put the irq into the classes mask */
652 /* we need to update all values in the intr_mask[irq] array */
654 /* update mask in chains of the interrupt multiplex handler as well */
659 * Add interrupt handler to linked list hung off of intreclist_head[irq]
660 * and install shared interrupt multiplex handler, if necessary
664 add_intrdesc(intrec *idesc)
666 int irq = idesc->intr;
668 intrec *head = intreclist_head[irq];
671 /* first handler for this irq, just install it */
672 if (icu_setup(irq, idesc->handler, idesc->argument,
673 idesc->maskptr, idesc->flags) != 0)
676 update_intrname(irq, idesc->name);
678 intreclist_head[irq] = idesc;
680 if ((idesc->flags & INTR_EXCL) != 0
681 || (head->flags & INTR_EXCL) != 0) {
683 * can't append new handler, if either list head or
684 * new handler do not allow interrupts to be shared
687 printf("\tdevice combination doesn't support "
688 "shared irq%d\n", irq);
691 if (head->next == NULL) {
693 * second handler for this irq, replace device driver's
694 * handler by shared interrupt multiplexer function
696 icu_unset(irq, head->handler);
697 if (icu_setup(irq, intr_mux, head, 0, 0) != 0)
700 printf("\tusing shared irq%d.\n", irq);
701 update_intrname(irq, "mux");
703 /* just append to the end of the chain */
704 while (head->next != NULL)
708 update_masks(idesc->maskptr, irq);
713 * Create and activate an interrupt handler descriptor data structure.
715 * The dev_instance pointer is required for resource management, and will
716 * only be passed through to resource_claim().
718 * There will be functions that derive a driver and unit name from a
719 * dev_instance variable, and those functions will be used to maintain the
720 * interrupt counter label array referenced by systat and vmstat to report
721 * device interrupt rates (->update_intrlabels).
723 * Add the interrupt handler descriptor data structure created by an
724 * earlier call of create_intr() to the linked list for its irq and
725 * adjust the interrupt masks if necessary.
729 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
730 intrmask_t *maskptr, int flags)
736 if (ICU_LEN > 8 * sizeof *maskptr) {
737 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
738 ICU_LEN, 8 * sizeof *maskptr);
741 if ((unsigned)irq >= ICU_LEN) {
742 printf("create_intr: requested irq%d too high, limit is %d\n",
747 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
750 bzero(idesc, sizeof *idesc);
754 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
755 if (idesc->name == NULL) {
756 free(idesc, M_DEVBUF);
759 strcpy(idesc->name, name);
761 idesc->handler = handler;
762 idesc->argument = arg;
763 idesc->maskptr = maskptr;
765 idesc->flags = flags;
768 oldspl = splq(1 << irq);
770 /* add irq to class selected by maskptr */
771 errcode = add_intrdesc(idesc);
776 printf("\tintr_connect(irq%d) failed, result=%d\n",
778 free(idesc->name, M_DEVBUF);
779 free(idesc, M_DEVBUF);
787 * Deactivate and remove the interrupt handler descriptor data connected
788 * created by an earlier call of intr_connect() from the linked list and
789 * adjust theinterrupt masks if necessary.
791 * Return the memory held by the interrupt handler descriptor data structure
792 * to the system. Make sure, the handler is not actively used anymore, before.
796 inthand_remove(intrec *idesc)
798 intrec **hook, *head;
808 /* find pointer that keeps the reference to this interrupt descriptor */
809 hook = find_pred(idesc, irq);
813 /* make copy of original list head, the line after may overwrite it */
814 head = intreclist_head[irq];
816 /* unlink: make predecessor point to idesc->next instead of to idesc */
819 /* now check whether the element we removed was the list head */
822 oldspl = splq(1 << irq);
824 /* check whether the new list head is the only element on list */
825 head = intreclist_head[irq];
827 icu_unset(irq, intr_mux);
828 if (head->next != NULL) {
829 /* install the multiplex handler with new list head as argument */
830 errcode = icu_setup(irq, intr_mux, head, 0, 0);
832 update_intrname(irq, NULL);
834 /* install the one remaining handler for this irq */
835 errcode = icu_setup(irq, head->handler,
837 head->maskptr, head->flags);
839 update_intrname(irq, head->name);
842 /* revert to old handler, eg: strayintr */
843 icu_unset(irq, idesc->handler);
847 update_masks(idesc->maskptr, irq);
848 free(idesc, M_DEVBUF);