From 298e3d15d7576b03eb2915970e400c1c6e64c75f Mon Sep 17 00:00:00 2001 From: Nate Lawson Date: Thu, 5 Aug 2004 06:54:16 +0000 Subject: [PATCH] Work around non-compliant BIOS PCI link devices. Some systems have the following behavior: * Link devices return invalid status (_STA) values. The results are very unreliable -- sometimes never present. Just ignore the status and pick the best configuration from _PRS. * Link devices return invalid current settings (_CRS). Even after setting the link value, many systems still return a different setting for _CRS. When setting an IRQ, don't bother to check _CRS to see if we succeeded. Note that we still check _CRS before routing and this should be addressed as well. Since this is a sensitive area, leave the old behavior accessible via uncommenting the define for ACPI_OLD_PCI_LINK at the top of the file. Once this has been thoroughly tested, this option and the code it covers will be removed. Thanks to Len Brown at Intel for informing us of these issues as he worked around them in Linux. --- sys/dev/acpica/acpi_pci_link.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sys/dev/acpica/acpi_pci_link.c b/sys/dev/acpica/acpi_pci_link.c index 400aa14de3a4..669aba41f279 100644 --- a/sys/dev/acpica/acpi_pci_link.c +++ b/sys/dev/acpica/acpi_pci_link.c @@ -24,6 +24,9 @@ * SUCH DAMAGE. */ +/* XXX Uncomment this if you have new PCI IRQ problems starting 2004/8/5. */ +/* #define ACPI_OLD_PCI_LINK 1 */ + #include __FBSDID("$FreeBSD$"); @@ -73,10 +76,12 @@ static struct acpi_prt_entries acpi_prt_entries; static int irq_penalty[MAX_ACPI_INTERRUPTS]; +#ifdef ACPI_OLD_PCI_LINK #define ACPI_STA_PRESENT 0x00000001 #define ACPI_STA_ENABLE 0x00000002 #define ACPI_STA_SHOWINUI 0x00000004 #define ACPI_STA_FUNCTIONAL 0x00000008 +#endif /* ACPI_OLD_PCI_LINK */ /* * PCI link object management @@ -171,6 +176,7 @@ acpi_pci_link_entry_dump(struct acpi_prt_entry *entry) (int)entry->prt.Pin); } +#ifdef ACPI_OLD_PCI_LINK static ACPI_STATUS acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta) { @@ -215,6 +221,7 @@ acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta) AcpiOsFree(buf.Pointer); return_ACPI_STATUS (AE_OK); } +#endif /* ACPI_OLD_PCI_LINK */ static ACPI_STATUS acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources, @@ -439,7 +446,9 @@ acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno) { ACPI_HANDLE handle; ACPI_STATUS error; +#ifdef ACPI_OLD_PCI_LINK UINT32 sta; +#endif struct acpi_prt_entry *entry; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -457,6 +466,11 @@ acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno) return_ACPI_STATUS (error); } + /* + * PCI link status (_STA) is unreliable. Many systems return + * erroneous values so we ignore it. + */ +#ifdef ACPI_OLD_PCI_LINK error = acpi_pci_link_get_object_status(handle, &sta); if (ACPI_FAILURE(error)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -471,6 +485,7 @@ acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno) acpi_name(handle))); return_ACPI_STATUS (AE_ERROR); } +#endif /* ACPI_OLD_PCI_LINK */ TAILQ_FOREACH(entry, &acpi_prt_entries, links) { if (entry->busno == busno && @@ -539,7 +554,9 @@ acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq) ACPI_STATUS error; ACPI_RESOURCE resbuf; ACPI_BUFFER crsbuf; +#ifdef ACPI_OLD_PCI_LINK UINT32 sta; +#endif ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -614,7 +631,13 @@ acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq) AcpiOsFree(crsbuf.Pointer); link->current_irq = 0; + error = AE_OK; + /* + * PCI link status (_STA) is unreliable. Many systems return + * erroneous values so we ignore it. + */ +#ifdef ACPI_OLD_PCI_LINK error = acpi_pci_link_get_object_status(link->handle, &sta); if (ACPI_FAILURE(error)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, @@ -629,7 +652,14 @@ acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq) acpi_name(link->handle))); return_ACPI_STATUS (AE_ERROR); } +#endif /* ACPI_OLD_PCI_LINK */ + /* + * Many systems always return invalid values for current settings + * (_CRS). Since we can't trust the value returned, we have to + * assume we were successful. + */ +#ifdef ACPI_OLD_PCI_LINK error = acpi_pci_link_get_current_irq(link, &link->current_irq); if (ACPI_FAILURE(error)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, @@ -647,6 +677,7 @@ acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq) link->current_irq = 0; error = AE_ERROR; } +#endif /* ACPI_OLD_PCI_LINK */ return_ACPI_STATUS (error); }