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
37 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
38 * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.c,v 1.23 2004/07/24 20:21:34 dillon Exp $
41 * This file contains an aggregated module marked:
42 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
43 * All rights reserved.
44 * See the notice for details.
49 #include "opt_auto_eoi.h"
51 #include <sys/param.h>
53 #include <machine/lock.h>
55 #include <sys/systm.h>
56 #include <sys/syslog.h>
57 #include <sys/malloc.h>
58 #include <sys/errno.h>
59 #include <sys/interrupt.h>
60 #include <machine/ipl.h>
61 #include <machine/md_var.h>
62 #include <machine/segments.h>
64 #include <machine/globaldata.h>
66 #include <sys/thread2.h>
68 #include <machine/smptests.h> /** FAST_HI */
69 #include <machine/smp.h>
71 #include <pc98/pc98/pc98.h>
72 #include <pc98/pc98/pc98_machdep.h>
73 #include <pc98/pc98/epsonio.h>
75 #include <bus/isa/i386/isa.h>
77 #include <i386/isa/icu.h>
80 #include <bus/isa/isavar.h>
82 #include <i386/isa/intr_machdep.h>
83 #include <bus/isa/isavar.h>
84 #include <sys/interrupt.h>
86 #include <machine/clock.h>
88 #include <machine/cpu.h>
91 #include <bus/mca/i386/mca_machdep.h>
94 /* XXX should be in suitable include files */
96 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
99 #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
100 #define ICU_SLAVEID 2
105 * This is to accommodate "mixed-mode" programming for
106 * motherboards that don't connect the 8254 to the IO APIC.
111 #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
113 static inthand2_t isa_strayintr;
114 #if defined(FAST_HI) && defined(APIC_IO)
115 static inthand2_t isa_wrongintr;
117 static void init_i8259(void);
119 void *intr_unit[ICU_LEN*2];
120 u_long *intr_countp[ICU_LEN*2];
121 inthand2_t *intr_handler[ICU_LEN*2] = {
122 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
123 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
124 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
125 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
126 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
127 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
128 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
129 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
132 static struct md_intr_info {
135 int mihandler_installed;
137 } intr_info[ICU_LEN*2];
139 static inthand_t *fastintr[ICU_LEN] = {
140 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
141 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
142 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
143 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
144 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
145 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
146 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
147 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
149 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
150 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
151 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
152 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
156 unpendhand_t *fastunpend[ICU_LEN] = {
157 IDTVEC(fastunpend0), IDTVEC(fastunpend1),
158 IDTVEC(fastunpend2), IDTVEC(fastunpend3),
159 IDTVEC(fastunpend4), IDTVEC(fastunpend5),
160 IDTVEC(fastunpend6), IDTVEC(fastunpend7),
161 IDTVEC(fastunpend8), IDTVEC(fastunpend9),
162 IDTVEC(fastunpend10), IDTVEC(fastunpend11),
163 IDTVEC(fastunpend12), IDTVEC(fastunpend13),
164 IDTVEC(fastunpend14), IDTVEC(fastunpend15),
166 IDTVEC(fastunpend16), IDTVEC(fastunpend17),
167 IDTVEC(fastunpend18), IDTVEC(fastunpend19),
168 IDTVEC(fastunpend20), IDTVEC(fastunpend21),
169 IDTVEC(fastunpend22), IDTVEC(fastunpend23),
173 static inthand_t *slowintr[ICU_LEN] = {
174 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
175 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
176 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
177 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
179 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
180 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
185 #define NMI_PARITY 0x04
186 #define NMI_EPARITY 0x02
188 #define NMI_PARITY (1 << 7)
189 #define NMI_IOCHAN (1 << 6)
190 #define ENMI_WATCHDOG (1 << 7)
191 #define ENMI_BUSTIMER (1 << 6)
192 #define ENMI_IOSTATUS (1 << 5)
196 * Handle a NMI, possibly a machine check.
197 * return true to panic system, false to ignore.
205 int port = inb(0x33);
207 log(LOG_CRIT, "NMI PC98 port = %x\n", port);
208 if (epson_machine_id == 0x20)
209 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
210 if (port & NMI_PARITY) {
211 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure.");
213 } else if (port & NMI_EPARITY) {
214 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure.");
217 log(LOG_CRIT, "\nNMI Resume ??\n");
220 int isa_port = inb(0x61);
221 int eisa_port = inb(0x461);
223 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
225 if (MCA_system && mca_bus_nmi())
229 if (isa_port & NMI_PARITY) {
230 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
234 if (isa_port & NMI_IOCHAN) {
235 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
240 * On a real EISA machine, this will never happen. However it can
241 * happen on ISA machines which implement XT style floating point
242 * error handling (very rare). Save them from a meaningless panic.
244 if (eisa_port == 0xff)
247 if (eisa_port & ENMI_WATCHDOG) {
248 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
252 if (eisa_port & ENMI_BUSTIMER) {
253 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
257 if (eisa_port & ENMI_IOSTATUS) {
258 log(LOG_CRIT, "EISA I/O port status error.");
266 * ICU reinitialize when ICU configuration has lost.
274 for(i=0;i<ICU_LEN;i++)
275 if(intr_handler[i] != isa_strayintr)
281 * Fill in default interrupt table (in case of spurious interrupt
282 * during configuration of kernel, setup interrupt control unit
290 for (i = 0; i < ICU_LEN; i++)
291 icu_unset(i, isa_strayintr);
299 /* initialize 8259's */
302 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
305 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
307 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
308 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
311 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
313 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
317 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
319 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
322 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
323 outb(IO_ICU1, 0x0a); /* default to IRR on read */
325 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
330 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
333 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
335 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
336 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
338 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
341 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
343 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
346 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
347 outb(IO_ICU2, 0x0a); /* default to IRR on read */
351 * Caught a stray interrupt, notify
354 isa_strayintr(void *vcookiep)
356 int intr = (void **)vcookiep - &intr_unit[0];
358 /* DON'T BOTHER FOR NOW! */
359 /* for some reason, we get bursts of intr #7, even if not enabled! */
361 * Well the reason you got bursts of intr #7 is because someone
362 * raised an interrupt line and dropped it before the 8259 could
363 * prioritize it. This is documented in the intel data book. This
364 * means you have BAD hardware! I have changed this so that only
365 * the first 5 get logged, then it quits logging them, and puts
366 * out a special message. rgrimes 3/25/1993
369 * XXX TODO print a different message for #7 if it is for a
370 * glitch. Glitches can be distinguished from real #7's by
371 * testing that the in-service bit is _not_ set. The test
372 * must be done before sending an EOI so it can't be done if
373 * we are using AUTO_EOI_1.
375 if (intrcnt[1 + intr] <= 5)
376 log(LOG_ERR, "stray irq %d\n", intr);
377 if (intrcnt[1 + intr] == 5)
379 "too many stray irq %d's; not logging any more\n", intr);
382 #if defined(FAST_HI) && defined(APIC_IO)
385 * This occurs if we mis-programmed the APIC and its vector is still
386 * pointing to the slow vector even when we thought we reprogrammed it
387 * to the high vector. This can occur when interrupts are improperly
388 * routed by the APIC. The unit data is opaque so we have to try to
389 * find it in the unit array.
392 isa_wrongintr(void *vcookiep)
396 for (intr = 0; intr < ICU_LEN*2; ++intr) {
397 if (intr_unit[intr] == vcookiep)
400 if (intr == ICU_LEN*2) {
401 log(LOG_ERR, "stray unknown irq (APIC misprogrammed)\n");
402 } else if (intrcnt[1 + intr] <= 5) {
403 log(LOG_ERR, "stray irq ~%d (APIC misprogrammed)\n", intr);
404 } else if (intrcnt[1 + intr] == 6) {
406 "too many stray irq ~%d's; not logging any more\n", intr);
414 * Return a bitmap of the current interrupt requests. This is 8259-specific
415 * and is only suitable for use at probe time.
418 isa_irq_pending(void)
425 return ((irr2 << 8) | irr1);
430 update_intr_masks(void)
435 for (intr=0; intr < ICU_LEN; intr ++) {
437 /* no 8259 SLAVE to ignore */
439 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
441 maskptr = intr_info[intr].maskp;
444 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
446 if (mask != intr_info[intr].mask) {
448 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
449 intr, intr_info[intr].mask, mask, maskptr);
451 intr_info[intr].mask = mask;
460 update_intrname(int intr, char *name)
464 int name_index, off, strayintr;
467 * Initialise strings for bitbucket and stray interrupt counters.
468 * These have statically allocated indices 0 and 1 through ICU_LEN.
470 if (intrnames[0] == '\0') {
471 off = sprintf(intrnames, "???") + 1;
472 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
473 off += sprintf(intrnames + off, "stray irq%d",
479 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
483 * Search for `buf' in `intrnames'. In the usual case when it is
484 * not found, append it to the end if there is enough space (the \0
485 * terminator for the previous string, if any, becomes a separator).
487 for (cp = intrnames, name_index = 0;
488 cp != eintrnames && name_index < NR_INTRNAMES;
489 cp += strlen(cp) + 1, name_index++) {
491 if (strlen(buf) >= eintrnames - cp)
496 if (strcmp(cp, buf) == 0)
501 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
505 intr_countp[intr] = &intrcnt[name_index];
509 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
510 * code ignores it for normal interrupts.
513 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
515 #if defined(FAST_HI) && defined(APIC_IO)
516 int select; /* the select register is 8 bits */
518 u_int32_t value; /* the window register is 32 bits */
521 u_int mask = (maskptr ? *maskptr : 0);
524 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
526 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
529 if (intr_handler[intr] != isa_strayintr)
533 cpu_disable_intr(); /* YYY */
534 intr_handler[intr] = handler;
535 intr_unit[intr] = arg;
536 intr_info[intr].maskp = maskptr;
537 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
539 /* YYY fast ints supported and mp protected but ... */
542 #if defined(FAST_HI) && defined(APIC_IO)
543 if (flags & INTR_FAST) {
545 * Install a spurious interrupt in the low space in case
546 * the IO apic is not properly reprogrammed.
548 vector = TPR_SLOW_INTS + intr;
549 setidt(vector, isa_wrongintr,
550 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
551 vector = TPR_FAST_INTS + intr;
552 setidt(vector, fastintr[intr],
553 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
555 vector = TPR_SLOW_INTS + intr;
556 #ifdef APIC_INTR_REORDER
557 #ifdef APIC_INTR_HIGHPRI_CLOCK
558 /* XXX: Hack (kludge?) for more accurate clock. */
559 if (intr == apic_8254_intr || intr == 8) {
560 vector = TPR_FAST_INTS + intr;
564 setidt(vector, slowintr[intr],
565 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
567 #ifdef APIC_INTR_REORDER
568 set_lapic_isrloc(intr, vector);
571 * Reprogram the vector in the IO APIC.
573 * XXX EOI/mask a pending (stray) interrupt on the old vector?
575 if (int_to_apicintpin[intr].ioapic >= 0) {
576 select = int_to_apicintpin[intr].redirindex;
577 value = io_apic_read(int_to_apicintpin[intr].ioapic,
578 select) & ~IOART_INTVEC;
579 io_apic_write(int_to_apicintpin[intr].ioapic,
580 select, value | vector);
583 setidt(ICU_OFFSET + intr,
584 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
585 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
586 #endif /* FAST_HI && APIC_IO */
593 icu_unset(intr, handler)
599 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) {
600 printf("icu_unset: invalid handler %d %p/%p\n", intr, handler,
601 (((u_int)intr >= ICU_LEN) ? (void *)-1 : intr_handler[intr]));
607 cpu_disable_intr(); /* YYY */
608 intr_countp[intr] = &intrcnt[1 + intr];
609 intr_handler[intr] = isa_strayintr;
610 intr_info[intr].maskp = NULL;
611 intr_info[intr].mask = HWI_MASK | SWI_MASK;
612 intr_unit[intr] = &intr_unit[intr];
614 /* XXX how do I re-create dvp here? */
615 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
616 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
618 #ifdef APIC_INTR_REORDER
619 set_lapic_isrloc(intr, ICU_OFFSET + intr);
621 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
622 GSEL(GCODE_SEL, SEL_KPL));
629 /* The following notice applies beyond this point in the file */
632 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
633 * All rights reserved.
635 * Redistribution and use in source and binary forms, with or without
636 * modification, are permitted provided that the following conditions
638 * 1. Redistributions of source code must retain the above copyright
639 * notice unmodified, this list of conditions, and the following
641 * 2. Redistributions in binary form must reproduce the above copyright
642 * notice, this list of conditions and the following disclaimer in the
643 * documentation and/or other materials provided with the distribution.
645 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
646 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
647 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
648 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
649 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
650 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
651 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
652 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
653 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
654 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
656 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
660 typedef struct intrec {
671 static intrec *intreclist_head[ICU_LEN];
674 * The interrupt multiplexer calls each of the handlers in turn. The
675 * ipl is initially quite low. It is raised as necessary for each call
676 * and lowered after the call. Thus out of order handling is possible
677 * even for interrupts of the same type. This is probably no more
678 * harmful than out of order handling in general (not harmful except
679 * for real time response which we don't support anyway).
688 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
689 oldspl = splq(p->mask);
690 p->handler(p->argument);
696 find_idesc(unsigned *maskptr, int irq)
698 intrec *p = intreclist_head[irq];
700 while (p && p->maskptr != maskptr)
707 find_pred(intrec *idesc, int irq)
709 intrec **pp = &intreclist_head[irq];
722 * Both the low level handler and the shared interrupt multiplexer
723 * block out further interrupts as set in the handlers "mask", while
724 * the handler is running. In fact *maskptr should be used for this
725 * purpose, but since this requires one more pointer dereference on
726 * each interrupt, we rather bother update "mask" whenever *maskptr
727 * changes. The function "update_masks" should be called **after**
728 * all manipulation of the linked list of interrupt handlers hung
729 * off of intrdec_head[irq] is complete, since the chain of handlers
730 * will both determine the *maskptr values and the instances of mask
731 * that are fixed. This function should be called with the irq for
732 * which a new handler has been add blocked, since the masks may not
733 * yet know about the use of this irq for a device of a certain class.
737 update_mux_masks(void)
740 for (irq = 0; irq < ICU_LEN; irq++) {
741 intrec *idesc = intreclist_head[irq];
742 while (idesc != NULL) {
743 if (idesc->maskptr != NULL) {
744 /* our copy of *maskptr may be stale, refresh */
745 idesc->mask = *idesc->maskptr;
753 update_masks(intrmask_t *maskptr, int irq)
755 intrmask_t mask = 1 << irq;
760 if (find_idesc(maskptr, irq) == NULL) {
761 /* no reference to this maskptr was found in this irq's chain */
764 /* a reference to this maskptr was found in this irq's chain */
767 /* we need to update all values in the intr_mask[irq] array */
769 /* update mask in chains of the interrupt multiplex handler as well */
774 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
775 * and install a shared interrupt multiplex handler, if necessary. Install
776 * an interrupt thread for each interrupt (though FAST interrupts will not
777 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
778 * check relative thread priorities for us as long as we properly pass through
781 * The interrupt thread has already been put on the run queue, so if we cannot
782 * preempt we should force a reschedule.
784 * YYY needs work. At the moment the handler is run inside a critical
785 * section so only the preemption cpl check is used.
788 cpu_intr_preempt(struct thread *td, int critpri)
790 struct md_intr_info *info = td->td_info.intdata;
792 if ((curthread->td_cpl & (1 << info->irq)) == 0)
793 lwkt_preempt(td, critpri);
795 need_lwkt_resched(); /* XXX may not be required */
799 add_intrdesc(intrec *idesc)
801 int irq = idesc->intr;
805 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
806 * handles interrupt thread scheduling for NORMAL interrupts. It
807 * will never get called for fast interrupts. On the otherhand,
808 * the handler this code installs in intr_handler[] for a NORMAL
809 * interrupt is not used by the *vector.s code, so we need this
810 * temporary hack to run normal interrupts as interrupt threads.
813 if (intr_info[irq].mihandler_installed == 0) {
816 intr_info[irq].mihandler_installed = 1;
817 intr_info[irq].irq = irq;
818 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
819 td->td_info.intdata = &intr_info[irq];
820 td->td_preemptable = cpu_intr_preempt;
821 printf("installed MI handler for int %d\n", irq);
824 head = intreclist_head[irq];
827 /* first handler for this irq, just install it */
828 if (icu_setup(irq, idesc->handler, idesc->argument,
829 idesc->maskptr, idesc->flags) != 0)
832 update_intrname(irq, idesc->name);
834 intreclist_head[irq] = idesc;
836 if ((idesc->flags & INTR_EXCL) != 0
837 || (head->flags & INTR_EXCL) != 0) {
839 * can't append new handler, if either list head or
840 * new handler do not allow interrupts to be shared
843 printf("\tdevice combination doesn't support "
844 "shared irq%d\n", irq);
847 if (head->next == NULL) {
849 * second handler for this irq, replace device driver's
850 * handler by shared interrupt multiplexer function
852 icu_unset(irq, head->handler);
853 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
856 printf("\tusing shared irq%d.\n", irq);
857 update_intrname(irq, "mux");
859 /* just append to the end of the chain */
860 while (head->next != NULL)
864 update_masks(idesc->maskptr, irq);
869 * Create and activate an interrupt handler descriptor data structure.
871 * The dev_instance pointer is required for resource management, and will
872 * only be passed through to resource_claim().
874 * There will be functions that derive a driver and unit name from a
875 * dev_instance variable, and those functions will be used to maintain the
876 * interrupt counter label array referenced by systat and vmstat to report
877 * device interrupt rates (->update_intrlabels).
879 * Add the interrupt handler descriptor data structure created by an
880 * earlier call of create_intr() to the linked list for its irq and
881 * adjust the interrupt masks if necessary.
883 * WARNING: This is an internal function and not to be used by device
884 * drivers. It is subject to change without notice.
888 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
889 intrmask_t *maskptr, int flags)
895 if (ICU_LEN > 8 * sizeof *maskptr) {
896 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
897 ICU_LEN, 8 * sizeof *maskptr);
900 if ((unsigned)irq >= ICU_LEN) {
901 printf("create_intr: requested irq%d too high, limit is %d\n",
906 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
909 bzero(idesc, sizeof *idesc);
913 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
914 if (idesc->name == NULL) {
915 free(idesc, M_DEVBUF);
918 strcpy(idesc->name, name);
920 idesc->handler = handler;
921 idesc->argument = arg;
922 idesc->maskptr = maskptr;
924 idesc->flags = flags;
927 oldspl = splq(1 << irq);
929 /* add irq to class selected by maskptr */
930 errcode = add_intrdesc(idesc);
935 printf("\tintr_connect(irq%d) failed, result=%d\n",
937 free(idesc->name, M_DEVBUF);
938 free(idesc, M_DEVBUF);
946 * Deactivate and remove the interrupt handler descriptor data connected
947 * created by an earlier call of intr_connect() from the linked list and
948 * adjust theinterrupt masks if necessary.
950 * Return the memory held by the interrupt handler descriptor data structure
951 * to the system. Make sure, the handler is not actively used anymore, before.
955 inthand_remove(intrec *idesc)
957 intrec **hook, *head;
967 /* find pointer that keeps the reference to this interrupt descriptor */
968 hook = find_pred(idesc, irq);
972 /* make copy of original list head, the line after may overwrite it */
973 head = intreclist_head[irq];
975 /* unlink: make predecessor point to idesc->next instead of to idesc */
978 /* now check whether the element we removed was the list head */
981 oldspl = splq(1 << irq);
983 /* check whether the new list head is the only element on list */
984 head = intreclist_head[irq];
986 icu_unset(irq, intr_mux);
987 if (head->next != NULL) {
988 /* install the multiplex handler with new list head as argument */
989 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
991 update_intrname(irq, NULL);
993 /* install the one remaining handler for this irq */
994 errcode = icu_setup(irq, head->handler,
996 head->maskptr, head->flags);
998 update_intrname(irq, head->name);
1001 /* revert to old handler, eg: strayintr */
1002 icu_unset(irq, idesc->handler);
1006 update_masks(idesc->maskptr, irq);
1007 free(idesc, M_DEVBUF);
1014 * This function is called by an interrupt thread when it has completed
1015 * processing a loop. We re-enable interrupts and interlock with
1018 * See kern/kern_intr.c for more information.
1021 ithread_done(int irq)
1023 struct mdglobaldata *gd = mdcpu;
1024 int mask = 1 << irq;
1027 td = gd->mi.gd_curthread;
1029 KKASSERT(td->td_pri >= TDPRI_CRIT);
1030 lwkt_deschedule_self(td);
1032 if (gd->gd_ipending & mask) {
1033 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
1035 lwkt_schedule_self(td);
1043 * forward_fast_remote()
1045 * This function is called from the receiving end of an IPIQ when a
1046 * remote cpu wishes to forward a fast interrupt to us. All we have to
1047 * do is set the interrupt pending and let the IPI's doreti deal with it.
1050 forward_fastint_remote(void *arg)
1053 struct mdglobaldata *gd = mdcpu;
1055 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
1056 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);