From 5ec303afa34da1dad80ec11cf4e02ff19e5e2ccc Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Tue, 9 Feb 2010 19:36:06 +0000 Subject: 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. --- sys/arch/amd64/pci/pchb.c | 50 ++++++++++++++++++++++++++++++++++++----------- sys/arch/i386/pci/pchb.c | 34 ++++++++++++++++++++------------ 2 files changed, 61 insertions(+), 23 deletions(-) (limited to 'sys/arch') 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 #include +#include #include @@ -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 #include +#include #include @@ -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 -- cgit v1.2.3