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.7 2003/07/08 06:27:27 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.
47 #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 <i386/isa/isa.h>
79 #include <i386/isa/icu.h>
82 #include <isa/isavar.h>
84 #include <i386/isa/intr_machdep.h>
85 #include <sys/interrupt.h>
87 #include <machine/clock.h>
92 #include <i386/isa/mca_machdep.h>
95 /* XXX should be in suitable include files */
97 #define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
100 #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
101 #define ICU_SLAVEID 2
106 * This is to accommodate "mixed-mode" programming for
107 * motherboards that don't connect the 8254 to the IO APIC.
112 #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
114 static inthand2_t isa_strayintr;
116 void *intr_unit[ICU_LEN*2];
117 u_long *intr_countp[ICU_LEN*2];
118 inthand2_t *intr_handler[ICU_LEN*2] = {
119 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
120 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
121 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
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,
129 static struct md_intr_info {
132 int mihandler_installed;
134 } intr_info[ICU_LEN*2];
136 static inthand_t *fastintr[ICU_LEN] = {
137 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
138 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
139 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
140 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
141 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
142 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
143 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
144 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
146 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
147 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
148 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
149 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
153 unpendhand_t *fastunpend[ICU_LEN] = {
154 IDTVEC(fastunpend0), IDTVEC(fastunpend1),
155 IDTVEC(fastunpend2), IDTVEC(fastunpend3),
156 IDTVEC(fastunpend4), IDTVEC(fastunpend5),
157 IDTVEC(fastunpend6), IDTVEC(fastunpend7),
158 IDTVEC(fastunpend8), IDTVEC(fastunpend9),
159 IDTVEC(fastunpend10), IDTVEC(fastunpend11),
160 IDTVEC(fastunpend12), IDTVEC(fastunpend13),
161 IDTVEC(fastunpend14), IDTVEC(fastunpend15),
163 IDTVEC(fastunpend16), IDTVEC(fastunpend17),
164 IDTVEC(fastunpend18), IDTVEC(fastunpend19),
165 IDTVEC(fastunpend20), IDTVEC(fastunpend21),
166 IDTVEC(fastunpend22), IDTVEC(fastunpend23),
170 static inthand_t *slowintr[ICU_LEN] = {
171 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
172 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
173 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
174 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
176 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
177 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
182 #define NMI_PARITY 0x04
183 #define NMI_EPARITY 0x02
185 #define NMI_PARITY (1 << 7)
186 #define NMI_IOCHAN (1 << 6)
187 #define ENMI_WATCHDOG (1 << 7)
188 #define ENMI_BUSTIMER (1 << 6)
189 #define ENMI_IOSTATUS (1 << 5)
193 * Handle a NMI, possibly a machine check.
194 * return true to panic system, false to ignore.
202 int port = inb(0x33);
204 log(LOG_CRIT, "NMI PC98 port = %x\n", port);
205 if (epson_machine_id == 0x20)
206 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
207 if (port & NMI_PARITY) {
208 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure.");
210 } else if (port & NMI_EPARITY) {
211 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure.");
214 log(LOG_CRIT, "\nNMI Resume ??\n");
217 int isa_port = inb(0x61);
218 int eisa_port = inb(0x461);
220 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
222 if (MCA_system && mca_bus_nmi())
226 if (isa_port & NMI_PARITY) {
227 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
231 if (isa_port & NMI_IOCHAN) {
232 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
237 * On a real EISA machine, this will never happen. However it can
238 * happen on ISA machines which implement XT style floating point
239 * error handling (very rare). Save them from a meaningless panic.
241 if (eisa_port == 0xff)
244 if (eisa_port & ENMI_WATCHDOG) {
245 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
249 if (eisa_port & ENMI_BUSTIMER) {
250 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
254 if (eisa_port & ENMI_IOSTATUS) {
255 log(LOG_CRIT, "EISA I/O port status error.");
263 * Fill in default interrupt table (in case of spuruious interrupt
264 * during configuration of kernel, setup interrupt control unit
272 for (i = 0; i < ICU_LEN; i++)
273 icu_unset(i, (inthand2_t *)NULL);
275 /* initialize 8259's */
278 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
281 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
283 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
284 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
287 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
289 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
293 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
295 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
298 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
299 outb(IO_ICU1, 0x0a); /* default to IRR on read */
301 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
306 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
309 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
311 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
312 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
314 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
317 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
319 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
322 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
323 outb(IO_ICU2, 0x0a); /* default to IRR on read */
327 * Caught a stray interrupt, notify
330 isa_strayintr(void *vcookiep)
332 int intr = (void **)vcookiep - &intr_unit[0];
334 /* DON'T BOTHER FOR NOW! */
335 /* for some reason, we get bursts of intr #7, even if not enabled! */
337 * Well the reason you got bursts of intr #7 is because someone
338 * raised an interrupt line and dropped it before the 8259 could
339 * prioritize it. This is documented in the intel data book. This
340 * means you have BAD hardware! I have changed this so that only
341 * the first 5 get logged, then it quits logging them, and puts
342 * out a special message. rgrimes 3/25/1993
345 * XXX TODO print a different message for #7 if it is for a
346 * glitch. Glitches can be distinguished from real #7's by
347 * testing that the in-service bit is _not_ set. The test
348 * must be done before sending an EOI so it can't be done if
349 * we are using AUTO_EOI_1.
351 printf("STRAY %d\n", intr);
352 if (intrcnt[1 + intr] <= 5)
353 log(LOG_ERR, "stray irq %d\n", intr);
354 if (intrcnt[1 + intr] == 5)
356 "too many stray irq %d's; not logging any more\n", intr);
361 * Return a bitmap of the current interrupt requests. This is 8259-specific
362 * and is only suitable for use at probe time.
372 return ((irr2 << 8) | irr1);
377 update_intr_masks(void)
382 for (intr=0; intr < ICU_LEN; intr ++) {
384 /* no 8259 SLAVE to ignore */
386 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
388 maskptr = intr_info[intr].maskp;
391 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
393 if (mask != intr_info[intr].mask) {
395 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
396 intr, intr_info[intr].mask, mask, maskptr);
398 intr_info[intr].mask = mask;
407 update_intrname(int intr, char *name)
411 int name_index, off, strayintr;
414 * Initialise strings for bitbucket and stray interrupt counters.
415 * These have statically allocated indices 0 and 1 through ICU_LEN.
417 if (intrnames[0] == '\0') {
418 off = sprintf(intrnames, "???") + 1;
419 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
420 off += sprintf(intrnames + off, "stray irq%d",
426 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
430 * Search for `buf' in `intrnames'. In the usual case when it is
431 * not found, append it to the end if there is enough space (the \0
432 * terminator for the previous string, if any, becomes a separator).
434 for (cp = intrnames, name_index = 0;
435 cp != eintrnames && name_index < NR_INTRNAMES;
436 cp += strlen(cp) + 1, name_index++) {
438 if (strlen(buf) >= eintrnames - cp)
443 if (strcmp(cp, buf) == 0)
448 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
452 intr_countp[intr] = &intrcnt[name_index];
456 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
457 * code ignores it for normal interrupts.
460 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
463 int select; /* the select register is 8 bits */
465 u_int32_t value; /* the window register is 32 bits */
468 u_int mask = (maskptr ? *maskptr : 0);
471 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
473 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
475 if (intr_handler[intr] != isa_strayintr)
479 cpu_disable_intr(); /* YYY */
480 intr_handler[intr] = handler;
481 intr_unit[intr] = arg;
482 intr_info[intr].maskp = maskptr;
483 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
485 /* YYY fast ints supported and mp protected but ... */
489 if (flags & INTR_FAST) {
490 vector = TPR_FAST_INTS + intr;
491 setidt(vector, fastintr[intr],
492 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
494 vector = TPR_SLOW_INTS + intr;
495 #ifdef APIC_INTR_REORDER
496 #ifdef APIC_INTR_HIGHPRI_CLOCK
497 /* XXX: Hack (kludge?) for more accurate clock. */
498 if (intr == apic_8254_intr || intr == 8) {
499 vector = TPR_FAST_INTS + intr;
503 setidt(vector, slowintr[intr],
504 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
506 #ifdef APIC_INTR_REORDER
507 set_lapic_isrloc(intr, vector);
510 * Reprogram the vector in the IO APIC.
512 if (int_to_apicintpin[intr].ioapic >= 0) {
513 select = int_to_apicintpin[intr].redirindex;
514 value = io_apic_read(int_to_apicintpin[intr].ioapic,
515 select) & ~IOART_INTVEC;
516 io_apic_write(int_to_apicintpin[intr].ioapic,
517 select, value | vector);
520 setidt(ICU_OFFSET + intr,
521 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
522 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
530 icu_unset(intr, handler)
536 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
541 cpu_disable_intr(); /* YYY */
542 intr_countp[intr] = &intrcnt[1 + intr];
543 intr_handler[intr] = isa_strayintr;
544 intr_info[intr].maskp = NULL;
545 intr_info[intr].mask = HWI_MASK | SWI_MASK;
546 intr_unit[intr] = &intr_unit[intr];
548 /* XXX how do I re-create dvp here? */
549 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
550 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
552 #ifdef APIC_INTR_REORDER
553 set_lapic_isrloc(intr, ICU_OFFSET + intr);
555 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
556 GSEL(GCODE_SEL, SEL_KPL));
563 /* The following notice applies beyond this point in the file */
566 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
567 * All rights reserved.
569 * Redistribution and use in source and binary forms, with or without
570 * modification, are permitted provided that the following conditions
572 * 1. Redistributions of source code must retain the above copyright
573 * notice unmodified, this list of conditions, and the following
575 * 2. Redistributions in binary form must reproduce the above copyright
576 * notice, this list of conditions and the following disclaimer in the
577 * documentation and/or other materials provided with the distribution.
579 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
580 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
581 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
582 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
583 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
584 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
585 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
586 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
587 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
588 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
590 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
594 typedef struct intrec {
605 static intrec *intreclist_head[ICU_LEN];
608 * The interrupt multiplexer calls each of the handlers in turn. The
609 * ipl is initially quite low. It is raised as necessary for each call
610 * and lowered after the call. Thus out of order handling is possible
611 * even for interrupts of the same type. This is probably no more
612 * harmful than out of order handling in general (not harmful except
613 * for real time response which we don't support anyway).
622 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
623 oldspl = splq(p->mask);
624 p->handler(p->argument);
630 find_idesc(unsigned *maskptr, int irq)
632 intrec *p = intreclist_head[irq];
634 while (p && p->maskptr != maskptr)
641 find_pred(intrec *idesc, int irq)
643 intrec **pp = &intreclist_head[irq];
656 * Both the low level handler and the shared interrupt multiplexer
657 * block out further interrupts as set in the handlers "mask", while
658 * the handler is running. In fact *maskptr should be used for this
659 * purpose, but since this requires one more pointer dereference on
660 * each interrupt, we rather bother update "mask" whenever *maskptr
661 * changes. The function "update_masks" should be called **after**
662 * all manipulation of the linked list of interrupt handlers hung
663 * off of intrdec_head[irq] is complete, since the chain of handlers
664 * will both determine the *maskptr values and the instances of mask
665 * that are fixed. This function should be called with the irq for
666 * which a new handler has been add blocked, since the masks may not
667 * yet know about the use of this irq for a device of a certain class.
671 update_mux_masks(void)
674 for (irq = 0; irq < ICU_LEN; irq++) {
675 intrec *idesc = intreclist_head[irq];
676 while (idesc != NULL) {
677 if (idesc->maskptr != NULL) {
678 /* our copy of *maskptr may be stale, refresh */
679 idesc->mask = *idesc->maskptr;
687 update_masks(intrmask_t *maskptr, int irq)
689 intrmask_t mask = 1 << irq;
694 if (find_idesc(maskptr, irq) == NULL) {
695 /* no reference to this maskptr was found in this irq's chain */
698 /* a reference to this maskptr was found in this irq's chain */
701 /* we need to update all values in the intr_mask[irq] array */
703 /* update mask in chains of the interrupt multiplex handler as well */
708 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
709 * and install a shared interrupt multiplex handler, if necessary. Install
710 * an interrupt thread for each interrupt (though FAST interrupts will not
711 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
712 * check relative thread priorities for us as long as we properly pass through
715 * YYY needs work. At the moment the handler is run inside a critical
716 * section so only the preemption cpl check is used.
719 cpu_intr_preempt(struct thread *td, int critpri)
721 struct md_intr_info *info = td->td_info.intdata;
723 if ((curthread->td_cpl & (1 << info->irq)) == 0)
724 lwkt_preempt(td, critpri);
728 add_intrdesc(intrec *idesc)
730 int irq = idesc->intr;
734 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
735 * handles interrupt thread scheduling for NORMAL interrupts. It
736 * will never get called for fast interrupts. On the otherhand,
737 * the handler this code installs in intr_handler[] for a NORMAL
738 * interrupt is not used by the *vector.s code, so we need this
739 * temporary hack to run normal interrupts as interrupt threads.
742 if (intr_info[irq].mihandler_installed == 0) {
745 intr_info[irq].mihandler_installed = 1;
746 intr_info[irq].irq = irq;
747 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
748 td->td_info.intdata = &intr_info[irq];
749 td->td_preemptable = cpu_intr_preempt;
750 printf("installed MI handler for int %d\n", irq);
753 head = intreclist_head[irq];
756 /* first handler for this irq, just install it */
757 if (icu_setup(irq, idesc->handler, idesc->argument,
758 idesc->maskptr, idesc->flags) != 0)
761 update_intrname(irq, idesc->name);
763 intreclist_head[irq] = idesc;
765 if ((idesc->flags & INTR_EXCL) != 0
766 || (head->flags & INTR_EXCL) != 0) {
768 * can't append new handler, if either list head or
769 * new handler do not allow interrupts to be shared
772 printf("\tdevice combination doesn't support "
773 "shared irq%d\n", irq);
776 if (head->next == NULL) {
778 * second handler for this irq, replace device driver's
779 * handler by shared interrupt multiplexer function
781 icu_unset(irq, head->handler);
782 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
785 printf("\tusing shared irq%d.\n", irq);
786 update_intrname(irq, "mux");
788 /* just append to the end of the chain */
789 while (head->next != NULL)
793 update_masks(idesc->maskptr, irq);
798 * Create and activate an interrupt handler descriptor data structure.
800 * The dev_instance pointer is required for resource management, and will
801 * only be passed through to resource_claim().
803 * There will be functions that derive a driver and unit name from a
804 * dev_instance variable, and those functions will be used to maintain the
805 * interrupt counter label array referenced by systat and vmstat to report
806 * device interrupt rates (->update_intrlabels).
808 * Add the interrupt handler descriptor data structure created by an
809 * earlier call of create_intr() to the linked list for its irq and
810 * adjust the interrupt masks if necessary.
812 * WARNING: This is an internal function and not to be used by device
813 * drivers. It is subject to change without notice.
817 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
818 intrmask_t *maskptr, int flags)
824 if (ICU_LEN > 8 * sizeof *maskptr) {
825 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
826 ICU_LEN, 8 * sizeof *maskptr);
829 if ((unsigned)irq >= ICU_LEN) {
830 printf("create_intr: requested irq%d too high, limit is %d\n",
835 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
838 bzero(idesc, sizeof *idesc);
842 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
843 if (idesc->name == NULL) {
844 free(idesc, M_DEVBUF);
847 strcpy(idesc->name, name);
849 idesc->handler = handler;
850 idesc->argument = arg;
851 idesc->maskptr = maskptr;
853 idesc->flags = flags;
856 oldspl = splq(1 << irq);
858 /* add irq to class selected by maskptr */
859 errcode = add_intrdesc(idesc);
864 printf("\tintr_connect(irq%d) failed, result=%d\n",
866 free(idesc->name, M_DEVBUF);
867 free(idesc, M_DEVBUF);
875 * Deactivate and remove the interrupt handler descriptor data connected
876 * created by an earlier call of intr_connect() from the linked list and
877 * adjust theinterrupt masks if necessary.
879 * Return the memory held by the interrupt handler descriptor data structure
880 * to the system. Make sure, the handler is not actively used anymore, before.
884 inthand_remove(intrec *idesc)
886 intrec **hook, *head;
896 /* find pointer that keeps the reference to this interrupt descriptor */
897 hook = find_pred(idesc, irq);
901 /* make copy of original list head, the line after may overwrite it */
902 head = intreclist_head[irq];
904 /* unlink: make predecessor point to idesc->next instead of to idesc */
907 /* now check whether the element we removed was the list head */
910 oldspl = splq(1 << irq);
912 /* check whether the new list head is the only element on list */
913 head = intreclist_head[irq];
915 icu_unset(irq, intr_mux);
916 if (head->next != NULL) {
917 /* install the multiplex handler with new list head as argument */
918 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
920 update_intrname(irq, NULL);
922 /* install the one remaining handler for this irq */
923 errcode = icu_setup(irq, head->handler,
925 head->maskptr, head->flags);
927 update_intrname(irq, head->name);
930 /* revert to old handler, eg: strayintr */
931 icu_unset(irq, idesc->handler);
935 update_masks(idesc->maskptr, irq);
936 free(idesc, M_DEVBUF);
943 * This function is called by an interrupt thread when it has completed
944 * processing a loop. We re-enable itnerrupts and interlock with
947 * See kern/kern_intr.c for more information.
950 ithread_done(int irq)
952 struct mdglobaldata *gd = mdcpu;
955 KKASSERT(curthread->td_pri >= TDPRI_CRIT);
956 lwkt_deschedule_self();
958 if (gd->gd_ipending & mask) {
959 atomic_clear_int(&gd->gd_ipending, mask);
961 lwkt_schedule_self();