summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2000-03-26 22:38:40 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2000-03-26 22:38:40 +0000
commit971bb4bc1ce2f7f91c9871b0f50a68e39326fd1c (patch)
tree349aff69b835169acc1c72f4e2c4ad13c674fcbd /sys/arch
parent4a8a2378aeebf4afb7f090031193a8fc582384e2 (diff)
from netbsd: pci interrupt routing code.
also, change a few pcidevs names to match netbsd (and more descriptive). tested on a bunch of laptops, helps resolving 'pin X unmapped' problems for (usually) usb and cardbus cntrollers.
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/i386/conf/GENERIC4
-rw-r--r--sys/arch/i386/conf/files.i38615
-rw-r--r--sys/arch/i386/i386/autoconf.c13
-rw-r--r--sys/arch/i386/i386/bios32.c180
-rw-r--r--sys/arch/i386/include/biosvar.h25
-rw-r--r--sys/arch/i386/pci/opti82c558.c248
-rw-r--r--sys/arch/i386/pci/opti82c558reg.h65
-rw-r--r--sys/arch/i386/pci/opti82c700.c290
-rw-r--r--sys/arch/i386/pci/opti82c700reg.h71
-rw-r--r--sys/arch/i386/pci/pci_bus_fixup.c135
-rw-r--r--sys/arch/i386/pci/pci_bus_fixup.h28
-rw-r--r--sys/arch/i386/pci/pci_intr_fixup.c696
-rw-r--r--sys/arch/i386/pci/pci_intr_fixup.h65
-rw-r--r--sys/arch/i386/pci/pcib.c2
-rw-r--r--sys/arch/i386/pci/pcibios.c475
-rw-r--r--sys/arch/i386/pci/pcibios.h87
-rw-r--r--sys/arch/i386/pci/piix.c237
-rw-r--r--sys/arch/i386/pci/piixreg.h55
-rw-r--r--sys/arch/i386/pci/piixvar.h77
-rw-r--r--sys/arch/i386/pci/sis85c503.c180
-rw-r--r--sys/arch/i386/pci/sis85c503reg.h52
-rw-r--r--sys/arch/i386/pci/via82c586.c270
-rw-r--r--sys/arch/i386/pci/via82c586reg.h62
23 files changed, 3326 insertions, 6 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 1d47e9180bb..b838ef7be8c 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.162 2000/03/26 18:49:43 aaron Exp $
+# $OpenBSD: GENERIC,v 1.163 2000/03/26 22:38:31 mickey Exp $
# $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $
#
# GENERIC -- everything that's currently supported
@@ -48,6 +48,8 @@ option EISAVERBOSE
#option PCMCIAVERBOSE
#option USBVERBOSE
+option BIOS32,PCIBIOS,PCIBIOS_INTR_FIXUP
+
pchb* at pci? dev ? function ? # PCI-Host bridges
ppb* at pci? dev ? function ? # PCI-PCI bridges
pci* at ppb? bus ?
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 8c17435b5cd..809930770b0 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.62 2000/02/21 17:09:08 mickey Exp $
+# $OpenBSD: files.i386,v 1.63 2000/03/26 22:38:32 mickey Exp $
# $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $
#
# new style config file for i386 architecture
@@ -84,8 +84,17 @@ file arch/i386/i386/mainbus.c mainbus
include "../../../dev/pci/files.pci"
file arch/i386/pci/pci_machdep.c pci
-file arch/i386/pci/pciide_machdep.c pciide
file arch/i386/pci/pci_compat.c pci # XXX compatibility
+file arch/i386/pci/pcibios.c pcibios
+file arch/i386/pci/pci_intr_fixup.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/piix.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/opti82c558.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/opti82c700.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/sis85c503.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/via82c586.c pcibios & pcibios_intr_fixup
+file arch/i386/pci/pci_bus_fixup.c pcibios & pcibios_bus_fixup
+file arch/i386/pci/pciide_machdep.c pciide
+file arch/i386/pci/pcic_pci_machdep.c pcic_pci
# PCI-Host bridge chipsets
device pchb: pcibus
@@ -244,6 +253,8 @@ attach apm at bios
file arch/i386/i386/apm.c apm needs-count
file arch/i386/i386/apmcall.S apm
+file arch/i386/i386/bios32.c bios32
+
# XXXX pcic here because it needs to be late. The catch: pcic needs
# to be late, so devices which attach to it are attached late. But it
# needs to be before its isa and pci attachments. This answer is
diff --git a/sys/arch/i386/i386/autoconf.c b/sys/arch/i386/i386/autoconf.c
index 28c2a8ed743..bbff08f8189 100644
--- a/sys/arch/i386/i386/autoconf.c
+++ b/sys/arch/i386/i386/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.30 1999/09/12 19:44:04 weingart Exp $ */
+/* $OpenBSD: autoconf.c,v 1.31 2000/03/26 22:38:32 mickey Exp $ */
/* $NetBSD: autoconf.c,v 1.20 1996/05/03 19:41:56 christos Exp $ */
/*-
@@ -59,6 +59,9 @@
#include <machine/pte.h>
#include <machine/cpu.h>
+#include <machine/biosvar.h>
+
+#include <i386/pci/pcibios.h>
#include <dev/cons.h>
@@ -84,6 +87,14 @@ configure()
startrtclock();
+#ifdef BIOS32
+ bios32_init();
+#endif
+
+#ifdef PCIBIOS
+ pcibios_init();
+#endif
+
if (config_rootfound("mainbus", NULL) == NULL)
panic("configure: mainbus not configured");
diff --git a/sys/arch/i386/i386/bios32.c b/sys/arch/i386/i386/bios32.c
new file mode 100644
index 00000000000..75a0d47b239
--- /dev/null
+++ b/sys/arch/i386/i386/bios32.c
@@ -0,0 +1,180 @@
+/* $NetBSD: bios32.c,v 1.1 1999/11/17 00:55:50 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Basic interface to BIOS32 services.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <dev/isa/isareg.h>
+#ifdef __NetBSD__
+#include <machine/isa_machdep.h>
+#include <machine/bios32.h>
+#elif defined(__OpenBSD__)
+#include <i386/isa/isa_machdep.h>
+#include <machine/biosvar.h>
+#endif
+
+#include <machine/segments.h>
+
+#define BIOS32_START 0xe0000
+#define BIOS32_SIZE 0x20000
+#define BIOS32_END (BIOS32_START + BIOS32_SIZE - 0x10)
+
+struct bios32_entry bios32_entry;
+
+/*
+ * Initialize the BIOS32 interface.
+ */
+void
+bios32_init()
+{
+ paddr_t entry = 0;
+ caddr_t p;
+ unsigned char cksum;
+ int i;
+
+ for (p = (caddr_t)ISA_HOLE_VADDR(BIOS32_START);
+ p < (caddr_t)ISA_HOLE_VADDR(BIOS32_END);
+ p += 16) {
+ if (*(int *)p != BIOS32_MAKESIG('_', '3', '2', '_'))
+ continue;
+
+ cksum = 0;
+ for (i = 0; i < 16; i++)
+ cksum += *(unsigned char *)(p + i);
+ if (cksum != 0)
+ continue;
+
+ if (*(p + 9) != 1)
+ continue;
+
+ entry = *(u_int32_t *)(p + 4);
+
+ printf("BIOS32 rev. %d found at 0x%lx\n",
+ *(p + 8), entry);
+
+ if (entry < BIOS32_START ||
+ entry >= BIOS32_END) {
+ printf("BIOS32 entry point outside "
+ "allowable range\n");
+ entry = 0;
+ }
+ break;
+ }
+
+ if (entry != 0) {
+ bios32_entry.offset = (caddr_t)ISA_HOLE_VADDR(entry);
+ bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL);
+ }
+}
+
+/*
+ * Call BIOS32 to locate the specified BIOS32 service, and fill
+ * in the entry point information.
+ */
+int
+bios32_service(service, e, ei)
+ u_int32_t service;
+ bios32_entry_t e;
+ bios32_entry_info_t ei;
+{
+ u_int32_t eax, ebx, ecx, edx;
+ paddr_t entry;
+
+ if (bios32_entry.offset == 0)
+ return (0); /* BIOS32 not present */
+
+ __asm __volatile("lcall (%%edi)"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "0" (service), "1" (0), "D" (&bios32_entry));
+
+ if ((eax & 0xff) != 0)
+ return (0); /* service not found */
+
+ entry = ebx + edx;
+
+ if (entry < BIOS32_START || entry >= BIOS32_END) {
+ printf("bios32: entry point for service %c%c%c%c is outside "
+ "allowable range\n",
+ service & 0xff,
+ (service >> 8) & 0xff,
+ (service >> 16) & 0xff,
+ (service >> 24) & 0xff);
+ return (0);
+ }
+
+ e->offset = (caddr_t)ISA_HOLE_VADDR(entry);
+ e->segment = GSEL(GCODE_SEL, SEL_KPL);
+
+ ei->bei_base = ebx;
+ ei->bei_size = ecx;
+ ei->bei_entry = entry;
+
+ return (1);
+}
diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h
index 2b77643e0d5..a80bf2f4a2d 100644
--- a/sys/arch/i386/include/biosvar.h
+++ b/sys/arch/i386/include/biosvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: biosvar.h,v 1.34 2000/03/05 19:07:43 mickey Exp $ */
+/* $OpenBSD: biosvar.h,v 1.35 2000/03/26 22:38:33 mickey Exp $ */
/*
* Copyright (c) 1997-1999 Michael Shalayeff
@@ -61,6 +61,25 @@
#define BIOS_MAP_NVS 0x04 /* ACPI NVS memory */
/*
+ * BIOS32
+ */
+typedef
+struct bios32_entry_info {
+ paddr_t bei_base;
+ psize_t bei_size;
+ paddr_t bei_entry;
+} *bios32_entry_info_t;
+
+typedef
+struct bios32_entry {
+ caddr_t offset;
+ u_int16_t segment;
+} __attribute__((__packed__)) *bios32_entry_t;
+
+#define BIOS32_MAKESIG(a, b, c, d) \
+ ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+
+/*
* CTL_BIOS definitions.
*/
#define BIOS_DEV 1 /* int: BIOS boot device */
@@ -192,6 +211,10 @@ int bioscngetc __P((dev_t));
void bioscnpollc __P((dev_t, int));
void bios_getopt __P((void));
+/* bios32.c */
+void bios32_init __P((void));
+int bios32_service __P((u_int32_t, bios32_entry_t, bios32_entry_info_t));
+
extern u_int bootapiver;
extern bios_memmap_t *bios_memmap;
extern bios_pciinfo_t *bios_pciinfo;
diff --git a/sys/arch/i386/pci/opti82c558.c b/sys/arch/i386/pci/opti82c558.c
new file mode 100644
index 00000000000..74fd3280e3b
--- /dev/null
+++ b/sys/arch/i386/pci/opti82c558.c
@@ -0,0 +1,248 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the Opti 82c558 PCI-ISA bridge interrupt controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/opti82c558reg.h>
+
+int opti82c558_getclink __P((pciintr_icu_handle_t, int, int *));
+int opti82c558_get_intr __P((pciintr_icu_handle_t, int, int *));
+int opti82c558_set_intr __P((pciintr_icu_handle_t, int, int));
+int opti82c558_get_trigger __P((pciintr_icu_handle_t, int, int *));
+int opti82c558_set_trigger __P((pciintr_icu_handle_t, int, int));
+
+const struct pciintr_icu opti82c558_pci_icu = {
+ opti82c558_getclink,
+ opti82c558_get_intr,
+ opti82c558_set_intr,
+ opti82c558_get_trigger,
+ opti82c558_set_trigger,
+};
+
+struct opti82c558_handle {
+ pci_chipset_tag_t ph_pc;
+ pcitag_t ph_tag;
+};
+
+static const int viper_pirq_decode[] = {
+ -1, 5, 9, 10, 11, 12, 14, 15
+};
+
+static const int viper_pirq_encode[] = {
+ -1, /* 0 */
+ -1, /* 1 */
+ -1, /* 2 */
+ -1, /* 3 */
+ -1, /* 4 */
+ VIPER_PIRQ_5, /* 5 */
+ -1, /* 6 */
+ -1, /* 7 */
+ -1, /* 8 */
+ VIPER_PIRQ_9, /* 9 */
+ VIPER_PIRQ_10, /* 10 */
+ VIPER_PIRQ_11, /* 11 */
+ VIPER_PIRQ_12, /* 12 */
+ -1, /* 13 */
+ VIPER_PIRQ_14, /* 14 */
+ VIPER_PIRQ_15, /* 15 */
+};
+
+int
+opti82c558_init(pc, iot, tag, ptagp, phandp)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ pcitag_t tag;
+ pciintr_icu_tag_t *ptagp;
+ pciintr_icu_handle_t *phandp;
+{
+ struct opti82c558_handle *ph;
+
+ ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
+ if (ph == NULL)
+ return (1);
+
+ ph->ph_pc = pc;
+ ph->ph_tag = tag;
+
+ *ptagp = &opti82c558_pci_icu;
+ *phandp = ph;
+ return (0);
+}
+
+int
+opti82c558_getclink(v, link, clinkp)
+ pciintr_icu_handle_t v;
+ int link, *clinkp;
+{
+
+ if (VIPER_LEGAL_LINK(link - 1)) {
+ *clinkp = link - 1;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+opti82c558_get_intr(v, clink, irqp)
+ pciintr_icu_handle_t v;
+ int clink, *irqp;
+{
+ struct opti82c558_handle *ph = v;
+ pcireg_t reg;
+ int val;
+
+ if (VIPER_LEGAL_LINK(clink) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ);
+ val = VIPER_PIRQ(reg, clink);
+ *irqp = (val == VIPER_PIRQ_NONE) ? 0xff : viper_pirq_decode[val];
+
+ return (0);
+}
+
+int
+opti82c558_set_intr(v, clink, irq)
+ pciintr_icu_handle_t v;
+ int clink, irq;
+{
+ struct opti82c558_handle *ph = v;
+ int shift;
+ pcireg_t reg;
+
+ if (VIPER_LEGAL_LINK(clink) == 0 || VIPER_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ);
+ shift = VIPER_PIRQ_SELECT_SHIFT * clink;
+ reg &= ~(VIPER_PIRQ_SELECT_MASK << shift);
+ reg |= (viper_pirq_encode[irq] << shift);
+ pci_conf_write(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ, reg);
+
+ return (0);
+}
+
+int
+opti82c558_get_trigger(v, irq, triggerp)
+ pciintr_icu_handle_t v;
+ int irq, *triggerp;
+{
+ struct opti82c558_handle *ph = v;
+ pcireg_t reg;
+
+ if (VIPER_LEGAL_IRQ(irq) == 0) {
+ /* ISA IRQ? */
+ *triggerp = IST_EDGE;
+ return (0);
+ }
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ);
+ if ((reg >> (VIPER_CFG_TRIGGER_SHIFT + viper_pirq_encode[irq])) & 1)
+ *triggerp = IST_LEVEL;
+ else
+ *triggerp = IST_EDGE;
+
+ return (0);
+}
+
+int
+opti82c558_set_trigger(v, irq, trigger)
+ pciintr_icu_handle_t v;
+ int irq, trigger;
+{
+ struct opti82c558_handle *ph = v;
+ int shift;
+ pcireg_t reg;
+
+ if (VIPER_LEGAL_IRQ(irq) == 0) {
+ /* ISA IRQ? */
+ return ((trigger != IST_LEVEL) ? 0 : 1);
+ }
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ);
+ shift = (VIPER_CFG_TRIGGER_SHIFT + viper_pirq_encode[irq]);
+ if (trigger == IST_LEVEL)
+ reg |= (1 << shift);
+ else
+ reg &= ~(1 << shift);
+ pci_conf_write(ph->ph_pc, ph->ph_tag, VIPER_CFG_PIRQ, reg);
+
+ return (0);
+}
diff --git a/sys/arch/i386/pci/opti82c558reg.h b/sys/arch/i386/pci/opti82c558reg.h
new file mode 100644
index 00000000000..f1279fa1c15
--- /dev/null
+++ b/sys/arch/i386/pci/opti82c558reg.h
@@ -0,0 +1,65 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Register definitions for the Opti 82c558 PCI-ISA bridge interrupt
+ * controller.
+ */
+
+/*
+ * PCI IRQ Select Register
+ */
+
+#define VIPER_CFG_PIRQ 0x40 /* PCI configuration space */
+
+/*
+ * Trigger setting:
+ *
+ * [1:7]=>5,9,10,11,12,14,15 Edge = 0 Level = 1
+ */
+#define VIPER_CFG_TRIGGER_SHIFT 16
+
+#define VIPER_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3)
+
+#define VIPER_PIRQ_MASK 0xde20
+#define VIPER_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \
+ ((1 << (irq)) & VIPER_PIRQ_MASK) != 0)
+
+#define VIPER_PIRQ_NONE 0
+#define VIPER_PIRQ_5 1
+#define VIPER_PIRQ_9 2
+#define VIPER_PIRQ_10 3
+#define VIPER_PIRQ_11 4
+#define VIPER_PIRQ_12 5
+#define VIPER_PIRQ_14 6
+#define VIPER_PIRQ_15 7
+
+#define VIPER_PIRQ_SELECT_MASK 0x07
+#define VIPER_PIRQ_SELECT_SHIFT 3
+
+#define VIPER_PIRQ(reg, x) (((reg) >> ((x) * VIPER_PIRQ_SELECT_SHIFT)) \
+ & VIPER_PIRQ_SELECT_MASK)
diff --git a/sys/arch/i386/pci/opti82c700.c b/sys/arch/i386/pci/opti82c700.c
new file mode 100644
index 00000000000..423796b0a19
--- /dev/null
+++ b/sys/arch/i386/pci/opti82c700.c
@@ -0,0 +1,290 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the Opti 82c700 PCI-ISA bridge interrupt controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/opti82c700reg.h>
+
+int opti82c700_getclink __P((pciintr_icu_handle_t, int, int *));
+int opti82c700_get_intr __P((pciintr_icu_handle_t, int, int *));
+int opti82c700_set_intr __P((pciintr_icu_handle_t, int, int));
+int opti82c700_get_trigger __P((pciintr_icu_handle_t, int, int *));
+int opti82c700_set_trigger __P((pciintr_icu_handle_t, int, int));
+
+const struct pciintr_icu opti82c700_pci_icu = {
+ opti82c700_getclink,
+ opti82c700_get_intr,
+ opti82c700_set_intr,
+ opti82c700_get_trigger,
+ opti82c700_set_trigger,
+};
+
+struct opti82c700_handle {
+ pci_chipset_tag_t ph_pc;
+ pcitag_t ph_tag;
+};
+
+int opti82c700_addr __P((int, int *, int *));
+
+int
+opti82c700_init(pc, iot, tag, ptagp, phandp)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ pcitag_t tag;
+ pciintr_icu_tag_t *ptagp;
+ pciintr_icu_handle_t *phandp;
+{
+ struct opti82c700_handle *ph;
+
+ ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
+ if (ph == NULL)
+ return (1);
+
+ ph->ph_pc = pc;
+ ph->ph_tag = tag;
+
+ *ptagp = &opti82c700_pci_icu;
+ *phandp = ph;
+ return (0);
+}
+
+int
+opti82c700_addr(link, addrofs, ofs)
+ int link, *addrofs, *ofs;
+{
+ int regofs, src;
+
+ regofs = FIRESTAR_PIR_REGOFS(link);
+ src = FIRESTAR_PIR_SELECTSRC(link);
+
+ switch (src) {
+ case FIRESTAR_PIR_SELECT_NONE:
+ return (1);
+
+ case FIRESTAR_PIR_SELECT_IRQ:
+ if (regofs < 0 || regofs > 7)
+ return (1);
+ *addrofs = FIRESTAR_CFG_INTR_IRQ + (regofs >> 2);
+ *ofs = (regofs & 3) << 3;
+ break;
+
+ case FIRESTAR_PIR_SELECT_PIRQ:
+ case FIRESTAR_PIR_SELECT_BRIDGE:
+ if (regofs < 0 || regofs > 3)
+ return (1);
+ *addrofs = FIRESTAR_CFG_INTR_PIRQ;
+ *ofs = regofs << 2;
+ break;
+
+ default:
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+opti82c700_getclink(v, link, clinkp)
+ pciintr_icu_handle_t v;
+ int link, *clinkp;
+{
+
+ if (FIRESTAR_LEGAL_LINK(link)) {
+ *clinkp = link;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+opti82c700_get_intr(v, clink, irqp)
+ pciintr_icu_handle_t v;
+ int clink, *irqp;
+{
+ struct opti82c700_handle *ph = v;
+ pcireg_t reg;
+ int val, addrofs, ofs;
+
+ if (FIRESTAR_LEGAL_LINK(clink) == 0)
+ return (1);
+
+ if (opti82c700_addr(clink, &addrofs, &ofs))
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
+ val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
+ *irqp = (val == FIRESTAR_PIRQ_NONE) ? 0xff : val;
+
+ return (0);
+}
+
+int
+opti82c700_set_intr(v, clink, irq)
+ pciintr_icu_handle_t v;
+ int clink, irq;
+{
+ struct opti82c700_handle *ph = v;
+ int addrofs, ofs;
+ pcireg_t reg;
+
+ if (FIRESTAR_LEGAL_LINK(clink) == 0 || FIRESTAR_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ if (opti82c700_addr(clink, &addrofs, &ofs))
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
+ reg &= ~(FIRESTAR_CFG_PIRQ_MASK << ofs);
+ reg |= (irq << ofs);
+ pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg);
+
+ return (0);
+}
+
+int
+opti82c700_get_trigger(v, irq, triggerp)
+ pciintr_icu_handle_t v;
+ int irq, *triggerp;
+{
+ struct opti82c700_handle *ph = v;
+ int i, val, addrofs, ofs;
+ pcireg_t reg;
+
+ if (FIRESTAR_LEGAL_IRQ(irq) == 0) {
+ /* ISA IRQ? */
+ *triggerp = IST_EDGE;
+ return (0);
+ }
+
+ /*
+ * Search PCIDV1 registers.
+ */
+ for (i = 0; i < 8; i++) {
+ opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ,
+ i), &addrofs, &ofs);
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
+ val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
+ if (val != irq)
+ continue;
+ val = ((reg >> ofs) >> FIRESTAR_TRIGGER_SHIFT) &
+ FIRESTAR_TRIGGER_MASK;
+ *triggerp = val ? IST_LEVEL : IST_EDGE;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+opti82c700_set_trigger(v, irq, trigger)
+ pciintr_icu_handle_t v;
+ int irq, trigger;
+{
+ struct opti82c700_handle *ph = v;
+ int i, val, addrofs, ofs;
+ pcireg_t reg;
+
+ if (FIRESTAR_LEGAL_IRQ(irq) == 0) {
+ /* ISA IRQ? */
+ return ((trigger != IST_LEVEL) ? 0 : 1);
+ }
+
+ /*
+ * Search PCIDV1 registers.
+ */
+ for (i = 0; i < 8; i++) {
+ opti82c700_addr(FIRESTAR_PIR_MAKELINK(FIRESTAR_PIR_SELECT_IRQ,
+ i), &addrofs, &ofs);
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, addrofs);
+ val = (reg >> ofs) & FIRESTAR_CFG_PIRQ_MASK;
+ if (val != irq)
+ continue;
+ if (trigger == IST_LEVEL)
+ reg |= (FIRESTAR_TRIGGER_MASK <<
+ (FIRESTAR_TRIGGER_SHIFT + ofs));
+ else
+ reg &= ~(FIRESTAR_TRIGGER_MASK <<
+ (FIRESTAR_TRIGGER_SHIFT + ofs));
+ pci_conf_write(ph->ph_pc, ph->ph_tag, addrofs, reg);
+ return (0);
+ }
+
+ return (1);
+}
diff --git a/sys/arch/i386/pci/opti82c700reg.h b/sys/arch/i386/pci/opti82c700reg.h
new file mode 100644
index 00000000000..21d0b3a45a4
--- /dev/null
+++ b/sys/arch/i386/pci/opti82c700reg.h
@@ -0,0 +1,71 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Register definitions for the Opti 82c700 PCI-ISA bridge interrupt
+ * controller.
+ */
+
+#define FIRESTAR_CFG_INTR_IRQ 0xb0 /* PCI configuration space */
+#define FIRESTAR_CFG_INTR_PIRQ 0xb8 /* PCI configuration space */
+
+#define FIRESTAR_PIRQ_NONE 0
+#define FIRESTAR_PIRQ_MIN FIRESTAR_CFG_INTR_IRQ
+#define FIRESTAR_PIRQ_MAX (FIRESTAR_CFG_INTR_PIRQ + 1)
+#define FIRESTAR_LEGAL_LINK(link) ((link) >= FIRESTAR_PIRQ_MIN && \
+ (link) <= FIRESTAR_PIRQ_MAX)
+
+#define FIRESTAR_PIRQ_MASK 0xdffa
+#define FIRESTAR_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \
+ ((1 << (irq)) & FIRESTAR_PIRQ_MASK) != 0)
+
+#define FIRESTAR_CFG_PIRQ_MASK 0x0f
+
+#define FIRESTAR_TRIGGER_MASK 0x01
+#define FIRESTAR_TRIGGER_SHIFT 4
+
+/*
+ * Opti's suggested Link values.
+ */
+#define FIRESTAR_PIR_REGOFS_MASK 0x07
+#define FIRESTAR_PIR_REGOFS_SHIFT 4
+#define FIRESTAR_PIR_REGOFS(link) \
+ (((link) >> FIRESTAR_PIR_REGOFS_SHIFT) & FIRESTAR_PIR_REGOFS_MASK)
+
+#define FIRESTAR_PIR_SELECTSRC_MASK 0x07
+#define FIRESTAR_PIR_SELECTSRC_SHIFT 0
+#define FIRESTAR_PIR_SELECTSRC(link) \
+ (((link) >> FIRESTAR_PIR_SELECTSRC_SHIFT) & FIRESTAR_PIR_SELECTSRC_MASK)
+
+#define FIRESTAR_PIR_SELECT_NONE 0
+#define FIRESTAR_PIR_SELECT_IRQ 1
+#define FIRESTAR_PIR_SELECT_PIRQ 2
+#define FIRESTAR_PIR_SELECT_BRIDGE 3
+
+#define FIRESTAR_PIR_MAKELINK(src, ofs) \
+ (((src) << FIRESTAR_PIR_SELECTSRC_SHIFT) | \
+ ((ofs) << FIRESTAR_PIR_REGOFS_SHIFT))
diff --git a/sys/arch/i386/pci/pci_bus_fixup.c b/sys/arch/i386/pci/pci_bus_fixup.c
new file mode 100644
index 00000000000..57b7d0cfaa1
--- /dev/null
+++ b/sys/arch/i386/pci/pci_bus_fixup.c
@@ -0,0 +1,135 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * PCI bus renumbering support.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/ppbreg.h>
+
+#include <i386/pci/pci_bus_fixup.h>
+#include <i386/pci/pcibios.h>
+
+int
+pci_bus_fixup(pc, bus)
+ pci_chipset_tag_t pc;
+ int bus;
+{
+ static int bus_total;
+ static int bridge_cnt;
+ int device, maxdevs, function, nfuncs, bridge, bus_max, bus_sub;
+ const struct pci_quirkdata *qd;
+ pcireg_t reg;
+ pcitag_t tag;
+
+ bus_max = bus;
+ bus_sub = 0;
+
+ if (++bus_total > 256)
+ panic("pci_bus_fixup: more than 256 PCI busses?");
+
+ maxdevs = pci_bus_maxdevs(pc, bus);
+
+ for (device = 0; device < maxdevs; device++) {
+ tag = pci_make_tag(pc, bus, device, 0);
+ reg = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
+ continue;
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(reg) == 0)
+ continue;
+
+ qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
+
+ reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ if (PCI_HDRTYPE_MULTIFN(reg) ||
+ (qd != NULL &&
+ (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ nfuncs = 8;
+ else
+ nfuncs = 1;
+
+ for (function = 0; function < nfuncs; function++) {
+ tag = pci_make_tag(pc, bus, device, function);
+ reg = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
+ continue;
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(reg) == 0)
+ continue;
+
+ reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
+ if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
+ (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
+ PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
+ /* Assign the bridge #. */
+ bridge = bridge_cnt++;
+
+ /* Assign the bridge's secondary bus #. */
+ bus_max++;
+
+ reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
+ reg &= 0xff000000;
+ reg |= bus | (bus_max << 8) | (0xff << 16);
+ pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
+
+ /* Scan subordinate bus. */
+ bus_sub = pci_bus_fixup(pc, bus_max);
+
+ /* Configure the bridge. */
+ reg &= 0xff000000;
+ reg |= bus | (bus_max << 8) | (bus_sub << 16);
+ pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
+
+#ifdef PCIBIOSVERBOSE
+ printf("PCI bridge %d: primary %d, "
+ "secondary %d, subordinate %d\n",
+ bridge, bus, bus_max, bus_sub);
+#endif
+
+ /* Next bridge's secondary bus #. */
+ bus_max = (bus_sub > bus_max) ?
+ bus_sub : bus_max;
+ }
+ }
+ }
+
+ return (bus_max); /* last # of subordinate bus */
+}
diff --git a/sys/arch/i386/pci/pci_bus_fixup.h b/sys/arch/i386/pci/pci_bus_fixup.h
new file mode 100644
index 00000000000..d93a3ac3427
--- /dev/null
+++ b/sys/arch/i386/pci/pci_bus_fixup.h
@@ -0,0 +1,28 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+int pci_bus_fixup __P((pci_chipset_tag_t, int));
diff --git a/sys/arch/i386/pci/pci_intr_fixup.c b/sys/arch/i386/pci/pci_intr_fixup.c
new file mode 100644
index 00000000000..22f354f6887
--- /dev/null
+++ b/sys/arch/i386/pci/pci_intr_fixup.c
@@ -0,0 +1,696 @@
+/* $NetBSD: pci_intr_fixup.c,v 1.3 1999/12/13 15:42:05 uch Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * PCI Interrupt Router support.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/isa/icu.h>
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/pcibios.h>
+
+struct pciintr_link_map {
+ int link;
+ int clink;
+ int irq;
+ u_int16_t bitmap;
+ int fixup_stage;
+ int old_irq;
+ SIMPLEQ_ENTRY(pciintr_link_map) list;
+};
+
+pciintr_icu_tag_t pciintr_icu_tag;
+pciintr_icu_handle_t pciintr_icu_handle;
+
+struct pciintr_link_map *pciintr_link_lookup_pin
+ __P((struct pcibios_intr_routing *, int));
+struct pciintr_link_map *pciintr_link_lookup_link __P((int));
+struct pciintr_link_map *pciintr_link_alloc __P((struct pcibios_intr_routing *,
+ int));
+struct pcibios_intr_routing *pciintr_pir_lookup __P((int, int));
+int pciintr_link_init __P((void));
+int pciintr_link_fixup __P((void));
+int pciintr_link_route __P((u_int16_t *));
+int pciintr_irq_release __P((u_int16_t *));
+int pciintr_header_fixup __P((pci_chipset_tag_t));
+
+SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list;
+
+const struct pciintr_icu_table {
+ pci_vendor_id_t piit_vendor;
+ pci_product_id_t piit_product;
+ int (*piit_init) __P((pci_chipset_tag_t,
+ bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *,
+ pciintr_icu_handle_t *));
+} pciintr_icu_table[] = {
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX,
+ piix_init },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA,
+ piix_init },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA,
+ piix_init },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA,
+ piix_init },
+
+ { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558,
+ opti82c558_init },
+ { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700,
+ opti82c700_init },
+
+ { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA,
+ via82c586_init, },
+
+ { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503,
+ sis85c503_init },
+
+ { 0, 0,
+ NULL },
+};
+
+const struct pciintr_icu_table *pciintr_icu_lookup __P((pcireg_t));
+
+const struct pciintr_icu_table *
+pciintr_icu_lookup(id)
+ pcireg_t id;
+{
+ const struct pciintr_icu_table *piit;
+
+ for (piit = pciintr_icu_table;
+ piit->piit_init != NULL;
+ piit++) {
+ if (PCI_VENDOR(id) == piit->piit_vendor &&
+ PCI_PRODUCT(id) == piit->piit_product)
+ return (piit);
+ }
+
+ return (NULL);
+}
+
+struct pciintr_link_map *
+pciintr_link_lookup_pin(pir, pin)
+ struct pcibios_intr_routing *pir;
+ int pin;
+{
+
+ return (pciintr_link_lookup_link(pir->linkmap[pin].link));
+}
+
+struct pciintr_link_map *
+pciintr_link_lookup_link(link)
+ int link;
+{
+ struct pciintr_link_map *l;
+
+ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
+ l = SIMPLEQ_NEXT(l, list)) {
+ if (l->link == link)
+ return (l);
+ }
+
+ return (NULL);
+}
+
+struct pciintr_link_map *
+pciintr_link_alloc(pir, pin)
+ struct pcibios_intr_routing *pir;
+ int pin;
+{
+ struct pciintr_link_map *l, *lstart;
+
+ l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT);
+ if (l == NULL)
+ panic("pciintr_link_alloc");
+
+ memset(l, 0, sizeof(*l));
+
+ l->link = pir->linkmap[pin].link;
+ l->bitmap = pir->linkmap[pin].bitmap;
+
+ lstart = SIMPLEQ_FIRST(&pciintr_link_map_list);
+ if (lstart == NULL || lstart->link < l->link)
+ SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list);
+ else
+ SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list);
+
+ return (l);
+}
+
+struct pcibios_intr_routing *
+pciintr_pir_lookup(bus, device)
+ int bus, device;
+{
+ struct pcibios_intr_routing *pir;
+ int entry;
+
+ if (pcibios_pir_table == NULL)
+ return (NULL);
+
+ for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
+ pir = &pcibios_pir_table[entry];
+ if (pir->bus == bus && ((pir->device >> 3) & 0x1f) == device)
+ return (pir);
+ }
+
+ return (NULL);
+}
+
+int
+pciintr_link_init()
+{
+ int entry, pin, error, link, clink;
+ struct pcibios_intr_routing *pir;
+ struct pciintr_link_map *l;
+
+ if (pcibios_pir_table == NULL) {
+ /* No PIR table; can't do anything. */
+ printf("pciintr_link_init: no PIR table\n");
+ return (1);
+ }
+
+ error = 0;
+ SIMPLEQ_INIT(&pciintr_link_map_list);
+
+ for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
+ pir = &pcibios_pir_table[entry];
+ for (pin = 0; pin < 4; pin++) {
+ link = pir->linkmap[pin].link;
+ if (link == 0) {
+ /* No connection for this pin. */
+ continue;
+ }
+
+ /*
+ * Check the link value by asking the ICU for
+ * the canonical link value.
+ */
+ if (pciintr_icu_getclink(pciintr_icu_tag,
+ pciintr_icu_handle, link, &clink) != 0) {
+ /*
+ * Table entry is bogus. Just ignore it.
+ */
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_init: bad table entry: "
+ "bus %d device %d link 0x%02x\n",
+ pir->bus, (pir->device >> 3 & 0x1f), link);
+#endif
+ continue;
+ }
+
+ /*
+ * Multiple devices may be wired to the same
+ * interrupt; check to see if we've seen this
+ * one already. If not, allocate a new link
+ * map entry and stuff it in the map.
+ */
+ l = pciintr_link_lookup_pin(pir, pin);
+ if (l == NULL)
+ (void) pciintr_link_alloc(pir, pin);
+ }
+ }
+
+ return (error);
+}
+
+int
+pciintr_link_fixup()
+{
+ struct pciintr_link_map *l;
+ u_int16_t pciirq, bitmap;
+ int i, j, cnt, irq;
+
+ /*
+ * First stage: Attempt to connect PIRQs which aren't
+ * yet connected.
+ */
+ pciirq = 0;
+
+ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
+ l = SIMPLEQ_NEXT(l, list)) {
+ /*
+ * Get the canonical link value for this entry.
+ */
+ if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle,
+ l->link, &l->clink) != 0) {
+ /*
+ * ICU doesn't understand this link value.
+ */
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_fixup: link 0x%02x invalid\n",
+ l->link);
+#endif
+ l->clink = -1;
+ continue;
+ }
+
+ /*
+ * Determine if this PIRQ is mapped to an IRQ.
+ */
+ if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle,
+ l->clink, &irq) != 0) {
+ /*
+ * ICU doesn't understand this PIRQ value.
+ */
+ l->clink = -1;
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_fixup: PIRQ %d invalid\n",
+ l->clink);
+#endif
+ continue;
+ }
+
+ if (irq == 0xff) {
+ /*
+ * Interrupt isn't connected. Attempt to assign
+ * it to an IRQ.
+ */
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_fixup: PIRQ %d not connected",
+ l->clink);
+#endif
+ bitmap = l->bitmap;
+ for (i = 0, j = 0xff, cnt = 0; i < 16; i++)
+ if (bitmap & (1 << i))
+ j = i, cnt++;
+ /*
+ * Just do the easy case now; we'll defer the
+ * harder ones to Stage 2.
+ */
+ if (cnt == 1) {
+ l->irq = j;
+ l->old_irq = irq;
+ l->fixup_stage = 1;
+ pciirq |= 1 << j;
+#ifdef PCIINTR_DEBUG
+ printf(", assigning IRQ %d", l->irq);
+#endif
+ }
+#ifdef PCIINTR_DEBUG
+ printf("\n");
+#endif
+ } else {
+ /*
+ * Interrupt is already connected. Don't do
+ * anything to it.
+ */
+ l->irq = irq;
+ pciirq |= 1 << irq;
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_fixup: PIRQ %d already connected "
+ "to IRQ %d\n", l->clink, l->irq);
+#endif
+ }
+ }
+
+#ifdef PCIBIOS_IRQS
+ /* In case the user supplied a mask for the PCI irqs we use it. */
+ pciirq = PCIBIOS_IRQS;
+#endif
+
+ /*
+ * Stage 2: Attempt to connect PIRQs which we didn't
+ * connect in Stage 1.
+ */
+ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
+ l = SIMPLEQ_NEXT(l, list)) {
+ if (l->irq == 0) {
+ bitmap = l->bitmap;
+ for (i = 0; i < 16; i++) {
+ if ((pciirq & (1 << i)) != 0 &&
+ (bitmap & (1 << i)) != 0) {
+ /*
+ * This IRQ is a valid PCI
+ * IRQ already connected to
+ * another PIRQ, and also an
+ * IRQ our PIRQ can use; connect
+ * it up!
+ */
+ l->irq = i;
+ l->old_irq = 0xff;
+ l->fixup_stage = 2;
+#ifdef PCIINTR_DEBUG
+ printf("pciintr_link_fixup: assigning "
+ "IRQ %d to PIRQ %d\n", l->irq,
+ l->clink);
+#endif
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * Stage 3: Allow the user to specify interrupt routing
+ * information, overriding what we've done above.
+ */
+ /* XXX Not implemented. */
+
+ return (0);
+}
+
+int
+pciintr_link_route(pciirq)
+ u_int16_t *pciirq;
+{
+ struct pciintr_link_map *l;
+ int rv = 0;
+
+ *pciirq = 0;
+
+ for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
+ l = SIMPLEQ_NEXT(l, list)) {
+ if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle,
+ l->clink, l->irq) != 0 ||
+ pciintr_icu_set_trigger(pciintr_icu_tag, pciintr_icu_handle,
+ l->irq, IST_LEVEL) != 0) {
+ printf("pciintr_link_route: route of PIRQ %d -> IRQ %d"
+ " failed\n", l->clink, l->irq);
+ rv = 1;
+ } else {
+ /*
+ * Succssfully routed interrupt. Mark this as
+ * a PCI interrupt.
+ */
+ *pciirq |= (1 << l->irq);
+ }
+ }
+
+ return (rv);
+}
+
+int
+pciintr_irq_release(pciirq)
+ u_int16_t *pciirq;
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if ((*pciirq & (1 << i)) == 0)
+ (void) pciintr_icu_set_trigger(pciintr_icu_tag,
+ pciintr_icu_handle, i, IST_EDGE);
+ }
+
+ return (0);
+}
+
+int
+pciintr_header_fixup(pc)
+ pci_chipset_tag_t pc;
+{
+ const struct pci_quirkdata *qd;
+ struct pcibios_intr_routing *pir;
+ struct pciintr_link_map *l;
+ int pin, bus, device, function, maxdevs, nfuncs, irq, link;
+ pcireg_t id, bhlcr, intr;
+ pcitag_t tag;
+
+#ifdef PCIBIOSVERBOSE
+ printf("--------------------------------------------\n");
+ printf(" device vendor product pin PIRQ IRQ stage\n");
+ printf("--------------------------------------------\n");
+#endif
+
+ for (bus = 0; bus <= pcibios_max_bus; bus++) {
+ maxdevs = pci_bus_maxdevs(pc, bus);
+ for (device = 0; device < maxdevs; device++) {
+ tag = pci_make_tag(pc, bus, device, 0);
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ continue;
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(id) == 0)
+ continue;
+
+ qd = pci_lookup_quirkdata(PCI_VENDOR(id),
+ PCI_PRODUCT(id));
+
+ bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
+ if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
+ (qd != NULL &&
+ (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ nfuncs = 8;
+ else
+ nfuncs = 1;
+
+ for (function = 0; function < nfuncs; function++) {
+ tag = pci_make_tag(pc, bus, device, function);
+ id = pci_conf_read(pc, tag, PCI_ID_REG);
+ intr = pci_conf_read(pc, tag,
+ PCI_INTERRUPT_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ continue;
+ /*
+ * XXX Not invalid, but we've done this
+ * ~forever.
+ */
+ if (PCI_VENDOR(id) == 0)
+ continue;
+
+ pin = PCI_INTERRUPT_PIN(intr);
+ irq = PCI_INTERRUPT_LINE(intr);
+
+ if (pin == 0) {
+ /*
+ * No interrupt used.
+ */
+ continue;
+ }
+
+ pir = pciintr_pir_lookup(bus, device);
+ if (pir == NULL ||
+ (link = pir->linkmap[pin - 1].link) == 0) {
+ /*
+ * Interrupt not connected; no
+ * need to change.
+ */
+ continue;
+ }
+
+ l = pciintr_link_lookup_link(link);
+ if (l == NULL) {
+ /*
+ * No link map entry?!
+ */
+ printf("pciintr_header_fixup: no entry "
+ "for link 0x%02x (%d:%d:%d:%c)\n",
+ link, bus, device, function,
+ '@' + pin);
+ continue;
+ }
+
+ /*
+ * IRQs 14 and 15 are reserved for
+ * PCI IDE interrupts; don't muck
+ * with them.
+ */
+ if (irq == 14 || irq == 15)
+ continue;
+
+#ifdef PCIBIOSVERBOSE
+ printf("%03d:%02d:%d 0x%04x 0x%04x %c "
+ "0x%02x %02d %d\n",
+ bus, device, function,
+ PCI_VENDOR(id), PCI_PRODUCT(id),
+ '@' + pin, l->clink, l->irq,
+ l->fixup_stage);
+#endif
+
+ intr &= ~(PCI_INTERRUPT_LINE_MASK <<
+ PCI_INTERRUPT_LINE_SHIFT);
+ intr |= (l->irq << PCI_INTERRUPT_LINE_SHIFT);
+ pci_conf_write(pc, tag, PCI_INTERRUPT_REG,
+ intr);
+ }
+ }
+ }
+
+#ifdef PCIBIOSVERBOSE
+ printf("--------------------------------------------\n");
+#endif
+
+ return (0);
+}
+
+int
+pci_intr_fixup(pc, iot, pciirq)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ u_int16_t *pciirq;
+{
+ const struct pciintr_icu_table *piit = NULL;
+ pcitag_t icutag;
+ pcireg_t icuid;
+
+ /*
+ * Attempt to initialize our PCI interrupt router. If
+ * the PIR Table is present in ROM, use the location
+ * specified by the PIR Table, and use the compat ID,
+ * if present. Otherwise, we have to look for the router
+ * ourselves (the PCI-ISA bridge).
+ */
+ if (pcibios_pir_header.signature != 0) {
+ icutag = pci_make_tag(pc, pcibios_pir_header.router_bus,
+ (pcibios_pir_header.router_devfunc >> 3) & 0x1f,
+ pcibios_pir_header.router_devfunc & 7);
+ icuid = pcibios_pir_header.compat_router;
+ if (icuid == 0 ||
+ (piit = pciintr_icu_lookup(icuid)) == NULL) {
+ /*
+ * No compat ID, or don't know the compat ID? Read
+ * it from the configuration header.
+ */
+ icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
+ }
+ if (piit == NULL)
+ piit = pciintr_icu_lookup(icuid);
+ } else {
+ int device, maxdevs = pci_bus_maxdevs(pc, 0);
+
+ /*
+ * Search configuration space for a known interrupt
+ * router.
+ */
+ for (device = 0; device < maxdevs; device++) {
+ icutag = pci_make_tag(pc, 0, device, 0);
+ icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
+ continue;
+ /* XXX Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(icuid) == 0)
+ continue;
+
+ piit = pciintr_icu_lookup(icuid);
+ if (piit != NULL)
+ break;
+ }
+ }
+
+ if (piit == NULL) {
+ printf("pci_intr_fixup: no compatible PCI ICU found\n");
+ return (-1); /* non-fatal */
+ }
+
+ /*
+ * Initialize the PCI ICU.
+ */
+ if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag,
+ &pciintr_icu_handle) != 0)
+ return (-1); /* non-fatal */
+
+ /*
+ * Initialize the PCI interrupt link map.
+ */
+ if (pciintr_link_init())
+ return (-1); /* non-fatal */
+
+ /*
+ * Fix up the link->IRQ mappings.
+ */
+ if (pciintr_link_fixup() != 0)
+ return (-1); /* non-fatal */
+
+ /*
+ * Now actually program the PCI ICU with the new
+ * routing information.
+ */
+ if (pciintr_link_route(pciirq) != 0)
+ return (1); /* fatal */
+
+ /*
+ * Now that we've routed all of the PIRQs, rewrite the PCI
+ * configuration headers to reflect the new mapping.
+ */
+ if (pciintr_header_fixup(pc) != 0)
+ return (1); /* fatal */
+
+ /*
+ * Free any unused PCI IRQs for ISA devices.
+ */
+ if (pciintr_irq_release(pciirq) != 0)
+ return (-1); /* non-fatal */
+
+ /*
+ * All done!
+ */
+ return (0); /* success! */
+}
diff --git a/sys/arch/i386/pci/pci_intr_fixup.h b/sys/arch/i386/pci/pci_intr_fixup.h
new file mode 100644
index 00000000000..feebdfb47f0
--- /dev/null
+++ b/sys/arch/i386/pci/pci_intr_fixup.h
@@ -0,0 +1,65 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+typedef void *pciintr_icu_handle_t;
+
+struct pciintr_icu {
+ int (*pi_getclink) __P((pciintr_icu_handle_t, int, int *));
+ int (*pi_get_intr) __P((pciintr_icu_handle_t, int, int *));
+ int (*pi_set_intr) __P((pciintr_icu_handle_t, int, int));
+ int (*pi_get_trigger) __P((pciintr_icu_handle_t, int, int *));
+ int (*pi_set_trigger) __P((pciintr_icu_handle_t, int, int));
+};
+
+typedef const struct pciintr_icu *pciintr_icu_tag_t;
+
+#define pciintr_icu_getclink(t, h, link, pirqp) \
+ (*(t)->pi_getclink)((h), (link), (pirqp))
+#define pciintr_icu_get_intr(t, h, pirq, irqp) \
+ (*(t)->pi_get_intr)((h), (pirq), (irqp))
+#define pciintr_icu_set_intr(t, h, pirq, irq) \
+ (*(t)->pi_set_intr)((h), (pirq), (irq))
+#define pciintr_icu_get_trigger(t, h, irq, triggerp) \
+ (*(t)->pi_get_trigger)((h), (irq), (triggerp))
+#define pciintr_icu_set_trigger(t, h, irq, trigger) \
+ (*(t)->pi_set_trigger)((h), (irq), (trigger))
+
+int pci_intr_fixup __P((pci_chipset_tag_t, bus_space_tag_t, u_int16_t *));
+
+/*
+ * Init functions for our known PCI ICUs.
+ */
+int piix_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t,
+ pciintr_icu_tag_t *, pciintr_icu_handle_t *));
+int opti82c558_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t,
+ pciintr_icu_tag_t *, pciintr_icu_handle_t *));
+int opti82c700_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t,
+ pciintr_icu_tag_t *, pciintr_icu_handle_t *));
+int via82c586_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t,
+ pciintr_icu_tag_t *, pciintr_icu_handle_t *));
+int sis85c503_init __P((pci_chipset_tag_t, bus_space_tag_t, pcitag_t,
+ pciintr_icu_tag_t *, pciintr_icu_handle_t *));
diff --git a/sys/arch/i386/pci/pcib.c b/sys/arch/i386/pci/pcib.c
index ac3f00f9325..3004c1ef20a 100644
--- a/sys/arch/i386/pci/pcib.c
+++ b/sys/arch/i386/pci/pcib.c
@@ -80,7 +80,7 @@ pcibmatch(parent, match, aux)
switch (PCI_PRODUCT(pa->pa_id)) {
case PCI_PRODUCT_INTEL_SIO:
case PCI_PRODUCT_INTEL_82371MX:
- case PCI_PRODUCT_INTEL_82371AB:
+ case PCI_PRODUCT_INTEL_82371AB_ISA:
/* The above bridges mis-identify themselves */
return (1);
}
diff --git a/sys/arch/i386/pci/pcibios.c b/sys/arch/i386/pci/pcibios.c
new file mode 100644
index 00000000000..70e6b6a187b
--- /dev/null
+++ b/sys/arch/i386/pci/pcibios.c
@@ -0,0 +1,475 @@
+/* $NetBSD: pcibios.c,v 1.1 1999/11/17 01:16:37 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Interface to the PCI BIOS and PCI Interrupt Routing table.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <dev/isa/isareg.h>
+#include <i386/isa/isa_machdep.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <i386/pci/pcibios.h>
+#ifdef PCIBIOS_INTR_FIXUP
+#include <i386/pci/pci_intr_fixup.h>
+#endif
+#ifdef PCIBIOS_BUS_FIXUP
+#include <i386/pci/pci_bus_fixup.h>
+#endif
+
+#ifdef __NetBSD__
+#include <machine/bios32.h>
+#elif __OpenBSD__
+#include <machine/biosvar.h>
+#endif
+
+int pcibios_present;
+
+struct pcibios_pir_header pcibios_pir_header;
+struct pcibios_intr_routing *pcibios_pir_table;
+int pcibios_pir_table_nentries;
+int pcibios_max_bus;
+
+struct bios32_entry pcibios_entry;
+
+void pcibios_pir_init __P((void));
+
+int pcibios_get_status __P((u_int32_t *, u_int32_t *, u_int32_t *,
+ u_int32_t *, u_int32_t *, u_int32_t *, u_int32_t *));
+int pcibios_get_intr_routing __P((struct pcibios_intr_routing *,
+ int *, u_int16_t *));
+
+int pcibios_return_code __P((u_int16_t, const char *));
+
+void pcibios_print_exclirq __P((void));
+#ifdef PCIINTR_DEBUG
+void pcibios_print_pir_table __P((void));
+#endif
+
+#define PCI_IRQ_TABLE_START 0xf0000
+#define PCI_IRQ_TABLE_END 0xfffff
+
+void
+pcibios_init()
+{
+ struct bios32_entry_info ei;
+ u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2;
+
+ if (bios32_service(BIOS32_MAKESIG('$', 'P', 'C', 'I'),
+ &pcibios_entry, &ei) == 0) {
+ /*
+ * No PCI BIOS found; will fall back on old
+ * mechanism.
+ */
+ return;
+ }
+
+ /*
+ * We've located the PCI BIOS service; get some information
+ * about it.
+ */
+ if (pcibios_get_status(&rev_maj, &rev_min, &mech1, &mech2,
+ &scmech1, &scmech2, &pcibios_max_bus) != PCIBIOS_SUCCESS) {
+ /*
+ * We can't use the PCI BIOS; will fall back on old
+ * mechanism.
+ */
+ return;
+ }
+
+ printf("PCI BIOS rev. %d.%d found at 0x%lx\n", rev_maj, rev_min >> 4,
+ ei.bei_entry);
+#ifdef PCIBIOSVERBOSE
+ printf("pcibios: config mechanism %s%s, special cycles %s%s, "
+ "last bus %d\n",
+ mech1 ? "[1]" : "[x]",
+ mech2 ? "[2]" : "[x]",
+ scmech1 ? "[1]" : "[x]",
+ scmech2 ? "[2]" : "[x]",
+ pcibios_max_bus);
+
+#endif
+
+ /*
+ * The PCI BIOS tells us the config mechanism; fill it in now
+ * so that pci_mode_detect() doesn't have to look for it.
+ */
+ pci_mode = mech1 ? 1 : 2;
+
+ pcibios_present = 1;
+
+ /*
+ * Find the PCI IRQ Routing table.
+ */
+ pcibios_pir_init();
+
+#ifdef PCIBIOS_INTR_FIXUP
+ if (pcibios_pir_table != NULL) {
+ int rv;
+ u_int16_t pciirq;
+
+ /*
+ * Fixup interrupt routing.
+ */
+ rv = pci_intr_fixup(NULL, I386_BUS_SPACE_IO, &pciirq);
+ switch (rv) {
+ case -1:
+ /* Non-fatal error. */
+ printf("Warning: unable to fix up PCI interrupt "
+ "routing\n");
+ break;
+
+ case 1:
+ /* Fatal error. */
+ panic("pcibios_init: interrupt fixup failed");
+ break;
+ }
+
+ /*
+ * XXX Clear `pciirq' from the ISA interrupt allocation
+ * XXX mask.
+ */
+ }
+#endif
+
+#ifdef PCIBIOS_BUS_FIXUP
+ pcibios_max_bus = pci_bus_fixup(NULL, 0);
+#ifdef PCIBIOSVERBOSE
+ printf("PCI bus #%d is the last bus\n", pcibios_max_bus);
+#endif
+#endif
+}
+
+void
+pcibios_pir_init()
+{
+ char devinfo[256];
+ paddr_t pa;
+ caddr_t p;
+ unsigned char cksum;
+ u_int16_t tablesize;
+ u_int8_t rev_maj, rev_min;
+ int i;
+
+ for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) {
+ p = (caddr_t)ISA_HOLE_VADDR(pa);
+ if (*(int *)p != BIOS32_MAKESIG('$', 'P', 'I', 'R'))
+ continue;
+
+ rev_min = *(p + 4);
+ rev_maj = *(p + 5);
+ tablesize = *(u_int16_t *)(p + 6);
+
+ cksum = 0;
+ for (i = 0; i < tablesize; i++)
+ cksum += *(unsigned char *)(p + i);
+
+ printf("PCI IRQ Routing Table rev. %d.%d found at 0x%lx, "
+ "size %d bytes (%d entries)\n", rev_maj, rev_min, pa,
+ tablesize, (tablesize - 32) / 16);
+
+ if (cksum != 0) {
+ printf("pcibios_pir_init: bad IRQ table checksum\n");
+ continue;
+ }
+
+ if (tablesize < 32 || (tablesize % 16) != 0) {
+ printf("pcibios_pir_init: bad IRQ table size\n");
+ continue;
+ }
+
+ if (rev_maj != 1 || rev_min != 0) {
+ printf("pcibios_pir_init: unsupported IRQ table "
+ "version\n");
+ continue;
+ }
+
+ /*
+ * We can handle this table! Make a copy of it.
+ */
+ bcopy(p, &pcibios_pir_header, 32);
+ pcibios_pir_table = malloc(tablesize - 32, M_DEVBUF,
+ M_NOWAIT);
+ if (pcibios_pir_table == NULL) {
+ printf("pcibios_pir_init: no memory for $PIR\n");
+ return;
+ }
+ bcopy(p + 32, pcibios_pir_table, tablesize - 32);
+ pcibios_pir_table_nentries = (tablesize - 32) / 16;
+
+ printf("PCI Interrupt Router at %03d:%02d:%01d",
+ pcibios_pir_header.router_bus,
+ (pcibios_pir_header.router_devfunc >> 3) & 0x1f,
+ pcibios_pir_header.router_devfunc & 7);
+ if (pcibios_pir_header.compat_router != 0) {
+ pci_devinfo(pcibios_pir_header.compat_router, 0, 0,
+ devinfo);
+ printf(" (%s)", devinfo);
+ }
+ printf("\n");
+ pcibios_print_exclirq();
+#ifdef PCIINTR_DEBUG
+ pcibios_print_pir_table();
+#endif
+ return;
+ }
+
+ /*
+ * If there was no PIR table found, try using the PCI BIOS
+ * Get Interrupt Routing call.
+ *
+ * XXX The interface to this call sucks; just allocate enough
+ * XXX room for 32 entries.
+ */
+ pcibios_pir_table_nentries = 32;
+ pcibios_pir_table = malloc(pcibios_pir_table_nentries *
+ sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT);
+ if (pcibios_pir_table == NULL) {
+ printf("pcibios_pir_init: no memory for $PIR\n");
+ return;
+ }
+ if (pcibios_get_intr_routing(pcibios_pir_table,
+ &pcibios_pir_table_nentries,
+ &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) {
+ printf("No PCI IRQ Routing information available.\n");
+ free(pcibios_pir_table, M_DEVBUF);
+ pcibios_pir_table = NULL;
+ pcibios_pir_table_nentries = 0;
+ return;
+ }
+ printf("PCI BIOS has %d Interrupt Routing table entries\n",
+ pcibios_pir_table_nentries);
+ pcibios_print_exclirq();
+#ifdef PCIINTR_DEBUG
+ pcibios_print_pir_table();
+#endif
+}
+
+int
+pcibios_get_status(rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus)
+ u_int32_t *rev_maj, *rev_min, *mech1, *mech2, *scmech1, *scmech2,
+ *maxbus;
+{
+ u_int16_t ax, bx, cx;
+ u_int32_t edx;
+ int rv;
+
+ __asm __volatile("lcall (%%edi) ; \
+ jc 1f ; \
+ xor %%ah, %%ah ; \
+ 1:"
+ : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx)
+ : "0" (0xb101), "D" (&pcibios_entry));
+
+ rv = pcibios_return_code(ax, "pcibios_get_status");
+ if (rv != PCIBIOS_SUCCESS)
+ return (rv);
+
+ if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' '))
+ return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */
+
+ /*
+ * Fill in the various pieces if info we're looking for.
+ */
+ *mech1 = ax & 1;
+ *mech2 = ax & (1 << 1);
+ *scmech1 = ax & (1 << 4);
+ *scmech2 = ax & (1 << 5);
+ *rev_maj = (bx >> 8) & 0xff;
+ *rev_min = bx & 0xff;
+ *maxbus = cx & 0xff;
+
+ return (PCIBIOS_SUCCESS);
+}
+
+int
+pcibios_get_intr_routing(table, nentries, exclirq)
+ struct pcibios_intr_routing *table;
+ int *nentries;
+ u_int16_t *exclirq;
+{
+ u_int16_t ax, bx;
+ int rv;
+ struct {
+ u_int16_t size;
+ caddr_t offset;
+ u_int16_t segment;
+ } __attribute__((__packed__)) args;
+
+ args.size = *nentries * sizeof(*table);
+ args.offset = (caddr_t)table;
+ args.segment = GSEL(GDATA_SEL, SEL_KPL);
+
+ memset(table, 0, args.size);
+
+ __asm __volatile("lcall (%%esi) ; \
+ jc 1f ; \
+ xor %%ah, %%ah ; \
+ 1: movw %w2, %%ds ; \
+ movw %w2, %%es"
+ : "=a" (ax), "=b" (bx)
+ : "r" GSEL(GDATA_SEL, SEL_KPL), "0" (0xb10e), "1" (0),
+ "D" (&args), "S" (&pcibios_entry));
+
+ rv = pcibios_return_code(ax, "pcibios_get_intr_routing");
+ if (rv != PCIBIOS_SUCCESS)
+ return (rv);
+
+ *nentries = args.size / sizeof(*table);
+ *exclirq = bx;
+
+ return (PCIBIOS_SUCCESS);
+}
+
+int
+pcibios_return_code(ax, func)
+ u_int16_t ax;
+ const char *func;
+{
+ const char *errstr;
+ int rv = ax >> 8;
+
+ switch (rv) {
+ case PCIBIOS_SUCCESS:
+ return (PCIBIOS_SUCCESS);
+
+ case PCIBIOS_SERVICE_NOT_PRESENT:
+ errstr = "service not present";
+ break;
+
+ case PCIBIOS_FUNCTION_NOT_SUPPORTED:
+ errstr = "function not supported";
+ break;
+
+ case PCIBIOS_BAD_VENDOR_ID:
+ errstr = "bad vendor ID";
+ break;
+
+ case PCIBIOS_DEVICE_NOT_FOUND:
+ errstr = "device not found";
+ break;
+
+ case PCIBIOS_BAD_REGISTER_NUMBER:
+ errstr = "bad register number";
+ break;
+
+ case PCIBIOS_SET_FAILED:
+ errstr = "set failed";
+ break;
+
+ case PCIBIOS_BUFFER_TOO_SMALL:
+ errstr = "buffer too small";
+ break;
+
+ default:
+ printf("%s: unknown return code 0x%x\n", func, rv);
+ return (rv);
+ }
+
+ printf("%s: %s\n", func, errstr);
+ return (rv);
+}
+
+void
+pcibios_print_exclirq()
+{
+ int i;
+
+ if (pcibios_pir_header.exclusive_irq) {
+ printf("PCI Exclusive IRQs:");
+ for (i = 0; i < 16; i++) {
+ if (pcibios_pir_header.exclusive_irq & (1 << i))
+ printf(" %d", i);
+ }
+ printf("\n");
+ }
+}
+
+#ifdef PCIINTR_DEBUG
+void
+pcibios_print_pir_table()
+{
+ int i, j;
+
+ for (i = 0; i < pcibios_pir_table_nentries; i++) {
+ printf("PIR Entry %d:\n", i);
+ printf("\tBus: %d Device: %d\n",
+ pcibios_pir_table[i].bus,
+ pcibios_pir_table[i].device >> 3);
+ for (j = 0; j < 4; j++) {
+ printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n",
+ 'A' + j,
+ pcibios_pir_table[i].linkmap[j].link,
+ pcibios_pir_table[i].linkmap[j].bitmap);
+ }
+ }
+}
+#endif
diff --git a/sys/arch/i386/pci/pcibios.h b/sys/arch/i386/pci/pcibios.h
new file mode 100644
index 00000000000..6b584c9c5ac
--- /dev/null
+++ b/sys/arch/i386/pci/pcibios.h
@@ -0,0 +1,87 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Data structure definitions for the PCI BIOS interface.
+ */
+
+/*
+ * PCI BIOS return codes.
+ */
+#define PCIBIOS_SUCCESS 0x00
+#define PCIBIOS_SERVICE_NOT_PRESENT 0x80
+#define PCIBIOS_FUNCTION_NOT_SUPPORTED 0x81
+#define PCIBIOS_BAD_VENDOR_ID 0x83
+#define PCIBIOS_DEVICE_NOT_FOUND 0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
+#define PCIBIOS_SET_FAILED 0x88
+#define PCIBIOS_BUFFER_TOO_SMALL 0x89
+
+/*
+ * PCI IRQ Routing Table definitions.
+ */
+
+/*
+ * Slot entry (per PCI 2.1)
+ */
+struct pcibios_linkmap {
+ u_int8_t link;
+ u_int16_t bitmap;
+} __attribute__((__packed__));
+
+struct pcibios_intr_routing {
+ u_int8_t bus;
+ u_int8_t device;
+ struct pcibios_linkmap linkmap[4]; /* INT[A:D]# */
+ u_int8_t slot;
+ u_int8_t reserved;
+} __attribute__((__packed__));
+
+/*
+ * $PIR header. Reference:
+ *
+ * http://www.microsoft.com/HWDEV/busbios/PCIIRQ.htm
+ */
+struct pcibios_pir_header {
+ u_int32_t signature; /* $PIR */
+ u_int16_t version;
+ u_int16_t tablesize;
+ u_int8_t router_bus;
+ u_int8_t router_devfunc;
+ u_int16_t exclusive_irq;
+ u_int32_t compat_router; /* PCI vendor/product */
+ u_int32_t miniport;
+ u_int8_t reserved[11];
+ u_int8_t checksum;
+} __attribute__((__packed__));
+
+void pcibios_init __P((void));
+
+extern struct pcibios_pir_header pcibios_pir_header;
+extern struct pcibios_intr_routing *pcibios_pir_table;
+extern int pcibios_pir_table_nentries;
+extern int pcibios_max_bus;
diff --git a/sys/arch/i386/pci/piix.c b/sys/arch/i386/pci/piix.c
new file mode 100644
index 00000000000..19cbded0860
--- /dev/null
+++ b/sys/arch/i386/pci/piix.c
@@ -0,0 +1,237 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the Intel PIIX PCI-ISA bridge interrupt controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/piixreg.h>
+#include <i386/pci/piixvar.h>
+
+int piix_getclink __P((pciintr_icu_handle_t, int, int *));
+int piix_get_intr __P((pciintr_icu_handle_t, int, int *));
+int piix_set_intr __P((pciintr_icu_handle_t, int, int));
+
+const struct pciintr_icu piix_pci_icu = {
+ piix_getclink,
+ piix_get_intr,
+ piix_set_intr,
+ piix_get_trigger,
+ piix_set_trigger,
+};
+
+int
+piix_init(pc, iot, tag, ptagp, phandp)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ pcitag_t tag;
+ pciintr_icu_tag_t *ptagp;
+ pciintr_icu_handle_t *phandp;
+{
+ struct piix_handle *ph;
+
+ ph = malloc(sizeof(*ph), M_DEVBUF, M_NOWAIT);
+ if (ph == NULL)
+ return (1);
+
+ ph->ph_iot = iot;
+ ph->ph_pc = pc;
+ ph->ph_tag = tag;
+
+ if (bus_space_map(iot, PIIX_REG_ELCR, PIIX_REG_ELCR_SIZE, 0,
+ &ph->ph_elcr_ioh) != 0) {
+ free(ph, M_DEVBUF);
+ return (1);
+ }
+
+ *ptagp = &piix_pci_icu;
+ *phandp = ph;
+ return (0);
+}
+
+int
+piix_getclink(v, link, clinkp)
+ pciintr_icu_handle_t v;
+ int link, *clinkp;
+{
+
+ /* Pattern 1: simple. */
+ if (PIIX_LEGAL_LINK(link - 1)) {
+ *clinkp = link - 1;
+ return (0);
+ }
+
+ /* Pattern 2: configuration register offset */
+ if (link >= 0x60 && link <= 0x63) {
+ *clinkp = link - 0x60;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+piix_get_intr(v, clink, irqp)
+ pciintr_icu_handle_t v;
+ int clink, *irqp;
+{
+ struct piix_handle *ph = v;
+ int shift;
+ pcireg_t reg;
+
+ if (PIIX_LEGAL_LINK(clink) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ);
+ shift = clink << 3;
+ if ((reg >> shift) & PIIX_CFG_PIRQ_NONE)
+ *irqp = 0xff;
+ else
+ *irqp = PIIX_PIRQ(reg, clink);
+
+ return (0);
+}
+
+int
+piix_set_intr(v, clink, irq)
+ pciintr_icu_handle_t v;
+ int clink, irq;
+{
+ struct piix_handle *ph = v;
+ int shift;
+ pcireg_t reg;
+
+ if (PIIX_LEGAL_LINK(clink) == 0 || PIIX_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ);
+ shift = clink << 3;
+ reg &= ~((PIIX_CFG_PIRQ_NONE | PIIX_CFG_PIRQ_MASK) << shift);
+ reg |= irq << shift;
+ pci_conf_write(ph->ph_pc, ph->ph_tag, PIIX_CFG_PIRQ, reg);
+
+ return (0);
+}
+
+int
+piix_get_trigger(v, irq, triggerp)
+ pciintr_icu_handle_t v;
+ int irq, *triggerp;
+{
+ struct piix_handle *ph = v;
+ int off, bit;
+ u_int8_t elcr;
+
+ if (PIIX_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ off = (irq > 7) ? 1 : 0;
+ bit = irq & 7;
+
+ elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off);
+ if (elcr & (1 << bit))
+ *triggerp = IST_LEVEL;
+ else
+ *triggerp = IST_EDGE;
+
+ return (0);
+}
+
+int
+piix_set_trigger(v, irq, trigger)
+ pciintr_icu_handle_t v;
+ int irq, trigger;
+{
+ struct piix_handle *ph = v;
+ int off, bit;
+ u_int8_t elcr;
+
+ if (PIIX_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ off = (irq > 7) ? 1 : 0;
+ bit = irq & 7;
+
+ elcr = bus_space_read_1(ph->ph_iot, ph->ph_elcr_ioh, off);
+ if (trigger == IST_LEVEL)
+ elcr |= (1 << bit);
+ else
+ elcr &= ~(1 << bit);
+ bus_space_write_1(ph->ph_iot, ph->ph_elcr_ioh, off, elcr);
+
+ return (0);
+}
diff --git a/sys/arch/i386/pci/piixreg.h b/sys/arch/i386/pci/piixreg.h
new file mode 100644
index 00000000000..36f18b8eb73
--- /dev/null
+++ b/sys/arch/i386/pci/piixreg.h
@@ -0,0 +1,55 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Register definitions for the Intel PIIX PCI-ISA bridge interrupt controller.
+ */
+
+/*
+ * PIRQ[3:0]# - PIRQ ROUTE CONTROL REGISTERS
+ *
+ * PCI Configuration registers 0x60, 0x61, 0x62, 0x63
+ */
+
+#define PIIX_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3)
+
+#define PIIX_PIRQ_MASK 0xdef8
+#define PIIX_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \
+ ((1 << (irq)) & PIIX_PIRQ_MASK) != 0)
+
+#define PIIX_CFG_PIRQ 0x60 /* PCI configuration space */
+#define PIIX_CFG_PIRQ_NONE 0x80
+#define PIIX_CFG_PIRQ_MASK 0x0f
+#define PIIX_PIRQ(reg, x) (((reg) >> ((x) << 3)) & 0xff)
+
+/*
+ * ELCR - EDGE/LEVEL CONTROL REGISTER
+ *
+ * PCI I/O registers 0x4d0, 0x4d1
+ */
+#define PIIX_REG_ELCR 0x4d0
+#define PIIX_REG_ELCR_SIZE 2
diff --git a/sys/arch/i386/pci/piixvar.h b/sys/arch/i386/pci/piixvar.h
new file mode 100644
index 00000000000..64b192cc513
--- /dev/null
+++ b/sys/arch/i386/pci/piixvar.h
@@ -0,0 +1,77 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the Intel PIIX PCI-ISA bridge interrupt controller.
+ */
+
+int piix_get_trigger __P((pciintr_icu_handle_t, int, int *));
+int piix_set_trigger __P((pciintr_icu_handle_t, int, int));
+
+struct piix_handle {
+ bus_space_tag_t ph_iot;
+ bus_space_handle_t ph_elcr_ioh;
+ pci_chipset_tag_t ph_pc;
+ pcitag_t ph_tag;
+};
diff --git a/sys/arch/i386/pci/sis85c503.c b/sys/arch/i386/pci/sis85c503.c
new file mode 100644
index 00000000000..50c5fbf4357
--- /dev/null
+++ b/sys/arch/i386/pci/sis85c503.c
@@ -0,0 +1,180 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the SiS 85c503 PCI-ISA bridge interrupt controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/sis85c503reg.h>
+#include <i386/pci/piixvar.h>
+
+int sis85c503_getclink __P((pciintr_icu_handle_t, int, int *));
+int sis85c503_get_intr __P((pciintr_icu_handle_t, int, int *));
+int sis85c503_set_intr __P((pciintr_icu_handle_t, int, int));
+
+const struct pciintr_icu sis85c503_pci_icu = {
+ sis85c503_getclink,
+ sis85c503_get_intr,
+ sis85c503_set_intr,
+ piix_get_trigger,
+ piix_set_trigger,
+};
+
+int
+sis85c503_init(pc, iot, tag, ptagp, phandp)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ pcitag_t tag;
+ pciintr_icu_tag_t *ptagp;
+ pciintr_icu_handle_t *phandp;
+{
+
+ if (piix_init(pc, iot, tag, ptagp, phandp) == 0) {
+ *ptagp = &sis85c503_pci_icu;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+sis85c503_getclink(v, link, clinkp)
+ pciintr_icu_handle_t v;
+ int link, *clinkp;
+{
+
+ /* Pattern 1: simple. */
+ if (link >= 1 && link <= 4) {
+ *clinkp = SIS85C503_CFG_PIRQ_REGSTART + link - 1;
+ return (0);
+ }
+
+ /* Pattern 2: configuration register offset */
+ if (link >= SIS85C503_CFG_PIRQ_REGSTART &&
+ link <= SIS85C503_CFG_PIRQ_REGEND) {
+ *clinkp = link;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+sis85c503_get_intr(v, clink, irqp)
+ pciintr_icu_handle_t v;
+ int clink, *irqp;
+{
+ struct piix_handle *ph = v;
+ pcireg_t reg;
+
+ if (SIS85C503_LEGAL_LINK(clink) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
+ SIS85C503_CFG_PIRQ_REGOFS(clink));
+ reg = SIS85C503_CFG_PIRQ_REG(reg, clink);
+
+ if (reg & SIS85C503_CFG_PIRQ_ROUTE_DISABLE)
+ *irqp = 0xff;
+ else
+ *irqp = reg & SIS85C503_CFG_PIRQ_INTR_MASK;
+
+ return (0);
+}
+
+int
+sis85c503_set_intr(v, clink, irq)
+ pciintr_icu_handle_t v;
+ int clink, irq;
+{
+ struct piix_handle *ph = v;
+ int shift;
+ pcireg_t reg;
+
+ if (SIS85C503_LEGAL_LINK(clink) == 0 || SIS85C503_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
+ SIS85C503_CFG_PIRQ_REGOFS(clink));
+ shift = SIS85C503_CFG_PIRQ_SHIFT(clink);
+ reg &= ~((SIS85C503_CFG_PIRQ_ROUTE_DISABLE |
+ SIS85C503_CFG_PIRQ_INTR_MASK) << shift);
+ reg |= (irq << shift);
+ pci_conf_write(ph->ph_pc, ph->ph_tag, SIS85C503_CFG_PIRQ_REGOFS(clink),
+ reg);
+
+ return (0);
+}
diff --git a/sys/arch/i386/pci/sis85c503reg.h b/sys/arch/i386/pci/sis85c503reg.h
new file mode 100644
index 00000000000..a96ef90836e
--- /dev/null
+++ b/sys/arch/i386/pci/sis85c503reg.h
@@ -0,0 +1,52 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Register definitions for the SiS 85c503 PCI-ISA bridge interrupt controller.
+ */
+
+#define SIS85C503_CFG_PIRQ_REGSTART 0x41 /* PCI configuration space */
+#define SIS85C503_CFG_PIRQ_REGEND 0x44
+
+#define SIS85C503_LEGAL_LINK(link) ((link) >= SIS85C503_CFG_PIRQ_REGSTART && \
+ (link) <= SIS85C503_CFG_PIRQ_REGEND)
+
+#define SIS85C503_CFG_PIRQ_REGOFS(regofs) (((regofs) >> 2) << 2)
+#define SIS85C503_CFG_PIRQ_SHIFT(regofs) \
+ (((regofs) - SIS85C503_CFG_PIRQ_REGOFS(regofs)) << 3)
+
+#define SIS85C503_CFG_PIRQ_MASK 0xff
+#define SIS85C503_CFG_PIRQ_INTR_MASK 0x0f
+
+#define SIS85C503_CFG_PIRQ_REG(reg, regofs) \
+ (((reg) >> SIS85C503_CFG_PIRQ_SHIFT(regofs)) & SIS85C503_CFG_PIRQ_MASK)
+
+#define SIS85C503_CFG_PIRQ_ROUTE_DISABLE 0x80
+
+#define SIS85C503_PIRQ_MASK 0xdef8
+#define SIS85C503_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \
+ ((1 << (irq)) & SIS85C503_PIRQ_MASK) != 0)
diff --git a/sys/arch/i386/pci/via82c586.c b/sys/arch/i386/pci/via82c586.c
new file mode 100644
index 00000000000..021eaa2ff0c
--- /dev/null
+++ b/sys/arch/i386/pci/via82c586.c
@@ -0,0 +1,270 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Support for the VIA 82c586 PCI-ISA bridge interrupt controller.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+#include <i386/pci/pci_intr_fixup.h>
+#include <i386/pci/via82c586reg.h>
+#include <i386/pci/piixvar.h>
+
+int via82c586_getclink __P((pciintr_icu_handle_t, int, int *));
+int via82c586_get_intr __P((pciintr_icu_handle_t, int, int *));
+int via82c586_set_intr __P((pciintr_icu_handle_t, int, int));
+int via82c586_get_trigger __P((pciintr_icu_handle_t, int, int *));
+int via82c586_set_trigger __P((pciintr_icu_handle_t, int, int));
+
+const struct pciintr_icu via82c586_pci_icu = {
+ via82c586_getclink,
+ via82c586_get_intr,
+ via82c586_set_intr,
+ via82c586_get_trigger,
+ via82c586_set_trigger,
+};
+
+const int vp3_cfg_trigger_shift[] = {
+ VP3_CFG_TRIGGER_SHIFT_PIRQA,
+ VP3_CFG_TRIGGER_SHIFT_PIRQB,
+ VP3_CFG_TRIGGER_SHIFT_PIRQC,
+ VP3_CFG_TRIGGER_SHIFT_PIRQD,
+};
+
+#define VP3_TRIGGER(reg, pirq) (((reg) >> vp3_cfg_trigger_shift[(pirq)]) & \
+ VP3_CFG_TRIGGER_MASK)
+
+const int vp3_cfg_intr_shift[] = {
+ VP3_CFG_INTR_SHIFT_PIRQA,
+ VP3_CFG_INTR_SHIFT_PIRQB,
+ VP3_CFG_INTR_SHIFT_PIRQC,
+ VP3_CFG_INTR_SHIFT_PIRQD,
+};
+
+#define VP3_PIRQ(req, pirq) (((reg) >> vp3_cfg_intr_shift[(pirq)]) & \
+ VP3_CFG_INTR_MASK)
+
+int
+via82c586_init(pc, iot, tag, ptagp, phandp)
+ pci_chipset_tag_t pc;
+ bus_space_tag_t iot;
+ pcitag_t tag;
+ pciintr_icu_tag_t *ptagp;
+ pciintr_icu_handle_t *phandp;
+{
+ pcireg_t reg;
+
+ if (piix_init(pc, iot, tag, ptagp, phandp) == 0) {
+ *ptagp = &via82c586_pci_icu;
+
+ /*
+ * Enable EISA ELCR.
+ */
+ reg = pci_conf_read(pc, tag, VP3_CFG_KBDMISCCTRL12_REG);
+ reg |= VP3_CFG_MISCCTRL2_EISA4D04D1PORT_ENABLE <<
+ VP3_CFG_MISCCTRL2_SHIFT;
+ pci_conf_write(pc, tag, VP3_CFG_KBDMISCCTRL12_REG, reg);
+
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+via82c586_getclink(v, link, clinkp)
+ pciintr_icu_handle_t v;
+ int link, *clinkp;
+{
+
+ if (VP3_LEGAL_LINK(link - 1)) {
+ *clinkp = link - 1;
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+via82c586_get_intr(v, clink, irqp)
+ pciintr_icu_handle_t v;
+ int clink, *irqp;
+{
+ struct piix_handle *ph = v;
+ pcireg_t reg;
+ int val;
+
+ if (VP3_LEGAL_LINK(clink) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG);
+ val = VP3_PIRQ(reg, clink);
+ *irqp = (val == VP3_PIRQ_NONE) ? 0xff : val;
+
+ return (0);
+}
+
+int
+via82c586_set_intr(v, clink, irq)
+ pciintr_icu_handle_t v;
+ int clink, irq;
+{
+ struct piix_handle *ph = v;
+ int shift, val;
+ pcireg_t reg;
+
+ if (VP3_LEGAL_LINK(clink) == 0 || VP3_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG);
+ via82c586_get_intr(v, clink, &val);
+ shift = vp3_cfg_intr_shift[clink];
+ reg &= ~(VP3_CFG_INTR_MASK << shift);
+ reg |= (irq << shift);
+ pci_conf_write(ph->ph_pc, ph->ph_tag, VP3_CFG_PIRQ_REG, reg);
+ if (via82c586_get_intr(v, clink, &val) != 0 ||
+ val != irq)
+ return (1);
+
+ return (0);
+}
+
+int
+via82c586_get_trigger(v, irq, triggerp)
+ pciintr_icu_handle_t v;
+ int irq, *triggerp;
+{
+ struct piix_handle *ph = v;
+ int i, error, check_consistency, pciirq, pcitrigger = IST_NONE;
+ pcireg_t reg;
+
+ if (VP3_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ check_consistency = 0;
+ for (i = 0; i <= 3; i++) {
+ via82c586_get_intr(v, i, &pciirq);
+ if (pciirq == irq) {
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
+ VP3_CFG_PIRQ_REG);
+ if (VP3_TRIGGER(reg, i) == VP3_CFG_TRIGGER_EDGE)
+ pcitrigger = IST_EDGE;
+ else
+ pcitrigger = IST_LEVEL;
+ check_consistency = 1;
+ break;
+ }
+ }
+
+ error = piix_get_trigger(v, irq, triggerp);
+ if (error == 0 && check_consistency && pcitrigger != *triggerp)
+ return (1);
+ return (error);
+}
+
+int
+via82c586_set_trigger(v, irq, trigger)
+ pciintr_icu_handle_t v;
+ int irq, trigger;
+{
+ struct piix_handle *ph = v;
+ int i, pciirq, shift, testtrig;
+ pcireg_t reg;
+
+ if (VP3_LEGAL_IRQ(irq) == 0)
+ return (1);
+
+ for (i = 0; i <= 3; i++) {
+ via82c586_get_intr(v, i, &pciirq);
+ if (pciirq == irq) {
+ reg = pci_conf_read(ph->ph_pc, ph->ph_tag,
+ VP3_CFG_PIRQ_REG);
+ shift = vp3_cfg_trigger_shift[i];
+ if (trigger == IST_LEVEL)
+ reg &= ~(VP3_CFG_TRIGGER_MASK << shift);
+ else
+ reg |= (VP3_CFG_TRIGGER_EDGE << shift);
+ pci_conf_write(ph->ph_pc, ph->ph_tag,
+ VP3_CFG_PIRQ_REG, reg);
+ break;
+ }
+ }
+
+ if (piix_set_trigger(v, irq, trigger) != 0 ||
+ via82c586_get_trigger(v, irq, &testtrig) != 0 ||
+ testtrig != trigger)
+ return (1);
+
+ return (0);
+}
diff --git a/sys/arch/i386/pci/via82c586reg.h b/sys/arch/i386/pci/via82c586reg.h
new file mode 100644
index 00000000000..fa812d1b1b8
--- /dev/null
+++ b/sys/arch/i386/pci/via82c586reg.h
@@ -0,0 +1,62 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1999, by UCHIYAMA Yasushi
+ * 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. The name of the developer may NOT be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Register definitions for the VIA 82c586 PCI-ISA bridge interrupt controller.
+ */
+
+#define VP3_CFG_PIRQ_REG 0x54 /* PCI configuration space */
+#define VP3_CFG_KBDMISCCTRL12_REG 0x44
+#define VP3_CFG_IDEMISCCTRL3_REG 0x48
+
+#define VP3_CFG_MISCCTRL2_SHIFT 24
+#define VP3_CFG_MISCCTRL2_MASK 0x0f
+#define VP3_CFG_MISCCTRL2_EISA4D04D1PORT_ENABLE 0x20
+#define VP3_CFG_MISCCTRL2_REG(reg) \
+ (((reg) >> VP3_CFG_MISCCTRL2_SHIFT) & VP3_CFG_MISCCTRL2_MASK)
+
+#define VP3_CFG_TRIGGER_LEVEL 0
+#define VP3_CFG_TRIGGER_EDGE 1
+
+#define VP3_CFG_TRIGGER_MASK 0x01
+#define VP3_CFG_TRIGGER_SHIFT_PIRQA 3
+#define VP3_CFG_TRIGGER_SHIFT_PIRQB 2
+#define VP3_CFG_TRIGGER_SHIFT_PIRQC 1
+#define VP3_CFG_TRIGGER_SHIFT_PIRQD 0
+
+#define VP3_CFG_INTR_MASK 0x04
+#define VP3_PIRQ_MASK 0xdefa
+
+#define VP3_CFG_INTR_SHIFT_PIRQA 0x14
+#define VP3_CFG_INTR_SHIFT_PIRQB 0x10
+#define VP3_CFG_INTR_SHIFT_PIRQC 0x1c
+#define VP3_CFG_INTR_SHIFT_PIRQD 0x0c
+
+#define VP3_PIRQ_NONE 0
+#define VP3_LEGAL_LINK(link) ((link) >= 0 && (link) <= 3)
+#define VP3_LEGAL_IRQ(irq) ((irq) >= 0 && (irq) <= 15 && \
+ ((1 << (irq)) & VP3_PIRQ_MASK) != 0)