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.31 2005/06/16 21:12:47 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.
48 #include "opt_auto_eoi.h"
50 #include <sys/param.h>
52 #include <machine/lock.h>
54 #include <sys/systm.h>
55 #include <sys/syslog.h>
56 #include <sys/malloc.h>
57 #include <sys/errno.h>
58 #include <sys/interrupt.h>
59 #include <machine/ipl.h>
60 #include <machine/md_var.h>
61 #include <machine/segments.h>
63 #include <machine/globaldata.h>
65 #include <sys/thread2.h>
67 #include <machine/smptests.h> /** FAST_HI */
68 #include <machine/smp.h>
69 #include <bus/isa/i386/isa.h>
70 #include <i386/isa/icu.h>
73 #include <bus/isa/isavar.h>
75 #include <i386/isa/intr_machdep.h>
76 #include <bus/isa/isavar.h>
77 #include <sys/interrupt.h>
79 #include <machine/clock.h>
81 #include <machine/cpu.h>
83 /* XXX should be in suitable include files */
84 #define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
89 * This is to accommodate "mixed-mode" programming for
90 * motherboards that don't connect the 8254 to the IO APIC.
95 #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
97 static inthand2_t isa_strayintr;
98 #if defined(FAST_HI) && defined(APIC_IO)
99 static inthand2_t isa_wrongintr;
101 static void init_i8259(void);
103 void *intr_unit[ICU_LEN*2];
104 u_long *intr_countp[ICU_LEN*2];
105 inthand2_t *intr_handler[ICU_LEN*2] = {
106 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
107 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
108 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
109 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
110 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
111 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
112 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
113 isa_strayintr, isa_strayintr, isa_strayintr, isa_strayintr,
116 static struct md_intr_info {
118 int mihandler_installed;
119 } intr_info[ICU_LEN*2];
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),
155 static inthand_t *slowintr[ICU_LEN] = {
156 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
157 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
158 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
159 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15),
161 &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
162 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23),
166 #define NMI_PARITY (1 << 7)
167 #define NMI_IOCHAN (1 << 6)
168 #define ENMI_WATCHDOG (1 << 7)
169 #define ENMI_BUSTIMER (1 << 6)
170 #define ENMI_IOSTATUS (1 << 5)
173 * Handle a NMI, possibly a machine check.
174 * return true to panic system, false to ignore.
181 int isa_port = inb(0x61);
182 int eisa_port = inb(0x461);
184 log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
186 if (isa_port & NMI_PARITY) {
187 log(LOG_CRIT, "RAM parity error, likely hardware failure.");
191 if (isa_port & NMI_IOCHAN) {
192 log(LOG_CRIT, "I/O channel check, likely hardware failure.");
197 * On a real EISA machine, this will never happen. However it can
198 * happen on ISA machines which implement XT style floating point
199 * error handling (very rare). Save them from a meaningless panic.
201 if (eisa_port == 0xff)
204 if (eisa_port & ENMI_WATCHDOG) {
205 log(LOG_CRIT, "EISA watchdog timer expired, likely hardware failure.");
209 if (eisa_port & ENMI_BUSTIMER) {
210 log(LOG_CRIT, "EISA bus timeout, likely hardware failure.");
214 if (eisa_port & ENMI_IOSTATUS) {
215 log(LOG_CRIT, "EISA I/O port status error.");
222 * ICU reinitialize when ICU configuration has lost.
230 for(i=0;i<ICU_LEN;i++)
231 if(intr_handler[i] != isa_strayintr)
237 * Fill in default interrupt table (in case of spurious interrupt
238 * during configuration of kernel, setup interrupt control unit
246 for (i = 0; i < ICU_LEN; i++)
247 icu_unset(i, isa_strayintr);
255 /* initialize 8259's */
256 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
257 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
258 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
260 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
262 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
264 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
265 outb(IO_ICU1, 0x0a); /* default to IRR on read */
266 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
267 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
268 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
269 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
271 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
273 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
275 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
276 outb(IO_ICU2, 0x0a); /* default to IRR on read */
280 * Caught a stray interrupt, notify
283 isa_strayintr(void *vcookiep)
285 int intr = (void **)vcookiep - &intr_unit[0];
287 /* DON'T BOTHER FOR NOW! */
288 /* for some reason, we get bursts of intr #7, even if not enabled! */
290 * Well the reason you got bursts of intr #7 is because someone
291 * raised an interrupt line and dropped it before the 8259 could
292 * prioritize it. This is documented in the intel data book. This
293 * means you have BAD hardware! I have changed this so that only
294 * the first 5 get logged, then it quits logging them, and puts
295 * out a special message. rgrimes 3/25/1993
298 * XXX TODO print a different message for #7 if it is for a
299 * glitch. Glitches can be distinguished from real #7's by
300 * testing that the in-service bit is _not_ set. The test
301 * must be done before sending an EOI so it can't be done if
302 * we are using AUTO_EOI_1.
304 if (intrcnt[1 + intr] <= 5)
305 log(LOG_ERR, "stray irq %d\n", intr);
306 if (intrcnt[1 + intr] == 5)
308 "too many stray irq %d's; not logging any more\n", intr);
311 #if defined(FAST_HI) && defined(APIC_IO)
314 * This occurs if we mis-programmed the APIC and its vector is still
315 * pointing to the slow vector even when we thought we reprogrammed it
316 * to the high vector. This can occur when interrupts are improperly
317 * routed by the APIC. The unit data is opaque so we have to try to
318 * find it in the unit array.
321 isa_wrongintr(void *vcookiep)
325 for (intr = 0; intr < ICU_LEN*2; ++intr) {
326 if (intr_unit[intr] == vcookiep)
329 if (intr == ICU_LEN*2) {
330 log(LOG_ERR, "stray unknown irq (APIC misprogrammed)\n");
331 } else if (intrcnt[1 + intr] <= 5) {
332 log(LOG_ERR, "stray irq ~%d (APIC misprogrammed)\n", intr);
333 } else if (intrcnt[1 + intr] == 6) {
335 "too many stray irq ~%d's; not logging any more\n", intr);
343 * Return a bitmap of the current interrupt requests. This is 8259-specific
344 * and is only suitable for use at probe time.
347 isa_irq_pending(void)
354 return ((irr2 << 8) | irr1);
359 update_intrname(int intr, char *name)
363 int name_index, off, strayintr;
366 * Initialise strings for bitbucket and stray interrupt counters.
367 * These have statically allocated indices 0 and 1 through ICU_LEN.
369 if (intrnames[0] == '\0') {
370 off = sprintf(intrnames, "???") + 1;
371 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
372 off += sprintf(intrnames + off, "stray irq%d",
378 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
382 * Search for `buf' in `intrnames'. In the usual case when it is
383 * not found, append it to the end if there is enough space (the \0
384 * terminator for the previous string, if any, becomes a separator).
386 for (cp = intrnames, name_index = 0;
387 cp != eintrnames && name_index < NR_INTRNAMES;
388 cp += strlen(cp) + 1, name_index++) {
390 if (strlen(buf) >= eintrnames - cp)
395 if (strcmp(cp, buf) == 0)
400 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
404 intr_countp[intr] = &intrcnt[name_index];
408 * NOTE! intr_handler[] is only used for FAST interrupts, the *vector.s
409 * code ignores it for normal interrupts.
412 icu_setup(int intr, inthand2_t *handler, void *arg, int flags)
414 #if defined(FAST_HI) && defined(APIC_IO)
415 int select; /* the select register is 8 bits */
417 u_int32_t value; /* the window register is 32 bits */
422 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
424 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
427 if (intr_handler[intr] != isa_strayintr)
431 cpu_disable_intr(); /* YYY */
432 intr_handler[intr] = handler;
433 intr_unit[intr] = arg;
435 /* YYY fast ints supported and mp protected but ... */
438 #if defined(FAST_HI) && defined(APIC_IO)
439 if (flags & INTR_FAST) {
441 * Install a spurious interrupt in the low space in case
442 * the IO apic is not properly reprogrammed.
444 vector = TPR_SLOW_INTS + intr;
445 setidt(vector, isa_wrongintr,
446 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
447 vector = TPR_FAST_INTS + intr;
448 setidt(vector, fastintr[intr],
449 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
451 vector = TPR_SLOW_INTS + intr;
452 #ifdef APIC_INTR_REORDER
453 #ifdef APIC_INTR_HIGHPRI_CLOCK
454 /* XXX: Hack (kludge?) for more accurate clock. */
455 if (intr == apic_8254_intr || intr == 8) {
456 vector = TPR_FAST_INTS + intr;
460 setidt(vector, slowintr[intr],
461 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
463 #ifdef APIC_INTR_REORDER
464 set_lapic_isrloc(intr, vector);
467 * Reprogram the vector in the IO APIC.
469 * XXX EOI/mask a pending (stray) interrupt on the old vector?
471 if (int_to_apicintpin[intr].ioapic >= 0) {
472 select = int_to_apicintpin[intr].redirindex;
473 value = io_apic_read(int_to_apicintpin[intr].ioapic,
474 select) & ~IOART_INTVEC;
475 io_apic_write(int_to_apicintpin[intr].ioapic,
476 select, value | vector);
479 setidt(ICU_OFFSET + intr,
480 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
481 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
482 #endif /* FAST_HI && APIC_IO */
489 icu_unset(intr, handler)
495 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr]) {
496 printf("icu_unset: invalid handler %d %p/%p\n", intr, handler,
497 (((u_int)intr >= ICU_LEN) ? (void *)-1 : intr_handler[intr]));
503 cpu_disable_intr(); /* YYY */
504 intr_countp[intr] = &intrcnt[1 + intr];
505 intr_handler[intr] = isa_strayintr;
506 intr_unit[intr] = &intr_unit[intr];
508 /* XXX how do I re-create dvp here? */
509 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
510 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
512 #ifdef APIC_INTR_REORDER
513 set_lapic_isrloc(intr, ICU_OFFSET + intr);
515 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
516 GSEL(GCODE_SEL, SEL_KPL));
523 /* The following notice applies beyond this point in the file */
526 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
527 * All rights reserved.
529 * Redistribution and use in source and binary forms, with or without
530 * modification, are permitted provided that the following conditions
532 * 1. Redistributions of source code must retain the above copyright
533 * notice unmodified, this list of conditions, and the following
535 * 2. Redistributions in binary form must reproduce the above copyright
536 * notice, this list of conditions and the following disclaimer in the
537 * documentation and/or other materials provided with the distribution.
539 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
540 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
541 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
542 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
543 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
544 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
545 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
546 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
547 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
548 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
550 * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
554 typedef struct intrec {
561 lwkt_serialize_t serializer;
562 volatile int in_handler;
565 static intrec *intreclist_head[ICU_LEN];
568 * The interrupt multiplexer calls each of the handlers in turn. A handler
569 * is called only if we can successfully obtain the interlock, meaning
570 * (1) we aren't recursed and (2) the handler has not been disabled via
571 * inthand_disabled().
573 * XXX the IPL is currently raised as necessary for the handler. However,
574 * IPLs are not MP safe so the IPL code will be removed when the device
575 * drivers, BIO, and VM no longer depend on it.
583 for (pp = arg; (p = *pp) != NULL; pp = &p->next) {
586 * New handler dispatch method. Only the serializer
587 * is used to interlock access. Note that this
588 * API includes a handler disablement feature.
590 lwkt_serialize_handler_call(p->serializer,
591 p->handler, p->argument);
594 * Old handlers may expect multiple interrupt
595 * sources to be masked. We must use a critical
599 p->handler(p->argument);
606 * Add an interrupt handler to the linked list hung off of intreclist_head[irq]
607 * and install a shared interrupt multiplex handler. Install an interrupt
608 * thread for each interrupt (though FAST interrupts will not use it).
609 * The preemption procedure checks the CPL. lwkt_preempt() will check
610 * relative thread priorities for us as long as we properly pass through
613 * The interrupt thread has already been put on the run queue, so if we cannot
614 * preempt we should force a reschedule.
616 * This preemption check routine is currently empty, but will be used in the
617 * future to pre-check interrupts for preemptability to avoid the
618 * inefficiencies of having to instantly block. We used to do a CPL check
619 * here (otherwise the interrupt thread could preempt even when it wasn't
620 * supposed to), but with CPLs gone we no longer have to do this.
623 cpu_intr_preempt(struct thread *td, int critpri)
625 lwkt_preempt(td, critpri);
629 add_intrdesc(intrec *idesc)
631 int irq = idesc->intr;
636 * There are two ways to enter intr_mux(). (1) via the scheduled
637 * interrupt thread or (2) directly. The thread mechanism is the
638 * normal mechanism used by SLOW interrupts, while the direct method
639 * is used by FAST interrupts.
641 * We need to create an interrupt thread if none exists.
643 if (intr_info[irq].mihandler_installed == 0) {
646 intr_info[irq].mihandler_installed = 1;
647 intr_info[irq].irq = irq;
648 td = register_int(irq, intr_mux, &intreclist_head[irq], idesc->name);
649 td->td_info.intdata = &intr_info[irq];
650 td->td_preemptable = cpu_intr_preempt;
651 printf("installed MI handler for int %d\n", irq);
654 headp = &intreclist_head[irq];
661 if ((idesc->flags & INTR_EXCL) || (head->flags & INTR_EXCL)) {
662 printf("\tdevice combination doesn't support "
663 "shared irq%d\n", irq);
666 if ((idesc->flags & INTR_FAST) || (head->flags & INTR_FAST)) {
667 printf("\tdevice combination doesn't support "
668 "multiple FAST interrupts on IRQ%d\n", irq);
673 * Always install intr_mux as the hard handler so it can deal with
674 * individual enablement on handlers.
677 if (icu_setup(irq, idesc->handler, idesc->argument, idesc->flags) != 0)
679 update_intrname(irq, idesc->name);
680 } else if (head->next == NULL) {
681 icu_unset(irq, head->handler);
682 if (icu_setup(irq, intr_mux, &intreclist_head[irq], 0) != 0)
684 if (bootverbose && head->next == NULL)
685 printf("\tusing shared irq%d.\n", irq);
686 update_intrname(irq, "mux");
690 * Append to the end of the chain.
692 while (*headp != NULL)
693 headp = &(*headp)->next;
700 * Create and activate an interrupt handler descriptor data structure.
702 * The dev_instance pointer is required for resource management, and will
703 * only be passed through to resource_claim().
705 * There will be functions that derive a driver and unit name from a
706 * dev_instance variable, and those functions will be used to maintain the
707 * interrupt counter label array referenced by systat and vmstat to report
708 * device interrupt rates (->update_intrlabels).
710 * Add the interrupt handler descriptor data structure created by an
711 * earlier call of create_intr() to the linked list for its irq.
713 * WARNING: This is an internal function and not to be used by device
714 * drivers. It is subject to change without notice.
718 inthand_add(const char *name, int irq, inthand2_t handler, void *arg,
719 int flags, lwkt_serialize_t serializer)
724 if ((unsigned)irq >= ICU_LEN) {
725 printf("create_intr: requested irq%d too high, limit is %d\n",
730 idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK | M_ZERO);
736 idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
737 if (idesc->name == NULL) {
738 free(idesc, M_DEVBUF);
741 strcpy(idesc->name, name);
743 idesc->handler = handler;
744 idesc->argument = arg;
746 idesc->flags = flags;
747 idesc->serializer = serializer;
750 errcode = add_intrdesc(idesc);
755 printf("\tintr_connect(irq%d) failed, result=%d\n",
757 free(idesc->name, M_DEVBUF);
758 free(idesc, M_DEVBUF);
766 * Deactivate and remove the interrupt handler descriptor data connected
767 * created by an earlier call of intr_connect() from the linked list.
769 * Return the memory held by the interrupt handler descriptor data structure
770 * to the system. Make sure, the handler is not actively used anymore, before.
773 inthand_remove(intrec *idesc)
775 intrec **hook, *head;
785 * Find and remove the interrupt descriptor.
787 hook = &intreclist_head[irq];
788 while (*hook != idesc) {
793 hook = &(*hook)->next;
798 * If the list is now empty, revert the hard vector to the spurious
801 head = intreclist_head[irq];
804 * No more interrupts on this irq
806 icu_unset(irq, idesc->handler);
807 update_intrname(irq, NULL);
808 } else if (head->next) {
810 * This irq is still shared (has at least two handlers)
811 * (the name should already be set to "mux").
815 * This irq is no longer shared
817 icu_unset(irq, intr_mux);
818 icu_setup(irq, head->handler, head->argument, head->flags);
819 update_intrname(irq, head->name);
822 free(idesc, M_DEVBUF);
830 * This function is called by an interrupt thread when it has completed
831 * processing a loop. We re-enable interrupts and interlock with
834 * See kern/kern_intr.c for more information.
837 ithread_done(int irq)
839 struct mdglobaldata *gd = mdcpu;
843 td = gd->mi.gd_curthread;
845 KKASSERT(td->td_pri >= TDPRI_CRIT);
846 lwkt_deschedule_self(td);
848 if (gd->gd_ipending & mask) {
849 atomic_clear_int_nonlocked(&gd->gd_ipending, mask);
851 lwkt_schedule_self(td);
859 * forward_fast_remote()
861 * This function is called from the receiving end of an IPIQ when a
862 * remote cpu wishes to forward a fast interrupt to us. All we have to
863 * do is set the interrupt pending and let the IPI's doreti deal with it.
866 forward_fastint_remote(void *arg)
869 struct mdglobaldata *gd = mdcpu;
871 atomic_set_int_nonlocked(&gd->gd_fpending, 1 << irq);
872 atomic_set_int_nonlocked(&gd->mi.gd_reqflags, RQF_INTPEND);