diff options
author | John Baldwin <jhb@FreeBSD.org> | 2012-03-29 19:03:22 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2012-03-29 19:03:22 +0000 |
commit | 0d95597ca9bf2cbe6081f13b60320fc99c7eeb9c (patch) | |
tree | 16d6f5200857c5f9b1d5733c5b7289fa5ebbdc2d /sys/dev/acpica | |
parent | 46092aeec08ee89e493904d0972667ebd6326a17 (diff) | |
download | src-0d95597ca9bf2cbe6081f13b60320fc99c7eeb9c.tar.gz src-0d95597ca9bf2cbe6081f13b60320fc99c7eeb9c.zip |
Use a more proper fix for enabling HT MSI mapping windows on Host-PCI
bridges. Rather than blindly enabling the windows on all of them, only
enable the window when an MSI interrupt is enabled for a device behind
the bridge, similar to what already happens for HT PCI-PCI bridges.
To implement this, each x86 Host-PCI bridge driver has to be able to
locate it's actual backing device on bus 0. For ACPI, use the _ADR
method to find the slot and function of the device. For the non-ACPI
case, the legacy(4) driver already scans bus 0 looking for Host-PCI
bridge devices. Now it saves the slot and function of each bridge that
it finds as ivars that the Host-PCI bridge driver can then use in its
pcib_map_msi() method.
This fixes machines where non-MSI interrupts were broken by the previous
round of HT MSI changes.
Tested by: bapt
MFC after: 1 week
Notes
Notes:
svn path=/head/; revision=233676
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r-- | sys/dev/acpica/acpi_pcib_acpi.c | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c index 9770f513bb15..8e2cfea7c5c2 100644 --- a/sys/dev/acpica/acpi_pcib_acpi.c +++ b/sys/dev/acpica/acpi_pcib_acpi.c @@ -59,8 +59,9 @@ struct acpi_hpcib_softc { ACPI_HANDLE ap_handle; int ap_flags; - int ap_segment; /* analagous to Alpha 'hose' */ + int ap_segment; /* PCI domain */ int ap_bus; /* bios-assigned bus number */ + int ap_addr; /* device/func of PCI-Host bridge */ ACPI_BUFFER ap_prt; /* interrupt routing table */ #ifdef NEW_PCIB @@ -276,7 +277,7 @@ acpi_pcib_acpi_attach(device_t dev) struct acpi_hpcib_softc *sc; ACPI_STATUS status; static int bus0_seen = 0; - u_int addr, slot, func, busok; + u_int slot, func, busok; uint8_t busno; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -286,7 +287,7 @@ acpi_pcib_acpi_attach(device_t dev) sc->ap_handle = acpi_get_handle(dev); /* - * Get our segment number by evaluating _SEG + * 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); @@ -300,6 +301,18 @@ acpi_pcib_acpi_attach(device_t dev) sc->ap_segment = 0; } + /* + * Get the address (device and function) of the associated + * PCI-Host bridge device from _ADR. Assume we don't have one if + * it doesn't exist. + */ + status = acpi_GetInteger(sc->ap_handle, "_ADR", &sc->ap_addr); + if (ACPI_FAILURE(status)) { + device_printf(dev, "could not evaluate _ADR - %s\n", + AcpiFormatException(status)); + sc->ap_addr = -1; + } + #ifdef NEW_PCIB /* * Determine which address ranges this bridge decodes and setup @@ -354,18 +367,10 @@ acpi_pcib_acpi_attach(device_t dev) busok = 1; if (sc->ap_segment == 0 && sc->ap_bus == 0 && bus0_seen) { busok = 0; - status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) { - device_printf(dev, "could not evaluate _ADR - %s\n", - AcpiFormatException(status)); - return_VALUE (ENXIO); - } else - device_printf(dev, "couldn't find _ADR\n"); - } else { + if (sc->ap_addr != -1) { /* XXX: We assume bus 0. */ - slot = ACPI_ADR_PCI_SLOT(addr); - func = ACPI_ADR_PCI_FUNC(addr); + slot = ACPI_ADR_PCI_SLOT(sc->ap_addr); + func = ACPI_ADR_PCI_FUNC(sc->ap_addr); if (bootverbose) device_printf(dev, "reading config registers from 0:%d:%d\n", slot, func); @@ -488,10 +493,24 @@ static int acpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { - device_t bus; + struct acpi_hpcib_softc *sc; + device_t bus, hostb; + int error; bus = device_get_parent(pcib); - return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); + error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); + if (error) + return (error); + + sc = device_get_softc(dev); + if (sc->ap_addr == -1) + return (0); + /* XXX: Assumes all bridges are on bus 0. */ + hostb = pci_find_dbsf(sc->ap_segment, 0, ACPI_ADR_PCI_SLOT(sc->ap_addr), + ACPI_ADR_PCI_FUNC(sc->ap_addr)); + if (hostb != NULL) + pci_ht_map_msi(hostb, *addr); + return (0); } struct resource * |