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.15 2003/10/27 16:42:17 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 isa_wrongintr(void *vcookiep)
389 int intr = (void **)vcookiep - &intr_unit[0];
391 if (intrcnt[1 + intr] <= 5)
392 log(LOG_ERR, "stray irq %d (APIC misprogrammed)\n", intr);
393 if (intrcnt[1 + intr] == 5)
395 "too many stray irq %d's; not logging any more\n", intr);
402 * Return a bitmap of the current interrupt requests. This is 8259-specific
403 * and is only suitable for use at probe time.
406 isa_irq_pending(void)
413 return ((irr2 << 8) | irr1);
418 update_intr_masks(void)
423 for (intr=0; intr < ICU_LEN; intr ++) {
425 /* no 8259 SLAVE to ignore */
427 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
429 maskptr = intr_info[intr].maskp;
432 *maskptr |= SWI_CLOCK_MASK | (1 << intr);
434 if (mask != intr_info[intr].mask) {
436 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
437 intr, intr_info[intr].mask, mask, maskptr);
439 intr_info[intr].mask = mask;
448 update_intrname(int intr, char *name)
452 int name_index, off, strayintr;
455 * Initialise strings for bitbucket and stray interrupt counters.
456 * These have statically allocated indices 0 and 1 through ICU_LEN.
458 if (intrnames[0] == '\0') {
459 off = sprintf(intrnames, "???") + 1;
460 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
461 off += sprintf(intrnames + off, "stray irq%d",
467 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
471 * Search for `buf' in `intrnames'. In the usual case when it is
472 * not found, append it to the end if there is enough space (the \0
473 * terminator for the previous string, if any, becomes a separator).
475 for (cp = intrnames, name_index = 0;
476 cp != eintrnames && name_index < NR_INTRNAMES;
477 cp += strlen(cp) + 1, name_index++) {
479 if (strlen(buf) >= eintrnames - cp)
484 if (strcmp(cp, buf) == 0)
489 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
493 intr_countp[intr] = &intrcnt[name_index];
497 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
498 * code ignores it for normal interrupts.
501 icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
503 #if defined(FAST_HI) && defined(APIC_IO)
504 int select; /* the select register is 8 bits */
506 u_int32_t value; /* the window register is 32 bits */
509 u_int mask = (maskptr ? *maskptr : 0);
512 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
514 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
516 if (intr_handler[intr] != isa_strayintr)
520 cpu_disable_intr(); /* YYY */
521 intr_handler[intr] = handler;
522 intr_unit[intr] = arg;
523 intr_info[intr].maskp = maskptr;
524 intr_info[intr].mask = mask | SWI_CLOCK_MASK | (1 << intr);
526 /* YYY fast ints supported and mp protected but ... */
529 #if defined(FAST_HI) && defined(APIC_IO)
530 if (flags & INTR_FAST) {
532 * Install a spurious interrupt in the low space in case
533 * the IO apic is not properly reprogrammed.
535 vector = TPR_SLOW_INTS + intr;
536 setidt(vector, isa_wrongintr,
537 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
538 vector = TPR_FAST_INTS + intr;
539 setidt(vector, fastintr[intr],
540 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
542 vector = TPR_SLOW_INTS + intr;
543 #ifdef APIC_INTR_REORDER
544 #ifdef APIC_INTR_HIGHPRI_CLOCK
545 /* XXX: Hack (kludge?) for more accurate clock. */
546 if (intr == apic_8254_intr || intr == 8) {
547 vector = TPR_FAST_INTS + intr;
551 setidt(vector, slowintr[intr],
552 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
554 #ifdef APIC_INTR_REORDER
555 set_lapic_isrloc(intr, vector);
558 * Reprogram the vector in the IO APIC.
560 * XXX EOI/mask a pending (stray) interrupt on the old vector?
562 if (int_to_apicintpin[intr].ioapic >= 0) {
563 select = int_to_apicintpin[intr].redirindex;
564 value = io_apic_read(int_to_apicintpin[intr].ioapic,
565 select) & ~IOART_INTVEC;
566 io_apic_write(int_to_apicintpin[intr].ioapic,
567 select, value | vector);
570 setidt(ICU_OFFSET + intr,
571 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
572 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
573 #endif /* FAST_HI && APIC_IO */
580 icu_unset(intr, handler)
586 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) {
587 printf("icu_unset: invalid handler %d %p/%p\n", intr, handler,
588 (((u_int)intr >= ICU_LEN) ? (void *)-1 : intr_handler[intr]));
594 cpu_disable_intr(); /* YYY */
595 intr_countp[intr] = &intrcnt[1 + intr];
596 intr_handler[intr] = isa_strayintr;
597 intr_info[intr].maskp = NULL;
598 intr_info[intr].mask = HWI_MASK | SWI_MASK;
599 intr_unit[intr] = &intr_unit[intr];
601 /* XXX how do I re-create dvp here? */
602 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
603 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
605 #ifdef APIC_INTR_REORDER
606 set_lapic_isrloc(intr, ICU_OFFSET + intr);
608 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
609 GSEL(GCODE_SEL, SEL_KPL));
616 /* The following notice applies beyond this point in the file */
619 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
620 * All rights reserved.
622 * Redistribution and use in source and binary forms, with or without
623 * modification, are permitted provided that the following conditions
625 * 1. Redistributions of source code must retain the above copyright
626 * notice unmodified, this list of conditions, and the following
628 * 2. Redistributions in binary form must reproduce the above copyright
629 * notice, this list of conditions and the following disclaimer in the
630 * documentation and/or other materials provided with the distribution.
632 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
633 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
634 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
635 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
636 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
637 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
638 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
639 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
640 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
641 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
643 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
647 typedef struct intrec {
658 static intrec *intreclist_head[ICU_LEN];
661 * The interrupt multiplexer calls each of the handlers in turn. The
662 * ipl is initially quite low. It is raised as necessary for each call
663 * and lowered after the call. Thus out of order handling is possible
664 * even for interrupts of the same type. This is probably no more
665 * harmful than out of order handling in general (not harmful except
666 * for real time response which we don't support anyway).
675 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
676 oldspl = splq(p->mask);
677 p->handler(p->argument);
683 find_idesc(unsigned *maskptr, int irq)
685 intrec *p = intreclist_head[irq];
687 while (p && p->maskptr != maskptr)
694 find_pred(intrec *idesc, int irq)
696 intrec **pp = &intreclist_head[irq];
709 * Both the low level handler and the shared interrupt multiplexer
710 * block out further interrupts as set in the handlers "mask", while
711 * the handler is running. In fact *maskptr should be used for this
712 * purpose, but since this requires one more pointer dereference on
713 * each interrupt, we rather bother update "mask" whenever *maskptr
714 * changes. The function "update_masks" should be called **after**
715 * all manipulation of the linked list of interrupt handlers hung
716 * off of intrdec_head[irq] is complete, since the chain of handlers
717 * will both determine the *maskptr values and the instances of mask
718 * that are fixed. This function should be called with the irq for
719 * which a new handler has been add blocked, since the masks may not
720 * yet know about the use of this irq for a device of a certain class.
724 update_mux_masks(void)
727 for (irq = 0; irq < ICU_LEN; irq++) {
728 intrec *idesc = intreclist_head[irq];
729 while (idesc != NULL) {
730 if (idesc->maskptr != NULL) {
731 /* our copy of *maskptr may be stale, refresh */
732 idesc->mask = *idesc->maskptr;
740 update_masks(intrmask_t *maskptr, int irq)
742 intrmask_t mask = 1 << irq;
747 if (find_idesc(maskptr, irq) == NULL) {
748 /* no reference to this maskptr was found in this irq's chain */
751 /* a reference to this maskptr was found in this irq's chain */
754 /* we need to update all values in the intr_mask[irq] array */
756 /* update mask in chains of the interrupt multiplex handler as well */
761 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
762 * and install a shared interrupt multiplex handler, if necessary. Install
763 * an interrupt thread for each interrupt (though FAST interrupts will not
764 * use it). The preemption procedure checks the CPL. lwkt_preempt() will
765 * check relative thread priorities for us as long as we properly pass through
768 * The interrupt thread has already been put on the run queue, so if we cannot
769 * preempt we should force a reschedule.
771 * YYY needs work. At the moment the handler is run inside a critical
772 * section so only the preemption cpl check is used.
775 cpu_intr_preempt(struct thread *td, int critpri)
777 struct md_intr_info *info = td->td_info.intdata;
779 if ((curthread->td_cpl & (1 << info->irq)) == 0)
780 lwkt_preempt(td, critpri);
786 add_intrdesc(intrec *idesc)
788 int irq = idesc->intr;
792 * YYY This is a hack. The MI interrupt code in kern/kern_intr.c
793 * handles interrupt thread scheduling for NORMAL interrupts. It
794 * will never get called for fast interrupts. On the otherhand,
795 * the handler this code installs in intr_handler[] for a NORMAL
796 * interrupt is not used by the *vector.s code, so we need this
797 * temporary hack to run normal interrupts as interrupt threads.
800 if (intr_info[irq].mihandler_installed == 0) {
803 intr_info[irq].mihandler_installed = 1;
804 intr_info[irq].irq = irq;
805 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
806 td->td_info.intdata = &intr_info[irq];
807 td->td_preemptable = cpu_intr_preempt;
808 printf("installed MI handler for int %d\n", irq);
811 head = intreclist_head[irq];
814 /* first handler for this irq, just install it */
815 if (icu_setup(irq, idesc->handler, idesc->argument,
816 idesc->maskptr, idesc->flags) != 0)
819 update_intrname(irq, idesc->name);
821 intreclist_head[irq] = idesc;
823 if ((idesc->flags & INTR_EXCL) != 0
824 || (head->flags & INTR_EXCL) != 0) {
826 * can't append new handler, if either list head or
827 * new handler do not allow interrupts to be shared
830 printf("\tdevice combination doesn't support "
831 "shared irq%d\n", irq);
834 if (head->next == NULL) {
836 * second handler for this irq, replace device driver's
837 * handler by shared interrupt multiplexer function
839 icu_unset(irq, head->handler);
840 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0) != 0)
843 printf("\tusing shared irq%d.\n", irq);
844 update_intrname(irq, "mux");
846 /* just append to the end of the chain */
847 while (head->next != NULL)
851 update_masks(idesc->maskptr, irq);
856 * Create and activate an interrupt handler descriptor data structure.
858 * The dev_instance pointer is required for resource management, and will
859 * only be passed through to resource_claim().
861 * There will be functions that derive a driver and unit name from a
862 * dev_instance variable, and those functions will be used to maintain the
863 * interrupt counter label array referenced by systat and vmstat to report
864 * device interrupt rates (->update_intrlabels).
866 * Add the interrupt handler descriptor data structure created by an
867 * earlier call of create_intr() to the linked list for its irq and
868 * adjust the interrupt masks if necessary.
870 * WARNING: This is an internal function and not to be used by device
871 * drivers. It is subject to change without notice.
875 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
876 intrmask_t *maskptr, int flags)
882 if (ICU_LEN > 8 * sizeof *maskptr) {
883 printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
884 ICU_LEN, 8 * sizeof *maskptr);
887 if ((unsigned)irq >= ICU_LEN) {
888 printf("create_intr: requested irq%d too high, limit is %d\n",
893 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
896 bzero(idesc, sizeof *idesc);
900 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
901 if (idesc->name == NULL) {
902 free(idesc, M_DEVBUF);
905 strcpy(idesc->name, name);
907 idesc->handler = handler;
908 idesc->argument = arg;
909 idesc->maskptr = maskptr;
911 idesc->flags = flags;
914 oldspl = splq(1 << irq);
916 /* add irq to class selected by maskptr */
917 errcode = add_intrdesc(idesc);
922 printf("\tintr_connect(irq%d) failed, result=%d\n",
924 free(idesc->name, M_DEVBUF);
925 free(idesc, M_DEVBUF);
933 * Deactivate and remove the interrupt handler descriptor data connected
934 * created by an earlier call of intr_connect() from the linked list and
935 * adjust theinterrupt masks if necessary.
937 * Return the memory held by the interrupt handler descriptor data structure
938 * to the system. Make sure, the handler is not actively used anymore, before.
942 inthand_remove(intrec *idesc)
944 intrec **hook, *head;
954 /* find pointer that keeps the reference to this interrupt descriptor */
955 hook = find_pred(idesc, irq);
959 /* make copy of original list head, the line after may overwrite it */
960 head = intreclist_head[irq];
962 /* unlink: make predecessor point to idesc->next instead of to idesc */
965 /* now check whether the element we removed was the list head */
968 oldspl = splq(1 << irq);
970 /* check whether the new list head is the only element on list */
971 head = intreclist_head[irq];
973 icu_unset(irq, intr_mux);
974 if (head->next != NULL) {
975 /* install the multiplex handler with new list head as argument */
976 errcode = icu_setup(irq, intr_mux, &intreclist_head[irq], 0, 0);
978 update_intrname(irq, NULL);
980 /* install the one remaining handler for this irq */
981 errcode = icu_setup(irq, head->handler,
983 head->maskptr, head->flags);
985 update_intrname(irq, head->name);
988 /* revert to old handler, eg: strayintr */
989 icu_unset(irq, idesc->handler);
993 update_masks(idesc->maskptr, irq);
994 free(idesc, M_DEVBUF);
1001 * This function is called by an interrupt thread when it has completed
1002 * processing a loop. We re-enable itnerrupts and interlock with
1005 * See kern/kern_intr.c for more information.
1008 ithread_done(int irq)
1010 struct mdglobaldata *gd = mdcpu;
1011 int mask = 1 << irq;
1013 KKASSERT(curthread->td_pri >= TDPRI_CRIT);
1014 lwkt_deschedule_self();
1016 if (gd->gd_ipending & mask) {
1017 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
1019 lwkt_schedule_self();
1027 * forward_fast_remote()
1029 * This function is called from the receiving end of an IPIQ when a
1030 * remote cpu wishes to forward a fast interrupt to us. All we have to
1031 * do is set the interrupt pending and let the IPI's doreti deal with it.
1034 forward_fastint_remote(void *arg)
1037 struct mdglobaldata *gd = mdcpu;
1039 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
1040 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);