Rework the _BBN handling for Host-PCI bridges. Previously we only trusted
a _BBN value of 0 if it was for the first bridge encountered since some older systems returned _BBN of 0 for all bridges. However, some newer systems enumerate bridges with non-zero _BBN before bus 0 which is perfectly valid. Handle both cases by trusting the first bridge that has a _BBN of 0 and falling back to reading from non-standard config registers only for subsequent bridges with a _BBN of 0. We also only perform this check for segment (domain) 0. We assume that _BBN is always correct for segments other than 0. Tested by: Josef Moellers josef.moellers at fujitsu MFC after: 1 week
This commit is contained in:
parent
3e7865bcfc
commit
0668724b99
@ -148,6 +148,7 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||||||
{
|
{
|
||||||
struct acpi_hpcib_softc *sc;
|
struct acpi_hpcib_softc *sc;
|
||||||
ACPI_STATUS status;
|
ACPI_STATUS status;
|
||||||
|
static int bus0_seen = 0;
|
||||||
u_int addr, slot, func, busok;
|
u_int addr, slot, func, busok;
|
||||||
uint8_t busno;
|
uint8_t busno;
|
||||||
|
|
||||||
@ -157,6 +158,21 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||||||
sc->ap_dev = dev;
|
sc->ap_dev = dev;
|
||||||
sc->ap_handle = acpi_get_handle(dev);
|
sc->ap_handle = acpi_get_handle(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get our segment number by evaluating _SEG
|
||||||
|
* It's OK for this to not exist.
|
||||||
|
*/
|
||||||
|
status = acpi_GetInteger(sc->ap_handle, "_SEG", &sc->ap_segment);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
if (status != AE_NOT_FOUND) {
|
||||||
|
device_printf(dev, "could not evaluate _SEG - %s\n",
|
||||||
|
AcpiFormatException(status));
|
||||||
|
return_VALUE (ENXIO);
|
||||||
|
}
|
||||||
|
/* If it's not found, assume 0. */
|
||||||
|
sc->ap_segment = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get our base bus number by evaluating _BBN.
|
* Get our base bus number by evaluating _BBN.
|
||||||
* If this doesn't work, we assume we're bus number 0.
|
* If this doesn't work, we assume we're bus number 0.
|
||||||
@ -171,8 +187,10 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||||||
* XXX invoke _REG on this for the PCI config space address space?
|
* XXX invoke _REG on this for the PCI config space address space?
|
||||||
* XXX It seems many BIOS's with multiple Host-PCI bridges do not set
|
* XXX It seems many BIOS's with multiple Host-PCI bridges do not set
|
||||||
* _BBN correctly. They set _BBN to zero for all bridges. Thus,
|
* _BBN correctly. They set _BBN to zero for all bridges. Thus,
|
||||||
* if _BBN is zero and pcib0 already exists, we try to read our
|
* if _BBN is zero and PCI bus 0 already exists, we try to read our
|
||||||
* bus number from the configuration registers at address _ADR.
|
* bus number from the configuration registers at address _ADR.
|
||||||
|
* We only do this for domain/segment 0 in the hopes that this is
|
||||||
|
* only needed for old single-domain machines.
|
||||||
*/
|
*/
|
||||||
status = acpi_GetInteger(sc->ap_handle, "_BBN", &sc->ap_bus);
|
status = acpi_GetInteger(sc->ap_handle, "_BBN", &sc->ap_bus);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
@ -187,11 +205,11 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the bus is zero and pcib0 already exists, read the bus number
|
* If this is segment 0, the bus is zero, and PCI bus 0 already
|
||||||
* via PCI config space.
|
* exists, read the bus number via PCI config space.
|
||||||
*/
|
*/
|
||||||
busok = 1;
|
busok = 1;
|
||||||
if (sc->ap_bus == 0 && devclass_get_device(pcib_devclass, 0) != dev) {
|
if (sc->ap_segment == 0 && sc->ap_bus == 0 && bus0_seen) {
|
||||||
busok = 0;
|
busok = 0;
|
||||||
status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr);
|
status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
@ -228,20 +246,9 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||||||
device_printf(dev, "trying bus number %d\n", sc->ap_bus);
|
device_printf(dev, "trying bus number %d\n", sc->ap_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* If this is bus 0 on segment 0, note that it has been seen already. */
|
||||||
* Get our segment number by evaluating _SEG
|
if (sc->ap_segment == 0 && sc->ap_bus == 0)
|
||||||
* It's OK for this to not exist.
|
bus0_seen = 1;
|
||||||
*/
|
|
||||||
status = acpi_GetInteger(sc->ap_handle, "_SEG", &sc->ap_segment);
|
|
||||||
if (ACPI_FAILURE(status)) {
|
|
||||||
if (status != AE_NOT_FOUND) {
|
|
||||||
device_printf(dev, "could not evaluate _SEG - %s\n",
|
|
||||||
AcpiFormatException(status));
|
|
||||||
return_VALUE (ENXIO);
|
|
||||||
}
|
|
||||||
/* If it's not found, assume 0. */
|
|
||||||
sc->ap_segment = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus));
|
return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user