summaryrefslogtreecommitdiffstats
path: root/sys/amd64/pci
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>1999-07-16 01:00:30 +0000
committermsmith <msmith@FreeBSD.org>1999-07-16 01:00:30 +0000
commit7e710934a0b5e0debab4f9edb0e2eed6318a7eaa (patch)
tree9057d3ff97065f456da5a321a703bfa0a60f0da8 /sys/amd64/pci
parentfeb93f418cbcbeb6cd66407e2a4465384f67e16a (diff)
downloadFreeBSD-src-7e710934a0b5e0debab4f9edb0e2eed6318a7eaa.zip
FreeBSD-src-7e710934a0b5e0debab4f9edb0e2eed6318a7eaa.tar.gz
Add support for multiple PCI busses directly connected to the nexus.
This is only partially complete, but allows 450NX-based systems with more than one PCI bus to be used again. Submitted by: dfr
Diffstat (limited to 'sys/amd64/pci')
-rw-r--r--sys/amd64/pci/pci_bus.c184
-rw-r--r--sys/amd64/pci/pci_cfgreg.c184
2 files changed, 360 insertions, 8 deletions
diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c
index 14ed525..b3253ac 100644
--- a/sys/amd64/pci/pci_bus.c
+++ b/sys/amd64/pci/pci_bus.c
@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: pcibus.c,v 1.41 1997/12/20 09:04:25 se Exp $
+ * $Id: pcibus.c,v 1.42 1999/05/18 20:48:43 peter Exp $
*
*/
@@ -33,6 +33,7 @@
#include <sys/kernel.h>
#include <pci/pcivar.h>
+#include <pci/pcireg.h>
#include <i386/isa/pcibus.h>
#ifdef PCI_COMPAT
@@ -268,13 +269,187 @@ pci_cfgopen(void)
static devclass_t pcib_devclass;
+static const char *
+nexus_pcib_is_host_bridge(pcicfgregs *cfg,
+ u_int32_t id, u_int8_t class, u_int8_t subclass,
+ u_int8_t *busnum)
+{
+ const char *s = "Host to PCI bridge";
+ static u_int8_t pxb[4]; /* hack for 450nx */
+
+ if (class != PCIC_BRIDGE || subclass != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ *busnum = 0;
+
+ switch (id) {
+ case 0x12258086:
+ s = "Intel 824?? host to PCI bridge";
+ /* XXX This is a guess */
+ *busnum = pci_cfgread(cfg, 0x41, 1);
+ break;
+ case 0x71808086:
+ s = "Intel 82443LX (440 LX) host to PCI bridge";
+ break;
+ case 0x71908086:
+ s = "Intel 82443BX (440 BX) host to PCI bridge";
+ break;
+ case 0x71928086:
+ s = "Intel 82443BX host to PCI bridge (AGP disabled)";
+ break;
+ case 0x71a08086:
+ s = "Intel 82443GX host to PCI bridge";
+ break;
+ case 0x71a18086:
+ s = "Intel 82443GX host to AGP bridge";
+ break;
+ case 0x71a28086:
+ s = "Intel 82443GX host to PCI bridge (AGP disabled)";
+ break;
+ case 0x84c48086:
+ s = "Intel 82454KX/GX (Orion) host to PCI bridge";
+ *busnum = pci_cfgread(cfg, 0x4a, 1);
+ break;
+ case 0x84ca8086:
+ /*
+ * For the 450nx chipset, there is a whole bundle of
+ * things pretending to be host bridges. The MIOC will
+ * be seen first and isn't really a pci bridge (the
+ * actual busses are attached to the PXB's). We need to
+ * read the registers of the MIOC to figure out the
+ * bus numbers for the PXB channels.
+ *
+ * Since the MIOC doesn't have a pci bus attached, we
+ * pretend it wasn't there.
+ */
+ pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */
+ pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */
+ pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */
+ pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */
+ return NULL;
+ case 0x84cb8086:
+ switch (cfg->slot) {
+ case 0x12:
+ s = "Intel 82454NX PXB#0, Bus#A";
+ *busnum = pxb[0];
+ break;
+ case 0x13:
+ s = "Intel 82454NX PXB#0, Bus#B";
+ *busnum = pxb[1];
+ break;
+ case 0x14:
+ s = "Intel 82454NX PXB#1, Bus#A";
+ *busnum = pxb[2];
+ break;
+ case 0x15:
+ s = "Intel 82454NX PXB#1, Bus#B";
+ *busnum = pxb[3];
+ break;
+ }
+ break;
+
+ /* SiS -- vendor 0x1039 */
+ case 0x04961039:
+ s = "SiS 85c496";
+ break;
+ case 0x04061039:
+ s = "SiS 85c501";
+ break;
+ case 0x06011039:
+ s = "SiS 85c601";
+ break;
+ case 0x55911039:
+ s = "SiS 5591 host to PCI bridge";
+ break;
+ case 0x00011039:
+ s = "SiS 5591 host to AGP bridge";
+ break;
+
+ /* VLSI -- vendor 0x1004 */
+ case 0x00051004:
+ s = "VLSI 82C592 Host to PCI bridge";
+ break;
+
+ /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */
+ /* totally. Please let me know if anything wrong. -F */
+ /* XXX need info on the MVP3 -- any takers? */
+ case 0x05981106:
+ s = "VIA 82C598MVP (Apollo MVP3) host bridge";
+ break;
+
+ /* AcerLabs -- vendor 0x10b9 */
+ /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
+ /* id is '10b9" but the register always shows "10b9". -Foxfair */
+ case 0x154110b9:
+ s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
+ break;
+
+ /* OPTi -- vendor 0x1045 */
+ case 0xc8221045:
+ s = "OPTi 82C822 host to PCI Bridge";
+ break;
+
+ /* Ross (?) -- vendor 0x1166 */
+ case 0x00051166:
+ s = "Ross (?) host to PCI bridge";
+ /* just guessing the secondary bus register number ... */
+ *busnum = pci_cfgread(cfg, 0x45, 1);
+ break;
+ }
+
+ return s;
+}
+
+/*
+ * Scan the first pci bus for host-pci bridges and add pcib instances
+ * to the nexus for each bridge.
+ */
+static void
+nexus_pcib_identify(driver_t *driver, device_t parent)
+{
+ pcicfgregs probe;
+
+ probe.hose = 0;
+ probe.bus = 0;
+
+ pci_cfgopen();
+ for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
+ int pcifunchigh = 0;
+ for (probe.func = 0;
+ probe.func <= pcifunchigh;
+ probe.func++) {
+ /*
+ * Read the IDs and class from the device.
+ */
+ u_int32_t id;
+ u_int8_t class, subclass, busnum;
+ device_t child;
+ const char *s;
+
+ id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4);
+ if (id == -1)
+ continue;
+ class = pci_cfgread(&probe, PCIR_CLASS, 1);
+ subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1);
+
+ s = nexus_pcib_is_host_bridge(&probe, id,
+ class, subclass,
+ &busnum);
+ if (s) {
+ child = BUS_ADD_CHILD(parent, 0,
+ "pcib", busnum);
+ device_set_desc(child, s);
+ }
+ }
+ }
+
+}
+
static int
nexus_pcib_probe(device_t dev)
{
if (pci_cfgopen() != 0) {
- device_set_desc(dev, "PCI host bus adapter");
-
- device_add_child(dev, "pci", 0, 0);
+ device_add_child(dev, "pci", device_get_unit(dev), 0);
return 0;
}
return ENXIO;
@@ -282,6 +457,7 @@ nexus_pcib_probe(device_t dev)
static device_method_t nexus_pcib_methods[] = {
/* Device interface */
+ DEVMETHOD(device_identify, nexus_pcib_identify),
DEVMETHOD(device_probe, nexus_pcib_probe),
DEVMETHOD(device_attach, bus_generic_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c
index 14ed525..b3253ac 100644
--- a/sys/amd64/pci/pci_cfgreg.c
+++ b/sys/amd64/pci/pci_cfgreg.c
@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: pcibus.c,v 1.41 1997/12/20 09:04:25 se Exp $
+ * $Id: pcibus.c,v 1.42 1999/05/18 20:48:43 peter Exp $
*
*/
@@ -33,6 +33,7 @@
#include <sys/kernel.h>
#include <pci/pcivar.h>
+#include <pci/pcireg.h>
#include <i386/isa/pcibus.h>
#ifdef PCI_COMPAT
@@ -268,13 +269,187 @@ pci_cfgopen(void)
static devclass_t pcib_devclass;
+static const char *
+nexus_pcib_is_host_bridge(pcicfgregs *cfg,
+ u_int32_t id, u_int8_t class, u_int8_t subclass,
+ u_int8_t *busnum)
+{
+ const char *s = "Host to PCI bridge";
+ static u_int8_t pxb[4]; /* hack for 450nx */
+
+ if (class != PCIC_BRIDGE || subclass != PCIS_BRIDGE_HOST)
+ return NULL;
+
+ *busnum = 0;
+
+ switch (id) {
+ case 0x12258086:
+ s = "Intel 824?? host to PCI bridge";
+ /* XXX This is a guess */
+ *busnum = pci_cfgread(cfg, 0x41, 1);
+ break;
+ case 0x71808086:
+ s = "Intel 82443LX (440 LX) host to PCI bridge";
+ break;
+ case 0x71908086:
+ s = "Intel 82443BX (440 BX) host to PCI bridge";
+ break;
+ case 0x71928086:
+ s = "Intel 82443BX host to PCI bridge (AGP disabled)";
+ break;
+ case 0x71a08086:
+ s = "Intel 82443GX host to PCI bridge";
+ break;
+ case 0x71a18086:
+ s = "Intel 82443GX host to AGP bridge";
+ break;
+ case 0x71a28086:
+ s = "Intel 82443GX host to PCI bridge (AGP disabled)";
+ break;
+ case 0x84c48086:
+ s = "Intel 82454KX/GX (Orion) host to PCI bridge";
+ *busnum = pci_cfgread(cfg, 0x4a, 1);
+ break;
+ case 0x84ca8086:
+ /*
+ * For the 450nx chipset, there is a whole bundle of
+ * things pretending to be host bridges. The MIOC will
+ * be seen first and isn't really a pci bridge (the
+ * actual busses are attached to the PXB's). We need to
+ * read the registers of the MIOC to figure out the
+ * bus numbers for the PXB channels.
+ *
+ * Since the MIOC doesn't have a pci bus attached, we
+ * pretend it wasn't there.
+ */
+ pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */
+ pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */
+ pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */
+ pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */
+ return NULL;
+ case 0x84cb8086:
+ switch (cfg->slot) {
+ case 0x12:
+ s = "Intel 82454NX PXB#0, Bus#A";
+ *busnum = pxb[0];
+ break;
+ case 0x13:
+ s = "Intel 82454NX PXB#0, Bus#B";
+ *busnum = pxb[1];
+ break;
+ case 0x14:
+ s = "Intel 82454NX PXB#1, Bus#A";
+ *busnum = pxb[2];
+ break;
+ case 0x15:
+ s = "Intel 82454NX PXB#1, Bus#B";
+ *busnum = pxb[3];
+ break;
+ }
+ break;
+
+ /* SiS -- vendor 0x1039 */
+ case 0x04961039:
+ s = "SiS 85c496";
+ break;
+ case 0x04061039:
+ s = "SiS 85c501";
+ break;
+ case 0x06011039:
+ s = "SiS 85c601";
+ break;
+ case 0x55911039:
+ s = "SiS 5591 host to PCI bridge";
+ break;
+ case 0x00011039:
+ s = "SiS 5591 host to AGP bridge";
+ break;
+
+ /* VLSI -- vendor 0x1004 */
+ case 0x00051004:
+ s = "VLSI 82C592 Host to PCI bridge";
+ break;
+
+ /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */
+ /* totally. Please let me know if anything wrong. -F */
+ /* XXX need info on the MVP3 -- any takers? */
+ case 0x05981106:
+ s = "VIA 82C598MVP (Apollo MVP3) host bridge";
+ break;
+
+ /* AcerLabs -- vendor 0x10b9 */
+ /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
+ /* id is '10b9" but the register always shows "10b9". -Foxfair */
+ case 0x154110b9:
+ s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
+ break;
+
+ /* OPTi -- vendor 0x1045 */
+ case 0xc8221045:
+ s = "OPTi 82C822 host to PCI Bridge";
+ break;
+
+ /* Ross (?) -- vendor 0x1166 */
+ case 0x00051166:
+ s = "Ross (?) host to PCI bridge";
+ /* just guessing the secondary bus register number ... */
+ *busnum = pci_cfgread(cfg, 0x45, 1);
+ break;
+ }
+
+ return s;
+}
+
+/*
+ * Scan the first pci bus for host-pci bridges and add pcib instances
+ * to the nexus for each bridge.
+ */
+static void
+nexus_pcib_identify(driver_t *driver, device_t parent)
+{
+ pcicfgregs probe;
+
+ probe.hose = 0;
+ probe.bus = 0;
+
+ pci_cfgopen();
+ for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
+ int pcifunchigh = 0;
+ for (probe.func = 0;
+ probe.func <= pcifunchigh;
+ probe.func++) {
+ /*
+ * Read the IDs and class from the device.
+ */
+ u_int32_t id;
+ u_int8_t class, subclass, busnum;
+ device_t child;
+ const char *s;
+
+ id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4);
+ if (id == -1)
+ continue;
+ class = pci_cfgread(&probe, PCIR_CLASS, 1);
+ subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1);
+
+ s = nexus_pcib_is_host_bridge(&probe, id,
+ class, subclass,
+ &busnum);
+ if (s) {
+ child = BUS_ADD_CHILD(parent, 0,
+ "pcib", busnum);
+ device_set_desc(child, s);
+ }
+ }
+ }
+
+}
+
static int
nexus_pcib_probe(device_t dev)
{
if (pci_cfgopen() != 0) {
- device_set_desc(dev, "PCI host bus adapter");
-
- device_add_child(dev, "pci", 0, 0);
+ device_add_child(dev, "pci", device_get_unit(dev), 0);
return 0;
}
return ENXIO;
@@ -282,6 +457,7 @@ nexus_pcib_probe(device_t dev)
static device_method_t nexus_pcib_methods[] = {
/* Device interface */
+ DEVMETHOD(device_identify, nexus_pcib_identify),
DEVMETHOD(device_probe, nexus_pcib_probe),
DEVMETHOD(device_attach, bus_generic_attach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
OpenPOWER on IntegriCloud