diff options
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/amd64/mpbios.c | 10 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/mpbios_intr_fixup.c | 186 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/mpbiosvar.h | 4 |
4 files changed, 200 insertions, 3 deletions
diff --git a/sys/arch/amd64/amd64/mpbios.c b/sys/arch/amd64/amd64/mpbios.c index a5e459fc6fd..5347fe93071 100644 --- a/sys/arch/amd64/amd64/mpbios.c +++ b/sys/arch/amd64/amd64/mpbios.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbios.c,v 1.3 2005/10/21 18:55:00 martin Exp $ */ +/* $OpenBSD: mpbios.c,v 1.4 2006/03/22 21:16:00 kettenis Exp $ */ /* $NetBSD: mpbios.c,v 1.7 2003/05/15 16:32:50 fvdl Exp $ */ /*- @@ -122,11 +122,14 @@ #include <machine/i82489var.h> #include <dev/isa/isareg.h> +#include <dev/pci/pcivar.h> #ifdef X86_MPBIOS_SUPPORT_EISA #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ #endif +#include "pci.h" + static struct mpbios_ioapic default_ioapic = { 2, 0, 1, IOAPICENTRY_FLAG_EN, (u_int32_t)IOAPIC_BASE_DEFAULT @@ -662,6 +665,11 @@ mpbios_scan(self) mpbios_unmap (&mp_cfg_table_map); } mpbios_scanned = 1; + +#if NPCI > 0 + if (pci_mode != 0) + mpbios_intr_fixup(); +#endif } void diff --git a/sys/arch/amd64/amd64/mpbios_intr_fixup.c b/sys/arch/amd64/amd64/mpbios_intr_fixup.c new file mode 100644 index 00000000000..7df0c2e4796 --- /dev/null +++ b/sys/arch/amd64/amd64/mpbios_intr_fixup.c @@ -0,0 +1,186 @@ +/* $OpenBSD: mpbios_intr_fixup.c,v 1.1 2006/03/22 21:16:00 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 } +}; + +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_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 + +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_SATA1_MASK) >> NFORCE4_SATA1_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 7, 1, pin); + pin = (reg & NFORCE4_SATA2_MASK) >> NFORCE4_SATA2_SHIFT; + if (pin != 0) + mpbios_pin_fixup(bus, 8, 1, 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_pic.pic_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/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index 9655fff362e..0b6cd58fa6a 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.20 2006/03/08 03:33:21 uwe Exp $ +# $OpenBSD: files.amd64,v 1.21 2006/03/22 21:16:00 kettenis Exp $ maxpartitions 16 maxusers 2 16 128 @@ -34,6 +34,7 @@ file arch/amd64/amd64/ipi.c multiprocessor file arch/amd64/amd64/apic.c ioapic | lapic file arch/amd64/amd64/mpbios.c mpbios +file arch/amd64/amd64/mpbios_intr_fixup.c mpbios & pci file arch/amd64/amd64/consinit.c diff --git a/sys/arch/amd64/include/mpbiosvar.h b/sys/arch/amd64/include/mpbiosvar.h index b10bbe44fc7..c6f1a9063f4 100644 --- a/sys/arch/amd64/include/mpbiosvar.h +++ b/sys/arch/amd64/include/mpbiosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpbiosvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: mpbiosvar.h,v 1.2 2006/03/22 21:16:00 kettenis Exp $ */ /* $NetBSD: mpbiosvar.h,v 1.2 2003/04/02 07:53:57 thorpej Exp $ */ /*- @@ -54,6 +54,8 @@ void mpbios_scan(struct device *); int mpbios_probe(struct device *); +void mpbios_intr_fixup(void); + extern int mpbios_scanned; #endif |