aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2012-03-29 19:03:22 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2012-03-29 19:03:22 +0000
commit0d95597ca9bf2cbe6081f13b60320fc99c7eeb9c (patch)
tree16d6f5200857c5f9b1d5733c5b7289fa5ebbdc2d /sys/dev/acpica
parent46092aeec08ee89e493904d0972667ebd6326a17 (diff)
downloadsrc-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.c51
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 *