Stage 1 of a cleanup of the i386 interrupt registration mechanism.

Interrupts under the new scheme are managed by the i386 nexus with the
awareness of the resource manager.  There is further room for optimizing
the interfaces still.  All the users of register_intr()/intr_create()
should be gone, with the exception of pcic and i386/isa/clock.c.
This commit is contained in:
peter 1999-04-21 07:26:30 +00:00
parent 47b96f90c0
commit fa628c268c
31 changed files with 1888 additions and 803 deletions

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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>

View File

@ -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);
}

View File

@ -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 */
/*

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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>

View File

@ -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.
*

View File

@ -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>

View File

@ -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);
}

View File

@ -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>

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -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);

View File

@ -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

View File

@ -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));