diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-02-09 19:36:06 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-02-09 19:36:06 +0000 |
commit | 5ec303afa34da1dad80ec11cf4e02ff19e5e2ccc (patch) | |
tree | 470568f3138c78ba3cfee38ef68c9129d7b476f8 /sys/arch | |
parent | 13bd74560baae4e828c8bccda35ddca3be220c8a (diff) |
Switching the strange VIA VT8251 PCIE host bridge into a PCI-PCI bridge
didn't quite work since the bridge seems to end up largely unconfigured, and
our PCI resource configuration code isn't quite smart enough (yet) to fix
things up. So instead switch it only into PCI-PCI bridge mode long enough to
snoop the bus number, and attach pci(4) using that number.
This is probably safer anyway, since ACPI may not like us switching things
around behind its back. Fixes PR 6253 & 6304.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/pci/pchb.c | 50 | ||||
-rw-r--r-- | sys/arch/i386/pci/pchb.c | 34 |
2 files changed, 61 insertions, 23 deletions
diff --git a/sys/arch/amd64/pci/pchb.c b/sys/arch/amd64/pci/pchb.c index 6b13b95ff59..dee6033b0bd 100644 --- a/sys/arch/amd64/pci/pchb.c +++ b/sys/arch/amd64/pci/pchb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pchb.c,v 1.31 2009/11/23 15:33:37 deraadt Exp $ */ +/* $OpenBSD: pchb.c,v 1.32 2010/02/09 19:36:05 kettenis Exp $ */ /* $NetBSD: pchb.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ /* * Copyright (c) 2000 Michael Shalayeff @@ -66,6 +66,7 @@ #include <dev/pci/pcidevs.h> #include <dev/pci/agpvar.h> +#include <dev/pci/ppbreg.h> #include <dev/rndvar.h> @@ -143,8 +144,12 @@ pchbattach(struct device *parent, struct device *self, void *aux) { struct pchb_softc *sc = (struct pchb_softc *)self; struct pci_attach_args *pa = aux; - pcireg_t bcreg; + struct pcibus_attach_args pba; + pcireg_t bcreg, bir; + u_char pbnum; + pcitag_t tag; int i, r; + int doattach = 0; switch (PCI_VENDOR(pa->pa_id)) { case PCI_VENDOR_AMD: @@ -201,17 +206,27 @@ pchbattach(struct device *parent, struct device *self, void *aux) break; case PCI_VENDOR_VIATECH: switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_VIATECH_VT8251_VLINK: + case PCI_PRODUCT_VIATECH_VT8251_PCIE_0: /* - * For some strange reason, the VIA VT8251 - * chipset can be configured to its PCIe - * bridge show up as a host bridge. We whack - * it into PCI bridge mode here such that we - * can see the devices behind it. + * Bump the host bridge into PCI-PCI bridge + * mode by clearing magic bit on the VLINK + * device. This allows us to read the bus + * number for the PCI bus attached to this + * host bridge. */ - bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0xfc); + tag = pci_make_tag(pa->pa_pc, 0, 17, 7); + bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc); bcreg &= ~0x00000004; /* XXX Magic */ - pci_conf_write(pa->pa_pc, pa->pa_tag, 0xfc, bcreg); + pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); + + bir = pci_conf_read(pa->pa_pc, + pa->pa_tag, PPB_REG_BUSINFO); + pbnum = PPB_BUSINFO_PRIMARY(bir); + doattach = 1; + + /* Switch back to host bridge mode. */ + bcreg |= 0x00000004; /* XXX Magic */ + pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); break; } printf("\n"); @@ -223,7 +238,7 @@ pchbattach(struct device *parent, struct device *self, void *aux) #if NAGP > 0 /* - * Intel IGD have an odd interface and attach at vga, however + * Intel IGD have an odd interface and attach at vga, however, * in that mode they don't have the AGP cap bit, so this * test should be sufficient */ @@ -236,6 +251,19 @@ pchbattach(struct device *parent, struct device *self, void *aux) config_found(self, &aa, agpdev_print); } #endif /* NAGP > 0 */ + + if (doattach == 0) + return; + + bzero(&pba, sizeof(pba)); + pba.pba_busname = "pci"; + pba.pba_iot = pa->pa_iot; + pba.pba_memt = pa->pa_memt; + pba.pba_dmat = pa->pa_dmat; + pba.pba_domain = pa->pa_domain; + pba.pba_bus = pbnum; + pba.pba_pc = pa->pa_pc; + config_found(self, &pba, pchb_print); } int diff --git a/sys/arch/i386/pci/pchb.c b/sys/arch/i386/pci/pchb.c index 7b8a4b1676d..2321e146130 100644 --- a/sys/arch/i386/pci/pchb.c +++ b/sys/arch/i386/pci/pchb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pchb.c,v 1.79 2009/11/23 15:33:37 deraadt Exp $ */ +/* $OpenBSD: pchb.c,v 1.80 2010/02/09 19:36:05 kettenis Exp $ */ /* $NetBSD: pchb.c,v 1.65 2007/08/15 02:26:13 markd Exp $ */ /* @@ -67,6 +67,7 @@ #include <dev/pci/pcidevs.h> #include <dev/pci/agpvar.h> +#include <dev/pci/ppbreg.h> #include <dev/rndvar.h> @@ -169,7 +170,7 @@ pchbattach(struct device *parent, struct device *self, void *aux) struct pchb_softc *sc = (struct pchb_softc *)self; struct pci_attach_args *pa = aux; struct pcibus_attach_args pba; - pcireg_t bcreg; + pcireg_t bcreg, bir; u_char bdnum, pbnum; pcitag_t tag; int i, r; @@ -348,17 +349,27 @@ pchbattach(struct device *parent, struct device *self, void *aux) break; case PCI_VENDOR_VIATECH: switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_VIATECH_VT8251_VLINK: + case PCI_PRODUCT_VIATECH_VT8251_PCIE_0: /* - * For some strange reason, the VIA VT8251 - * chipset can be configured to its PCIe - * bridge show up as a host bridge. We whack - * it into PCI bridge mode here such that we - * can see the devices behind it. + * Bump the host bridge into PCI-PCI bridge + * mode by clearing magic bit on the VLINK + * device. This allows us to read the bus + * number for the PCI bus attached to this + * host bridge. */ - bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0xfc); + tag = pci_make_tag(pa->pa_pc, 0, 17, 7); + bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc); bcreg &= ~0x00000004; /* XXX Magic */ - pci_conf_write(pa->pa_pc, pa->pa_tag, 0xfc, bcreg); + pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); + + bir = pci_conf_read(pa->pa_pc, + pa->pa_tag, PPB_REG_BUSINFO); + pbnum = PPB_BUSINFO_PRIMARY(bir); + doattach = 1; + + /* Switch back to host bridge mode. */ + bcreg |= 0x00000004; /* XXX Magic */ + pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg); break; } printf("\n"); @@ -383,7 +394,7 @@ pchbattach(struct device *parent, struct device *self, void *aux) config_found(self, &aa, agpdev_print); } #endif /* NAGP > 0 */ -#ifdef __i386__ + if (doattach == 0) return; @@ -396,7 +407,6 @@ pchbattach(struct device *parent, struct device *self, void *aux) pba.pba_bus = pbnum; pba.pba_pc = pa->pa_pc; config_found(self, &pba, pchb_print); -#endif /* __i386__ */ } int |