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/platform/pc32/isa/intr_machdep.c,v 1.17 2004/02/20 22:01:20 drhodus 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>
69 #include <machine/smptests.h> /** FAST_HI */
70 #include <machine/smp.h>
73 #include <pc98/pc98/pc98.h>
74 #include <pc98/pc98/pc98_machdep.h>
75 #include <pc98/pc98/epsonio.h>
77 #include <bus/isa/i386/isa.h>
79 #include <i386/isa/icu.h>
82 #include <bus/isa/isavar.h>
84 #include <i386/isa/intr_machdep.h>
85 #include <bus/isa/isavar.h>
86 #include <sys/interrupt.h>
88 #include <machine/clock.h>
90 #include <machine/cpu.h>
93 #include <bus/mca/i386/mca_machdep.h>
96 /* XXX should be in suitable include files */
98 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
101 #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
102 #define ICU_SLAVEID 2
107 * This is to accommodate "mixed-mode" programming for
108 * motherboards that don't connect the 8254 to the IO APIC.
113 #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
115 static inthand2_t isa_strayintr;
116 #if defined(FAST_HI) && defined(APIC_IO)
117 static inthand2_t isa_wrongintr;
119 static void init_i8259(void);
121 void *intr_unit[ICU_LEN*2];
122 u_long *intr_countp[ICU_LEN*2];
123 inthand2_t *intr_handler[ICU_LEN*2] = {
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,
130 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
131 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
134 static struct md_intr_info {
137 int mihandler_installed;
139 } intr_info[ICU_LEN*2];
141 static inthand_t *fastintr[ICU_LEN] = {
142 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
143 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
144 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
145 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
146 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
147 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
148 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
149 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
151 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
152 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
153 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
154 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
158 unpendhand_t *fastunpend[ICU_LEN] = {
159 IDTVEC(fastunpend0), IDTVEC(fastunpend1),
160 IDTVEC(fastunpend2), IDTVEC(fastunpend3),
161 IDTVEC(fastunpend4), IDTVEC(fastunpend5),
162 IDTVEC(fastunpend6), IDTVEC(fastunpend7),
163 IDTVEC(fastunpend8), IDTVEC(fastunpend9),
164 IDTVEC(fastunpend10), IDTVEC(fastunpend11),
165 IDTVEC(fastunpend12), IDTVEC(fastunpend13),
166 IDTVEC(fastunpend14), IDTVEC(fastunpend15),
168 IDTVEC(fastunpend16), IDTVEC(fastunpend17),
169 IDTVEC(fastunpend18), IDTVEC(fastunpend19),
170 IDTVEC(fastunpend20), IDTVEC(fastunpend21),
171 IDTVEC(fastunpend22), IDTVEC(fastunpend23),
175 static inthand_t *slowintr[ICU_LEN] = {
176 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
177 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
178 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
179 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
181 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
182 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
187 #define NMI_PARITY 0x04
188 #define NMI_EPARITY 0x02
190 #define NMI_PARITY (1 << 7)
191 #define NMI_IOCHAN (1 << 6)
192 #define ENMI_WATCHDOG (1 << 7)
193 #define ENMI_BUSTIMER (1 << 6)
194 #define ENMI_IOSTATUS (1 << 5)
198 * Handle a NMI, possibly a machine check.
199 * return true to panic system, false to ignore.
207 int port = inb(0x33);
209 log(LOG_CRIT, "NMI PC98 port = %x\n", port);
210 if (epson_machine_id == 0x20)
211 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
212 if (port & NMI_PARITY) {
213 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure.");
215 } else if (port & NMI_EPARITY) {
216 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure.");
219 log(LOG_CRIT, "\nNMI Resume ??\n");
222 int isa_port = inb(0x61);
223 int eisa_port = inb(0x461);
225 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
227 if (MCA_system && mca_bus_nmi())
231 if (isa_port & NMI_PARITY) {
232 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
236 if (isa_port & NMI_IOCHAN) {
237 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
242 * On a real EISA machine, this will never happen. However it can
243 * happen on ISA machines which implement XT style floating point
244 * error handling (very rare). Save them from a meaningless panic.
246 if (eisa_port == 0xff)
249 if (eisa_port & ENMI_WATCHDOG) {
250 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
254 if (eisa_port & ENMI_BUSTIMER) {
255 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
259 if (eisa_port & ENMI_IOSTATUS) {
260 log(LOG_CRIT, "EISA I/O port status error.");
268 * ICU reinitialize when ICU configuration has lost.
276 for(i=0;i<ICU_LEN;i++)
277 if(intr_handler[i] != isa_strayintr)
283 * Fill in default interrupt table (in case of spurious interrupt
284 * during configuration of kernel, setup interrupt control unit
292 for (i = 0; i < ICU_LEN; i++)
293 icu_unset(i, isa_strayintr);
301 /* initialize 8259's */
304 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
307 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
309 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
310 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
313 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
315 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
319 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
321 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
324 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
325 outb(IO_ICU1, 0x0a); /* default to IRR on read */
327 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
332 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
335 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
337 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
338 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
340 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
343 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
345 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
348 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
349 outb(IO_ICU2, 0x0a); /* default to IRR on read */
353 * Caught a stray interrupt, notify
356 isa_strayintr(void *vcookiep)
358 int intr = (void **)vcookiep - &intr_unit[0];
360 /* DON'T BOTHER FOR NOW! */
361 /* for some reason, we get bursts of intr #7, even if not enabled! */
363 * Well the reason you got bursts of intr #7 is because someone
364 * raised an interrupt line and dropped it before the 8259 could
365 * prioritize it. This is documented in the intel data book. This
366 * means you have BAD hardware! I have changed this so that only
367 * the first 5 get logged, then it quits logging them, and puts
368 * out a special message. rgrimes 3/25/1993
371 * XXX TODO print a different message for #7 if it is for a
372 * glitch. Glitches can be distinguished from real #7's by
373 * testing that the in-service bit is _not_ set. The test
374 * must be done before sending an EOI so it can't be done if
375 * we are using AUTO_EOI_1.
377 if (intrcnt[1 + intr] <= 5)
378 log(LOG_ERR, "stray irq %d\n", intr);
379 if (intrcnt[1 + intr] == 5)
381 "too many stray irq %d's; not logging any more\n", intr);
384 #if defined(FAST_HI) && defined(APIC_IO)
387 * This occurs if we mis-programmed the APIC and its vector is still
388 * pointing to the slow vector even when we thought we reprogrammed it
389 * to the high vector. This can occur when interrupts are improperly
390 * routed by the APIC. The unit data is opaque so we have to try to
391 * find it in the unit array.
394 isa_wrongintr(void *vcookiep)
398 for (intr = 0; intr < ICU_LEN*2; ++intr) {
399 if (intr_unit[intr] == vcookiep)
402 if (intr == ICU_LEN*2) {
403 log(LOG_ERR, "stray unknown irq (APIC misprogrammed)\n");
404 } else if (intrcnt[1 + intr] <= 5) {
405 log(LOG_ERR, "stray irq ~%d (APIC misprogrammed)\n", intr);
406 } else if (intrcnt[1 + intr] == 6) {
408 "too many stray irq ~%d's; not logging any more\n", intr);
416 * Return a bitmap of the current interrupt requests. This is 8259-specific
417 * and is only suitable for use at probe time.
420 isa_irq_pending(void)
427 return ((irr2 << 8) | irr1);
432 update_intr_masks(void)
437 for (intr=0; intr < ICU_LEN; intr ++) {
439 /* no 8259 SLAVE to ignore */
441 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
443 maskptr = intr_info[intr].maskp;
446 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
448 if (mask != intr_info[intr].mask) {
450 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
451 intr, intr_info[intr].mask, mask, maskptr);
453 intr_info[intr].mask = mask;
462 update_intrname(int intr, char *name)
466 int name_index, off, strayintr;
469 * Initialise strings for bitbucket and stray interrupt counters.
470 * These have statically allocated indices 0 and 1 through ICU_LEN.
472 if (intrnames[0] == '\0') {
473 off = sprintf(intrnames, "???") + 1;
474 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
475 off += sprintf(intrnames + off, "stray irq%d",
481 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
485 * Search for `buf' in `intrnames'. In the usual case when it is
486 * not found, append it to the end if there is enough space (the \0
487 * terminator for the previous string, if any, becomes a separator).
489 for (cp = intrnames, name_index = 0;
490 cp != eintrnames && name_index < NR_INTRNAMES;
491 cp += strlen(cp) + 1, name_index++) {
493 if (strlen(buf) >= eintrnames - cp)
498 if (strcmp(cp, buf) == 0)
503 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
507 intr_countp[intr] = &intrcnt[name_index];
511 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
512 * code ignores it for normal interrupts.
515 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
517 #if defined(FAST_HI) && defined(APIC_IO)
518 int select; /* the select register is 8 bits */
520 u_int32_t value; /* the window register is 32 bits */
523 u_int mask = (maskptr ? *maskptr : 0);
526 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
528 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
531 if (intr_handler[intr] != isa_strayintr)
535 cpu_disable_intr(); /* YYY */
536 intr_handler[intr] = handler;
537 intr_unit[intr] = arg;
538 intr_info[intr].maskp = maskptr;
539 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
541 /* YYY fast ints supported and mp protected but ... */
544 #if defined(FAST_HI) && defined(APIC_IO)
545 if (flags & INTR_FAST) {
547 * Install a spurious interrupt in the low space in case
548 * the IO apic is not properly reprogrammed.
550 vector = TPR_SLOW_INTS + intr;
551 setidt(vector, isa_wrongintr,
552 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
553 vector = TPR_FAST_INTS + intr;
554 setidt(vector, fastintr[intr],
555 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
557 vector = TPR_SLOW_INTS + intr;
558 #ifdef APIC_INTR_REORDER
559 #ifdef APIC_INTR_HIGHPRI_CLOCK
560 /* XXX: Hack (kludge?) for more accurate clock. */
561 if (intr == apic_8254_intr || intr == 8) {
562 vector = TPR_FAST_INTS + intr;
566 setidt(vector, slowintr[intr],
567 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
569 #ifdef APIC_INTR_REORDER
570 set_lapic_isrloc(intr, vector);
573 * Reprogram the vector in the IO APIC.
575 * XXX EOI/mask a pending (stray) interrupt on the old vector?
577 if (int_to_apicintpin[intr].ioapic >= 0) {
578 select = int_to_apicintpin[intr].redirindex;
579 value = io_apic_read(int_to_apicintpin[intr].ioapic,
580 select) & ~IOART_INTVEC;
581 io_apic_write(int_to_apicintpin[intr].ioapic,
582 select, value | vector);
585 setidt(ICU_OFFSET + intr,
586 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
587 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
588 #endif /* FAST_HI && APIC_IO */
595 icu_unset(intr, handler)
601 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) {
602 printf("icu_unset: invalid handler %d %p/%p\n", intr, handler,
603 (((u_int)intr >= ICU_LEN) ? (void *)-1 : intr_handler[intr]));
609 cpu_disable_intr(); /* YYY */
610 intr_countp[intr] = &intrcnt[1 + intr];
611 intr_handler[intr] = isa_strayintr;
612 intr_info[intr].maskp = NULL;
613 intr_info[intr].mask = HWI_MASK | SWI_MASK;
614 intr_unit[intr] = &intr_unit[intr];
616 /* XXX how do I re-create dvp here? */
617 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
618 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
620 #ifdef APIC_INTR_REORDER
621 set_lapic_isrloc(intr, ICU_OFFSET + intr);
623 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
624 GSEL(GCODE_SEL, SEL_KPL));
631 /* The following notice applies beyond this point in the file */
634 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
635 * All rights reserved.
637 * Redistribution and use in source and binary forms, with or without
638 * modification, are permitted provided that the following conditions
640 * 1. Redistributions of source code must retain the above copyright
641 * notice unmodified, this list of conditions, and the following
643 * 2. Redistributions in binary form must reproduce the above copyright
644 * notice, this list of conditions and the following disclaimer in the
645 * documentation and/or other materials provided with the distribution.
647 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
648 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
649 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
650 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
651 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
652 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
653 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
654 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
655 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
656 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
658 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
662 typedef struct intrec {
673 static intrec *intreclist_head[ICU_LEN];
676 * The interrupt multiplexer calls each of the handlers in turn. The
677 * ipl is initially quite low. It is raised as necessary for each call
678 * and lowered after the call. Thus out of order handling is possible
679 * even for interrupts of the same type. This is probably no more
680 * harmful than out of order handling in general (not harmful except
681 * for real time response which we don't support anyway).
690 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
691 oldspl = splq(p->mask);
692 p->handler(p->argument);
698 find_idesc(unsigned *maskptr, int irq)
700 intrec *p = intreclist_head[irq];
702 while (p && p->maskptr != maskptr)
709 find_pred(intrec *idesc, int irq)
711 intrec **pp = &intreclist_head[irq];
724 * Both the low level handler and the shared interrupt multiplexer
725 * block out further interrupts as set in the handlers "mask", while
726 * the handler is running. In fact *maskptr should be used for this
727 * purpose, but since this requires one more pointer dereference on
728 * each interrupt, we rather bother update "mask" whenever *maskptr
729 * changes. The function "update_masks" should be called **after**
730 * all manipulation of the linked list of interrupt handlers hung
731 * off of intrdec_head[irq] is complete, since the chain of handlers
732 * will both determine the *maskptr values and the instances of mask
733 * that are fixed. This function should be called with the irq for
734 * which a new handler has been add blocked, since the masks may not
735 * yet know about the use of this irq for a device of a certain class.
739 update_mux_masks(void)
742 for (irq = 0; irq < ICU_LEN; irq++) {
743 intrec *idesc = intreclist_head[irq];
744 while (idesc != NULL) {
745 if (idesc->maskptr != NULL) {
746 /* our copy of *maskptr may be stale, refresh */
747 idesc->mask = *idesc->maskptr;
755 update_masks(intrmask_t *maskptr, int irq)
757 intrmask_t mask = 1 << irq;
762 if (find_idesc(maskptr, irq) == NULL) {
763 /* no reference to this maskptr was found in this irq's chain */
766 /* a reference to this maskptr was found in this irq's chain */
769 /* we need to update all values in the intr_mask[irq] array */
771 /* update mask in chains of the interrupt multiplex handler as well */
776 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
777 * and install a shared interrupt multiplex handler, if necessary. Install
778 * an interrupt thread for each interrupt (though FAST interrupts will not
779 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
780 * check relative thread priorities for us as long as we properly pass through
783 * The interrupt thread has already been put on the run queue, so if we cannot
784 * preempt we should force a reschedule.
786 * YYY needs work. At the moment the handler is run inside a critical
787 * section so only the preemption cpl check is used.
790 cpu_intr_preempt(struct thread *td, int critpri)
792 struct md_intr_info *info = td->td_info.intdata;
794 if ((curthread->td_cpl & (1 << info->irq)) == 0)
795 lwkt_preempt(td, critpri);
801 add_intrdesc(intrec *idesc)
803 int irq = idesc->intr;
807 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
808 * handles interrupt thread scheduling for NORMAL interrupts. It
809 * will never get called for fast interrupts. On the otherhand,
810 * the handler this code installs in intr_handler[] for a NORMAL
811 * interrupt is not used by the *vector.s code, so we need this
812 * temporary hack to run normal interrupts as interrupt threads.
815 if (intr_info[irq].mihandler_installed == 0) {
818 intr_info[irq].mihandler_installed = 1;
819 intr_info[irq].irq = irq;
820 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
821 td->td_info.intdata = &intr_info[irq];
822 td->td_preemptable = cpu_intr_preempt;
823 printf("installed MI handler for int %d\n", irq);
826 head = intreclist_head[irq];
829 /* first handler for this irq, just install it */
830 if (icu_setup(irq, idesc->handler, idesc->argument,
831 idesc->maskptr, idesc->flags) != 0)
834 update_intrname(irq, idesc->name);
836 intreclist_head[irq] = idesc;
838 if ((idesc->flags & INTR_EXCL) != 0
839 || (head->flags & INTR_EXCL) != 0) {
841 * can't append new handler, if either list head or
842 * new handler do not allow interrupts to be shared
845 printf("\tdevice combination doesn't support "
846 "shared irq%d\n", irq);
849 if (head->next == NULL) {
851 * second handler for this irq, replace device driver's
852 * handler by shared interrupt multiplexer function
854 icu_unset(irq, head->handler);
855 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
858 printf("\tusing shared irq%d.\n", irq);
859 update_intrname(irq, "mux");
861 /* just append to the end of the chain */
862 while (head->next != NULL)
866 update_masks(idesc->maskptr, irq);
871 * Create and activate an interrupt handler descriptor data structure.
873 * The dev_instance pointer is required for resource management, and will
874 * only be passed through to resource_claim().
876 * There will be functions that derive a driver and unit name from a
877 * dev_instance variable, and those functions will be used to maintain the
878 * interrupt counter label array referenced by systat and vmstat to report
879 * device interrupt rates (->update_intrlabels).
881 * Add the interrupt handler descriptor data structure created by an
882 * earlier call of create_intr() to the linked list for its irq and
883 * adjust the interrupt masks if necessary.
885 * WARNING: This is an internal function and not to be used by device
886 * drivers. It is subject to change without notice.
890 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
891 intrmask_t *maskptr, int flags)
897 if (ICU_LEN > 8 * sizeof *maskptr) {
898 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
899 ICU_LEN, 8 * sizeof *maskptr);
902 if ((unsigned)irq >= ICU_LEN) {
903 printf("create_intr: requested irq%d too high, limit is %d\n",
908 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
911 bzero(idesc, sizeof *idesc);
915 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
916 if (idesc->name == NULL) {
917 free(idesc, M_DEVBUF);
920 strcpy(idesc->name, name);
922 idesc->handler = handler;
923 idesc->argument = arg;
924 idesc->maskptr = maskptr;
926 idesc->flags = flags;
929 oldspl = splq(1 << irq);
931 /* add irq to class selected by maskptr */
932 errcode = add_intrdesc(idesc);
937 printf("\tintr_connect(irq%d) failed, result=%d\n",
939 free(idesc->name, M_DEVBUF);
940 free(idesc, M_DEVBUF);
948 * Deactivate and remove the interrupt handler descriptor data connected
949 * created by an earlier call of intr_connect() from the linked list and
950 * adjust theinterrupt masks if necessary.
952 * Return the memory held by the interrupt handler descriptor data structure
953 * to the system. Make sure, the handler is not actively used anymore, before.
957 inthand_remove(intrec *idesc)
959 intrec **hook, *head;
969 /* find pointer that keeps the reference to this interrupt descriptor */
970 hook = find_pred(idesc, irq);
974 /* make copy of original list head, the line after may overwrite it */
975 head = intreclist_head[irq];
977 /* unlink: make predecessor point to idesc->next instead of to idesc */
980 /* now check whether the element we removed was the list head */
983 oldspl = splq(1 << irq);
985 /* check whether the new list head is the only element on list */
986 head = intreclist_head[irq];
988 icu_unset(irq, intr_mux);
989 if (head->next != NULL) {
990 /* install the multiplex handler with new list head as argument */
991 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
993 update_intrname(irq, NULL);
995 /* install the one remaining handler for this irq */
996 errcode = icu_setup(irq, head->handler,
998 head->maskptr, head->flags);
1000 update_intrname(irq, head->name);
1003 /* revert to old handler, eg: strayintr */
1004 icu_unset(irq, idesc->handler);
1008 update_masks(idesc->maskptr, irq);
1009 free(idesc, M_DEVBUF);
1016 * This function is called by an interrupt thread when it has completed
1017 * processing a loop. We re-enable itnerrupts and interlock with
1020 * See kern/kern_intr.c for more information.
1023 ithread_done(int irq)
1025 struct mdglobaldata *gd = mdcpu;
1026 int mask = 1 << irq;
1028 KKASSERT(curthread->td_pri >= TDPRI_CRIT);
1029 lwkt_deschedule_self();
1031 if (gd->gd_ipending & mask) {
1032 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
1034 lwkt_schedule_self();
1042 * forward_fast_remote()
1044 * This function is called from the receiving end of an IPIQ when a
1045 * remote cpu wishes to forward a fast interrupt to us. All we have to
1046 * do is set the interrupt pending and let the IPI's doreti deal with it.
1049 forward_fastint_remote(void *arg)
1052 struct mdglobaldata *gd = mdcpu;
1054 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
1055 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);