diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2006-05-01 17:01:15 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2006-05-01 17:01:15 +0000 |
commit | 3d579079b8bc6ea2df1ade8f73ede6870084fe69 (patch) | |
tree | f1353920de5407c57cad722b0a683b76af170ce7 /sys | |
parent | 75ab94a0356c1d625f55df6f8a76947ea1b5d5e7 (diff) |
Fixup broken mpbios'es on VT8237 and nForce4 chipsets. Fixes interrupt
routing for several integrated devices on those chipsets in GENERIC.MP.
ok brad@, mickey@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/mpbios.c | 11 | ||||
-rw-r--r-- | sys/arch/i386/i386/mpbios_intr_fixup.c | 205 | ||||
-rw-r--r-- | sys/arch/i386/include/mpbiosvar.h | 4 |
4 files changed, 220 insertions, 3 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 72a268d8bb6..2feff89137d 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.145 2006/04/27 15:37:48 mickey Exp $ +# $OpenBSD: files.i386,v 1.146 2006/05/01 17:01:14 kettenis Exp $ # # new style config file for i386 architecture # @@ -285,6 +285,7 @@ file arch/i386/i386/apmcall.S apm # Intel SMP specification 1.4 define mpbios file arch/i386/i386/mpbios.c mpbios needs-flag +file arch/i386/i386/mpbios_intr_fixup.c mpbios & pci # CPUS define cpu {[apid = -1]} diff --git a/sys/arch/i386/i386/mpbios.c b/sys/arch/i386/i386/mpbios.c index 6de7ad458d3..c37ac264198 100644 --- a/sys/arch/i386/i386/mpbios.c +++ b/sys/arch/i386/i386/mpbios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbios.c,v 1.10 2006/04/30 17:38:26 kettenis Exp $ */ +/* $OpenBSD: mpbios.c,v 1.11 2006/05/01 17:01:14 kettenis Exp $ */ /* $NetBSD: mpbios.c,v 1.2 2002/10/01 12:56:57 fvdl Exp $ */ /*- @@ -124,10 +124,14 @@ #include <machine/i82093var.h> #include <machine/i82489reg.h> #include <machine/i82489var.h> + #include <dev/isa/isareg.h> +#include <dev/pci/pcivar.h> #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ +#include "pci.h" + static struct mpbios_ioapic default_ioapic = { 2, 0, 1, IOAPICENTRY_FLAG_EN, (caddr_t)IOAPIC_BASE_DEFAULT @@ -678,6 +682,11 @@ mpbios_scan(self) mp_cth = NULL; mpbios_unmap(&mp_cfg_table_map); } + +#if NPCI > 0 + if (pci_mode != 0) + mpbios_intr_fixup(); +#endif } int diff --git a/sys/arch/i386/i386/mpbios_intr_fixup.c b/sys/arch/i386/i386/mpbios_intr_fixup.c new file mode 100644 index 00000000000..2fd1994f4e8 --- /dev/null +++ b/sys/arch/i386/i386/mpbios_intr_fixup.c @@ -0,0 +1,205 @@ +/* $OpenBSD: mpbios_intr_fixup.c,v 1.1 2006/05/01 17:01:14 kettenis Exp $ */ + +/* + * Copyright (c) 2006 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> + +void mpbios_pin_fixup(int, int, int, int); +const struct mpbios_icu_table *mpbios_icu_lookup(pcireg_t); + +void via8237_mpbios_fixup(pci_chipset_tag_t, pcitag_t); +void nforce4_mpbios_fixup(pci_chipset_tag_t, pcitag_t); + +const struct mpbios_icu_table { + pci_vendor_id_t mpit_vendor; + pci_product_id_t mpit_product; + void (*mpit_mpbios_fixup)(pci_chipset_tag_t, pcitag_t); +} mpbios_icu_table[] = { + { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA, + via8237_mpbios_fixup }, + { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_ISA, + nforce4_mpbios_fixup }, + { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_ISA2, + nforce4_mpbios_fixup } +}; + +const struct mpbios_icu_table * +mpbios_icu_lookup(pcireg_t id) +{ + const struct mpbios_icu_table *mpit; + + for (mpit = mpbios_icu_table; mpit->mpit_mpbios_fixup != NULL; mpit++) + if (PCI_VENDOR(id) == mpit->mpit_vendor && + PCI_PRODUCT(id) == mpit->mpit_product) + return (mpit); + + return (NULL); +} + +/* + * NVIDIA nForce4 PCI-ISA bridge. + */ + +#define NFORCE4_PNPIRQ1 0x7c +#define NFORCE4_PNPIRQ2 0x80 +#define NFORCE4_USB2_SHIFT 12 +#define NFORCE4_USB2_MASK (0xf << NFORCE4_USB2_SHIFT) +#define NFORCE4_SATA1_SHIFT 28 +#define NFORCE4_SATA1_MASK (0xf << NFORCE4_SATA1_SHIFT) +#define NFORCE4_SATA2_SHIFT 24 +#define NFORCE4_SATA2_MASK (0xf << NFORCE4_SATA2_SHIFT) +#define NFORCE4_PNPIRQ3 0x84 +#define NFORCE4_USB1_SHIFT 0 +#define NFORCE4_USB1_MASK (0xf << NFORCE4_USB1_SHIFT) +#define NFORCE4_LAN_SHIFT 8 +#define NFORCE4_LAN_MASK (0xf << NFORCE4_LAN_SHIFT) + +void +nforce4_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag) +{ + pcireg_t reg; + int bus, pin; + + pci_decompose_tag (pc, tag, &bus, NULL, NULL); + + reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ2); + pin = (reg & NFORCE4_USB2_MASK) >> NFORCE4_USB2_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_B, pin); + pin = (reg & NFORCE4_SATA1_MASK) >> NFORCE4_SATA1_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 7, PCI_INTERRUPT_PIN_A, pin); + pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 8, PCI_INTERRUPT_PIN_A, pin); + + reg = pci_conf_read(pc, tag, NFORCE4_PNPIRQ3); + pin = (reg & NFORCE4_USB1_MASK) >> NFORCE4_USB1_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 2, PCI_INTERRUPT_PIN_A, pin); + pin = (reg & NFORCE4_LAN_MASK) >> NFORCE4_LAN_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 10, PCI_INTERRUPT_PIN_A, pin); +} + +/* + * VIA VT8237 PCI-ISA bridge. + */ + +void +via8237_mpbios_fixup(pci_chipset_tag_t pc, pcitag_t tag) +{ + int bus; + + pci_decompose_tag (pc, tag, &bus, NULL, NULL); + + /* SATA is hardwired to APIC pin 20. */ + mpbios_pin_fixup(bus, 15, 2, 20); +} + +void +mpbios_pin_fixup(int bus, int dev, int rawpin, int pin) +{ + struct mp_bus *mpb = &mp_busses[bus]; + struct mp_intr_map *mip; + + for (mip = mpb->mb_intrs; mip != NULL; mip = mip->next) { + if (mip->bus_pin == ((dev << 2) | (rawpin - 1)) && + mip->ioapic_pin != pin) { + + if (mp_verbose) { + + printf("%s: int%d attached to %s", + mip->ioapic->sc_dev.dv_xname, + pin, mpb->mb_name); + + if (mpb->mb_idx != -1) + printf("%d", mpb->mb_idx); + + (*(mpb->mb_intr_print))(mip->bus_pin); + + printf(" (fixup)\n"); + } + + mip->ioapic_pin = pin; + mip->ioapic_ih &= ~APIC_INT_PIN_MASK; + mip->ioapic_ih |= (pin << APIC_INT_PIN_SHIFT); + if (mip->ioapic->sc_pins[pin].ip_map == NULL) + mip->ioapic->sc_pins[pin].ip_map = mip; + } + } +} + +void +mpbios_intr_fixup(void) +{ + const struct mpbios_icu_table *mpit = NULL; + pci_chipset_tag_t pc = NULL; + pcitag_t icutag; + int device, maxdevs = pci_bus_maxdevs(pc, 0); + + /* Search configuration space for a known interrupt router. */ + for (device = 0; device < maxdevs; device++) { + const struct pci_quirkdata *qd; + int function, nfuncs; + pcireg_t icuid; + pcireg_t bhlcr; + + 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; + + qd = pci_lookup_quirkdata(PCI_VENDOR(icuid), + PCI_PRODUCT(icuid)); + + bhlcr = pci_conf_read(pc, icutag, 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++) { + icutag = pci_make_tag(pc, 0, device, function); + icuid = pci_conf_read(pc, icutag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) + continue; + + if ((mpit = mpbios_icu_lookup(icuid))) + break; + } + + if (mpit != NULL) + break; + } + + if (mpit) + mpit->mpit_mpbios_fixup(pc, icutag); +} diff --git a/sys/arch/i386/include/mpbiosvar.h b/sys/arch/i386/include/mpbiosvar.h index 83f3b140bea..bba6da5683e 100644 --- a/sys/arch/i386/include/mpbiosvar.h +++ b/sys/arch/i386/include/mpbiosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbiosvar.h,v 1.4 2006/03/24 12:17:03 mickey Exp $ */ +/* $OpenBSD: mpbiosvar.h,v 1.5 2006/05/01 17:01:14 kettenis Exp $ */ /* $NetBSD: mpbiosvar.h,v 1.1.2.3 2000/02/29 13:17:20 sommerfeld Exp $ */ /*- @@ -82,6 +82,8 @@ extern int mp_eisa_bus; void mpbios_scan(struct device *); int mpbios_probe(struct device *); int mpbios_invent(int, int, int); + +void mpbios_intr_fixup(void); #endif #endif |