diff options
31 files changed, 1888 insertions, 803 deletions
diff --git a/sys/alpha/isa/isa.c b/sys/alpha/isa/isa.c index 5b6b54e..db1104c 100644 --- a/sys/alpha/isa/isa.c +++ b/sys/alpha/isa/isa.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: isa.c,v 1.9 1999/01/23 16:53:27 dfr Exp $ + * $Id: isa.c,v 1.10 1999/04/16 21:21:37 peter Exp $ */ #include <sys/param.h> @@ -202,7 +202,7 @@ isa_intr_disable(int irq) splx(s); } -int +intrmask_t isa_irq_pending(void) { u_char irr1; @@ -213,7 +213,7 @@ isa_irq_pending(void) return ((irr2 << 8) | irr1); } -int +intrmask_t isa_irq_mask(void) { u_char irr1; diff --git a/sys/alpha/pci/pcibus.c b/sys/alpha/pci/pcibus.c index f6cde88..f0c0eb2 100644 --- a/sys/alpha/pci/pcibus.c +++ b/sys/alpha/pci/pcibus.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: pcibus.c,v 1.9 1999/04/16 21:21:39 peter Exp $ + * $Id: pcibus.c,v 1.10 1999/04/19 08:55:11 dfr Exp $ * */ @@ -131,41 +131,6 @@ pci_cvt_to_bwx(vm_offset_t sparse) return NULL; } -#if 0 - -/* - * These can disappear when I update the pci code to use the new - * device framework. - */ -struct intrec * -intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg, - intrmask_t *maskptr, int flags) -{ - struct resource *res; - device_t pcib = chipset.intrdev; - int zero = 0; - void *cookie; - - res = BUS_ALLOC_RESOURCE(pcib, NULL, SYS_RES_IRQ, &zero, - irq, irq, 1, RF_SHAREABLE | RF_ACTIVE); - if (BUS_SETUP_INTR(pcib, pcib, res, (driver_intr_t *)handler, arg, &cookie)) - return 0; - - return (struct intrec *)cookie; -} - -int -intr_connect(struct intrec *idesc) -{ - /* - * intr_create has already connected it (doesn't matter for the - * only consumer of this interface (pci). - */ - return 0; -} - -#endif - void alpha_platform_assign_pciintr(pcicfgregs *cfg) { diff --git a/sys/amd64/amd64/legacy.c b/sys/amd64/amd64/legacy.c index 0cf03f0..cfb7b03 100644 --- a/sys/amd64/amd64/legacy.c +++ b/sys/amd64/amd64/legacy.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: nexus.c,v 1.2 1999/04/18 14:30:55 kato Exp $ + * $Id: nexus.c,v 1.3 1999/04/19 08:04:19 peter Exp $ */ /* @@ -305,6 +305,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, intrmask_t *mask; driver_t *driver; int error, icflags; + char name[32]; if (child) device_printf(child, "interrupting at irq %d\n", @@ -348,11 +349,11 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, if (error) return (error); - *cookiep = intr_create((void *)(intptr_t)-1, irq->r_start, ihand, arg, + snprintf(name, sizeof(name), "%s%d", device_get_name(child), + device_get_unit(child)); + *cookiep = inthand_add(name, irq->r_start, ihand, arg, mask, icflags); - if (*cookiep) - error = intr_connect(*cookiep); - else + if (*cookiep == NULL) error = EINVAL; /* XXX ??? */ return (error); @@ -361,7 +362,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { - return (intr_destroy(ih)); + return (inthand_remove(ih)); } static devclass_t pcib_devclass; diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c index 0cf03f0..cfb7b03 100644 --- a/sys/amd64/amd64/nexus.c +++ b/sys/amd64/amd64/nexus.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: nexus.c,v 1.2 1999/04/18 14:30:55 kato Exp $ + * $Id: nexus.c,v 1.3 1999/04/19 08:04:19 peter Exp $ */ /* @@ -305,6 +305,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, intrmask_t *mask; driver_t *driver; int error, icflags; + char name[32]; if (child) device_printf(child, "interrupting at irq %d\n", @@ -348,11 +349,11 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, if (error) return (error); - *cookiep = intr_create((void *)(intptr_t)-1, irq->r_start, ihand, arg, + snprintf(name, sizeof(name), "%s%d", device_get_name(child), + device_get_unit(child)); + *cookiep = inthand_add(name, irq->r_start, ihand, arg, mask, icflags); - if (*cookiep) - error = intr_connect(*cookiep); - else + if (*cookiep == NULL) error = EINVAL; /* XXX ??? */ return (error); @@ -361,7 +362,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { - return (intr_destroy(ih)); + return (inthand_remove(ih)); } static devclass_t pcib_devclass; diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c index d9bca71..3daaf94 100644 --- a/sys/amd64/amd64/tsc.c +++ b/sys/amd64/amd64/tsc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ + * $Id: clock.c,v 1.129 1998/12/14 13:30:29 mckay Exp $ */ /* @@ -86,7 +86,7 @@ #include <i386/isa/rtc.h> #include <i386/isa/timerreg.h> -#include <sys/interrupt.h> +#include <i386/isa/intr_machdep.h> #ifdef SMP #define disable_intr() CLOCK_DISABLE_INTR() @@ -948,6 +948,7 @@ cpu_initclocks() int diag; #ifdef APIC_IO int apic_8254_trial; + intrec *clkdesc; #endif /* APIC_IO */ if (statclock_disable) { @@ -982,16 +983,14 @@ cpu_initclocks() panic("APIC_IO: Cannot route 8254 interrupt to CPU"); } - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); #else /* APIC_IO */ - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, + INTR_EXCL); INTREN(IRQ0); #endif /* APIC_IO */ @@ -1012,9 +1011,8 @@ cpu_initclocks() panic("APIC RTC != 8"); #endif /* APIC_IO */ - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); + inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, + INTR_EXCL); #ifdef APIC_IO INTREN(APIC_IRQ8); @@ -1038,17 +1036,15 @@ cpu_initclocks() * Workaround: Limited variant of mixed mode. */ INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); + inthand_remove(clkdesc); printf("APIC_IO: Broken MP table detected: " "8254 is not connected to IO APIC int pin %d\n", apic_8254_intr); apic_8254_intr = 0; setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); } diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index d9bca71..3daaf94 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ + * $Id: clock.c,v 1.129 1998/12/14 13:30:29 mckay Exp $ */ /* @@ -86,7 +86,7 @@ #include <i386/isa/rtc.h> #include <i386/isa/timerreg.h> -#include <sys/interrupt.h> +#include <i386/isa/intr_machdep.h> #ifdef SMP #define disable_intr() CLOCK_DISABLE_INTR() @@ -948,6 +948,7 @@ cpu_initclocks() int diag; #ifdef APIC_IO int apic_8254_trial; + intrec *clkdesc; #endif /* APIC_IO */ if (statclock_disable) { @@ -982,16 +983,14 @@ cpu_initclocks() panic("APIC_IO: Cannot route 8254 interrupt to CPU"); } - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); #else /* APIC_IO */ - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, + INTR_EXCL); INTREN(IRQ0); #endif /* APIC_IO */ @@ -1012,9 +1011,8 @@ cpu_initclocks() panic("APIC RTC != 8"); #endif /* APIC_IO */ - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); + inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, + INTR_EXCL); #ifdef APIC_IO INTREN(APIC_IRQ8); @@ -1038,17 +1036,15 @@ cpu_initclocks() * Workaround: Limited variant of mixed mode. */ INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); + inthand_remove(clkdesc); printf("APIC_IO: Broken MP table detected: " "8254 is not connected to IO APIC int pin %d\n", apic_8254_intr); apic_8254_intr = 0; setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); } diff --git a/sys/amd64/isa/intr_machdep.c b/sys/amd64/isa/intr_machdep.c index 4f7c1e9..256c617 100644 --- a/sys/amd64/isa/intr_machdep.c +++ b/sys/amd64/isa/intr_machdep.c @@ -34,7 +34,13 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.17 1999/04/14 14:26:36 bde Exp $ + * $Id: intr_machdep.c,v 1.18 1999/04/16 21:22:22 peter Exp $ + */ +/* + * This file contains an aggregated module marked: + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * See the notice for details. */ #include "opt_auto_eoi.h" @@ -45,9 +51,14 @@ #endif #include <sys/systm.h> #include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/interrupt.h> #include <machine/ipl.h> #include <machine/md_var.h> #include <machine/segments.h> +#include <sys/bus.h> + #if defined(APIC_IO) #include <machine/smp.h> #include <machine/smptests.h> /** FAST_HI */ @@ -62,6 +73,7 @@ #endif #include <i386/isa/icu.h> +#include <isa/isavar.h> #include <i386/isa/intr_machdep.h> #include <sys/interrupt.h> #ifdef APIC_IO @@ -300,7 +312,8 @@ update_intr_masks(void) if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */ #endif /* APIC_IO */ maskptr = intr_mptr[intr]; - if (!maskptr) continue; + if (!maskptr) + continue; *maskptr |= 1 << intr; mask = *maskptr; if (mask != intr_mask[intr]) { @@ -316,48 +329,11 @@ update_intr_masks(void) return (n); } -static const char * -isa_get_nameunit(int id) -{ - static char buf[32]; - struct isa_device *dp; - - if (id == -1) - return ("pci"); /* XXX may also be eisa */ - if (id == 0) - return ("clk0"); /* XXX may also be sloppy driver */ - if (id == 1) - return ("rtc0"); -#if 0 - for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_net; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_null; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; -#endif - return "???"; - -found_device: - snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit); - return (buf); -} - -void -update_intrname(int intr, int device_id) +static void +update_intrname(int intr, char *name) { char buf[32]; char *cp; - const char *name; int name_index, off, strayintr; /* @@ -371,7 +347,8 @@ update_intrname(int intr, int device_id) strayintr) + 1; } - name = isa_get_nameunit(device_id); + if (name == NULL) + name = "???"; if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf)) goto use_bitbucket; @@ -516,3 +493,410 @@ icu_unset(intr, handler) write_eflags(ef); return (0); } + +/* The following notice applies beyond this point in the file */ + +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $ + * + */ + +typedef struct intrec { + intrmask_t mask; + inthand2_t *handler; + void *argument; + struct intrec *next; + char *name; + int intr; + intrmask_t *maskptr; + int flags; +} intrec; + +static intrec *intreclist_head[ICU_LEN]; + +typedef struct isarec { + int id_unit; + ointhand2_t *id_handler; +} isarec; + +static isarec *isareclist[ICU_LEN]; + +/* + * The interrupt multiplexer calls each of the handlers in turn, + * and applies the associated interrupt mask to "cpl", which is + * defined as a ".long" in /sys/i386/isa/ipl.s + */ + +static void +intr_mux(void *arg) +{ + intrec *p = arg; + int oldspl; + + while (p != NULL) { + oldspl = splq(p->mask); + p->handler(p->argument); + splx(oldspl); + p = p->next; + } +} + +static void +isa_intr_wrap(void *cookie) +{ + isarec *irec = (isarec *)cookie; + + irec->id_handler(irec->id_unit); +} + +static intrec* +find_idesc(unsigned *maskptr, int irq) +{ + intrec *p = intreclist_head[irq]; + + while (p && p->maskptr != maskptr) + p = p->next; + + return (p); +} + +static intrec** +find_pred(intrec *idesc, int irq) +{ + intrec **pp = &intreclist_head[irq]; + intrec *p = *pp; + + while (p != idesc) { + if (p == NULL) + return (NULL); + pp = &p->next; + p = *pp; + } + return (pp); +} + +/* + * Both the low level handler and the shared interrupt multiplexer + * block out further interrupts as set in the handlers "mask", while + * the handler is running. In fact *maskptr should be used for this + * purpose, but since this requires one more pointer dereference on + * each interrupt, we rather bother update "mask" whenever *maskptr + * changes. The function "update_masks" should be called **after** + * all manipulation of the linked list of interrupt handlers hung + * off of intrdec_head[irq] is complete, since the chain of handlers + * will both determine the *maskptr values and the instances of mask + * that are fixed. This function should be called with the irq for + * which a new handler has been add blocked, since the masks may not + * yet know about the use of this irq for a device of a certain class. + */ + +static void +update_mux_masks(void) +{ + int irq; + for (irq = 0; irq < ICU_LEN; irq++) { + intrec *idesc = intreclist_head[irq]; + while (idesc != NULL) { + if (idesc->maskptr != NULL) { + /* our copy of *maskptr may be stale, refresh */ + idesc->mask = *idesc->maskptr; + } + idesc = idesc->next; + } + } +} + +static void +update_masks(intrmask_t *maskptr, int irq) +{ + intrmask_t mask = 1 << irq; + + if (maskptr == NULL) + return; + + if (find_idesc(maskptr, irq) == NULL) { + /* no reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) == 0) + return; + /* the irq was included in the classes mask, remove it */ + INTRUNMASK(*maskptr, mask); + } else { + /* a reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) != 0) + return; + /* put the irq into the classes mask */ + INTRMASK(*maskptr, mask); + } + /* we need to update all values in the intr_mask[irq] array */ + update_intr_masks(); + /* update mask in chains of the interrupt multiplex handler as well */ + update_mux_masks(); +} + +/* + * Add interrupt handler to linked list hung off of intreclist_head[irq] + * and install shared interrupt multiplex handler, if necessary + */ + +static int +add_intrdesc(intrec *idesc) +{ + int irq = idesc->intr; + + intrec *head = intreclist_head[irq]; + + if (head == NULL) { + /* first handler for this irq, just install it */ + if (icu_setup(irq, idesc->handler, idesc->argument, + idesc->maskptr, idesc->flags) != 0) + return (-1); + + update_intrname(irq, idesc->name); + /* keep reference */ + intreclist_head[irq] = idesc; + } else { + if ((idesc->flags & INTR_EXCL) != 0 + || (head->flags & INTR_EXCL) != 0) { + /* + * can't append new handler, if either list head or + * new handler do not allow interrupts to be shared + */ + if (bootverbose) + printf("\tdevice combination doesn't support " + "shared irq%d\n", irq); + return (-1); + } + if (head->next == NULL) { + /* + * second handler for this irq, replace device driver's + * handler by shared interrupt multiplexer function + */ + icu_unset(irq, head->handler); + if (icu_setup(irq, intr_mux, head, 0, 0) != 0) + return (-1); + if (bootverbose) + printf("\tusing shared irq%d.\n", irq); + update_intrname(irq, "mux"); + } + /* just append to the end of the chain */ + while (head->next != NULL) + head = head->next; + head->next = idesc; + } + update_masks(idesc->maskptr, irq); + return (0); +} + +/* + * Create and activate an interrupt handler descriptor data structure. + * + * The dev_instance pointer is required for resource management, and will + * only be passed through to resource_claim(). + * + * There will be functions that derive a driver and unit name from a + * dev_instance variable, and those functions will be used to maintain the + * interrupt counter label array referenced by systat and vmstat to report + * device interrupt rates (->update_intrlabels). + * + * Add the interrupt handler descriptor data structure created by an + * earlier call of create_intr() to the linked list for its irq and + * adjust the interrupt masks if necessary. + */ + +intrec * +inthand_add(const char *name, int irq, inthand2_t handler, void *arg, + intrmask_t *maskptr, int flags) +{ + intrec *idesc; + int errcode = -1; + intrmask_t oldspl; + + if (ICU_LEN > 8 * sizeof *maskptr) { + printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", + ICU_LEN, 8 * sizeof *maskptr); + return (NULL); + } + if ((unsigned)irq >= ICU_LEN) { + printf("create_intr: requested irq%d too high, limit is %d\n", + irq, ICU_LEN -1); + return (NULL); + } + + idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); + if (idesc == NULL) + return NULL; + bzero(idesc, sizeof *idesc); + + if (name == NULL) + name = "???"; + idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK); + if (idesc->name == NULL) { + free(idesc, M_DEVBUF); + return NULL; + } + strcpy(idesc->name, name); + + idesc->handler = handler; + idesc->argument = arg; + idesc->maskptr = maskptr; + idesc->intr = irq; + idesc->flags = flags; + + /* block this irq */ + oldspl = splq(1 << irq); + + /* add irq to class selected by maskptr */ + errcode = add_intrdesc(idesc); + splx(oldspl); + + if (errcode != 0) { + if (bootverbose) + printf("\tintr_connect(irq%d) failed, result=%d\n", + irq, errcode); + free(idesc->name, M_DEVBUF); + free(idesc, M_DEVBUF); + idesc = NULL; + } + + return (idesc); +} + +/* + * Deactivate and remove the interrupt handler descriptor data connected + * created by an earlier call of intr_connect() from the linked list and + * adjust theinterrupt masks if necessary. + * + * Return the memory held by the interrupt handler descriptor data structure + * to the system. Make sure, the handler is not actively used anymore, before. + */ + +int +inthand_remove(intrec *idesc) +{ + intrec **hook, *head; + int irq; + int errcode = 0; + intrmask_t oldspl; + + if (idesc == NULL) + return (-1); + + irq = idesc->intr; + + /* find pointer that keeps the reference to this interrupt descriptor */ + hook = find_pred(idesc, irq); + if (hook == NULL) + return (-1); + + /* make copy of original list head, the line after may overwrite it */ + head = intreclist_head[irq]; + + /* unlink: make predecessor point to idesc->next instead of to idesc */ + *hook = idesc->next; + + /* now check whether the element we removed was the list head */ + if (idesc == head) { + + oldspl = splq(1 << irq); + + /* we want to remove the list head, which was known to intr_mux */ + icu_unset(irq, intr_mux); + + /* check whether the new list head is the only element on list */ + head = intreclist_head[irq]; + if (head != NULL) { + if (head->next != NULL) { + /* install the multiplex handler with new list head as argument */ + errcode = icu_setup(irq, intr_mux, head, 0, 0); + if (errcode == 0) + update_intrname(irq, NULL); + } else { + /* install the one remaining handler for this irq */ + errcode = icu_setup(irq, head->handler, + head->argument, + head->maskptr, head->flags); + if (errcode == 0) + update_intrname(irq, head->name); + } + } + splx(oldspl); + } + update_masks(idesc->maskptr, irq); + + free(idesc, M_DEVBUF); + return (0); +} + +/* + * Emulate the register_intr() call previously defined as low level function. + * That function (now icu_setup()) may no longer be directly called, since + * a conflict between an ISA and PCI interrupt might go by unnocticed, else. + */ + +int +register_intr(int intr, int device_id, u_int flags, + ointhand2_t handler, u_int *maskptr, int unit) +{ + intrec *idesc; + isarec *irec; + + irec = malloc(sizeof *irec, M_DEVBUF, M_WAITOK); + if (irec == NULL) + return NULL; + bzero(irec, sizeof *irec); + irec->id_unit = device_id; + irec->id_handler = handler; + + flags |= INTR_EXCL; + idesc = inthand_add("old", intr, isa_intr_wrap, irec, maskptr, flags); + if (idesc == NULL) { + free(irec, M_DEVBUF); + return -1; + } + return 0; +} + +/* + * Emulate the old unregister_intr() low level function. + * Make sure there is just one interrupt, that it was + * registered as non-shared, and that the handlers match. + */ + +int +unregister_intr(int intr, ointhand2_t handler) +{ + intrec *p = intreclist_head[intr]; + + if (p != NULL && (p->flags & INTR_EXCL) != 0 && + p->handler == isa_intr_wrap && isareclist[intr] != NULL && + isareclist[intr]->id_handler == handler) { + free(isareclist[intr], M_DEVBUF); + isareclist[intr] = NULL; + return (inthand_remove(p)); + } + return (EINVAL); +} diff --git a/sys/amd64/isa/intr_machdep.h b/sys/amd64/isa/intr_machdep.h index 7cdce87..1d49d1d 100644 --- a/sys/amd64/isa/intr_machdep.h +++ b/sys/amd64/isa/intr_machdep.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: intr_machdep.h,v 1.12 1998/05/31 10:53:54 bde Exp $ + * $Id: intr_machdep.h,v 1.13 1998/06/18 15:32:06 bde Exp $ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ @@ -190,15 +190,28 @@ inthand_t struct isa_device; void isa_defaultirq __P((void)); -intrmask_t isa_irq_pending __P((void)); int isa_nmi __P((int cd)); -void update_intrname __P((int intr, int device_id)); int icu_setup __P((int intr, inthand2_t *func, void *arg, u_int *maskptr, int flags)); int icu_unset __P((int intr, inthand2_t *handler)); int update_intr_masks __P((void)); void register_imask __P((struct isa_device *dvp, u_int mask)); +intrmask_t splq __P((intrmask_t mask)); + +/* XXX currently dev_instance must be set to the ISA device_id or -1 for PCI */ +#define INTR_FAST 0x00000001 /* fast interrupt handler */ +#define INTR_EXCL 0x00010000 /* excl. intr, default is shared */ + +struct intrec *inthand_add(const char *name, int irq, inthand2_t handler, + void *arg, intrmask_t *maskptr, int flags); + +int inthand_remove(struct intrec *idesc); + +int register_intr __P((int intr, int device_id, u_int flags, + ointhand2_t *handler, u_int *maskptr, int unit)); +int unregister_intr(int intr, ointhand2_t handler); + #endif /* LOCORE */ #endif /* KERNEL */ diff --git a/sys/amd64/isa/isa_dma.c b/sys/amd64/isa/isa_dma.c index abea7f8..bbc09fd 100644 --- a/sys/amd64/isa/isa_dma.c +++ b/sys/amd64/isa/isa_dma.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: isa.c,v 1.117 1998/11/29 15:42:40 phk Exp $ + * $Id: isa_dma.c,v 1.1 1999/04/16 21:22:24 peter Exp $ */ /* @@ -60,7 +60,6 @@ #include <vm/vm_param.h> #include <vm/pmap.h> #include <i386/isa/isa_device.h> -#include <i386/isa/intr_machdep.h> #include <i386/isa/isa.h> #include <i386/isa/ic/i8237.h> diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c index 4f7c1e9..256c617 100644 --- a/sys/amd64/isa/nmi.c +++ b/sys/amd64/isa/nmi.c @@ -34,7 +34,13 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.17 1999/04/14 14:26:36 bde Exp $ + * $Id: intr_machdep.c,v 1.18 1999/04/16 21:22:22 peter Exp $ + */ +/* + * This file contains an aggregated module marked: + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * See the notice for details. */ #include "opt_auto_eoi.h" @@ -45,9 +51,14 @@ #endif #include <sys/systm.h> #include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/interrupt.h> #include <machine/ipl.h> #include <machine/md_var.h> #include <machine/segments.h> +#include <sys/bus.h> + #if defined(APIC_IO) #include <machine/smp.h> #include <machine/smptests.h> /** FAST_HI */ @@ -62,6 +73,7 @@ #endif #include <i386/isa/icu.h> +#include <isa/isavar.h> #include <i386/isa/intr_machdep.h> #include <sys/interrupt.h> #ifdef APIC_IO @@ -300,7 +312,8 @@ update_intr_masks(void) if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */ #endif /* APIC_IO */ maskptr = intr_mptr[intr]; - if (!maskptr) continue; + if (!maskptr) + continue; *maskptr |= 1 << intr; mask = *maskptr; if (mask != intr_mask[intr]) { @@ -316,48 +329,11 @@ update_intr_masks(void) return (n); } -static const char * -isa_get_nameunit(int id) -{ - static char buf[32]; - struct isa_device *dp; - - if (id == -1) - return ("pci"); /* XXX may also be eisa */ - if (id == 0) - return ("clk0"); /* XXX may also be sloppy driver */ - if (id == 1) - return ("rtc0"); -#if 0 - for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_net; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_null; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; -#endif - return "???"; - -found_device: - snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit); - return (buf); -} - -void -update_intrname(int intr, int device_id) +static void +update_intrname(int intr, char *name) { char buf[32]; char *cp; - const char *name; int name_index, off, strayintr; /* @@ -371,7 +347,8 @@ update_intrname(int intr, int device_id) strayintr) + 1; } - name = isa_get_nameunit(device_id); + if (name == NULL) + name = "???"; if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf)) goto use_bitbucket; @@ -516,3 +493,410 @@ icu_unset(intr, handler) write_eflags(ef); return (0); } + +/* The following notice applies beyond this point in the file */ + +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $ + * + */ + +typedef struct intrec { + intrmask_t mask; + inthand2_t *handler; + void *argument; + struct intrec *next; + char *name; + int intr; + intrmask_t *maskptr; + int flags; +} intrec; + +static intrec *intreclist_head[ICU_LEN]; + +typedef struct isarec { + int id_unit; + ointhand2_t *id_handler; +} isarec; + +static isarec *isareclist[ICU_LEN]; + +/* + * The interrupt multiplexer calls each of the handlers in turn, + * and applies the associated interrupt mask to "cpl", which is + * defined as a ".long" in /sys/i386/isa/ipl.s + */ + +static void +intr_mux(void *arg) +{ + intrec *p = arg; + int oldspl; + + while (p != NULL) { + oldspl = splq(p->mask); + p->handler(p->argument); + splx(oldspl); + p = p->next; + } +} + +static void +isa_intr_wrap(void *cookie) +{ + isarec *irec = (isarec *)cookie; + + irec->id_handler(irec->id_unit); +} + +static intrec* +find_idesc(unsigned *maskptr, int irq) +{ + intrec *p = intreclist_head[irq]; + + while (p && p->maskptr != maskptr) + p = p->next; + + return (p); +} + +static intrec** +find_pred(intrec *idesc, int irq) +{ + intrec **pp = &intreclist_head[irq]; + intrec *p = *pp; + + while (p != idesc) { + if (p == NULL) + return (NULL); + pp = &p->next; + p = *pp; + } + return (pp); +} + +/* + * Both the low level handler and the shared interrupt multiplexer + * block out further interrupts as set in the handlers "mask", while + * the handler is running. In fact *maskptr should be used for this + * purpose, but since this requires one more pointer dereference on + * each interrupt, we rather bother update "mask" whenever *maskptr + * changes. The function "update_masks" should be called **after** + * all manipulation of the linked list of interrupt handlers hung + * off of intrdec_head[irq] is complete, since the chain of handlers + * will both determine the *maskptr values and the instances of mask + * that are fixed. This function should be called with the irq for + * which a new handler has been add blocked, since the masks may not + * yet know about the use of this irq for a device of a certain class. + */ + +static void +update_mux_masks(void) +{ + int irq; + for (irq = 0; irq < ICU_LEN; irq++) { + intrec *idesc = intreclist_head[irq]; + while (idesc != NULL) { + if (idesc->maskptr != NULL) { + /* our copy of *maskptr may be stale, refresh */ + idesc->mask = *idesc->maskptr; + } + idesc = idesc->next; + } + } +} + +static void +update_masks(intrmask_t *maskptr, int irq) +{ + intrmask_t mask = 1 << irq; + + if (maskptr == NULL) + return; + + if (find_idesc(maskptr, irq) == NULL) { + /* no reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) == 0) + return; + /* the irq was included in the classes mask, remove it */ + INTRUNMASK(*maskptr, mask); + } else { + /* a reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) != 0) + return; + /* put the irq into the classes mask */ + INTRMASK(*maskptr, mask); + } + /* we need to update all values in the intr_mask[irq] array */ + update_intr_masks(); + /* update mask in chains of the interrupt multiplex handler as well */ + update_mux_masks(); +} + +/* + * Add interrupt handler to linked list hung off of intreclist_head[irq] + * and install shared interrupt multiplex handler, if necessary + */ + +static int +add_intrdesc(intrec *idesc) +{ + int irq = idesc->intr; + + intrec *head = intreclist_head[irq]; + + if (head == NULL) { + /* first handler for this irq, just install it */ + if (icu_setup(irq, idesc->handler, idesc->argument, + idesc->maskptr, idesc->flags) != 0) + return (-1); + + update_intrname(irq, idesc->name); + /* keep reference */ + intreclist_head[irq] = idesc; + } else { + if ((idesc->flags & INTR_EXCL) != 0 + || (head->flags & INTR_EXCL) != 0) { + /* + * can't append new handler, if either list head or + * new handler do not allow interrupts to be shared + */ + if (bootverbose) + printf("\tdevice combination doesn't support " + "shared irq%d\n", irq); + return (-1); + } + if (head->next == NULL) { + /* + * second handler for this irq, replace device driver's + * handler by shared interrupt multiplexer function + */ + icu_unset(irq, head->handler); + if (icu_setup(irq, intr_mux, head, 0, 0) != 0) + return (-1); + if (bootverbose) + printf("\tusing shared irq%d.\n", irq); + update_intrname(irq, "mux"); + } + /* just append to the end of the chain */ + while (head->next != NULL) + head = head->next; + head->next = idesc; + } + update_masks(idesc->maskptr, irq); + return (0); +} + +/* + * Create and activate an interrupt handler descriptor data structure. + * + * The dev_instance pointer is required for resource management, and will + * only be passed through to resource_claim(). + * + * There will be functions that derive a driver and unit name from a + * dev_instance variable, and those functions will be used to maintain the + * interrupt counter label array referenced by systat and vmstat to report + * device interrupt rates (->update_intrlabels). + * + * Add the interrupt handler descriptor data structure created by an + * earlier call of create_intr() to the linked list for its irq and + * adjust the interrupt masks if necessary. + */ + +intrec * +inthand_add(const char *name, int irq, inthand2_t handler, void *arg, + intrmask_t *maskptr, int flags) +{ + intrec *idesc; + int errcode = -1; + intrmask_t oldspl; + + if (ICU_LEN > 8 * sizeof *maskptr) { + printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", + ICU_LEN, 8 * sizeof *maskptr); + return (NULL); + } + if ((unsigned)irq >= ICU_LEN) { + printf("create_intr: requested irq%d too high, limit is %d\n", + irq, ICU_LEN -1); + return (NULL); + } + + idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); + if (idesc == NULL) + return NULL; + bzero(idesc, sizeof *idesc); + + if (name == NULL) + name = "???"; + idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK); + if (idesc->name == NULL) { + free(idesc, M_DEVBUF); + return NULL; + } + strcpy(idesc->name, name); + + idesc->handler = handler; + idesc->argument = arg; + idesc->maskptr = maskptr; + idesc->intr = irq; + idesc->flags = flags; + + /* block this irq */ + oldspl = splq(1 << irq); + + /* add irq to class selected by maskptr */ + errcode = add_intrdesc(idesc); + splx(oldspl); + + if (errcode != 0) { + if (bootverbose) + printf("\tintr_connect(irq%d) failed, result=%d\n", + irq, errcode); + free(idesc->name, M_DEVBUF); + free(idesc, M_DEVBUF); + idesc = NULL; + } + + return (idesc); +} + +/* + * Deactivate and remove the interrupt handler descriptor data connected + * created by an earlier call of intr_connect() from the linked list and + * adjust theinterrupt masks if necessary. + * + * Return the memory held by the interrupt handler descriptor data structure + * to the system. Make sure, the handler is not actively used anymore, before. + */ + +int +inthand_remove(intrec *idesc) +{ + intrec **hook, *head; + int irq; + int errcode = 0; + intrmask_t oldspl; + + if (idesc == NULL) + return (-1); + + irq = idesc->intr; + + /* find pointer that keeps the reference to this interrupt descriptor */ + hook = find_pred(idesc, irq); + if (hook == NULL) + return (-1); + + /* make copy of original list head, the line after may overwrite it */ + head = intreclist_head[irq]; + + /* unlink: make predecessor point to idesc->next instead of to idesc */ + *hook = idesc->next; + + /* now check whether the element we removed was the list head */ + if (idesc == head) { + + oldspl = splq(1 << irq); + + /* we want to remove the list head, which was known to intr_mux */ + icu_unset(irq, intr_mux); + + /* check whether the new list head is the only element on list */ + head = intreclist_head[irq]; + if (head != NULL) { + if (head->next != NULL) { + /* install the multiplex handler with new list head as argument */ + errcode = icu_setup(irq, intr_mux, head, 0, 0); + if (errcode == 0) + update_intrname(irq, NULL); + } else { + /* install the one remaining handler for this irq */ + errcode = icu_setup(irq, head->handler, + head->argument, + head->maskptr, head->flags); + if (errcode == 0) + update_intrname(irq, head->name); + } + } + splx(oldspl); + } + update_masks(idesc->maskptr, irq); + + free(idesc, M_DEVBUF); + return (0); +} + +/* + * Emulate the register_intr() call previously defined as low level function. + * That function (now icu_setup()) may no longer be directly called, since + * a conflict between an ISA and PCI interrupt might go by unnocticed, else. + */ + +int +register_intr(int intr, int device_id, u_int flags, + ointhand2_t handler, u_int *maskptr, int unit) +{ + intrec *idesc; + isarec *irec; + + irec = malloc(sizeof *irec, M_DEVBUF, M_WAITOK); + if (irec == NULL) + return NULL; + bzero(irec, sizeof *irec); + irec->id_unit = device_id; + irec->id_handler = handler; + + flags |= INTR_EXCL; + idesc = inthand_add("old", intr, isa_intr_wrap, irec, maskptr, flags); + if (idesc == NULL) { + free(irec, M_DEVBUF); + return -1; + } + return 0; +} + +/* + * Emulate the old unregister_intr() low level function. + * Make sure there is just one interrupt, that it was + * registered as non-shared, and that the handlers match. + */ + +int +unregister_intr(int intr, ointhand2_t handler) +{ + intrec *p = intreclist_head[intr]; + + if (p != NULL && (p->flags & INTR_EXCL) != 0 && + p->handler == isa_intr_wrap && isareclist[intr] != NULL && + isareclist[intr]->id_handler == handler) { + free(isareclist[intr], M_DEVBUF); + isareclist[intr] = NULL; + return (inthand_remove(p)); + } + return (EINVAL); +} diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 52428e0..3ed8344 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cam_xpt.c,v 1.51 1999/04/17 08:36:03 peter Exp $ + * $Id: cam_xpt.c,v 1.52 1999/04/19 21:26:08 gibbs Exp $ */ #include <sys/param.h> #include <sys/systm.h> @@ -63,8 +63,6 @@ #include "opt_cam.h" #include "opt_scsi.h" -extern void (*ihandlers[32]) __P((void)); - /* Datastructures internal to the xpt layer */ /* diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index f9683b9..f57e1f5 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: ata-all.c,v 1.7 1999/04/16 21:21:52 peter Exp $ + * $Id: ata-all.c,v 1.8 1999/04/18 20:48:15 sos Exp $ */ #include "ata.h" @@ -52,6 +52,7 @@ #include <machine/clock.h> #ifdef __i386__ #include <machine/smp.h> +#include <i386/isa/intr_machdep.h> #endif #include <pci/pcivar.h> #include <pci/pcireg.h> @@ -70,10 +71,10 @@ /* prototypes */ #if NPCI > 0 -static void promise_intr(int32_t); +static void promise_intr(void *); #endif static int32_t ata_probe(int32_t, int32_t, int32_t, device_t, int32_t *); -static void ataintr(int32_t); +static void ataintr(void *); /* * Ought to be handled by the devclass. @@ -132,8 +133,9 @@ ata_isaattach(device_t dev) { struct resource *port; struct resource *irq; - int rid, unit; void *ih; + int rid; + struct ata_softc *softc; /* Allocate the port range and interrupt */ rid = 0; @@ -147,14 +149,8 @@ ata_isaattach(device_t dev) bus_release_resource(dev, SYS_RES_IOPORT, 0, port); return (ENOMEM); } - - /* - * The interrupt code could be changed to take the ata_softc as - * its argument directly. - */ - unit = *(int *) device_get_softc(dev); - return bus_setup_intr(dev, irq, (driver_intr_t *) ataintr, - (void*)(uintptr_t) unit, &ih); + softc = device_get_softc(dev); + return bus_setup_intr(dev, irq, ataintr, softc, &ih); } static device_method_t ata_isa_methods[] = { @@ -232,6 +228,7 @@ static int ata_pciattach(device_t dev) { int unit = device_get_unit(dev); + struct ata_softc *softc; u_int32_t type; u_int8_t class, subclass; u_int32_t cmd; @@ -310,12 +307,14 @@ ata_pciattach(device_t dev) /* now probe the addresse found for "real" ATA/ATAPI hardware */ lun = 0; if (ata_probe(iobase_1, altiobase_1, bmaddr_1, dev, &lun)) { + softc = atadevices[lun]; if (iobase_1 == IO_WD1) #ifdef __i386__ - register_intr(irq1,(int)"",0,(inthand2_t *)ataintr,&bio_imask,lun); + inthand_add(device_get_nameunit(dev), irq1, ataintr, softc, + &bio_imask, INTR_EXCL); #endif #ifdef __alpha__ - alpha_platform_setup_ide_intr(0, ataintr, (void *)(intptr_t)lun); + alpha_platform_setup_ide_intr(0, ataintr, softc); #endif else { struct resource *irq; @@ -324,23 +323,23 @@ ata_pciattach(device_t dev) irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0,1,RF_ACTIVE); if (sysctrl) - bus_setup_intr(dev, irq, (driver_intr_t *)promise_intr, - (void *)lun, &ih); + bus_setup_intr(dev, irq, promise_intr, softc, &ih); else - bus_setup_intr(dev, irq, (driver_intr_t *)ataintr, - (void *)lun, &ih); + bus_setup_intr(dev, irq, ataintr, softc, &ih); } printf("ata%d at 0x%04x irq %d on ata-pci%d\n", lun, iobase_1, isa_apic_irq(irq1), unit); } lun = 1; if (ata_probe(iobase_2, altiobase_2, bmaddr_2, dev, &lun)) { + softc = atadevices[lun]; if (iobase_2 == IO_WD2) #ifdef __i386__ - register_intr(irq2,(int)"",0,(inthand2_t *)ataintr,&bio_imask,lun); + inthand_add(device_get_nameunit(dev), irq2, ataintr, softc, + &bio_imask, INTR_EXCL); #endif #ifdef __alpha__ - alpha_platform_setup_ide_intr(1, ataintr, (void *)(intptr_t)lun); + alpha_platform_setup_ide_intr(1, ataintr, softc); #endif else { struct resource *irq; @@ -349,8 +348,7 @@ ata_pciattach(device_t dev) irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0,1,RF_ACTIVE); if (!sysctrl) - bus_setup_intr(dev, irq, (driver_intr_t *)ataintr, - (void *)lun, &ih); + bus_setup_intr(dev, irq, ataintr, softc, &ih); } printf("ata%d at 0x%04x irq %d on ata-pci%d\n", lun, iobase_2, isa_apic_irq(irq2), unit); @@ -375,16 +373,16 @@ static driver_t ata_pci_driver = { DRIVER_MODULE(ata, pci, ata_pci_driver, ata_devclass, 0, 0); static void -promise_intr(int32_t unit) +promise_intr(void *data) { - struct ata_softc *scp = atadevices[unit]; + struct ata_softc *scp = (struct ata_softc *)data; int32_t channel = inl((pci_read_config(scp->dev, 0x20, 4) & 0xfffc) + 0x1c); if (channel & 0x00000400) - ataintr(unit); + ataintr(data); if (channel & 0x00004000) - ataintr(unit+1); + ataintr(atadevices[scp->unit + 1]); } #endif @@ -548,20 +546,17 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr, } static void -ataintr(int32_t unit) +ataintr(void *data) { struct ata_softc *scp; struct atapi_request *atapi_request; struct buf *ata_request; u_int8_t status; static int32_t intr_count = 0; + int unit; - if (unit < 0 || unit > atanlun) { - printf("ataintr: unit %d unusable\n", unit); - return; - } - - scp = atadevices[unit]; + scp = (struct ata_softc *)data; + unit = scp->unit; /* find & call the responsible driver to process this interrupt */ switch (scp->active) { diff --git a/sys/i386/i386/legacy.c b/sys/i386/i386/legacy.c index 0cf03f0..cfb7b03 100644 --- a/sys/i386/i386/legacy.c +++ b/sys/i386/i386/legacy.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: nexus.c,v 1.2 1999/04/18 14:30:55 kato Exp $ + * $Id: nexus.c,v 1.3 1999/04/19 08:04:19 peter Exp $ */ /* @@ -305,6 +305,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, intrmask_t *mask; driver_t *driver; int error, icflags; + char name[32]; if (child) device_printf(child, "interrupting at irq %d\n", @@ -348,11 +349,11 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, if (error) return (error); - *cookiep = intr_create((void *)(intptr_t)-1, irq->r_start, ihand, arg, + snprintf(name, sizeof(name), "%s%d", device_get_name(child), + device_get_unit(child)); + *cookiep = inthand_add(name, irq->r_start, ihand, arg, mask, icflags); - if (*cookiep) - error = intr_connect(*cookiep); - else + if (*cookiep == NULL) error = EINVAL; /* XXX ??? */ return (error); @@ -361,7 +362,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { - return (intr_destroy(ih)); + return (inthand_remove(ih)); } static devclass_t pcib_devclass; diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c index 0cf03f0..cfb7b03 100644 --- a/sys/i386/i386/nexus.c +++ b/sys/i386/i386/nexus.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: nexus.c,v 1.2 1999/04/18 14:30:55 kato Exp $ + * $Id: nexus.c,v 1.3 1999/04/19 08:04:19 peter Exp $ */ /* @@ -305,6 +305,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, intrmask_t *mask; driver_t *driver; int error, icflags; + char name[32]; if (child) device_printf(child, "interrupting at irq %d\n", @@ -348,11 +349,11 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, if (error) return (error); - *cookiep = intr_create((void *)(intptr_t)-1, irq->r_start, ihand, arg, + snprintf(name, sizeof(name), "%s%d", device_get_name(child), + device_get_unit(child)); + *cookiep = inthand_add(name, irq->r_start, ihand, arg, mask, icflags); - if (*cookiep) - error = intr_connect(*cookiep); - else + if (*cookiep == NULL) error = EINVAL; /* XXX ??? */ return (error); @@ -361,7 +362,7 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq, static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { - return (intr_destroy(ih)); + return (inthand_remove(ih)); } static devclass_t pcib_devclass; diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index d9bca71..3daaf94 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ + * $Id: clock.c,v 1.129 1998/12/14 13:30:29 mckay Exp $ */ /* @@ -86,7 +86,7 @@ #include <i386/isa/rtc.h> #include <i386/isa/timerreg.h> -#include <sys/interrupt.h> +#include <i386/isa/intr_machdep.h> #ifdef SMP #define disable_intr() CLOCK_DISABLE_INTR() @@ -948,6 +948,7 @@ cpu_initclocks() int diag; #ifdef APIC_IO int apic_8254_trial; + intrec *clkdesc; #endif /* APIC_IO */ if (statclock_disable) { @@ -982,16 +983,14 @@ cpu_initclocks() panic("APIC_IO: Cannot route 8254 interrupt to CPU"); } - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); #else /* APIC_IO */ - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, + INTR_EXCL); INTREN(IRQ0); #endif /* APIC_IO */ @@ -1012,9 +1011,8 @@ cpu_initclocks() panic("APIC RTC != 8"); #endif /* APIC_IO */ - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); + inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, + INTR_EXCL); #ifdef APIC_IO INTREN(APIC_IRQ8); @@ -1038,17 +1036,15 @@ cpu_initclocks() * Workaround: Limited variant of mixed mode. */ INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); + inthand_remove(clkdesc); printf("APIC_IO: Broken MP table detected: " "8254 is not connected to IO APIC int pin %d\n", apic_8254_intr); apic_8254_intr = 0; setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); } diff --git a/sys/i386/include/types.h b/sys/i386/include/types.h index f28d633..c7eec31 100644 --- a/sys/i386/include/types.h +++ b/sys/i386/include/types.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)types.h 8.3 (Berkeley) 1/5/94 - * $Id: types.h,v 1.15 1998/07/14 05:09:43 bde Exp $ + * $Id: types.h,v 1.16 1998/12/19 00:02:29 dt Exp $ */ #ifndef _MACHINE_TYPES_H_ @@ -65,5 +65,6 @@ typedef __uint32_t intrmask_t; /* Interrupt handler function type. */ typedef void inthand2_t __P((void *_cookie)); +typedef void ointhand2_t __P((int _device_id)); #endif /* !_MACHINE_TYPES_H_ */ diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index d9bca71..3daaf94 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ + * $Id: clock.c,v 1.129 1998/12/14 13:30:29 mckay Exp $ */ /* @@ -86,7 +86,7 @@ #include <i386/isa/rtc.h> #include <i386/isa/timerreg.h> -#include <sys/interrupt.h> +#include <i386/isa/intr_machdep.h> #ifdef SMP #define disable_intr() CLOCK_DISABLE_INTR() @@ -948,6 +948,7 @@ cpu_initclocks() int diag; #ifdef APIC_IO int apic_8254_trial; + intrec *clkdesc; #endif /* APIC_IO */ if (statclock_disable) { @@ -982,16 +983,14 @@ cpu_initclocks() panic("APIC_IO: Cannot route 8254 interrupt to CPU"); } - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); #else /* APIC_IO */ - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, + INTR_EXCL); INTREN(IRQ0); #endif /* APIC_IO */ @@ -1012,9 +1011,8 @@ cpu_initclocks() panic("APIC RTC != 8"); #endif /* APIC_IO */ - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); + inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, + INTR_EXCL); #ifdef APIC_IO INTREN(APIC_IRQ8); @@ -1038,17 +1036,15 @@ cpu_initclocks() * Workaround: Limited variant of mixed mode. */ INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); + inthand_remove(clkdesc); printf("APIC_IO: Broken MP table detected: " "8254 is not connected to IO APIC int pin %d\n", apic_8254_intr); apic_8254_intr = 0; setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); } diff --git a/sys/i386/isa/intr_machdep.c b/sys/i386/isa/intr_machdep.c index 4f7c1e9..256c617 100644 --- a/sys/i386/isa/intr_machdep.c +++ b/sys/i386/isa/intr_machdep.c @@ -34,7 +34,13 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.17 1999/04/14 14:26:36 bde Exp $ + * $Id: intr_machdep.c,v 1.18 1999/04/16 21:22:22 peter Exp $ + */ +/* + * This file contains an aggregated module marked: + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * See the notice for details. */ #include "opt_auto_eoi.h" @@ -45,9 +51,14 @@ #endif #include <sys/systm.h> #include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/interrupt.h> #include <machine/ipl.h> #include <machine/md_var.h> #include <machine/segments.h> +#include <sys/bus.h> + #if defined(APIC_IO) #include <machine/smp.h> #include <machine/smptests.h> /** FAST_HI */ @@ -62,6 +73,7 @@ #endif #include <i386/isa/icu.h> +#include <isa/isavar.h> #include <i386/isa/intr_machdep.h> #include <sys/interrupt.h> #ifdef APIC_IO @@ -300,7 +312,8 @@ update_intr_masks(void) if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */ #endif /* APIC_IO */ maskptr = intr_mptr[intr]; - if (!maskptr) continue; + if (!maskptr) + continue; *maskptr |= 1 << intr; mask = *maskptr; if (mask != intr_mask[intr]) { @@ -316,48 +329,11 @@ update_intr_masks(void) return (n); } -static const char * -isa_get_nameunit(int id) -{ - static char buf[32]; - struct isa_device *dp; - - if (id == -1) - return ("pci"); /* XXX may also be eisa */ - if (id == 0) - return ("clk0"); /* XXX may also be sloppy driver */ - if (id == 1) - return ("rtc0"); -#if 0 - for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_net; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_null; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; -#endif - return "???"; - -found_device: - snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit); - return (buf); -} - -void -update_intrname(int intr, int device_id) +static void +update_intrname(int intr, char *name) { char buf[32]; char *cp; - const char *name; int name_index, off, strayintr; /* @@ -371,7 +347,8 @@ update_intrname(int intr, int device_id) strayintr) + 1; } - name = isa_get_nameunit(device_id); + if (name == NULL) + name = "???"; if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf)) goto use_bitbucket; @@ -516,3 +493,410 @@ icu_unset(intr, handler) write_eflags(ef); return (0); } + +/* The following notice applies beyond this point in the file */ + +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $ + * + */ + +typedef struct intrec { + intrmask_t mask; + inthand2_t *handler; + void *argument; + struct intrec *next; + char *name; + int intr; + intrmask_t *maskptr; + int flags; +} intrec; + +static intrec *intreclist_head[ICU_LEN]; + +typedef struct isarec { + int id_unit; + ointhand2_t *id_handler; +} isarec; + +static isarec *isareclist[ICU_LEN]; + +/* + * The interrupt multiplexer calls each of the handlers in turn, + * and applies the associated interrupt mask to "cpl", which is + * defined as a ".long" in /sys/i386/isa/ipl.s + */ + +static void +intr_mux(void *arg) +{ + intrec *p = arg; + int oldspl; + + while (p != NULL) { + oldspl = splq(p->mask); + p->handler(p->argument); + splx(oldspl); + p = p->next; + } +} + +static void +isa_intr_wrap(void *cookie) +{ + isarec *irec = (isarec *)cookie; + + irec->id_handler(irec->id_unit); +} + +static intrec* +find_idesc(unsigned *maskptr, int irq) +{ + intrec *p = intreclist_head[irq]; + + while (p && p->maskptr != maskptr) + p = p->next; + + return (p); +} + +static intrec** +find_pred(intrec *idesc, int irq) +{ + intrec **pp = &intreclist_head[irq]; + intrec *p = *pp; + + while (p != idesc) { + if (p == NULL) + return (NULL); + pp = &p->next; + p = *pp; + } + return (pp); +} + +/* + * Both the low level handler and the shared interrupt multiplexer + * block out further interrupts as set in the handlers "mask", while + * the handler is running. In fact *maskptr should be used for this + * purpose, but since this requires one more pointer dereference on + * each interrupt, we rather bother update "mask" whenever *maskptr + * changes. The function "update_masks" should be called **after** + * all manipulation of the linked list of interrupt handlers hung + * off of intrdec_head[irq] is complete, since the chain of handlers + * will both determine the *maskptr values and the instances of mask + * that are fixed. This function should be called with the irq for + * which a new handler has been add blocked, since the masks may not + * yet know about the use of this irq for a device of a certain class. + */ + +static void +update_mux_masks(void) +{ + int irq; + for (irq = 0; irq < ICU_LEN; irq++) { + intrec *idesc = intreclist_head[irq]; + while (idesc != NULL) { + if (idesc->maskptr != NULL) { + /* our copy of *maskptr may be stale, refresh */ + idesc->mask = *idesc->maskptr; + } + idesc = idesc->next; + } + } +} + +static void +update_masks(intrmask_t *maskptr, int irq) +{ + intrmask_t mask = 1 << irq; + + if (maskptr == NULL) + return; + + if (find_idesc(maskptr, irq) == NULL) { + /* no reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) == 0) + return; + /* the irq was included in the classes mask, remove it */ + INTRUNMASK(*maskptr, mask); + } else { + /* a reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) != 0) + return; + /* put the irq into the classes mask */ + INTRMASK(*maskptr, mask); + } + /* we need to update all values in the intr_mask[irq] array */ + update_intr_masks(); + /* update mask in chains of the interrupt multiplex handler as well */ + update_mux_masks(); +} + +/* + * Add interrupt handler to linked list hung off of intreclist_head[irq] + * and install shared interrupt multiplex handler, if necessary + */ + +static int +add_intrdesc(intrec *idesc) +{ + int irq = idesc->intr; + + intrec *head = intreclist_head[irq]; + + if (head == NULL) { + /* first handler for this irq, just install it */ + if (icu_setup(irq, idesc->handler, idesc->argument, + idesc->maskptr, idesc->flags) != 0) + return (-1); + + update_intrname(irq, idesc->name); + /* keep reference */ + intreclist_head[irq] = idesc; + } else { + if ((idesc->flags & INTR_EXCL) != 0 + || (head->flags & INTR_EXCL) != 0) { + /* + * can't append new handler, if either list head or + * new handler do not allow interrupts to be shared + */ + if (bootverbose) + printf("\tdevice combination doesn't support " + "shared irq%d\n", irq); + return (-1); + } + if (head->next == NULL) { + /* + * second handler for this irq, replace device driver's + * handler by shared interrupt multiplexer function + */ + icu_unset(irq, head->handler); + if (icu_setup(irq, intr_mux, head, 0, 0) != 0) + return (-1); + if (bootverbose) + printf("\tusing shared irq%d.\n", irq); + update_intrname(irq, "mux"); + } + /* just append to the end of the chain */ + while (head->next != NULL) + head = head->next; + head->next = idesc; + } + update_masks(idesc->maskptr, irq); + return (0); +} + +/* + * Create and activate an interrupt handler descriptor data structure. + * + * The dev_instance pointer is required for resource management, and will + * only be passed through to resource_claim(). + * + * There will be functions that derive a driver and unit name from a + * dev_instance variable, and those functions will be used to maintain the + * interrupt counter label array referenced by systat and vmstat to report + * device interrupt rates (->update_intrlabels). + * + * Add the interrupt handler descriptor data structure created by an + * earlier call of create_intr() to the linked list for its irq and + * adjust the interrupt masks if necessary. + */ + +intrec * +inthand_add(const char *name, int irq, inthand2_t handler, void *arg, + intrmask_t *maskptr, int flags) +{ + intrec *idesc; + int errcode = -1; + intrmask_t oldspl; + + if (ICU_LEN > 8 * sizeof *maskptr) { + printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", + ICU_LEN, 8 * sizeof *maskptr); + return (NULL); + } + if ((unsigned)irq >= ICU_LEN) { + printf("create_intr: requested irq%d too high, limit is %d\n", + irq, ICU_LEN -1); + return (NULL); + } + + idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); + if (idesc == NULL) + return NULL; + bzero(idesc, sizeof *idesc); + + if (name == NULL) + name = "???"; + idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK); + if (idesc->name == NULL) { + free(idesc, M_DEVBUF); + return NULL; + } + strcpy(idesc->name, name); + + idesc->handler = handler; + idesc->argument = arg; + idesc->maskptr = maskptr; + idesc->intr = irq; + idesc->flags = flags; + + /* block this irq */ + oldspl = splq(1 << irq); + + /* add irq to class selected by maskptr */ + errcode = add_intrdesc(idesc); + splx(oldspl); + + if (errcode != 0) { + if (bootverbose) + printf("\tintr_connect(irq%d) failed, result=%d\n", + irq, errcode); + free(idesc->name, M_DEVBUF); + free(idesc, M_DEVBUF); + idesc = NULL; + } + + return (idesc); +} + +/* + * Deactivate and remove the interrupt handler descriptor data connected + * created by an earlier call of intr_connect() from the linked list and + * adjust theinterrupt masks if necessary. + * + * Return the memory held by the interrupt handler descriptor data structure + * to the system. Make sure, the handler is not actively used anymore, before. + */ + +int +inthand_remove(intrec *idesc) +{ + intrec **hook, *head; + int irq; + int errcode = 0; + intrmask_t oldspl; + + if (idesc == NULL) + return (-1); + + irq = idesc->intr; + + /* find pointer that keeps the reference to this interrupt descriptor */ + hook = find_pred(idesc, irq); + if (hook == NULL) + return (-1); + + /* make copy of original list head, the line after may overwrite it */ + head = intreclist_head[irq]; + + /* unlink: make predecessor point to idesc->next instead of to idesc */ + *hook = idesc->next; + + /* now check whether the element we removed was the list head */ + if (idesc == head) { + + oldspl = splq(1 << irq); + + /* we want to remove the list head, which was known to intr_mux */ + icu_unset(irq, intr_mux); + + /* check whether the new list head is the only element on list */ + head = intreclist_head[irq]; + if (head != NULL) { + if (head->next != NULL) { + /* install the multiplex handler with new list head as argument */ + errcode = icu_setup(irq, intr_mux, head, 0, 0); + if (errcode == 0) + update_intrname(irq, NULL); + } else { + /* install the one remaining handler for this irq */ + errcode = icu_setup(irq, head->handler, + head->argument, + head->maskptr, head->flags); + if (errcode == 0) + update_intrname(irq, head->name); + } + } + splx(oldspl); + } + update_masks(idesc->maskptr, irq); + + free(idesc, M_DEVBUF); + return (0); +} + +/* + * Emulate the register_intr() call previously defined as low level function. + * That function (now icu_setup()) may no longer be directly called, since + * a conflict between an ISA and PCI interrupt might go by unnocticed, else. + */ + +int +register_intr(int intr, int device_id, u_int flags, + ointhand2_t handler, u_int *maskptr, int unit) +{ + intrec *idesc; + isarec *irec; + + irec = malloc(sizeof *irec, M_DEVBUF, M_WAITOK); + if (irec == NULL) + return NULL; + bzero(irec, sizeof *irec); + irec->id_unit = device_id; + irec->id_handler = handler; + + flags |= INTR_EXCL; + idesc = inthand_add("old", intr, isa_intr_wrap, irec, maskptr, flags); + if (idesc == NULL) { + free(irec, M_DEVBUF); + return -1; + } + return 0; +} + +/* + * Emulate the old unregister_intr() low level function. + * Make sure there is just one interrupt, that it was + * registered as non-shared, and that the handlers match. + */ + +int +unregister_intr(int intr, ointhand2_t handler) +{ + intrec *p = intreclist_head[intr]; + + if (p != NULL && (p->flags & INTR_EXCL) != 0 && + p->handler == isa_intr_wrap && isareclist[intr] != NULL && + isareclist[intr]->id_handler == handler) { + free(isareclist[intr], M_DEVBUF); + isareclist[intr] = NULL; + return (inthand_remove(p)); + } + return (EINVAL); +} diff --git a/sys/i386/isa/intr_machdep.h b/sys/i386/isa/intr_machdep.h index 7cdce87..1d49d1d 100644 --- a/sys/i386/isa/intr_machdep.h +++ b/sys/i386/isa/intr_machdep.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: intr_machdep.h,v 1.12 1998/05/31 10:53:54 bde Exp $ + * $Id: intr_machdep.h,v 1.13 1998/06/18 15:32:06 bde Exp $ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ @@ -190,15 +190,28 @@ inthand_t struct isa_device; void isa_defaultirq __P((void)); -intrmask_t isa_irq_pending __P((void)); int isa_nmi __P((int cd)); -void update_intrname __P((int intr, int device_id)); int icu_setup __P((int intr, inthand2_t *func, void *arg, u_int *maskptr, int flags)); int icu_unset __P((int intr, inthand2_t *handler)); int update_intr_masks __P((void)); void register_imask __P((struct isa_device *dvp, u_int mask)); +intrmask_t splq __P((intrmask_t mask)); + +/* XXX currently dev_instance must be set to the ISA device_id or -1 for PCI */ +#define INTR_FAST 0x00000001 /* fast interrupt handler */ +#define INTR_EXCL 0x00010000 /* excl. intr, default is shared */ + +struct intrec *inthand_add(const char *name, int irq, inthand2_t handler, + void *arg, intrmask_t *maskptr, int flags); + +int inthand_remove(struct intrec *idesc); + +int register_intr __P((int intr, int device_id, u_int flags, + ointhand2_t *handler, u_int *maskptr, int unit)); +int unregister_intr(int intr, ointhand2_t handler); + #endif /* LOCORE */ #endif /* KERNEL */ diff --git a/sys/i386/isa/ipl_funcs.c b/sys/i386/isa/ipl_funcs.c index aeba4ac..c73fc22 100644 --- a/sys/i386/isa/ipl_funcs.c +++ b/sys/i386/isa/ipl_funcs.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ipl_funcs.c,v 1.14 1998/12/07 21:58:22 archie Exp $ + * $Id: ipl_funcs.c,v 1.15 1999/03/05 23:39:02 gibbs Exp $ */ #include <sys/types.h> @@ -105,6 +105,14 @@ splx(unsigned ipl) splz(); } +intrmask_t +splq(intrmask_t mask) +{ + intrmask_t tmp = cpl; + cpl |= mask; + return (tmp); +} + #else /* !SMP */ #include <machine/smp.h> diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h index 8a8615f..92a3d14 100644 --- a/sys/i386/isa/isa_device.h +++ b/sys/i386/isa/isa_device.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: isa_device.h,v 1.58 1999/04/16 21:22:23 peter Exp $ + * $Id: isa_device.h,v 1.59 1999/04/19 20:16:22 peter Exp $ */ #ifndef _I386_ISA_ISA_DEVICE_H_ @@ -45,8 +45,6 @@ * ISA Bus Autoconfiguration */ -typedef void ointhand2_t __P((int unit)); - /* * Per device structure. * diff --git a/sys/i386/isa/isa_dma.c b/sys/i386/isa/isa_dma.c index abea7f8..bbc09fd 100644 --- a/sys/i386/isa/isa_dma.c +++ b/sys/i386/isa/isa_dma.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: isa.c,v 1.117 1998/11/29 15:42:40 phk Exp $ + * $Id: isa_dma.c,v 1.1 1999/04/16 21:22:24 peter Exp $ */ /* @@ -60,7 +60,6 @@ #include <vm/vm_param.h> #include <vm/pmap.h> #include <i386/isa/isa_device.h> -#include <i386/isa/intr_machdep.h> #include <i386/isa/isa.h> #include <i386/isa/ic/i8237.h> diff --git a/sys/i386/isa/nmi.c b/sys/i386/isa/nmi.c index 4f7c1e9..256c617 100644 --- a/sys/i386/isa/nmi.c +++ b/sys/i386/isa/nmi.c @@ -34,7 +34,13 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: intr_machdep.c,v 1.17 1999/04/14 14:26:36 bde Exp $ + * $Id: intr_machdep.c,v 1.18 1999/04/16 21:22:22 peter Exp $ + */ +/* + * This file contains an aggregated module marked: + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * See the notice for details. */ #include "opt_auto_eoi.h" @@ -45,9 +51,14 @@ #endif #include <sys/systm.h> #include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/interrupt.h> #include <machine/ipl.h> #include <machine/md_var.h> #include <machine/segments.h> +#include <sys/bus.h> + #if defined(APIC_IO) #include <machine/smp.h> #include <machine/smptests.h> /** FAST_HI */ @@ -62,6 +73,7 @@ #endif #include <i386/isa/icu.h> +#include <isa/isavar.h> #include <i386/isa/intr_machdep.h> #include <sys/interrupt.h> #ifdef APIC_IO @@ -300,7 +312,8 @@ update_intr_masks(void) if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */ #endif /* APIC_IO */ maskptr = intr_mptr[intr]; - if (!maskptr) continue; + if (!maskptr) + continue; *maskptr |= 1 << intr; mask = *maskptr; if (mask != intr_mask[intr]) { @@ -316,48 +329,11 @@ update_intr_masks(void) return (n); } -static const char * -isa_get_nameunit(int id) -{ - static char buf[32]; - struct isa_device *dp; - - if (id == -1) - return ("pci"); /* XXX may also be eisa */ - if (id == 0) - return ("clk0"); /* XXX may also be sloppy driver */ - if (id == 1) - return ("rtc0"); -#if 0 - for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_net; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_null; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; - for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++) - if (dp->id_id == id) - goto found_device; -#endif - return "???"; - -found_device: - snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit); - return (buf); -} - -void -update_intrname(int intr, int device_id) +static void +update_intrname(int intr, char *name) { char buf[32]; char *cp; - const char *name; int name_index, off, strayintr; /* @@ -371,7 +347,8 @@ update_intrname(int intr, int device_id) strayintr) + 1; } - name = isa_get_nameunit(device_id); + if (name == NULL) + name = "???"; if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf)) goto use_bitbucket; @@ -516,3 +493,410 @@ icu_unset(intr, handler) write_eflags(ef); return (0); } + +/* The following notice applies beyond this point in the file */ + +/* + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $ + * + */ + +typedef struct intrec { + intrmask_t mask; + inthand2_t *handler; + void *argument; + struct intrec *next; + char *name; + int intr; + intrmask_t *maskptr; + int flags; +} intrec; + +static intrec *intreclist_head[ICU_LEN]; + +typedef struct isarec { + int id_unit; + ointhand2_t *id_handler; +} isarec; + +static isarec *isareclist[ICU_LEN]; + +/* + * The interrupt multiplexer calls each of the handlers in turn, + * and applies the associated interrupt mask to "cpl", which is + * defined as a ".long" in /sys/i386/isa/ipl.s + */ + +static void +intr_mux(void *arg) +{ + intrec *p = arg; + int oldspl; + + while (p != NULL) { + oldspl = splq(p->mask); + p->handler(p->argument); + splx(oldspl); + p = p->next; + } +} + +static void +isa_intr_wrap(void *cookie) +{ + isarec *irec = (isarec *)cookie; + + irec->id_handler(irec->id_unit); +} + +static intrec* +find_idesc(unsigned *maskptr, int irq) +{ + intrec *p = intreclist_head[irq]; + + while (p && p->maskptr != maskptr) + p = p->next; + + return (p); +} + +static intrec** +find_pred(intrec *idesc, int irq) +{ + intrec **pp = &intreclist_head[irq]; + intrec *p = *pp; + + while (p != idesc) { + if (p == NULL) + return (NULL); + pp = &p->next; + p = *pp; + } + return (pp); +} + +/* + * Both the low level handler and the shared interrupt multiplexer + * block out further interrupts as set in the handlers "mask", while + * the handler is running. In fact *maskptr should be used for this + * purpose, but since this requires one more pointer dereference on + * each interrupt, we rather bother update "mask" whenever *maskptr + * changes. The function "update_masks" should be called **after** + * all manipulation of the linked list of interrupt handlers hung + * off of intrdec_head[irq] is complete, since the chain of handlers + * will both determine the *maskptr values and the instances of mask + * that are fixed. This function should be called with the irq for + * which a new handler has been add blocked, since the masks may not + * yet know about the use of this irq for a device of a certain class. + */ + +static void +update_mux_masks(void) +{ + int irq; + for (irq = 0; irq < ICU_LEN; irq++) { + intrec *idesc = intreclist_head[irq]; + while (idesc != NULL) { + if (idesc->maskptr != NULL) { + /* our copy of *maskptr may be stale, refresh */ + idesc->mask = *idesc->maskptr; + } + idesc = idesc->next; + } + } +} + +static void +update_masks(intrmask_t *maskptr, int irq) +{ + intrmask_t mask = 1 << irq; + + if (maskptr == NULL) + return; + + if (find_idesc(maskptr, irq) == NULL) { + /* no reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) == 0) + return; + /* the irq was included in the classes mask, remove it */ + INTRUNMASK(*maskptr, mask); + } else { + /* a reference to this maskptr was found in this irq's chain */ + if ((*maskptr & mask) != 0) + return; + /* put the irq into the classes mask */ + INTRMASK(*maskptr, mask); + } + /* we need to update all values in the intr_mask[irq] array */ + update_intr_masks(); + /* update mask in chains of the interrupt multiplex handler as well */ + update_mux_masks(); +} + +/* + * Add interrupt handler to linked list hung off of intreclist_head[irq] + * and install shared interrupt multiplex handler, if necessary + */ + +static int +add_intrdesc(intrec *idesc) +{ + int irq = idesc->intr; + + intrec *head = intreclist_head[irq]; + + if (head == NULL) { + /* first handler for this irq, just install it */ + if (icu_setup(irq, idesc->handler, idesc->argument, + idesc->maskptr, idesc->flags) != 0) + return (-1); + + update_intrname(irq, idesc->name); + /* keep reference */ + intreclist_head[irq] = idesc; + } else { + if ((idesc->flags & INTR_EXCL) != 0 + || (head->flags & INTR_EXCL) != 0) { + /* + * can't append new handler, if either list head or + * new handler do not allow interrupts to be shared + */ + if (bootverbose) + printf("\tdevice combination doesn't support " + "shared irq%d\n", irq); + return (-1); + } + if (head->next == NULL) { + /* + * second handler for this irq, replace device driver's + * handler by shared interrupt multiplexer function + */ + icu_unset(irq, head->handler); + if (icu_setup(irq, intr_mux, head, 0, 0) != 0) + return (-1); + if (bootverbose) + printf("\tusing shared irq%d.\n", irq); + update_intrname(irq, "mux"); + } + /* just append to the end of the chain */ + while (head->next != NULL) + head = head->next; + head->next = idesc; + } + update_masks(idesc->maskptr, irq); + return (0); +} + +/* + * Create and activate an interrupt handler descriptor data structure. + * + * The dev_instance pointer is required for resource management, and will + * only be passed through to resource_claim(). + * + * There will be functions that derive a driver and unit name from a + * dev_instance variable, and those functions will be used to maintain the + * interrupt counter label array referenced by systat and vmstat to report + * device interrupt rates (->update_intrlabels). + * + * Add the interrupt handler descriptor data structure created by an + * earlier call of create_intr() to the linked list for its irq and + * adjust the interrupt masks if necessary. + */ + +intrec * +inthand_add(const char *name, int irq, inthand2_t handler, void *arg, + intrmask_t *maskptr, int flags) +{ + intrec *idesc; + int errcode = -1; + intrmask_t oldspl; + + if (ICU_LEN > 8 * sizeof *maskptr) { + printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", + ICU_LEN, 8 * sizeof *maskptr); + return (NULL); + } + if ((unsigned)irq >= ICU_LEN) { + printf("create_intr: requested irq%d too high, limit is %d\n", + irq, ICU_LEN -1); + return (NULL); + } + + idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); + if (idesc == NULL) + return NULL; + bzero(idesc, sizeof *idesc); + + if (name == NULL) + name = "???"; + idesc->name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK); + if (idesc->name == NULL) { + free(idesc, M_DEVBUF); + return NULL; + } + strcpy(idesc->name, name); + + idesc->handler = handler; + idesc->argument = arg; + idesc->maskptr = maskptr; + idesc->intr = irq; + idesc->flags = flags; + + /* block this irq */ + oldspl = splq(1 << irq); + + /* add irq to class selected by maskptr */ + errcode = add_intrdesc(idesc); + splx(oldspl); + + if (errcode != 0) { + if (bootverbose) + printf("\tintr_connect(irq%d) failed, result=%d\n", + irq, errcode); + free(idesc->name, M_DEVBUF); + free(idesc, M_DEVBUF); + idesc = NULL; + } + + return (idesc); +} + +/* + * Deactivate and remove the interrupt handler descriptor data connected + * created by an earlier call of intr_connect() from the linked list and + * adjust theinterrupt masks if necessary. + * + * Return the memory held by the interrupt handler descriptor data structure + * to the system. Make sure, the handler is not actively used anymore, before. + */ + +int +inthand_remove(intrec *idesc) +{ + intrec **hook, *head; + int irq; + int errcode = 0; + intrmask_t oldspl; + + if (idesc == NULL) + return (-1); + + irq = idesc->intr; + + /* find pointer that keeps the reference to this interrupt descriptor */ + hook = find_pred(idesc, irq); + if (hook == NULL) + return (-1); + + /* make copy of original list head, the line after may overwrite it */ + head = intreclist_head[irq]; + + /* unlink: make predecessor point to idesc->next instead of to idesc */ + *hook = idesc->next; + + /* now check whether the element we removed was the list head */ + if (idesc == head) { + + oldspl = splq(1 << irq); + + /* we want to remove the list head, which was known to intr_mux */ + icu_unset(irq, intr_mux); + + /* check whether the new list head is the only element on list */ + head = intreclist_head[irq]; + if (head != NULL) { + if (head->next != NULL) { + /* install the multiplex handler with new list head as argument */ + errcode = icu_setup(irq, intr_mux, head, 0, 0); + if (errcode == 0) + update_intrname(irq, NULL); + } else { + /* install the one remaining handler for this irq */ + errcode = icu_setup(irq, head->handler, + head->argument, + head->maskptr, head->flags); + if (errcode == 0) + update_intrname(irq, head->name); + } + } + splx(oldspl); + } + update_masks(idesc->maskptr, irq); + + free(idesc, M_DEVBUF); + return (0); +} + +/* + * Emulate the register_intr() call previously defined as low level function. + * That function (now icu_setup()) may no longer be directly called, since + * a conflict between an ISA and PCI interrupt might go by unnocticed, else. + */ + +int +register_intr(int intr, int device_id, u_int flags, + ointhand2_t handler, u_int *maskptr, int unit) +{ + intrec *idesc; + isarec *irec; + + irec = malloc(sizeof *irec, M_DEVBUF, M_WAITOK); + if (irec == NULL) + return NULL; + bzero(irec, sizeof *irec); + irec->id_unit = device_id; + irec->id_handler = handler; + + flags |= INTR_EXCL; + idesc = inthand_add("old", intr, isa_intr_wrap, irec, maskptr, flags); + if (idesc == NULL) { + free(irec, M_DEVBUF); + return -1; + } + return 0; +} + +/* + * Emulate the old unregister_intr() low level function. + * Make sure there is just one interrupt, that it was + * registered as non-shared, and that the handlers match. + */ + +int +unregister_intr(int intr, ointhand2_t handler) +{ + intrec *p = intreclist_head[intr]; + + if (p != NULL && (p->flags & INTR_EXCL) != 0 && + p->handler == isa_intr_wrap && isareclist[intr] != NULL && + isareclist[intr]->id_handler == handler) { + free(isareclist[intr], M_DEVBUF); + isareclist[intr] = NULL; + return (inthand_remove(p)); + } + return (EINVAL); +} diff --git a/sys/i386/isa/random_machdep.c b/sys/i386/isa/random_machdep.c index d635668..fbb0f86 100644 --- a/sys/i386/isa/random_machdep.c +++ b/sys/i386/isa/random_machdep.c @@ -1,7 +1,7 @@ /* * random_machdep.c -- A strong random number generator * - * $Id: random_machdep.c,v 1.28 1998/06/18 15:32:07 bde Exp $ + * $Id: random_machdep.c,v 1.29 1998/06/21 11:33:32 bde Exp $ * * Version 0.95, last modified 18-Oct-95 * @@ -45,6 +45,7 @@ #include <sys/select.h> #include <sys/poll.h> #include <sys/md5.h> +#include <sys/bus.h> #include <machine/random.h> diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index d9bca71..3daaf94 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ + * $Id: clock.c,v 1.129 1998/12/14 13:30:29 mckay Exp $ */ /* @@ -86,7 +86,7 @@ #include <i386/isa/rtc.h> #include <i386/isa/timerreg.h> -#include <sys/interrupt.h> +#include <i386/isa/intr_machdep.h> #ifdef SMP #define disable_intr() CLOCK_DISABLE_INTR() @@ -948,6 +948,7 @@ cpu_initclocks() int diag; #ifdef APIC_IO int apic_8254_trial; + intrec *clkdesc; #endif /* APIC_IO */ if (statclock_disable) { @@ -982,16 +983,14 @@ cpu_initclocks() panic("APIC_IO: Cannot route 8254 interrupt to CPU"); } - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); #else /* APIC_IO */ - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask, + INTR_EXCL); INTREN(IRQ0); #endif /* APIC_IO */ @@ -1012,9 +1011,8 @@ cpu_initclocks() panic("APIC RTC != 8"); #endif /* APIC_IO */ - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); + inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask, + INTR_EXCL); #ifdef APIC_IO INTREN(APIC_IRQ8); @@ -1038,17 +1036,15 @@ cpu_initclocks() * Workaround: Limited variant of mixed mode. */ INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); + inthand_remove(clkdesc); printf("APIC_IO: Broken MP table detected: " "8254 is not connected to IO APIC int pin %d\n", apic_8254_intr); apic_8254_intr = 0; setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); + inthand_add("clk", apic_8254_intr,(inthand2_t *)clkintr, + NULL, &clk_imask, INTR_EXCL); INTREN(1 << apic_8254_intr); } diff --git a/sys/isa/isavar.h b/sys/isa/isavar.h index 21447b6..f1eb25c 100644 --- a/sys/isa/isavar.h +++ b/sys/isa/isavar.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: isavar.h,v 1.2 1998/11/15 18:25:17 dfr Exp $ + * $Id: isavar.h,v 1.3 1999/04/16 21:22:34 peter Exp $ */ #define ISA_NPORT_IVARS 2 @@ -53,8 +53,8 @@ enum isa_device_ivars { ISA_IVAR_DRQ_1 }; -extern int isa_irq_pending(void); -extern int isa_irq_mask(void); +extern intrmask_t isa_irq_pending(void); +extern intrmask_t isa_irq_mask(void); /* * Simplified accessors for isa devices diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index 1d6756c..22565f7 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: kern_intr.c,v 1.20 1998/09/26 14:25:31 dfr Exp $ + * $Id: kern_intr.c,v 1.21 1998/11/10 09:16:29 peter Exp $ * */ @@ -32,38 +32,11 @@ #include <sys/systm.h> #include <sys/malloc.h> #include <sys/errno.h> -#ifdef RESOURCE_CHECK -#include <sys/drvresource.h> -#endif /* RESOURCE_CHECK */ #include <machine/ipl.h> -#ifdef __i386__ -#include <i386/isa/icu.h> -#include <i386/isa/intr_machdep.h> -#endif - #include <sys/interrupt.h> -#include <stddef.h> - -#ifdef __i386__ - -typedef struct intrec { - intrmask_t mask; - inthand2_t *handler; - void *argument; - struct intrec *next; - void *devdata; - int intr; - intrmask_t *maskptr; - int flags; -} intrec; - -static intrec *intreclist_head[NHWI]; - -#endif - struct swilist { swihand_t *sl_handler; struct swilist *sl_next; @@ -71,383 +44,6 @@ struct swilist { static struct swilist swilists[NSWI]; -#ifdef __i386__ - -/* - * The interrupt multiplexer calls each of the handlers in turn, - * and applies the associated interrupt mask to "cpl", which is - * defined as a ".long" in /sys/i386/isa/ipl.s - */ - -#ifndef SMP -static __inline intrmask_t -splq(intrmask_t mask) -{ - intrmask_t tmp = cpl; - cpl |= mask; - return (tmp); -} -#endif /* SMP */ - -static void -intr_mux(void *arg) -{ - intrec *p = arg; - - while (p != NULL) { - int oldspl = splq(p->mask); - p->handler(p->argument); - splx(oldspl); - p = p->next; - } -} - -static intrec* -find_idesc(unsigned *maskptr, int irq) -{ - intrec *p = intreclist_head[irq]; - - while (p && p->maskptr != maskptr) - p = p->next; - - return (p); -} - -static intrec** -find_pred(intrec *idesc, int irq) -{ - intrec **pp = &intreclist_head[irq]; - intrec *p = *pp; - - while (p != idesc) { - if (p == NULL) - return (NULL); - pp = &p->next; - p = *pp; - } - return (pp); -} - -/* - * Both the low level handler and the shared interrupt multiplexer - * block out further interrupts as set in the handlers "mask", while - * the handler is running. In fact *maskptr should be used for this - * purpose, but since this requires one more pointer dereference on - * each interrupt, we rather bother update "mask" whenever *maskptr - * changes. The function "update_masks" should be called **after** - * all manipulation of the linked list of interrupt handlers hung - * off of intrdec_head[irq] is complete, since the chain of handlers - * will both determine the *maskptr values and the instances of mask - * that are fixed. This function should be called with the irq for - * which a new handler has been add blocked, since the masks may not - * yet know about the use of this irq for a device of a certain class. - */ - -static void -update_mux_masks(void) -{ - int irq; - for (irq = 0; irq < ICU_LEN; irq++) { - intrec *idesc = intreclist_head[irq]; - while (idesc != NULL) { - if (idesc->maskptr != NULL) { - /* our copy of *maskptr may be stale, refresh */ - idesc->mask = *idesc->maskptr; - } - idesc = idesc->next; - } - } -} - -static void -update_masks(intrmask_t *maskptr, int irq) -{ - intrmask_t mask = 1 << irq; - - if (maskptr == NULL) - return; - - if (find_idesc(maskptr, irq) == NULL) { - /* no reference to this maskptr was found in this irq's chain */ - if ((*maskptr & mask) == 0) - return; - /* the irq was included in the classes mask, remove it */ - INTRUNMASK(*maskptr, mask); - } else { - /* a reference to this maskptr was found in this irq's chain */ - if ((*maskptr & mask) != 0) - return; - /* put the irq into the classes mask */ - INTRMASK(*maskptr, mask); - } - /* we need to update all values in the intr_mask[irq] array */ - update_intr_masks(); - /* update mask in chains of the interrupt multiplex handler as well */ - update_mux_masks(); -} - -/* - * Add interrupt handler to linked list hung off of intreclist_head[irq] - * and install shared interrupt multiplex handler, if necessary - */ - -static int -add_intrdesc(intrec *idesc) -{ - int irq = idesc->intr; - - intrec *head = intreclist_head[irq]; - - if (head == NULL) { - /* first handler for this irq, just install it */ - if (icu_setup(irq, idesc->handler, idesc->argument, - idesc->maskptr, idesc->flags) != 0) - return (-1); - - update_intrname(irq, (intptr_t)idesc->devdata); - /* keep reference */ - intreclist_head[irq] = idesc; - } else { - if ((idesc->flags & INTR_EXCL) != 0 - || (head->flags & INTR_EXCL) != 0) { - /* - * can't append new handler, if either list head or - * new handler do not allow interrupts to be shared - */ - if (bootverbose) - printf("\tdevice combination doesn't support " - "shared irq%d\n", irq); - return (-1); - } - if (head->next == NULL) { - /* - * second handler for this irq, replace device driver's - * handler by shared interrupt multiplexer function - */ - icu_unset(irq, head->handler); - if (icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0) != 0) - return (-1); - if (bootverbose) - printf("\tusing shared irq%d.\n", irq); - update_intrname(irq, -1); - } - /* just append to the end of the chain */ - while (head->next != NULL) - head = head->next; - head->next = idesc; - } - update_masks(idesc->maskptr, irq); - return (0); -} - -/* - * Add the interrupt handler descriptor data structure created by an - * earlier call of create_intr() to the linked list for its irq and - * adjust the interrupt masks if necessary. - * - * This function effectively activates the handler. - */ - -int -intr_connect(intrec *idesc) -{ - int errcode = -1; - int irq; - -#ifdef RESOURCE_CHECK - int resflag; -#endif /* RESOURCE_CHECK */ - - if (idesc == NULL) - return (-1); - - irq = idesc->intr; -#ifdef RESOURCE_CHECK - resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED; - if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0) -#endif /* RESOURCE_CHECK */ - { - /* block this irq */ - intrmask_t oldspl = splq(1 << irq); - - /* add irq to class selected by maskptr */ - errcode = add_intrdesc(idesc); - splx(oldspl); - } - if (errcode != 0 && bootverbose) - printf("\tintr_connect(irq%d) failed, result=%d\n", - irq, errcode); - - return (errcode); -} - -/* - * Remove the interrupt handler descriptor data connected created by an - * earlier call of intr_connect() from the linked list and adjust the - * interrupt masks if necessary. - * - * This function deactivates the handler. - */ - -int -intr_disconnect(intrec *idesc) -{ - intrec **hook, *head; - int irq; - int errcode = 0; - - if (idesc == NULL) - return (-1); - - irq = idesc->intr; - - /* find pointer that keeps the reference to this interrupt descriptor */ - hook = find_pred(idesc, irq); - if (hook == NULL) - return (-1); - - /* make copy of original list head, the line after may overwrite it */ - head = intreclist_head[irq]; - - /* unlink: make predecessor point to idesc->next instead of to idesc */ - *hook = idesc->next; - - /* now check whether the element we removed was the list head */ - if (idesc == head) { - intrmask_t oldspl = splq(1 << irq); - - /* we want to remove the list head, which was known to intr_mux */ - icu_unset(irq, (inthand2_t*)intr_mux); - - /* check whether the new list head is the only element on list */ - head = intreclist_head[irq]; - if (head != NULL) { - if (head->next != NULL) { - /* install the multiplex handler with new list head as argument */ - errcode = icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0); - if (errcode == 0) - update_intrname(irq, -1); - } else { - /* install the one remaining handler for this irq */ - errcode = icu_setup(irq, head->handler, - head->argument, - head->maskptr, head->flags); - if (errcode == 0) - update_intrname(irq, (intptr_t)head->devdata); - } - } - splx(oldspl); - } - update_masks(idesc->maskptr, irq); -#ifdef RESOURCE_CHECK - resource_free(idesc->devdata); -#endif /* RESOURCE_CHECK */ - return (0); -} - -/* - * Create an interrupt handler descriptor data structure, which later can - * be activated or deactivated at will by calls of [dis]connect(intrec*). - * - * The dev_instance pointer is required for resource management, and will - * only be passed through to resource_claim(). - * - * The interrupt handler takes an argument of type (void*), which is not - * what is currently used for ISA devices. But since the unit number passed - * to an ISA interrupt handler can be stored in a (void*) variable, this - * causes no problems. Eventually all the ISA interrupt handlers should be - * modified to accept the pointer to their private data, too, instead of - * an integer index. - * - * There will be functions that derive a driver and unit name from a - * dev_instance variable, and those functions will be used to maintain the - * interrupt counter label array referenced by systat and vmstat to report - * device interrupt rates (->update_intrlabels). - */ - -intrec * -intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg, - intrmask_t *maskptr, int flags) -{ - intrec *idesc; - - if (ICU_LEN > 8 * sizeof *maskptr) { - printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n", - ICU_LEN, 8 * sizeof *maskptr); - return (NULL); - } - if ((unsigned)irq >= ICU_LEN) { - printf("create_intr: requested irq%d too high, limit is %d\n", - irq, ICU_LEN -1); - return (NULL); - } - - idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK); - if (idesc) { - idesc->next = NULL; - bzero(idesc, sizeof *idesc); - - idesc->devdata = dev_instance; - idesc->handler = handler; - idesc->argument = arg; - idesc->maskptr = maskptr; - idesc->intr = irq; - idesc->flags = flags; - } - return (idesc); -} - -/* - * Return the memory held by the interrupt handler descriptor data structure - * to the system. Make sure, the handler is not actively used anymore, before. - */ - -int -intr_destroy(intrec *rec) -{ - if (intr_disconnect(rec) != 0) - return (-1); - free(rec, M_DEVBUF); - return (0); -} - -/* - * Emulate the register_intr() call previously defined as low level function. - * That function (now icu_setup()) may no longer be directly called, since - * a conflict between an ISA and PCI interrupt might go by unnocticed, else. - */ - -int -register_intr(int intr, int device_id, u_int flags, - inthand2_t handler, u_int *maskptr, int unit) -{ - /* XXX modify to include isa_device instead of device_id */ - intrec *idesc; - - flags |= INTR_EXCL; - idesc = intr_create((void *)(intptr_t)device_id, intr, handler, - (void*)(intptr_t)unit, maskptr, flags); - return (intr_connect(idesc)); -} - -/* - * Emulate the old unregister_intr() low level function. - * Make sure there is just one interrupt, that it was - * registered as non-shared, and that the handlers match. - */ - -int -unregister_intr(int intr, inthand2_t handler) -{ - intrec *p = intreclist_head[intr]; - - if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler) - return (intr_destroy(p)); - return (EINVAL); -} - -#endif /* __i386__ */ - void register_swi(intr, handler) int intr; diff --git a/sys/kern/kern_random.c b/sys/kern/kern_random.c index d635668..fbb0f86 100644 --- a/sys/kern/kern_random.c +++ b/sys/kern/kern_random.c @@ -1,7 +1,7 @@ /* * random_machdep.c -- A strong random number generator * - * $Id: random_machdep.c,v 1.28 1998/06/18 15:32:07 bde Exp $ + * $Id: random_machdep.c,v 1.29 1998/06/21 11:33:32 bde Exp $ * * Version 0.95, last modified 18-Oct-95 * @@ -45,6 +45,7 @@ #include <sys/select.h> #include <sys/poll.h> #include <sys/md5.h> +#include <sys/bus.h> #include <machine/random.h> diff --git a/sys/pci/intpm.c b/sys/pci/intpm.c index 705e8c6..a07d752 100644 --- a/sys/pci/intpm.c +++ b/sys/pci/intpm.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: intpm.c,v 1.3 1999/01/27 23:45:43 dillon Exp $ + * $Id: intpm.c,v 1.4 1999/01/28 00:57:53 dillon Exp $ */ #include "pci.h" @@ -670,12 +670,10 @@ static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsign #endif /* Spec sheet claims that it use IRQ 9*/ int irq = 9; - void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ void *idesc; - idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); - error = intr_connect(idesc); - if (error != 0) + idesc = inthand_add(NULL, irq, func, arg, maskptr, 0); + if (idesc == 0) return 0; #ifdef APIC_IO nextpin = next_apic_irq(irq); @@ -706,9 +704,7 @@ static int force_pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsign nextpin = next_apic_irq(irq); while (nextpin >= 0) { - idesc = intr_create(dev_instance, nextpin, func, arg, - maskptr, 0); - error = intr_connect(idesc); + idesc = inthand_add(NULL, nextpin, func, arg, maskptr, 0); if (error != 0) return 0; printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h index 5db9081..6c71703 100644 --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -23,35 +23,20 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: interrupt.h,v 1.6 1997/07/09 18:08:15 ache Exp $ + * $Id: interrupt.h,v 1.7 1998/08/11 15:08:13 bde Exp $ */ -/* XXX currently dev_instance must be set to the ISA device_id or -1 for PCI */ -#define INTR_FAST 0x00000001 /* fast interrupt handler */ -#define INTR_EXCL 0x00010000 /* excl. intr, default is shared */ +#ifndef _SYS_INTERRUPT_H_ +#define _SYS_INTERRUPT_H_ typedef void swihand_t __P((void)); -struct intrec *intr_create(void *dev_instance, int irq, inthand2_t handler, - void *arg, intrmask_t *maskptr, int flags); - -int intr_destroy(struct intrec *idesc); - -int intr_connect(struct intrec *idesc); -int intr_disconnect(struct intrec *idesc); - void register_swi __P((int intr, swihand_t *handler)); void swi_dispatcher __P((int intr)); swihand_t swi_generic; swihand_t swi_null; void unregister_swi __P((int intr, swihand_t *handler)); -/* XXX emulate old interface for now ... */ -int register_intr __P((int intr, int device_id, u_int flags, - inthand2_t *handler, u_int *maskptr, int unit)); -int unregister_intr(int intr, inthand2_t handler); +extern swihand_t *ihandlers[]; -#ifdef NHWI -/* XXX type change in middle; MI code uses only the top NSWI entries. */ -extern swihand_t *ihandlers[NHWI + NSWI]; #endif diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 99539f1..cb28195 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)systm.h 8.7 (Berkeley) 3/29/95 - * $Id: systm.h,v 1.86 1999/03/05 19:27:22 bde Exp $ + * $Id: systm.h,v 1.87 1999/03/11 15:09:40 phk Exp $ */ #ifndef _SYS_SYSTM_H_ @@ -220,9 +220,6 @@ intrmask_t splclock __P((void)); intrmask_t splhigh __P((void)); intrmask_t splimp __P((void)); intrmask_t splnet __P((void)); -#ifdef SMP -intrmask_t splq __P((intrmask_t mask)); -#endif intrmask_t splsoftcam __P((void)); intrmask_t splsoftcambio __P((void)); intrmask_t splsoftcamnet __P((void)); |