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.3 2003/06/29 03:28:43 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/smp.h>
70 #include <machine/smptests.h> /** FAST_HI */
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 u_long *intr_countp[ICU_LEN];
115 inthand2_t *intr_handler[ICU_LEN];
116 u_int intr_mask[ICU_LEN];
117 int intr_mihandler_installed[ICU_LEN];
118 static u_int* intr_mptr[ICU_LEN];
119 void *intr_unit[ICU_LEN];
121 static inthand_t *fastintr[ICU_LEN] = {
122 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
123 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
124 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
125 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
126 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
127 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
128 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
129 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
131 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
132 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
133 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
134 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
138 unpendhand_t *fastunpend[ICU_LEN] = {
139 IDTVEC(fastunpend0), IDTVEC(fastunpend1),
140 IDTVEC(fastunpend2), IDTVEC(fastunpend3),
141 IDTVEC(fastunpend4), IDTVEC(fastunpend5),
142 IDTVEC(fastunpend6), IDTVEC(fastunpend7),
143 IDTVEC(fastunpend8), IDTVEC(fastunpend9),
144 IDTVEC(fastunpend10), IDTVEC(fastunpend11),
145 IDTVEC(fastunpend12), IDTVEC(fastunpend13),
146 IDTVEC(fastunpend14), IDTVEC(fastunpend15),
148 IDTVEC(fastunpend16), IDTVEC(fastunpend17),
149 IDTVEC(fastunpend18), IDTVEC(fastunpend19),
150 IDTVEC(fastunpend20), IDTVEC(fastunpend21),
151 IDTVEC(fastunpend22), IDTVEC(fastunpend23),
152 IDTVEC(fastunpend24), IDTVEC(fastunpend25),
153 IDTVEC(fastunpend26), IDTVEC(fastunpend27),
154 IDTVEC(fastunpend28), IDTVEC(fastunpend29),
155 IDTVEC(fastunpend30), IDTVEC(fastunpend31),
159 static inthand_t *slowintr[ICU_LEN] = {
160 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
161 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
162 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
163 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
165 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
166 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
170 static inthand2_t isa_strayintr;
173 #define NMI_PARITY 0x04
174 #define NMI_EPARITY 0x02
176 #define NMI_PARITY (1 << 7)
177 #define NMI_IOCHAN (1 << 6)
178 #define ENMI_WATCHDOG (1 << 7)
179 #define ENMI_BUSTIMER (1 << 6)
180 #define ENMI_IOSTATUS (1 << 5)
184 * Handle a NMI, possibly a machine check.
185 * return true to panic system, false to ignore.
193 int port = inb(0x33);
195 log(LOG_CRIT, "NMI PC98 port = %x\n", port);
196 if (epson_machine_id == 0x20)
197 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
198 if (port & NMI_PARITY) {
199 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure.");
201 } else if (port & NMI_EPARITY) {
202 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure.");
205 log(LOG_CRIT, "\nNMI Resume ??\n");
208 int isa_port = inb(0x61);
209 int eisa_port = inb(0x461);
211 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
213 if (MCA_system && mca_bus_nmi())
217 if (isa_port & NMI_PARITY) {
218 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
222 if (isa_port & NMI_IOCHAN) {
223 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
228 * On a real EISA machine, this will never happen. However it can
229 * happen on ISA machines which implement XT style floating point
230 * error handling (very rare). Save them from a meaningless panic.
232 if (eisa_port == 0xff)
235 if (eisa_port & ENMI_WATCHDOG) {
236 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
240 if (eisa_port & ENMI_BUSTIMER) {
241 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
245 if (eisa_port & ENMI_IOSTATUS) {
246 log(LOG_CRIT, "EISA I/O port status error.");
254 * Fill in default interrupt table (in case of spuruious interrupt
255 * during configuration of kernel, setup interrupt control unit
263 for (i = 0; i < ICU_LEN; i++)
264 icu_unset(i, (inthand2_t *)NULL);
266 /* initialize 8259's */
269 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
272 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
274 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
275 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
278 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
280 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
284 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
286 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
289 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
290 outb(IO_ICU1, 0x0a); /* default to IRR on read */
292 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
297 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
300 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
302 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
303 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
305 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
308 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
310 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
313 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
314 outb(IO_ICU2, 0x0a); /* default to IRR on read */
318 * Caught a stray interrupt, notify
321 isa_strayintr(vcookiep)
324 int intr = (void **)vcookiep - &intr_unit[0];
326 /* DON'T BOTHER FOR NOW! */
327 /* for some reason, we get bursts of intr #7, even if not enabled! */
329 * Well the reason you got bursts of intr #7 is because someone
330 * raised an interrupt line and dropped it before the 8259 could
331 * prioritize it. This is documented in the intel data book. This
332 * means you have BAD hardware! I have changed this so that only
333 * the first 5 get logged, then it quits logging them, and puts
334 * out a special message. rgrimes 3/25/1993
337 * XXX TODO print a different message for #7 if it is for a
338 * glitch. Glitches can be distinguished from real #7's by
339 * testing that the in-service bit is _not_ set. The test
340 * must be done before sending an EOI so it can't be done if
341 * we are using AUTO_EOI_1.
343 if (intrcnt[1 + intr] <= 5)
344 log(LOG_ERR, "stray irq %d\n", intr);
345 if (intrcnt[1 + intr] == 5)
347 "too many stray irq %d's; not logging any more\n", intr);
352 * Return a bitmap of the current interrupt requests. This is 8259-specific
353 * and is only suitable for use at probe time.
363 return ((irr2 << 8) | irr1);
368 update_intr_masks(void)
373 for (intr=0; intr < ICU_LEN; intr ++) {
375 /* no 8259 SLAVE to ignore */
377 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
379 maskptr = intr_mptr[intr];
382 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
384 if (mask != intr_mask[intr]) {
386 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
387 intr, intr_mask[intr], mask, maskptr);
389 intr_mask[intr]=mask;
398 update_intrname(int intr, char *name)
402 int name_index, off, strayintr;
405 * Initialise strings for bitbucket and stray interrupt counters.
406 * These have statically allocated indices 0 and 1 through ICU_LEN.
408 if (intrnames[0] == '\0') {
409 off = sprintf(intrnames, "???") + 1;
410 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
411 off += sprintf(intrnames + off, "stray irq%d",
417 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
421 * Search for `buf' in `intrnames'. In the usual case when it is
422 * not found, append it to the end if there is enough space (the \0
423 * terminator for the previous string, if any, becomes a separator).
425 for (cp = intrnames, name_index = 0;
426 cp != eintrnames && name_index < NR_INTRNAMES;
427 cp += strlen(cp) + 1, name_index++) {
429 if (strlen(buf) >= eintrnames - cp)
434 if (strcmp(cp, buf) == 0)
439 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
443 intr_countp[intr] = &intrcnt[name_index];
447 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
448 * code ignores it for normal interrupts.
451 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
454 int select; /* the select register is 8 bits */
456 u_int32_t value; /* the window register is 32 bits */
459 u_int mask = (maskptr ? *maskptr : 0);
462 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
464 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
466 if (intr_handler[intr] != isa_strayintr)
471 intr_handler[intr] = handler;
472 intr_mptr[intr] = maskptr;
473 intr_mask[intr] = mask | SWI_CLOCK_MASK | (1 << intr);
474 intr_unit[intr] = arg;
476 if (flags & INTR_FAST) {
477 vector = TPR_FAST_INTS + intr;
478 setidt(vector, fastintr[intr],
479 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
481 vector = TPR_SLOW_INTS + intr;
482 #ifdef APIC_INTR_REORDER
483 #ifdef APIC_INTR_HIGHPRI_CLOCK
484 /* XXX: Hack (kludge?) for more accurate clock. */
485 if (intr == apic_8254_intr || intr == 8) {
486 vector = TPR_FAST_INTS + intr;
490 setidt(vector, slowintr[intr],
491 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
493 #ifdef APIC_INTR_REORDER
494 set_lapic_isrloc(intr, vector);
497 * Reprogram the vector in the IO APIC.
499 if (int_to_apicintpin[intr].ioapic >= 0) {
500 select = int_to_apicintpin[intr].redirindex;
501 value = io_apic_read(int_to_apicintpin[intr].ioapic,
502 select) & ~IOART_INTVEC;
503 io_apic_write(int_to_apicintpin[intr].ioapic,
504 select, value | vector);
507 setidt(ICU_OFFSET + intr,
508 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
509 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
518 icu_unset(intr, handler)
524 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
530 intr_countp[intr] = &intrcnt[1 + intr];
531 intr_handler[intr] = isa_strayintr;
532 intr_mptr[intr] = NULL;
533 intr_mask[intr] = HWI_MASK | SWI_MASK;
534 intr_unit[intr] = &intr_unit[intr];
536 /* XXX how do I re-create dvp here? */
537 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
538 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
540 #ifdef APIC_INTR_REORDER
541 set_lapic_isrloc(intr, ICU_OFFSET + intr);
543 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
544 GSEL(GCODE_SEL, SEL_KPL));
552 /* The following notice applies beyond this point in the file */
555 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
556 * All rights reserved.
558 * Redistribution and use in source and binary forms, with or without
559 * modification, are permitted provided that the following conditions
561 * 1. Redistributions of source code must retain the above copyright
562 * notice unmodified, this list of conditions, and the following
564 * 2. Redistributions in binary form must reproduce the above copyright
565 * notice, this list of conditions and the following disclaimer in the
566 * documentation and/or other materials provided with the distribution.
568 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
569 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
570 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
571 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
572 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
573 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
574 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
575 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
576 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
577 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
579 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
583 typedef struct intrec {
594 static intrec *intreclist_head[ICU_LEN];
597 * The interrupt multiplexer calls each of the handlers in turn. The
598 * ipl is initially quite low. It is raised as necessary for each call
599 * and lowered after the call. Thus out of order handling is possible
600 * even for interrupts of the same type. This is probably no more
601 * harmful than out of order handling in general (not harmful except
602 * for real time response which we don't support anyway).
611 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
612 oldspl = splq(p->mask);
613 p->handler(p->argument);
619 find_idesc(unsigned *maskptr, int irq)
621 intrec *p = intreclist_head[irq];
623 while (p && p->maskptr != maskptr)
630 find_pred(intrec *idesc, int irq)
632 intrec **pp = &intreclist_head[irq];
645 * Both the low level handler and the shared interrupt multiplexer
646 * block out further interrupts as set in the handlers "mask", while
647 * the handler is running. In fact *maskptr should be used for this
648 * purpose, but since this requires one more pointer dereference on
649 * each interrupt, we rather bother update "mask" whenever *maskptr
650 * changes. The function "update_masks" should be called **after**
651 * all manipulation of the linked list of interrupt handlers hung
652 * off of intrdec_head[irq] is complete, since the chain of handlers
653 * will both determine the *maskptr values and the instances of mask
654 * that are fixed. This function should be called with the irq for
655 * which a new handler has been add blocked, since the masks may not
656 * yet know about the use of this irq for a device of a certain class.
660 update_mux_masks(void)
663 for (irq = 0; irq < ICU_LEN; irq++) {
664 intrec *idesc = intreclist_head[irq];
665 while (idesc != NULL) {
666 if (idesc->maskptr != NULL) {
667 /* our copy of *maskptr may be stale, refresh */
668 idesc->mask = *idesc->maskptr;
676 update_masks(intrmask_t *maskptr, int irq)
678 intrmask_t mask = 1 << irq;
683 if (find_idesc(maskptr, irq) == NULL) {
684 /* no reference to this maskptr was found in this irq's chain */
687 /* a reference to this maskptr was found in this irq's chain */
690 /* we need to update all values in the intr_mask[irq] array */
692 /* update mask in chains of the interrupt multiplex handler as well */
697 * Add interrupt handler to linked list hung off of intreclist_head[irq]
698 * and install shared interrupt multiplex handler, if necessary
702 add_intrdesc(intrec *idesc)
704 int irq = idesc->intr;
708 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
709 * handles interrupt thread scheduling for NORMAL interrupts. It
710 * will never get called for fast interrupts. On the otherhand,
711 * the handler this code installs in intr_handler[] for a NORMAL
712 * interrupt is not used by the *vector.s code, so we need this
713 * temporary hack to run normal interrupts as interrupt threads.
716 if (intr_mihandler_installed[irq] == 0) {
717 intr_mihandler_installed[irq] = 1;
718 register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
719 printf("installing MI handler for int %d\n", irq);
722 head = intreclist_head[irq];
725 /* first handler for this irq, just install it */
726 if (icu_setup(irq, idesc->handler, idesc->argument,
727 idesc->maskptr, idesc->flags) != 0)
730 update_intrname(irq, idesc->name);
732 intreclist_head[irq] = idesc;
734 if ((idesc->flags & INTR_EXCL) != 0
735 || (head->flags & INTR_EXCL) != 0) {
737 * can't append new handler, if either list head or
738 * new handler do not allow interrupts to be shared
741 printf("\tdevice combination doesn't support "
742 "shared irq%d\n", irq);
745 if (head->next == NULL) {
747 * second handler for this irq, replace device driver's
748 * handler by shared interrupt multiplexer function
750 icu_unset(irq, head->handler);
751 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
754 printf("\tusing shared irq%d.\n", irq);
755 update_intrname(irq, "mux");
757 /* just append to the end of the chain */
758 while (head->next != NULL)
762 update_masks(idesc->maskptr, irq);
767 * Create and activate an interrupt handler descriptor data structure.
769 * The dev_instance pointer is required for resource management, and will
770 * only be passed through to resource_claim().
772 * There will be functions that derive a driver and unit name from a
773 * dev_instance variable, and those functions will be used to maintain the
774 * interrupt counter label array referenced by systat and vmstat to report
775 * device interrupt rates (->update_intrlabels).
777 * Add the interrupt handler descriptor data structure created by an
778 * earlier call of create_intr() to the linked list for its irq and
779 * adjust the interrupt masks if necessary.
781 * WARNING: This is an internal function and not to be used by device
782 * drivers. It is subject to change without notice.
786 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
787 intrmask_t *maskptr, int flags)
793 if (ICU_LEN > 8 * sizeof *maskptr) {
794 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
795 ICU_LEN, 8 * sizeof *maskptr);
798 if ((unsigned)irq >= ICU_LEN) {
799 printf("create_intr: requested irq%d too high, limit is %d\n",
804 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
807 bzero(idesc, sizeof *idesc);
811 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
812 if (idesc->name == NULL) {
813 free(idesc, M_DEVBUF);
816 strcpy(idesc->name, name);
818 idesc->handler = handler;
819 idesc->argument = arg;
820 idesc->maskptr = maskptr;
822 idesc->flags = flags;
825 oldspl = splq(1 << irq);
827 /* add irq to class selected by maskptr */
828 errcode = add_intrdesc(idesc);
833 printf("\tintr_connect(irq%d) failed, result=%d\n",
835 free(idesc->name, M_DEVBUF);
836 free(idesc, M_DEVBUF);
844 * Deactivate and remove the interrupt handler descriptor data connected
845 * created by an earlier call of intr_connect() from the linked list and
846 * adjust theinterrupt masks if necessary.
848 * Return the memory held by the interrupt handler descriptor data structure
849 * to the system. Make sure, the handler is not actively used anymore, before.
853 inthand_remove(intrec *idesc)
855 intrec **hook, *head;
865 /* find pointer that keeps the reference to this interrupt descriptor */
866 hook = find_pred(idesc, irq);
870 /* make copy of original list head, the line after may overwrite it */
871 head = intreclist_head[irq];
873 /* unlink: make predecessor point to idesc->next instead of to idesc */
876 /* now check whether the element we removed was the list head */
879 oldspl = splq(1 << irq);
881 /* check whether the new list head is the only element on list */
882 head = intreclist_head[irq];
884 icu_unset(irq, intr_mux);
885 if (head->next != NULL) {
886 /* install the multiplex handler with new list head as argument */
887 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
889 update_intrname(irq, NULL);
891 /* install the one remaining handler for this irq */
892 errcode = icu_setup(irq, head->handler,
894 head->maskptr, head->flags);
896 update_intrname(irq, head->name);
899 /* revert to old handler, eg: strayintr */
900 icu_unset(irq, idesc->handler);
904 update_masks(idesc->maskptr, irq);
905 free(idesc, M_DEVBUF);
910 call_fast_unpend(int irq)
918 * This function is called by an interrupt thread when it has completed
919 * processing a loop. We interlock with ipending and irunning. If
920 * a new interrupt is pending for the thread the function clears the
921 * pending bit and returns. If no new interrupt is pending we
922 * deschedule and sleep.
925 ithread_done(int irq)
927 struct mdglobaldata *gd = mdcpu;
932 if (gd->gd_ipending & mask) {
933 atomic_clear_int(&gd->gd_ipending, mask);
934 lwkt_schedule_self();
936 lwkt_deschedule_self();
937 if (gd->gd_ipending & mask) { /* race */
938 atomic_clear_int(&gd->gd_ipending, mask);
939 lwkt_schedule_self();
941 atomic_clear_int(&gd->gd_irunning, mask);