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.
This commit is contained in:
njl 2004-08-05 06:54:16 +00:00
parent 708c9dab9f
commit 562235ab97

View File

@ -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 <sys/cdefs.h>
__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);
}