Move interrupt handling code from isa.c to a new file. This should make

isa.c (slightly) more portable and will make my life developing the really
portable version much easier.

Reviewed by:	peter, fsmp
This commit is contained in:
Doug Rabson 1997-06-02 08:19:06 +00:00
parent a3faae319b
commit 683523378c
30 changed files with 1930 additions and 800 deletions

View File

@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91
* $Id: npx.c,v 1.43 1997/05/07 19:58:13 peter Exp $
* $Id: npx.c,v 1.44 1997/05/31 09:27:31 peter Exp $
*/
#include "npx.h"
@ -69,6 +69,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/isa.h>
/*

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
* $Id: identcpu.c,v 1.21 1997/05/23 06:22:47 charnier Exp $
* $Id: identcpu.c,v 1.22 1997/05/31 08:45:23 kato Exp $
*/
#include "opt_cpu.h"
@ -56,7 +56,7 @@
#include <machine/sysarch.h>
#include <machine/md_var.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
/* XXX - should be in header file */
void i486_bzero __P((void *buf, size_t len));

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
* $Id: machdep.c,v 1.244 1997/05/26 09:23:29 fsmp Exp $
* $Id: machdep.c,v 1.245 1997/05/26 18:40:45 fsmp Exp $
*/
#include "npx.h"
@ -117,6 +117,7 @@
#endif
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <machine/random.h>

View File

@ -38,7 +38,7 @@
*
* from: Utah $Hdr: mem.c 1.13 89/10/08$
* from: @(#)mem.c 7.2 (Berkeley) 5/9/91
* $Id: mem.c,v 1.43 1997/05/07 20:02:37 peter Exp $
* $Id: mem.c,v 1.44 1997/05/07 20:32:41 peter Exp $
*/
/*
@ -65,6 +65,7 @@
#ifdef PERFMON
#include <machine/perfmon.h>
#endif
#include <i386/isa/intr_machdep.h>
#include <vm/vm.h>
#include <vm/vm_param.h>

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.96 1997/05/29 05:04:30 peter Exp $
* $Id: trap.c,v 1.97 1997/05/31 09:27:29 peter Exp $
*/
/*
@ -76,7 +76,7 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/../isa/isa_device.h>
#include <machine/../isa/intr_machdep.h>
#include <machine/smp.h>
#ifdef POWERFAIL_NMI

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.85 1997/05/29 05:00:35 peter Exp $
* $Id: clock.c,v 1.86 1997/05/31 09:27:30 peter Exp $
*/
/*
@ -67,7 +67,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <i386/isa/timerreg.h>

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.85 1997/05/29 05:00:35 peter Exp $
* $Id: clock.c,v 1.86 1997/05/31 09:27:30 peter Exp $
*/
/*
@ -67,7 +67,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <i386/isa/timerreg.h>

View File

@ -0,0 +1,418 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.85 1997/05/26 14:42:24 se Exp $
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <machine/ipl.h>
#include <machine/md_var.h>
#include <machine/segments.h>
#if defined(APIC_IO)
#include <machine/smp.h>
#include <machine/apic.h>
#endif /* APIC_IO */
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/isa.h>
#include <i386/isa/icu.h>
#include <i386/isa/ic/i8237.h>
#include "vector.h"
#include <i386/isa/intr_machdep.h>
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static inthand2_t isa_strayintr;
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = (int) arg;
setidt(ICU_OFFSET + intr,
flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
* $Id: isa_device.h,v 1.39 1997/04/27 21:18:58 fsmp Exp $
*/
#ifndef _I386_ISA_INTR_MACHDEP_H_
#define _I386_ISA_INTR_MACHDEP_H_
/*
* Low level interrupt code.
*/
#ifdef KERNEL
/*
* Type of the first (asm) part of an interrupt handler.
*/
typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss));
#define IDTVEC(name) __CONCAT(X,name)
extern char eintrnames[]; /* end of intrnames[] */
extern u_long intrcnt[]; /* counts for for each device and stray */
extern char intrnames[]; /* string table containing device names */
extern u_long *intr_countp[]; /* pointers into intrcnt[] */
extern inthand2_t *intr_handler[]; /* C entry points of intr handlers */
extern u_int intr_mask[]; /* sets of intrs masked during handling of 1 */
extern int intr_unit[]; /* cookies to pass to intr handlers */
inthand_t
IDTVEC(fastintr0), IDTVEC(fastintr1),
IDTVEC(fastintr2), IDTVEC(fastintr3),
IDTVEC(fastintr4), IDTVEC(fastintr5),
IDTVEC(fastintr6), IDTVEC(fastintr7),
IDTVEC(fastintr8), IDTVEC(fastintr9),
IDTVEC(fastintr10), IDTVEC(fastintr11),
IDTVEC(fastintr12), IDTVEC(fastintr13),
IDTVEC(fastintr14), IDTVEC(fastintr15);
inthand_t
IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
/* these functions ONLY exist in an SMP/APIC_IO kernel: */
inthand_t
IDTVEC(fastintr16), IDTVEC(fastintr17),
IDTVEC(fastintr18), IDTVEC(fastintr19),
IDTVEC(fastintr20), IDTVEC(fastintr21),
IDTVEC(fastintr22), IDTVEC(fastintr23);
inthand_t
IDTVEC(intr16), IDTVEC(intr17), IDTVEC(intr18), IDTVEC(intr19),
IDTVEC(intr20), IDTVEC(intr21), IDTVEC(intr22), IDTVEC(intr23);
#define XINVLTLB_OFFSET 32
inthand_t
Xinvltlb;
struct isa_device;
void isa_defaultirq __P((void));
int isa_irq_pending __P((struct isa_device *dvp));
/* this function ONLY exists in an SMP/APIC_IO kernel: */
int icu_irq_pending __P((struct isa_device *dvp));
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));
#endif /* KERNEL */
#endif /* !_I386_ISA_INTR_MACHDEP_H_ */

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.87 1997/05/29 05:56:12 fsmp Exp $
* $Id: isa.c,v 1.88 1997/05/31 09:27:31 peter Exp $
*/
/*
@ -47,8 +47,6 @@
* isa_dmastart()
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
@ -65,6 +63,7 @@
#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/icu.h>
#include <i386/isa/ic/i8237.h>
@ -72,14 +71,6 @@
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
/*
** Register definitions for DMA controller 1 (channels 0..3):
*/
@ -96,40 +87,6 @@
#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static void config_isadev __P((struct isa_device *isdp, u_int *mp));
static void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
int reconfig));
@ -139,8 +96,6 @@ static void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
static int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
u_int checkbits));
static int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
static inthand2_t isa_strayintr;
static void register_imask __P((struct isa_device *dvp, u_int mask));
/*
* print a conflict message
@ -615,44 +570,6 @@ config_isadev_c(isdp, mp, reconfig)
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
static caddr_t dma_bouncebuf[8];
static u_int dma_bouncebufsize[8];
static u_int8_t dma_bounced = 0;
@ -956,70 +873,6 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan) {
return (0);
}
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Find the highest priority enabled display device. Since we can't
* distinguish display devices from ttys, depend on display devices
@ -1067,210 +920,3 @@ struct isa_device *find_isadev(table, driverp, unit)
return (table);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = arg;
setidt(ICU_OFFSET + intr,
flags & RI_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
static void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

418
sys/amd64/isa/nmi.c Normal file
View File

@ -0,0 +1,418 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.85 1997/05/26 14:42:24 se Exp $
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <machine/ipl.h>
#include <machine/md_var.h>
#include <machine/segments.h>
#if defined(APIC_IO)
#include <machine/smp.h>
#include <machine/apic.h>
#endif /* APIC_IO */
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/isa.h>
#include <i386/isa/icu.h>
#include <i386/isa/ic/i8237.h>
#include "vector.h"
#include <i386/isa/intr_machdep.h>
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static inthand2_t isa_strayintr;
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = (int) arg;
setidt(ICU_OFFSET + intr,
flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

View File

@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91
* $Id: npx.c,v 1.43 1997/05/07 19:58:13 peter Exp $
* $Id: npx.c,v 1.44 1997/05/31 09:27:31 peter Exp $
*/
#include "npx.h"
@ -69,6 +69,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/isa.h>
/*

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.163 1997/05/31 18:01:38 peter Exp $
# $Id: files.i386,v 1.164 1997/06/01 20:25:55 bde Exp $
#
aic7xxx_asm optional ahc device-driver \
dependency "$S/dev/aic7xxx/*.[chyl]" \
@ -126,6 +126,7 @@ i386/isa/if_ze.c optional ze device-driver
i386/isa/if_zp.c optional zp device-driver
i386/isa/ipl_funcs.c standard \
compile-with "${CC} -c ${CFLAGS} ${PROF:S/^$/-fomit-frame-pointer/} $<"
i386/isa/intr_machdep.c standard
i386/isa/isa.c optional isa device-driver
i386/isa/istallion.c optional stli device-driver
i386/isa/joy.c optional joy device-driver

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.163 1997/05/31 18:01:38 peter Exp $
# $Id: files.i386,v 1.164 1997/06/01 20:25:55 bde Exp $
#
aic7xxx_asm optional ahc device-driver \
dependency "$S/dev/aic7xxx/*.[chyl]" \
@ -126,6 +126,7 @@ i386/isa/if_ze.c optional ze device-driver
i386/isa/if_zp.c optional zp device-driver
i386/isa/ipl_funcs.c standard \
compile-with "${CC} -c ${CFLAGS} ${PROF:S/^$/-fomit-frame-pointer/} $<"
i386/isa/intr_machdep.c standard
i386/isa/isa.c optional isa device-driver
i386/isa/istallion.c optional stli device-driver
i386/isa/joy.c optional joy device-driver

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
* $Id: identcpu.c,v 1.21 1997/05/23 06:22:47 charnier Exp $
* $Id: identcpu.c,v 1.22 1997/05/31 08:45:23 kato Exp $
*/
#include "opt_cpu.h"
@ -56,7 +56,7 @@
#include <machine/sysarch.h>
#include <machine/md_var.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
/* XXX - should be in header file */
void i486_bzero __P((void *buf, size_t len));

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
* $Id: machdep.c,v 1.244 1997/05/26 09:23:29 fsmp Exp $
* $Id: machdep.c,v 1.245 1997/05/26 18:40:45 fsmp Exp $
*/
#include "npx.h"
@ -117,6 +117,7 @@
#endif
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <machine/random.h>

View File

@ -38,7 +38,7 @@
*
* from: Utah $Hdr: mem.c 1.13 89/10/08$
* from: @(#)mem.c 7.2 (Berkeley) 5/9/91
* $Id: mem.c,v 1.43 1997/05/07 20:02:37 peter Exp $
* $Id: mem.c,v 1.44 1997/05/07 20:32:41 peter Exp $
*/
/*
@ -65,6 +65,7 @@
#ifdef PERFMON
#include <machine/perfmon.h>
#endif
#include <i386/isa/intr_machdep.h>
#include <vm/vm.h>
#include <vm/vm_param.h>

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.96 1997/05/29 05:04:30 peter Exp $
* $Id: trap.c,v 1.97 1997/05/31 09:27:29 peter Exp $
*/
/*
@ -76,7 +76,7 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/../isa/isa_device.h>
#include <machine/../isa/intr_machdep.h>
#include <machine/smp.h>
#ifdef POWERFAIL_NMI

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.85 1997/05/29 05:00:35 peter Exp $
* $Id: clock.c,v 1.86 1997/05/31 09:27:30 peter Exp $
*/
/*
@ -67,7 +67,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <i386/isa/timerreg.h>

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.85 1997/05/29 05:00:35 peter Exp $
* $Id: clock.c,v 1.86 1997/05/31 09:27:30 peter Exp $
*/
/*
@ -67,7 +67,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <i386/isa/timerreg.h>

418
sys/i386/isa/intr_machdep.c Normal file
View File

@ -0,0 +1,418 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.85 1997/05/26 14:42:24 se Exp $
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <machine/ipl.h>
#include <machine/md_var.h>
#include <machine/segments.h>
#if defined(APIC_IO)
#include <machine/smp.h>
#include <machine/apic.h>
#endif /* APIC_IO */
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/isa.h>
#include <i386/isa/icu.h>
#include <i386/isa/ic/i8237.h>
#include "vector.h"
#include <i386/isa/intr_machdep.h>
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static inthand2_t isa_strayintr;
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = (int) arg;
setidt(ICU_OFFSET + intr,
flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

105
sys/i386/isa/intr_machdep.h Normal file
View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
* $Id: isa_device.h,v 1.39 1997/04/27 21:18:58 fsmp Exp $
*/
#ifndef _I386_ISA_INTR_MACHDEP_H_
#define _I386_ISA_INTR_MACHDEP_H_
/*
* Low level interrupt code.
*/
#ifdef KERNEL
/*
* Type of the first (asm) part of an interrupt handler.
*/
typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss));
#define IDTVEC(name) __CONCAT(X,name)
extern char eintrnames[]; /* end of intrnames[] */
extern u_long intrcnt[]; /* counts for for each device and stray */
extern char intrnames[]; /* string table containing device names */
extern u_long *intr_countp[]; /* pointers into intrcnt[] */
extern inthand2_t *intr_handler[]; /* C entry points of intr handlers */
extern u_int intr_mask[]; /* sets of intrs masked during handling of 1 */
extern int intr_unit[]; /* cookies to pass to intr handlers */
inthand_t
IDTVEC(fastintr0), IDTVEC(fastintr1),
IDTVEC(fastintr2), IDTVEC(fastintr3),
IDTVEC(fastintr4), IDTVEC(fastintr5),
IDTVEC(fastintr6), IDTVEC(fastintr7),
IDTVEC(fastintr8), IDTVEC(fastintr9),
IDTVEC(fastintr10), IDTVEC(fastintr11),
IDTVEC(fastintr12), IDTVEC(fastintr13),
IDTVEC(fastintr14), IDTVEC(fastintr15);
inthand_t
IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
/* these functions ONLY exist in an SMP/APIC_IO kernel: */
inthand_t
IDTVEC(fastintr16), IDTVEC(fastintr17),
IDTVEC(fastintr18), IDTVEC(fastintr19),
IDTVEC(fastintr20), IDTVEC(fastintr21),
IDTVEC(fastintr22), IDTVEC(fastintr23);
inthand_t
IDTVEC(intr16), IDTVEC(intr17), IDTVEC(intr18), IDTVEC(intr19),
IDTVEC(intr20), IDTVEC(intr21), IDTVEC(intr22), IDTVEC(intr23);
#define XINVLTLB_OFFSET 32
inthand_t
Xinvltlb;
struct isa_device;
void isa_defaultirq __P((void));
int isa_irq_pending __P((struct isa_device *dvp));
/* this function ONLY exists in an SMP/APIC_IO kernel: */
int icu_irq_pending __P((struct isa_device *dvp));
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));
#endif /* KERNEL */
#endif /* !_I386_ISA_INTR_MACHDEP_H_ */

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.87 1997/05/29 05:56:12 fsmp Exp $
* $Id: isa.c,v 1.88 1997/05/31 09:27:31 peter Exp $
*/
/*
@ -47,8 +47,6 @@
* isa_dmastart()
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
@ -65,6 +63,7 @@
#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/icu.h>
#include <i386/isa/ic/i8237.h>
@ -72,14 +71,6 @@
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
/*
** Register definitions for DMA controller 1 (channels 0..3):
*/
@ -96,40 +87,6 @@
#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static void config_isadev __P((struct isa_device *isdp, u_int *mp));
static void config_isadev_c __P((struct isa_device *isdp, u_int *mp,
int reconfig));
@ -139,8 +96,6 @@ static void conflict __P((struct isa_device *dvp, struct isa_device *tmpdvp,
static int haveseen __P((struct isa_device *dvp, struct isa_device *tmpdvp,
u_int checkbits));
static int isa_dmarangecheck __P((caddr_t va, u_int length, int chan));
static inthand2_t isa_strayintr;
static void register_imask __P((struct isa_device *dvp, u_int mask));
/*
* print a conflict message
@ -615,44 +570,6 @@ config_isadev_c(isdp, mp, reconfig)
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
static caddr_t dma_bouncebuf[8];
static u_int dma_bouncebufsize[8];
static u_int8_t dma_bounced = 0;
@ -956,70 +873,6 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan) {
return (0);
}
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Find the highest priority enabled display device. Since we can't
* distinguish display devices from ttys, depend on display devices
@ -1067,210 +920,3 @@ struct isa_device *find_isadev(table, driverp, unit)
return (table);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = arg;
setidt(ICU_OFFSET + intr,
flags & RI_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
static void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
* $Id: isa_device.h,v 1.40 1997/05/26 14:42:24 se Exp $
* $Id: isa_device.h,v 1.41 1997/05/31 09:07:36 peter Exp $
*/
#ifndef _I386_ISA_ISA_DEVICE_H_
@ -41,13 +41,6 @@
* ISA Bus Autoconfiguration
*/
#define IDTVEC(name) __CONCAT(X,name)
/*
* Type of the first (asm) part of an interrupt handler.
*/
typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss));
/*
* Per device structure.
*
@ -106,14 +99,6 @@ struct isa_driver {
#ifdef KERNEL
extern char eintrnames[]; /* end of intrnames[] */
extern u_long intrcnt[]; /* counts for for each device and stray */
extern char intrnames[]; /* string table containing device names */
extern u_long *intr_countp[]; /* pointers into intrcnt[] */
extern inthand2_t *intr_handler[]; /* C entry points of intr handlers */
extern u_int intr_mask[]; /* sets of intrs masked during handling of 1 */
extern int intr_unit[]; /* cookies to pass to intr handlers */
extern struct isa_device isa_biotab_fdc[];
extern struct isa_device isa_biotab_wdc[];
extern struct isa_device isa_devtab_bio[];
@ -121,34 +106,6 @@ extern struct isa_device isa_devtab_net[];
extern struct isa_device isa_devtab_null[];
extern struct isa_device isa_devtab_tty[];
inthand_t
IDTVEC(fastintr0), IDTVEC(fastintr1),
IDTVEC(fastintr2), IDTVEC(fastintr3),
IDTVEC(fastintr4), IDTVEC(fastintr5),
IDTVEC(fastintr6), IDTVEC(fastintr7),
IDTVEC(fastintr8), IDTVEC(fastintr9),
IDTVEC(fastintr10), IDTVEC(fastintr11),
IDTVEC(fastintr12), IDTVEC(fastintr13),
IDTVEC(fastintr14), IDTVEC(fastintr15);
inthand_t
IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
/* these functions ONLY exist in an SMP/APIC_IO kernel: */
inthand_t
IDTVEC(fastintr16), IDTVEC(fastintr17),
IDTVEC(fastintr18), IDTVEC(fastintr19),
IDTVEC(fastintr20), IDTVEC(fastintr21),
IDTVEC(fastintr22), IDTVEC(fastintr23);
inthand_t
IDTVEC(intr16), IDTVEC(intr17), IDTVEC(intr18), IDTVEC(intr19),
IDTVEC(intr20), IDTVEC(intr21), IDTVEC(intr22), IDTVEC(intr23);
#define XINVLTLB_OFFSET 32
inthand_t
Xinvltlb;
struct isa_device *
find_display __P((void));
struct isa_device *
@ -156,23 +113,13 @@ struct isa_device *
int unit));
int haveseen_isadev __P((struct isa_device *dvp, u_int checkbits));
void isa_configure __P((void));
void isa_defaultirq __P((void));
void isa_dmacascade __P((int chan));
void isa_dmadone __P((int flags, caddr_t addr, int nbytes, int chan));
void isa_dmainit __P((int chan, u_int bouncebufsize));
void isa_dmastart __P((int flags, caddr_t addr, u_int nbytes, int chan));
int isa_dma_acquire __P((int chan));
void isa_dma_release __P((int chan));
int isa_irq_pending __P((struct isa_device *dvp));
/* this function ONLY exists in an SMP/APIC_IO kernel: */
int icu_irq_pending __P((struct isa_device *dvp));
int isa_nmi __P((int cd));
void reconfig_isadev __P((struct isa_device *isdp, u_int *mp));
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));
#endif /* KERNEL */

418
sys/i386/isa/nmi.c Normal file
View File

@ -0,0 +1,418 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* 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, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
* $Id: isa.c,v 1.85 1997/05/26 14:42:24 se Exp $
*/
#include "opt_auto_eoi.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <machine/ipl.h>
#include <machine/md_var.h>
#include <machine/segments.h>
#if defined(APIC_IO)
#include <machine/smp.h>
#include <machine/apic.h>
#endif /* APIC_IO */
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/isa.h>
#include <i386/isa/icu.h>
#include <i386/isa/ic/i8237.h>
#include "vector.h"
#include <i386/isa/intr_machdep.h>
#include <sys/interrupt.h>
#ifdef APIC_IO
/*
* This is to accommodate "mixed-mode" programming for
* motherboards that don't connect the 8254 to the IO APIC.
*/
#define AUTO_EOI_1
#endif
u_long *intr_countp[ICU_LEN];
inthand2_t *intr_handler[ICU_LEN];
u_int intr_mask[ICU_LEN];
u_int* intr_mptr[ICU_LEN];
int intr_unit[ICU_LEN];
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
&IDTVEC(fastintr4), &IDTVEC(fastintr5),
&IDTVEC(fastintr6), &IDTVEC(fastintr7),
&IDTVEC(fastintr8), &IDTVEC(fastintr9),
&IDTVEC(fastintr10), &IDTVEC(fastintr11),
&IDTVEC(fastintr12), &IDTVEC(fastintr13),
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
#if defined(APIC_IO)
, &IDTVEC(fastintr16), &IDTVEC(fastintr17),
&IDTVEC(fastintr18), &IDTVEC(fastintr19),
&IDTVEC(fastintr20), &IDTVEC(fastintr21),
&IDTVEC(fastintr22), &IDTVEC(fastintr23)
#endif /* APIC_IO */
};
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
#if defined(APIC_IO)
, &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
&IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
#endif /* APIC_IO */
};
static inthand2_t isa_strayintr;
#define NMI_PARITY (1 << 7)
#define NMI_IOCHAN (1 << 6)
#define ENMI_WATCHDOG (1 << 7)
#define ENMI_BUSTIMER (1 << 6)
#define ENMI_IOSTATUS (1 << 5)
/*
* Handle a NMI, possibly a machine check.
* return true to panic system, false to ignore.
*/
int
isa_nmi(cd)
int cd;
{
int isa_port = inb(0x61);
int eisa_port = inb(0x461);
if(isa_port & NMI_PARITY) {
panic("RAM parity error, likely hardware failure.");
} else if(isa_port & NMI_IOCHAN) {
panic("I/O channel check, likely hardware failure.");
} else if(eisa_port & ENMI_WATCHDOG) {
panic("EISA watchdog timer expired, likely hardware failure.");
} else if(eisa_port & ENMI_BUSTIMER) {
panic("EISA bus timeout, likely hardware failure.");
} else if(eisa_port & ENMI_IOSTATUS) {
panic("EISA I/O port status error.");
} else {
printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
return(0);
}
}
/*
* Fill in default interrupt table (in case of spuruious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
isa_defaultirq()
{
int i;
/* icu vectors */
for (i = 0; i < ICU_LEN; i++)
icu_unset(i, (inthand2_t *)NULL);
/* initialize 8259's */
outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
#ifdef AUTO_EOI_1
outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU1+1, 1); /* 8086 mode */
#endif
outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
outb(IO_ICU1, 0x0a); /* default to IRR on read */
outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
outb(IO_ICU2+1,2); /* my slave id is 2 */
#ifdef AUTO_EOI_2
outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
#else
outb(IO_ICU2+1,1); /* 8086 mode */
#endif
outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
outb(IO_ICU2, 0x0a); /* default to IRR on read */
}
/*
* Caught a stray interrupt, notify
*/
static void
isa_strayintr(d)
int d;
{
/* DON'T BOTHER FOR NOW! */
/* for some reason, we get bursts of intr #7, even if not enabled! */
/*
* Well the reason you got bursts of intr #7 is because someone
* raised an interrupt line and dropped it before the 8259 could
* prioritize it. This is documented in the intel data book. This
* means you have BAD hardware! I have changed this so that only
* the first 5 get logged, then it quits logging them, and puts
* out a special message. rgrimes 3/25/1993
*/
/*
* XXX TODO print a different message for #7 if it is for a
* glitch. Glitches can be distinguished from real #7's by
* testing that the in-service bit is _not_ set. The test
* must be done before sending an EOI so it can't be done if
* we are using AUTO_EOI_1.
*/
if (intrcnt[NR_DEVICES + d] <= 5)
log(LOG_ERR, "stray irq %d\n", d);
if (intrcnt[NR_DEVICES + d] == 5)
log(LOG_CRIT,
"too many stray irq %d's; not logging any more\n", d);
}
/*
* Return nonzero if a (masked) irq is pending for a given device.
*/
#if defined(APIC_IO)
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
/* read APIC IRR containing the 16 ISA INTerrupts */
return ((lapic__irr1 & 0x00ffffff)
& (u_int32_t)dvp->id_irq) ? 1 : 0;
}
/*
* an 8259 specific routine,
* for use by boot probes in certain device drivers.
*/
int
icu_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#else /* APIC_IO */
int
isa_irq_pending(dvp)
struct isa_device *dvp;
{
unsigned id_irq;
id_irq = dvp->id_irq;
if (id_irq & 0xff)
return (inb(IO_ICU1) & id_irq);
return (inb(IO_ICU2) & (id_irq >> 8));
}
#endif /* APIC_IO */
int
update_intr_masks(void)
{
int intr, n=0;
u_int mask,*maskptr;
for (intr=0; intr < ICU_LEN; intr ++) {
#if defined(APIC_IO)
/* no 8259 SLAVE to ignore */
#else
if (intr==2) continue; /* ignore 8259 SLAVE output */
#endif /* APIC_IO */
maskptr = intr_mptr[intr];
if (!maskptr) continue;
*maskptr |= 1 << intr;
mask = *maskptr;
if (mask != intr_mask[intr]) {
#if 0
printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
intr, intr_mask[intr], mask, maskptr);
#endif
intr_mask[intr]=mask;
n++;
}
}
return (n);
}
/*
* The find_device_id function is only required because of the way the
* device names are currently stored for reporting in systat or vmstat.
* In fact, those programs should be modified to use the sysctl interface
* to obtain a list of driver names by traversing intreclist_head[irq].
*/
static int
find_device_id(int irq)
{
char buf[16];
char *cp;
int free_id, id;
sprintf(buf, "pci irq%d", irq);
cp = intrnames;
/* default to 0, which corresponds to clk0 */
free_id = 0;
for (id = 0; id < NR_DEVICES; id++) {
if (strcmp(cp, buf) == 0)
return (id);
if (free_id == 0 && strcmp(cp, "pci irqnn") == 0)
free_id = id;
while (*cp++ != '\0');
}
#if 0
if (free_id == 0) {
/*
* All pci irq counters are in use, perhaps because config
* is old so there aren't any. Abuse the clk0 counter.
*/
printf("\tcounting shared irq%d as clk0 irq\n", irq);
}
#endif
return (free_id);
}
void
update_intrname(int intr, int device_id)
{
char *cp;
int id;
if (device_id == -1)
device_id = find_device_id(intr);
if ((u_int)device_id >= NR_DEVICES)
return;
intr_countp[intr] = &intrcnt[device_id];
for (cp = intrnames, id = 0; id <= device_id; id++)
while (*cp++ != '\0')
;
if (cp > eintrnames)
return;
if (intr < 10) {
cp[-3] = intr + '0';
cp[-2] = ' ';
} else if (intr < 20) {
cp[-3] = '1';
cp[-2] = intr - 10 + '0';
} else {
cp[-3] = '2';
cp[-2] = intr - 20 + '0';
}
}
int
icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
{
u_long ef;
u_int mask = (maskptr ? *maskptr : 0);
#if defined(APIC_IO)
if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
#else
if ((u_int)intr >= ICU_LEN || intr == 2)
#endif /* APIC_IO */
if (intr_handler[intr] != isa_strayintr)
return (EBUSY);
ef = read_eflags();
disable_intr();
intr_handler[intr] = handler;
intr_mptr[intr] = maskptr;
intr_mask[intr] = mask | (1 << intr);
intr_unit[intr] = (int) arg;
setidt(ICU_OFFSET + intr,
flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
INTREN(1 << intr);
write_eflags(ef);
return (0);
}
void
register_imask(dvp, mask)
struct isa_device *dvp;
u_int mask;
{
if (dvp->id_alive && dvp->id_irq) {
int intr;
intr = ffs(dvp->id_irq) - 1;
intr_mask[intr] = mask | (1 <<intr);
}
(void) update_intr_masks();
}
int
icu_unset(intr, handler)
int intr;
inthand2_t *handler;
{
u_long ef;
if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
return (EINVAL);
INTRDIS(1 << intr);
ef = read_eflags();
disable_intr();
intr_countp[intr] = &intrcnt[NR_DEVICES + intr];
intr_handler[intr] = isa_strayintr;
intr_mptr[intr] = NULL;
intr_mask[intr] = HWI_MASK | SWI_MASK;
intr_unit[intr] = intr;
setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
write_eflags(ef);
return (0);
}

View File

@ -32,7 +32,7 @@
* SUCH DAMAGE.
*
* from: @(#)npx.c 7.2 (Berkeley) 5/12/91
* $Id: npx.c,v 1.43 1997/05/07 19:58:13 peter Exp $
* $Id: npx.c,v 1.44 1997/05/31 09:27:31 peter Exp $
*/
#include "npx.h"
@ -69,6 +69,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/isa.h>
/*

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.85 1997/05/29 05:00:35 peter Exp $
* $Id: clock.c,v 1.86 1997/05/31 09:27:30 peter Exp $
*/
/*
@ -67,7 +67,7 @@
#include <i386/isa/icu.h>
#include <i386/isa/isa.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/intr_machdep.h>
#include <i386/isa/rtc.h>
#include <i386/isa/timerreg.h>

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.3 1997/05/31 09:30:39 peter Exp $
* $Id: kern_intr.c,v 1.4 1997/06/01 16:05:13 peter Exp $
*
*/
@ -37,8 +37,8 @@
#endif /* RESOURCE_CHECK */
#include <i386/isa/icu.h>
#include <i386/isa/isa_device.h>
#include <sys/interrupt.h> /* XXX needs inthand2_t from isa_device.h */
#include <i386/isa/intr_machdep.h>
#include <sys/interrupt.h>
#include <machine/ipl.h>

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)trap.c 7.4 (Berkeley) 5/13/91
* $Id: trap.c,v 1.96 1997/05/29 05:04:30 peter Exp $
* $Id: trap.c,v 1.97 1997/05/31 09:27:29 peter Exp $
*/
/*
@ -76,7 +76,7 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/../isa/isa_device.h>
#include <machine/../isa/intr_machdep.h>
#include <machine/smp.h>
#ifdef POWERFAIL_NMI

View File

@ -70,7 +70,7 @@
* Paul Mackerras (paulus@cs.anu.edu.au).
*/
/* $Id: ppp_tty.c,v 1.16 1997/05/31 09:49:35 peter Exp $ */
/* $Id: ppp_tty.c,v 1.17 1997/05/31 10:13:46 peter Exp $ */
/* from Id: ppp_tty.c,v 1.3 1995/08/16 01:36:40 paulus Exp */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
@ -96,7 +96,7 @@
#define KERNEL
#ifdef i386 /* fiddle with the spl locking */
# include <i386/isa/isa_device.h>
# include <i386/isa/intr_machdep.h>
#endif
#include <net/if.h>