diff options
30 files changed, 1930 insertions, 800 deletions
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c index d364f4f..aca74fa 100644 --- a/sys/amd64/amd64/fpu.c +++ b/sys/amd64/amd64/fpu.c @@ -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> /* diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c index 30b17d8..474a1a9 100644 --- a/sys/amd64/amd64/identcpu.c +++ b/sys/amd64/amd64/identcpu.c @@ -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)); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 8a9a8d3..186541c 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -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> diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c index ae8e95c..c6eb954 100644 --- a/sys/amd64/amd64/mem.c +++ b/sys/amd64/amd64/mem.c @@ -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> diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index d508788..f73c4f2 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -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 diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c index 13e66f5..4ae5c36 100644 --- a/sys/amd64/amd64/tsc.c +++ b/sys/amd64/amd64/tsc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.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> diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 13e66f5..4ae5c36 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.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> diff --git a/sys/amd64/isa/intr_machdep.c b/sys/amd64/isa/intr_machdep.c new file mode 100644 index 0000000..40acb8e --- /dev/null +++ b/sys/amd64/isa/intr_machdep.c @@ -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); +} diff --git a/sys/amd64/isa/intr_machdep.h b/sys/amd64/isa/intr_machdep.h new file mode 100644 index 0000000..a9a512e --- /dev/null +++ b/sys/amd64/isa/intr_machdep.h @@ -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_ */ diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c index a54f7bb..ccadc08 100644 --- a/sys/amd64/isa/isa.c +++ b/sys/amd64/isa/isa.c @@ -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); -} diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c new file mode 100644 index 0000000..40acb8e --- /dev/null +++ b/sys/amd64/isa/nmi.c @@ -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); +} diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c index d364f4f..aca74fa 100644 --- a/sys/amd64/isa/npx.c +++ b/sys/amd64/isa/npx.c @@ -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> /* diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index f917fc0..f9d9342 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -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 diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index f917fc0..f9d9342 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -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 diff --git a/sys/i386/i386/identcpu.c b/sys/i386/i386/identcpu.c index 30b17d8..474a1a9 100644 --- a/sys/i386/i386/identcpu.c +++ b/sys/i386/i386/identcpu.c @@ -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)); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 8a9a8d3..186541c 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -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> diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c index ae8e95c..c6eb954 100644 --- a/sys/i386/i386/mem.c +++ b/sys/i386/i386/mem.c @@ -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> diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index d508788..f73c4f2 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -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 diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index 13e66f5..4ae5c36 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.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> diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 13e66f5..4ae5c36 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.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> diff --git a/sys/i386/isa/intr_machdep.c b/sys/i386/isa/intr_machdep.c new file mode 100644 index 0000000..40acb8e --- /dev/null +++ b/sys/i386/isa/intr_machdep.c @@ -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); +} diff --git a/sys/i386/isa/intr_machdep.h b/sys/i386/isa/intr_machdep.h new file mode 100644 index 0000000..a9a512e --- /dev/null +++ b/sys/i386/isa/intr_machdep.h @@ -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_ */ diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c index a54f7bb..ccadc08 100644 --- a/sys/i386/isa/isa.c +++ b/sys/i386/isa/isa.c @@ -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); -} diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h index dad1f4d..bf7c7a9 100644 --- a/sys/i386/isa/isa_device.h +++ b/sys/i386/isa/isa_device.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: isa_device.h,v 1.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 */ diff --git a/sys/i386/isa/nmi.c b/sys/i386/isa/nmi.c new file mode 100644 index 0000000..40acb8e --- /dev/null +++ b/sys/i386/isa/nmi.c @@ -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); +} diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index d364f4f..aca74fa 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -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> /* diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 13e66f5..4ae5c36 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.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> diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index 3f7feaf..6e258ab 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: kern_intr.c,v 1.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> diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index d508788..f73c4f2 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -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 diff --git a/sys/net/ppp_tty.c b/sys/net/ppp_tty.c index f0a0408..87f6840d 100644 --- a/sys/net/ppp_tty.c +++ b/sys/net/ppp_tty.c @@ -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> |