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.14 2003/09/24 03:32:17 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 static void init_i8259(void);
118 void *intr_unit[ICU_LEN*2];
119 u_long *intr_countp[ICU_LEN*2];
120 inthand2_t *intr_handler[ICU_LEN*2] = {
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,
127 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
128 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
131 static struct md_intr_info {
134 int mihandler_installed;
136 } intr_info[ICU_LEN*2];
138 static inthand_t *fastintr[ICU_LEN] = {
139 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
140 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
141 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
142 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
143 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
144 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
145 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
146 &IDTVEC(fastintr14), &IDTVEC(fastintr15),
148 &IDTVEC(fastintr16), &IDTVEC(fastintr17),
149 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
150 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
151 &IDTVEC(fastintr22), &IDTVEC(fastintr23),
155 unpendhand_t *fastunpend[ICU_LEN] = {
156 IDTVEC(fastunpend0), IDTVEC(fastunpend1),
157 IDTVEC(fastunpend2), IDTVEC(fastunpend3),
158 IDTVEC(fastunpend4), IDTVEC(fastunpend5),
159 IDTVEC(fastunpend6), IDTVEC(fastunpend7),
160 IDTVEC(fastunpend8), IDTVEC(fastunpend9),
161 IDTVEC(fastunpend10), IDTVEC(fastunpend11),
162 IDTVEC(fastunpend12), IDTVEC(fastunpend13),
163 IDTVEC(fastunpend14), IDTVEC(fastunpend15),
165 IDTVEC(fastunpend16), IDTVEC(fastunpend17),
166 IDTVEC(fastunpend18), IDTVEC(fastunpend19),
167 IDTVEC(fastunpend20), IDTVEC(fastunpend21),
168 IDTVEC(fastunpend22), IDTVEC(fastunpend23),
172 static inthand_t *slowintr[ICU_LEN] = {
173 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
174 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
175 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
176 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
178 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
179 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
184 #define NMI_PARITY 0x04
185 #define NMI_EPARITY 0x02
187 #define NMI_PARITY (1 << 7)
188 #define NMI_IOCHAN (1 << 6)
189 #define ENMI_WATCHDOG (1 << 7)
190 #define ENMI_BUSTIMER (1 << 6)
191 #define ENMI_IOSTATUS (1 << 5)
195 * Handle a NMI, possibly a machine check.
196 * return true to panic system, false to ignore.
204 int port = inb(0x33);
206 log(LOG_CRIT, "NMI PC98 port = %x\n", port);
207 if (epson_machine_id == 0x20)
208 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
209 if (port & NMI_PARITY) {
210 log(LOG_CRIT, "BASE RAM parity error, likely hardware failure.");
212 } else if (port & NMI_EPARITY) {
213 log(LOG_CRIT, "EXTENDED RAM parity error, likely hardware failure.");
216 log(LOG_CRIT, "\nNMI Resume ??\n");
219 int isa_port = inb(0x61);
220 int eisa_port = inb(0x461);
222 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
224 if (MCA_system && mca_bus_nmi())
228 if (isa_port & NMI_PARITY) {
229 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
233 if (isa_port & NMI_IOCHAN) {
234 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
239 * On a real EISA machine, this will never happen. However it can
240 * happen on ISA machines which implement XT style floating point
241 * error handling (very rare). Save them from a meaningless panic.
243 if (eisa_port == 0xff)
246 if (eisa_port & ENMI_WATCHDOG) {
247 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
251 if (eisa_port & ENMI_BUSTIMER) {
252 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
256 if (eisa_port & ENMI_IOSTATUS) {
257 log(LOG_CRIT, "EISA I/O port status error.");
265 * ICU reinitialize when ICU configuration has lost.
273 for(i=0;i<ICU_LEN;i++)
274 if(intr_handler[i] != isa_strayintr)
280 * Fill in default interrupt table (in case of spuruious interrupt
281 * during configuration of kernel, setup interrupt control unit
289 for (i = 0; i < ICU_LEN; i++)
290 icu_unset(i, (inthand2_t *)NULL);
298 /* initialize 8259's */
301 outb(IO_ICU1, 0x19); /* reset; program device, four bytes */
304 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
306 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
307 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
310 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
312 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
316 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
318 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
321 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
322 outb(IO_ICU1, 0x0a); /* default to IRR on read */
324 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
329 outb(IO_ICU2, 0x19); /* reset; program device, four bytes */
332 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
334 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
335 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
337 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
340 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
342 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
345 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
346 outb(IO_ICU2, 0x0a); /* default to IRR on read */
350 * Caught a stray interrupt, notify
353 isa_strayintr(void *vcookiep)
355 int intr = (void **)vcookiep - &intr_unit[0];
357 /* DON'T BOTHER FOR NOW! */
358 /* for some reason, we get bursts of intr #7, even if not enabled! */
360 * Well the reason you got bursts of intr #7 is because someone
361 * raised an interrupt line and dropped it before the 8259 could
362 * prioritize it. This is documented in the intel data book. This
363 * means you have BAD hardware! I have changed this so that only
364 * the first 5 get logged, then it quits logging them, and puts
365 * out a special message. rgrimes 3/25/1993
368 * XXX TODO print a different message for #7 if it is for a
369 * glitch. Glitches can be distinguished from real #7's by
370 * testing that the in-service bit is _not_ set. The test
371 * must be done before sending an EOI so it can't be done if
372 * we are using AUTO_EOI_1.
374 printf("STRAY %d\n", intr);
375 if (intrcnt[1 + intr] <= 5)
376 log(LOG_ERR, "stray irq %d\n", intr);
377 if (intrcnt[1 + intr] == 5)
379 "too many stray irq %d's; not logging any more\n", intr);
384 * Return a bitmap of the current interrupt requests. This is 8259-specific
385 * and is only suitable for use at probe time.
388 isa_irq_pending(void)
395 return ((irr2 << 8) | irr1);
400 update_intr_masks(void)
405 for (intr=0; intr < ICU_LEN; intr ++) {
407 /* no 8259 SLAVE to ignore */
409 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
411 maskptr = intr_info[intr].maskp;
414 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
416 if (mask != intr_info[intr].mask) {
418 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
419 intr, intr_info[intr].mask, mask, maskptr);
421 intr_info[intr].mask = mask;
430 update_intrname(int intr, char *name)
434 int name_index, off, strayintr;
437 * Initialise strings for bitbucket and stray interrupt counters.
438 * These have statically allocated indices 0 and 1 through ICU_LEN.
440 if (intrnames[0] == '\0') {
441 off = sprintf(intrnames, "???") + 1;
442 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
443 off += sprintf(intrnames + off, "stray irq%d",
449 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
453 * Search for `buf' in `intrnames'. In the usual case when it is
454 * not found, append it to the end if there is enough space (the \0
455 * terminator for the previous string, if any, becomes a separator).
457 for (cp = intrnames, name_index = 0;
458 cp != eintrnames && name_index < NR_INTRNAMES;
459 cp += strlen(cp) + 1, name_index++) {
461 if (strlen(buf) >= eintrnames - cp)
466 if (strcmp(cp, buf) == 0)
471 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
475 intr_countp[intr] = &intrcnt[name_index];
479 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
480 * code ignores it for normal interrupts.
483 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
486 int select; /* the select register is 8 bits */
488 u_int32_t value; /* the window register is 32 bits */
491 u_int mask = (maskptr ? *maskptr : 0);
494 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
496 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
498 if (intr_handler[intr] != isa_strayintr)
502 cpu_disable_intr(); /* YYY */
503 intr_handler[intr] = handler;
504 intr_unit[intr] = arg;
505 intr_info[intr].maskp = maskptr;
506 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
508 /* YYY fast ints supported and mp protected but ... */
512 if (flags & INTR_FAST) {
513 vector = TPR_FAST_INTS + intr;
514 setidt(vector, fastintr[intr],
515 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
517 vector = TPR_SLOW_INTS + intr;
518 #ifdef APIC_INTR_REORDER
519 #ifdef APIC_INTR_HIGHPRI_CLOCK
520 /* XXX: Hack (kludge?) for more accurate clock. */
521 if (intr == apic_8254_intr || intr == 8) {
522 vector = TPR_FAST_INTS + intr;
526 setidt(vector, slowintr[intr],
527 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
529 #ifdef APIC_INTR_REORDER
530 set_lapic_isrloc(intr, vector);
533 * Reprogram the vector in the IO APIC.
535 if (int_to_apicintpin[intr].ioapic >= 0) {
536 select = int_to_apicintpin[intr].redirindex;
537 value = io_apic_read(int_to_apicintpin[intr].ioapic,
538 select) & ~IOART_INTVEC;
539 io_apic_write(int_to_apicintpin[intr].ioapic,
540 select, value | vector);
543 setidt(ICU_OFFSET + intr,
544 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
545 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
553 icu_unset(intr, handler)
559 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
564 cpu_disable_intr(); /* YYY */
565 intr_countp[intr] = &intrcnt[1 + intr];
566 intr_handler[intr] = isa_strayintr;
567 intr_info[intr].maskp = NULL;
568 intr_info[intr].mask = HWI_MASK | SWI_MASK;
569 intr_unit[intr] = &intr_unit[intr];
571 /* XXX how do I re-create dvp here? */
572 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
573 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
575 #ifdef APIC_INTR_REORDER
576 set_lapic_isrloc(intr, ICU_OFFSET + intr);
578 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
579 GSEL(GCODE_SEL, SEL_KPL));
586 /* The following notice applies beyond this point in the file */
589 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
590 * All rights reserved.
592 * Redistribution and use in source and binary forms, with or without
593 * modification, are permitted provided that the following conditions
595 * 1. Redistributions of source code must retain the above copyright
596 * notice unmodified, this list of conditions, and the following
598 * 2. Redistributions in binary form must reproduce the above copyright
599 * notice, this list of conditions and the following disclaimer in the
600 * documentation and/or other materials provided with the distribution.
602 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
603 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
604 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
605 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
606 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
607 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
608 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
609 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
610 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
611 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
613 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
617 typedef struct intrec {
628 static intrec *intreclist_head[ICU_LEN];
631 * The interrupt multiplexer calls each of the handlers in turn. The
632 * ipl is initially quite low. It is raised as necessary for each call
633 * and lowered after the call. Thus out of order handling is possible
634 * even for interrupts of the same type. This is probably no more
635 * harmful than out of order handling in general (not harmful except
636 * for real time response which we don't support anyway).
645 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
646 oldspl = splq(p->mask);
647 p->handler(p->argument);
653 find_idesc(unsigned *maskptr, int irq)
655 intrec *p = intreclist_head[irq];
657 while (p && p->maskptr != maskptr)
664 find_pred(intrec *idesc, int irq)
666 intrec **pp = &intreclist_head[irq];
679 * Both the low level handler and the shared interrupt multiplexer
680 * block out further interrupts as set in the handlers "mask", while
681 * the handler is running. In fact *maskptr should be used for this
682 * purpose, but since this requires one more pointer dereference on
683 * each interrupt, we rather bother update "mask" whenever *maskptr
684 * changes. The function "update_masks" should be called **after**
685 * all manipulation of the linked list of interrupt handlers hung
686 * off of intrdec_head[irq] is complete, since the chain of handlers
687 * will both determine the *maskptr values and the instances of mask
688 * that are fixed. This function should be called with the irq for
689 * which a new handler has been add blocked, since the masks may not
690 * yet know about the use of this irq for a device of a certain class.
694 update_mux_masks(void)
697 for (irq = 0; irq < ICU_LEN; irq++) {
698 intrec *idesc = intreclist_head[irq];
699 while (idesc != NULL) {
700 if (idesc->maskptr != NULL) {
701 /* our copy of *maskptr may be stale, refresh */
702 idesc->mask = *idesc->maskptr;
710 update_masks(intrmask_t *maskptr, int irq)
712 intrmask_t mask = 1 << irq;
717 if (find_idesc(maskptr, irq) == NULL) {
718 /* no reference to this maskptr was found in this irq's chain */
721 /* a reference to this maskptr was found in this irq's chain */
724 /* we need to update all values in the intr_mask[irq] array */
726 /* update mask in chains of the interrupt multiplex handler as well */
731 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
732 * and install a shared interrupt multiplex handler, if necessary. Install
733 * an interrupt thread for each interrupt (though FAST interrupts will not
734 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
735 * check relative thread priorities for us as long as we properly pass through
738 * The interrupt thread has already been put on the run queue, so if we cannot
739 * preempt we should force a reschedule.
741 * YYY needs work. At the moment the handler is run inside a critical
742 * section so only the preemption cpl check is used.
745 cpu_intr_preempt(struct thread *td, int critpri)
747 struct md_intr_info *info = td->td_info.intdata;
749 if ((curthread->td_cpl & (1 << info->irq)) == 0)
750 lwkt_preempt(td, critpri);
756 add_intrdesc(intrec *idesc)
758 int irq = idesc->intr;
762 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
763 * handles interrupt thread scheduling for NORMAL interrupts. It
764 * will never get called for fast interrupts. On the otherhand,
765 * the handler this code installs in intr_handler[] for a NORMAL
766 * interrupt is not used by the *vector.s code, so we need this
767 * temporary hack to run normal interrupts as interrupt threads.
770 if (intr_info[irq].mihandler_installed == 0) {
773 intr_info[irq].mihandler_installed = 1;
774 intr_info[irq].irq = irq;
775 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
776 td->td_info.intdata = &intr_info[irq];
777 td->td_preemptable = cpu_intr_preempt;
778 printf("installed MI handler for int %d\n", irq);
781 head = intreclist_head[irq];
784 /* first handler for this irq, just install it */
785 if (icu_setup(irq, idesc->handler, idesc->argument,
786 idesc->maskptr, idesc->flags) != 0)
789 update_intrname(irq, idesc->name);
791 intreclist_head[irq] = idesc;
793 if ((idesc->flags & INTR_EXCL) != 0
794 || (head->flags & INTR_EXCL) != 0) {
796 * can't append new handler, if either list head or
797 * new handler do not allow interrupts to be shared
800 printf("\tdevice combination doesn't support "
801 "shared irq%d\n", irq);
804 if (head->next == NULL) {
806 * second handler for this irq, replace device driver's
807 * handler by shared interrupt multiplexer function
809 icu_unset(irq, head->handler);
810 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
813 printf("\tusing shared irq%d.\n", irq);
814 update_intrname(irq, "mux");
816 /* just append to the end of the chain */
817 while (head->next != NULL)
821 update_masks(idesc->maskptr, irq);
826 * Create and activate an interrupt handler descriptor data structure.
828 * The dev_instance pointer is required for resource management, and will
829 * only be passed through to resource_claim().
831 * There will be functions that derive a driver and unit name from a
832 * dev_instance variable, and those functions will be used to maintain the
833 * interrupt counter label array referenced by systat and vmstat to report
834 * device interrupt rates (->update_intrlabels).
836 * Add the interrupt handler descriptor data structure created by an
837 * earlier call of create_intr() to the linked list for its irq and
838 * adjust the interrupt masks if necessary.
840 * WARNING: This is an internal function and not to be used by device
841 * drivers. It is subject to change without notice.
845 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
846 intrmask_t *maskptr, int flags)
852 if (ICU_LEN > 8 * sizeof *maskptr) {
853 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
854 ICU_LEN, 8 * sizeof *maskptr);
857 if ((unsigned)irq >= ICU_LEN) {
858 printf("create_intr: requested irq%d too high, limit is %d\n",
863 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
866 bzero(idesc, sizeof *idesc);
870 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
871 if (idesc->name == NULL) {
872 free(idesc, M_DEVBUF);
875 strcpy(idesc->name, name);
877 idesc->handler = handler;
878 idesc->argument = arg;
879 idesc->maskptr = maskptr;
881 idesc->flags = flags;
884 oldspl = splq(1 << irq);
886 /* add irq to class selected by maskptr */
887 errcode = add_intrdesc(idesc);
892 printf("\tintr_connect(irq%d) failed, result=%d\n",
894 free(idesc->name, M_DEVBUF);
895 free(idesc, M_DEVBUF);
903 * Deactivate and remove the interrupt handler descriptor data connected
904 * created by an earlier call of intr_connect() from the linked list and
905 * adjust theinterrupt masks if necessary.
907 * Return the memory held by the interrupt handler descriptor data structure
908 * to the system. Make sure, the handler is not actively used anymore, before.
912 inthand_remove(intrec *idesc)
914 intrec **hook, *head;
924 /* find pointer that keeps the reference to this interrupt descriptor */
925 hook = find_pred(idesc, irq);
929 /* make copy of original list head, the line after may overwrite it */
930 head = intreclist_head[irq];
932 /* unlink: make predecessor point to idesc->next instead of to idesc */
935 /* now check whether the element we removed was the list head */
938 oldspl = splq(1 << irq);
940 /* check whether the new list head is the only element on list */
941 head = intreclist_head[irq];
943 icu_unset(irq, intr_mux);
944 if (head->next != NULL) {
945 /* install the multiplex handler with new list head as argument */
946 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
948 update_intrname(irq, NULL);
950 /* install the one remaining handler for this irq */
951 errcode = icu_setup(irq, head->handler,
953 head->maskptr, head->flags);
955 update_intrname(irq, head->name);
958 /* revert to old handler, eg: strayintr */
959 icu_unset(irq, idesc->handler);
963 update_masks(idesc->maskptr, irq);
964 free(idesc, M_DEVBUF);
971 * This function is called by an interrupt thread when it has completed
972 * processing a loop. We re-enable itnerrupts and interlock with
975 * See kern/kern_intr.c for more information.
978 ithread_done(int irq)
980 struct mdglobaldata *gd = mdcpu;
983 KKASSERT(curthread->td_pri >= TDPRI_CRIT);
984 lwkt_deschedule_self();
986 if (gd->gd_ipending & mask) {
987 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
989 lwkt_schedule_self();
997 * forward_fast_remote()
999 * This function is called from the receiving end of an IPIQ when a
1000 * remote cpu wishes to forward a fast interrupt to us. All we have to
1001 * do is set the interrupt pending and let the IPI's doreti deal with it.
1004 forward_fastint_remote(void *arg)
1007 struct mdglobaldata *gd = mdcpu;
1009 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
1010 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);