summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2000-09-05 00:53:34 +0000
committerpeter <peter@FreeBSD.org>2000-09-05 00:53:34 +0000
commita5b0eb55b9ec4e13507beed4a3c8c8ec781ce5a4 (patch)
tree45f9892c27e9e257318a0e1ec8937a1948017c7f /sys/amd64
parent9d40c775ca07e3e6b2f6b2ee7d6c624e85e94fed (diff)
downloadFreeBSD-src-a5b0eb55b9ec4e13507beed4a3c8c8ec781ce5a4.zip
FreeBSD-src-a5b0eb55b9ec4e13507beed4a3c8c8ec781ce5a4.tar.gz
Catch a few more bogosities in certain chipsets before they mess us up.
Some have dual host->PCI bridges for the same logical pci bus (!), eg: some of the RCC chipsets. This is a 32/64 bit 33/66MHz and dual pci voltage motherboard so persumably there are electical or signalling differences but they are otherwise the same logical bus. The new PCI probe code however was getting somewhat upset about it and ended up creating two pci bridges to the same logical bus, which caused devices on that logical bus to appear and be probed twice. The ACPI data on this box correctly identifies this stuff, so bring on ACPI! :-)
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/pci/pci_bus.c108
-rw-r--r--sys/amd64/pci/pci_cfgreg.c108
2 files changed, 178 insertions, 38 deletions
diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c
index 41e2226..2dd6694 100644
--- a/sys/amd64/pci/pci_bus.c
+++ b/sys/amd64/pci/pci_bus.c
@@ -595,6 +595,8 @@ nexus_pcib_identify(driver_t *driver, device_t parent)
u_int32_t id;
u_int8_t class, subclass, busnum;
const char *s;
+ device_t *devs;
+ int ndevs, i;
id = nexus_pcib_read_config(0, bus, slot, func,
PCIR_DEVVENDOR, 4);
@@ -608,26 +610,48 @@ nexus_pcib_identify(driver_t *driver, device_t parent)
s = nexus_pcib_is_host_bridge(bus, slot, func,
id, class, subclass,
&busnum);
- if (s) {
- /*
- * Add at priority 100 to make sure we
- * go after any motherboard resources
- */
- child = BUS_ADD_CHILD(parent, 100,
- "pcib", busnum);
- device_set_desc(child, s);
-
- ivar = malloc(sizeof ivar[0], M_DEVBUF,
- M_NOWAIT);
- if (ivar == NULL)
- panic("out of memory");
- device_set_ivars(child, ivar);
- ivar[0] = busnum;
-
- found = 1;
- if (id == 0x12258086)
- found824xx = 1;
+ if (s == NULL)
+ continue;
+
+ /*
+ * Check to see if the physical bus has already
+ * been seen. Eg: hybrid 32 and 64 bit host
+ * bridges to the same logical bus.
+ */
+ if (device_get_children(parent, &devs, &ndevs) == 0) {
+ for (i = 0; s != NULL && i < ndevs; i++) {
+ if (strcmp(device_get_name(devs[i]),
+ "pcib") != 0)
+ continue;
+ ivar = device_get_ivars(devs[i]);
+ if (ivar == NULL)
+ continue;
+ if (busnum == *ivar)
+ s = NULL;
+ }
+ free(devs, M_TEMP);
}
+
+ if (s == NULL)
+ continue;
+ /*
+ * Add at priority 100 to make sure we
+ * go after any motherboard resources
+ */
+ child = BUS_ADD_CHILD(parent, 100,
+ "pcib", busnum);
+ device_set_desc(child, s);
+
+ ivar = malloc(sizeof ivar[0], M_DEVBUF,
+ M_NOWAIT);
+ if (ivar == NULL)
+ panic("out of memory");
+ device_set_ivars(child, ivar);
+ ivar[0] = busnum;
+
+ found = 1;
+ if (id == 0x12258086)
+ found824xx = 1;
}
}
if (found824xx && bus == 0) {
@@ -734,6 +758,52 @@ static driver_t nexus_pcib_driver = {
DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);
+
+/*
+ * Provide a device to "eat" the host->pci bridges that we dug up above
+ * and stop them showing up twice on the probes. This also stops them
+ * showing up as 'none' in pciconf -l.
+ */
+static int
+pci_hostb_probe(device_t dev)
+{
+
+ if (pci_get_class(dev) == PCIC_BRIDGE &&
+ pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
+ device_set_desc(dev, "Host to PCI bridge");
+ device_quiet(dev);
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+pci_hostb_attach(device_t dev)
+{
+
+ return 0;
+}
+
+static device_method_t pci_hostb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pci_hostb_probe),
+ DEVMETHOD(device_attach, pci_hostb_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ { 0, 0 }
+};
+static driver_t pci_hostb_driver = {
+ "hostb",
+ pci_hostb_methods,
+ 1,
+};
+static devclass_t pci_hostb_devclass;
+
+DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
+
+
/*
* Install placeholder to claim the resources owned by the
* PCI bus interface. This could be used to extract the
diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c
index 41e2226..2dd6694 100644
--- a/sys/amd64/pci/pci_cfgreg.c
+++ b/sys/amd64/pci/pci_cfgreg.c
@@ -595,6 +595,8 @@ nexus_pcib_identify(driver_t *driver, device_t parent)
u_int32_t id;
u_int8_t class, subclass, busnum;
const char *s;
+ device_t *devs;
+ int ndevs, i;
id = nexus_pcib_read_config(0, bus, slot, func,
PCIR_DEVVENDOR, 4);
@@ -608,26 +610,48 @@ nexus_pcib_identify(driver_t *driver, device_t parent)
s = nexus_pcib_is_host_bridge(bus, slot, func,
id, class, subclass,
&busnum);
- if (s) {
- /*
- * Add at priority 100 to make sure we
- * go after any motherboard resources
- */
- child = BUS_ADD_CHILD(parent, 100,
- "pcib", busnum);
- device_set_desc(child, s);
-
- ivar = malloc(sizeof ivar[0], M_DEVBUF,
- M_NOWAIT);
- if (ivar == NULL)
- panic("out of memory");
- device_set_ivars(child, ivar);
- ivar[0] = busnum;
-
- found = 1;
- if (id == 0x12258086)
- found824xx = 1;
+ if (s == NULL)
+ continue;
+
+ /*
+ * Check to see if the physical bus has already
+ * been seen. Eg: hybrid 32 and 64 bit host
+ * bridges to the same logical bus.
+ */
+ if (device_get_children(parent, &devs, &ndevs) == 0) {
+ for (i = 0; s != NULL && i < ndevs; i++) {
+ if (strcmp(device_get_name(devs[i]),
+ "pcib") != 0)
+ continue;
+ ivar = device_get_ivars(devs[i]);
+ if (ivar == NULL)
+ continue;
+ if (busnum == *ivar)
+ s = NULL;
+ }
+ free(devs, M_TEMP);
}
+
+ if (s == NULL)
+ continue;
+ /*
+ * Add at priority 100 to make sure we
+ * go after any motherboard resources
+ */
+ child = BUS_ADD_CHILD(parent, 100,
+ "pcib", busnum);
+ device_set_desc(child, s);
+
+ ivar = malloc(sizeof ivar[0], M_DEVBUF,
+ M_NOWAIT);
+ if (ivar == NULL)
+ panic("out of memory");
+ device_set_ivars(child, ivar);
+ ivar[0] = busnum;
+
+ found = 1;
+ if (id == 0x12258086)
+ found824xx = 1;
}
}
if (found824xx && bus == 0) {
@@ -734,6 +758,52 @@ static driver_t nexus_pcib_driver = {
DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);
+
+/*
+ * Provide a device to "eat" the host->pci bridges that we dug up above
+ * and stop them showing up twice on the probes. This also stops them
+ * showing up as 'none' in pciconf -l.
+ */
+static int
+pci_hostb_probe(device_t dev)
+{
+
+ if (pci_get_class(dev) == PCIC_BRIDGE &&
+ pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
+ device_set_desc(dev, "Host to PCI bridge");
+ device_quiet(dev);
+ return 0;
+ }
+ return ENXIO;
+}
+
+static int
+pci_hostb_attach(device_t dev)
+{
+
+ return 0;
+}
+
+static device_method_t pci_hostb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pci_hostb_probe),
+ DEVMETHOD(device_attach, pci_hostb_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ { 0, 0 }
+};
+static driver_t pci_hostb_driver = {
+ "hostb",
+ pci_hostb_methods,
+ 1,
+};
+static devclass_t pci_hostb_devclass;
+
+DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
+
+
/*
* Install placeholder to claim the resources owned by the
* PCI bus interface. This could be used to extract the
OpenPOWER on IntegriCloud