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.16 2004/02/11 18:34:40 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>
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)
530 if (intr_handler[intr] != isa_strayintr)
534 cpu_disable_intr(); /* YYY */
535 intr_handler[intr] = handler;
536 intr_unit[intr] = arg;
537 intr_info[intr].maskp = maskptr;
538 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
540 /* YYY fast ints supported and mp protected but ... */
543 #if defined(FAST_HI) && defined(APIC_IO)
544 if (flags & INTR_FAST) {
546 * Install a spurious interrupt in the low space in case
547 * the IO apic is not properly reprogrammed.
549 vector = TPR_SLOW_INTS + intr;
550 setidt(vector, isa_wrongintr,
551 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
552 vector = TPR_FAST_INTS + intr;
553 setidt(vector, fastintr[intr],
554 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
556 vector = TPR_SLOW_INTS + intr;
557 #ifdef APIC_INTR_REORDER
558 #ifdef APIC_INTR_HIGHPRI_CLOCK
559 /* XXX: Hack (kludge?) for more accurate clock. */
560 if (intr == apic_8254_intr || intr == 8) {
561 vector = TPR_FAST_INTS + intr;
565 setidt(vector, slowintr[intr],
566 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
568 #ifdef APIC_INTR_REORDER
569 set_lapic_isrloc(intr, vector);
572 * Reprogram the vector in the IO APIC.
574 * XXX EOI/mask a pending (stray) interrupt on the old vector?
576 if (int_to_apicintpin[intr].ioapic >= 0) {
577 select = int_to_apicintpin[intr].redirindex;
578 value = io_apic_read(int_to_apicintpin[intr].ioapic,
579 select) & ~IOART_INTVEC;
580 io_apic_write(int_to_apicintpin[intr].ioapic,
581 select, value | vector);
584 setidt(ICU_OFFSET + intr,
585 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
586 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
587 #endif /* FAST_HI && APIC_IO */
594 icu_unset(intr, handler)
600 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) {
601 printf("icu_unset: invalid handler %d %p/%p\n", intr, handler,
602 (((u_int)intr >= ICU_LEN) ? (void *)-1 : intr_handler[intr]));
608 cpu_disable_intr(); /* YYY */
609 intr_countp[intr] = &intrcnt[1 + intr];
610 intr_handler[intr] = isa_strayintr;
611 intr_info[intr].maskp = NULL;
612 intr_info[intr].mask = HWI_MASK | SWI_MASK;
613 intr_unit[intr] = &intr_unit[intr];
615 /* XXX how do I re-create dvp here? */
616 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
617 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
619 #ifdef APIC_INTR_REORDER
620 set_lapic_isrloc(intr, ICU_OFFSET + intr);
622 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
623 GSEL(GCODE_SEL, SEL_KPL));
630 /* The following notice applies beyond this point in the file */
633 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
634 * All rights reserved.
636 * Redistribution and use in source and binary forms, with or without
637 * modification, are permitted provided that the following conditions
639 * 1. Redistributions of source code must retain the above copyright
640 * notice unmodified, this list of conditions, and the following
642 * 2. Redistributions in binary form must reproduce the above copyright
643 * notice, this list of conditions and the following disclaimer in the
644 * documentation and/or other materials provided with the distribution.
646 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
647 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
648 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
649 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
650 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
651 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
652 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
653 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
654 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
655 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
657 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
661 typedef struct intrec {
672 static intrec *intreclist_head[ICU_LEN];
675 * The interrupt multiplexer calls each of the handlers in turn. The
676 * ipl is initially quite low. It is raised as necessary for each call
677 * and lowered after the call. Thus out of order handling is possible
678 * even for interrupts of the same type. This is probably no more
679 * harmful than out of order handling in general (not harmful except
680 * for real time response which we don't support anyway).
689 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
690 oldspl = splq(p->mask);
691 p->handler(p->argument);
697 find_idesc(unsigned *maskptr, int irq)
699 intrec *p = intreclist_head[irq];
701 while (p && p->maskptr != maskptr)
708 find_pred(intrec *idesc, int irq)
710 intrec **pp = &intreclist_head[irq];
723 * Both the low level handler and the shared interrupt multiplexer
724 * block out further interrupts as set in the handlers "mask", while
725 * the handler is running. In fact *maskptr should be used for this
726 * purpose, but since this requires one more pointer dereference on
727 * each interrupt, we rather bother update "mask" whenever *maskptr
728 * changes. The function "update_masks" should be called **after**
729 * all manipulation of the linked list of interrupt handlers hung
730 * off of intrdec_head[irq] is complete, since the chain of handlers
731 * will both determine the *maskptr values and the instances of mask
732 * that are fixed. This function should be called with the irq for
733 * which a new handler has been add blocked, since the masks may not
734 * yet know about the use of this irq for a device of a certain class.
738 update_mux_masks(void)
741 for (irq = 0; irq < ICU_LEN; irq++) {
742 intrec *idesc = intreclist_head[irq];
743 while (idesc != NULL) {
744 if (idesc->maskptr != NULL) {
745 /* our copy of *maskptr may be stale, refresh */
746 idesc->mask = *idesc->maskptr;
754 update_masks(intrmask_t *maskptr, int irq)
756 intrmask_t mask = 1 << irq;
761 if (find_idesc(maskptr, irq) == NULL) {
762 /* no reference to this maskptr was found in this irq's chain */
765 /* a reference to this maskptr was found in this irq's chain */
768 /* we need to update all values in the intr_mask[irq] array */
770 /* update mask in chains of the interrupt multiplex handler as well */
775 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
776 * and install a shared interrupt multiplex handler, if necessary. Install
777 * an interrupt thread for each interrupt (though FAST interrupts will not
778 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
779 * check relative thread priorities for us as long as we properly pass through
782 * The interrupt thread has already been put on the run queue, so if we cannot
783 * preempt we should force a reschedule.
785 * YYY needs work. At the moment the handler is run inside a critical
786 * section so only the preemption cpl check is used.
789 cpu_intr_preempt(struct thread *td, int critpri)
791 struct md_intr_info *info = td->td_info.intdata;
793 if ((curthread->td_cpl & (1 << info->irq)) == 0)
794 lwkt_preempt(td, critpri);
800 add_intrdesc(intrec *idesc)
802 int irq = idesc->intr;
806 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
807 * handles interrupt thread scheduling for NORMAL interrupts. It
808 * will never get called for fast interrupts. On the otherhand,
809 * the handler this code installs in intr_handler[] for a NORMAL
810 * interrupt is not used by the *vector.s code, so we need this
811 * temporary hack to run normal interrupts as interrupt threads.
814 if (intr_info[irq].mihandler_installed == 0) {
817 intr_info[irq].mihandler_installed = 1;
818 intr_info[irq].irq = irq;
819 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
820 td->td_info.intdata = &intr_info[irq];
821 td->td_preemptable = cpu_intr_preempt;
822 printf("installed MI handler for int %d\n", irq);
825 head = intreclist_head[irq];
828 /* first handler for this irq, just install it */
829 if (icu_setup(irq, idesc->handler, idesc->argument,
830 idesc->maskptr, idesc->flags) != 0)
833 update_intrname(irq, idesc->name);
835 intreclist_head[irq] = idesc;
837 if ((idesc->flags & INTR_EXCL) != 0
838 || (head->flags & INTR_EXCL) != 0) {
840 * can't append new handler, if either list head or
841 * new handler do not allow interrupts to be shared
844 printf("\tdevice combination doesn't support "
845 "shared irq%d\n", irq);
848 if (head->next == NULL) {
850 * second handler for this irq, replace device driver's
851 * handler by shared interrupt multiplexer function
853 icu_unset(irq, head->handler);
854 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
857 printf("\tusing shared irq%d.\n", irq);
858 update_intrname(irq, "mux");
860 /* just append to the end of the chain */
861 while (head->next != NULL)
865 update_masks(idesc->maskptr, irq);
870 * Create and activate an interrupt handler descriptor data structure.
872 * The dev_instance pointer is required for resource management, and will
873 * only be passed through to resource_claim().
875 * There will be functions that derive a driver and unit name from a
876 * dev_instance variable, and those functions will be used to maintain the
877 * interrupt counter label array referenced by systat and vmstat to report
878 * device interrupt rates (->update_intrlabels).
880 * Add the interrupt handler descriptor data structure created by an
881 * earlier call of create_intr() to the linked list for its irq and
882 * adjust the interrupt masks if necessary.
884 * WARNING: This is an internal function and not to be used by device
885 * drivers. It is subject to change without notice.
889 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
890 intrmask_t *maskptr, int flags)
896 if (ICU_LEN > 8 * sizeof *maskptr) {
897 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
898 ICU_LEN, 8 * sizeof *maskptr);
901 if ((unsigned)irq >= ICU_LEN) {
902 printf("create_intr: requested irq%d too high, limit is %d\n",
907 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
910 bzero(idesc, sizeof *idesc);
914 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
915 if (idesc->name == NULL) {
916 free(idesc, M_DEVBUF);
919 strcpy(idesc->name, name);
921 idesc->handler = handler;
922 idesc->argument = arg;
923 idesc->maskptr = maskptr;
925 idesc->flags = flags;
928 oldspl = splq(1 << irq);
930 /* add irq to class selected by maskptr */
931 errcode = add_intrdesc(idesc);
936 printf("\tintr_connect(irq%d) failed, result=%d\n",
938 free(idesc->name, M_DEVBUF);
939 free(idesc, M_DEVBUF);
947 * Deactivate and remove the interrupt handler descriptor data connected
948 * created by an earlier call of intr_connect() from the linked list and
949 * adjust theinterrupt masks if necessary.
951 * Return the memory held by the interrupt handler descriptor data structure
952 * to the system. Make sure, the handler is not actively used anymore, before.
956 inthand_remove(intrec *idesc)
958 intrec **hook, *head;
968 /* find pointer that keeps the reference to this interrupt descriptor */
969 hook = find_pred(idesc, irq);
973 /* make copy of original list head, the line after may overwrite it */
974 head = intreclist_head[irq];
976 /* unlink: make predecessor point to idesc->next instead of to idesc */
979 /* now check whether the element we removed was the list head */
982 oldspl = splq(1 << irq);
984 /* check whether the new list head is the only element on list */
985 head = intreclist_head[irq];
987 icu_unset(irq, intr_mux);
988 if (head->next != NULL) {
989 /* install the multiplex handler with new list head as argument */
990 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
992 update_intrname(irq, NULL);
994 /* install the one remaining handler for this irq */
995 errcode = icu_setup(irq, head->handler,
997 head->maskptr, head->flags);
999 update_intrname(irq, head->name);
1002 /* revert to old handler, eg: strayintr */
1003 icu_unset(irq, idesc->handler);
1007 update_masks(idesc->maskptr, irq);
1008 free(idesc, M_DEVBUF);
1015 * This function is called by an interrupt thread when it has completed
1016 * processing a loop. We re-enable itnerrupts and interlock with
1019 * See kern/kern_intr.c for more information.
1022 ithread_done(int irq)
1024 struct mdglobaldata *gd = mdcpu;
1025 int mask = 1 << irq;
1027 KKASSERT(curthread->td_pri >= TDPRI_CRIT);
1028 lwkt_deschedule_self();
1030 if (gd->gd_ipending & mask) {
1031 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
1033 lwkt_schedule_self();
1041 * forward_fast_remote()
1043 * This function is called from the receiving end of an IPIQ when a
1044 * remote cpu wishes to forward a fast interrupt to us. All we have to
1045 * do is set the interrupt pending and let the IPI's doreti deal with it.
1048 forward_fastint_remote(void *arg)
1051 struct mdglobaldata *gd = mdcpu;
1053 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
1054 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);