Commit fade1033 authored by Len Brown's avatar Len Brown Committed by Len Brown

[ACPI] PCI Interrupt Link fixes

Handle BIOS that reference disabled PCI Interrupt Link Devices
http://bugme.osdl.org/show_bug.cgi?id=1581

Clean up VIA _CRS = 0 BIOS workaround

Handle BIOS returning _CRS outside _PRS
http://bugme.osdl.org/show_bug.cgi?id=2567

delete now unused _SRS retry code
disable redundant console messages
parent 762a222a
...@@ -2444,7 +2444,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a ...@@ -2444,7 +2444,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
entry.vector = assign_irq_vector(irq); entry.vector = assign_irq_vector(irq);
printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " Dprintk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
"IRQ %d Mode:%i Active:%i)\n", ioapic, "IRQ %d Mode:%i Active:%i)\n", ioapic,
mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
......
...@@ -1102,11 +1102,12 @@ void __init mp_parse_prt (void) ...@@ -1102,11 +1102,12 @@ void __init mp_parse_prt (void)
if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) { if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
acpi_gsi_to_irq(gsi, &entry->irq); acpi_gsi_to_irq(gsi, &entry->irq);
} }
printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d %s %s\n",
entry->id.segment, entry->id.bus, entry->id.segment, entry->id.bus,
entry->id.device, ('A' + entry->pin), entry->id.device, ('A' + entry->pin),
mp_ioapic_routing[ioapic].apic_id, ioapic_pin, mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
entry->irq); entry->irq, edge_level ? "level" : "edge",
active_high_low ? "low" : "high");
} }
print_IO_APIC(); print_IO_APIC();
......
...@@ -21,7 +21,6 @@ static int __init pci_acpi_init(void) ...@@ -21,7 +21,6 @@ static int __init pci_acpi_init(void)
if (!acpi_noirq) { if (!acpi_noirq) {
if (!acpi_pci_irq_init()) { if (!acpi_pci_irq_init()) {
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n");
pcibios_scanned++; pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable; pcibios_enable_irq = acpi_pci_irq_enable;
} else } else
......
...@@ -94,6 +94,9 @@ static struct { ...@@ -94,6 +94,9 @@ static struct {
PCI Link Device Management PCI Link Device Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
/*
* set context (link) possible list from resource list
*/
static acpi_status static acpi_status
acpi_pci_link_check_possible ( acpi_pci_link_check_possible (
struct acpi_resource *resource, struct acpi_resource *resource,
...@@ -132,7 +135,7 @@ acpi_pci_link_check_possible ( ...@@ -132,7 +135,7 @@ acpi_pci_link_check_possible (
struct acpi_resource_ext_irq *p = &resource->data.extended_irq; struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
if (!p || !p->number_of_interrupts) { if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n")); "Blank EXT IRQ resource\n"));
return AE_OK; return AE_OK;
} }
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) { for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
...@@ -197,8 +200,12 @@ acpi_pci_link_check_current ( ...@@ -197,8 +200,12 @@ acpi_pci_link_check_current (
{ {
struct acpi_resource_irq *p = &resource->data.irq; struct acpi_resource_irq *p = &resource->data.irq;
if (!p || !p->number_of_interrupts) { if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, /*
"Blank IRQ resource\n")); * IRQ descriptors may have no IRQ# bits set,
* particularly those those w/ _STA disabled
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Blank IRQ resource\n"));
return AE_OK; return AE_OK;
} }
*irq = p->interrupts[0]; *irq = p->interrupts[0];
...@@ -208,8 +215,12 @@ acpi_pci_link_check_current ( ...@@ -208,8 +215,12 @@ acpi_pci_link_check_current (
{ {
struct acpi_resource_ext_irq *p = &resource->data.extended_irq; struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
if (!p || !p->number_of_interrupts) { if (!p || !p->number_of_interrupts) {
/*
* extended IRQ descriptors must
* return at least 1 IRQ
*/
ACPI_DEBUG_PRINT((ACPI_DB_WARN, ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n")); "Blank EXT IRQ resource\n"));
return AE_OK; return AE_OK;
} }
*irq = p->interrupts[0]; *irq = p->interrupts[0];
...@@ -223,6 +234,13 @@ acpi_pci_link_check_current ( ...@@ -223,6 +234,13 @@ acpi_pci_link_check_current (
return AE_CTRL_TERMINATE; return AE_CTRL_TERMINATE;
} }
/*
* Run _CRS and set link->irq.active
*
* return value:
* 0 - success
* !0 - failure
*/
static int static int
acpi_pci_link_get_current ( acpi_pci_link_get_current (
struct acpi_pci_link *link) struct acpi_pci_link *link)
...@@ -238,15 +256,19 @@ acpi_pci_link_get_current ( ...@@ -238,15 +256,19 @@ acpi_pci_link_get_current (
link->irq.active = 0; link->irq.active = 0;
/* Make sure the link is enabled (no use querying if it isn't). */ /* in practice, status disabled is meaningless, ignore it */
result = acpi_bus_get_status(link->device); if (acpi_strict) {
if (result) { /* Query _STA, set link->device->status */
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); result = acpi_bus_get_status(link->device);
goto end; if (result) {
} ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
if (!link->device->status.enabled) { goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); }
return_VALUE(0);
if (!link->device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
return_VALUE(0);
}
} }
/* /*
...@@ -261,18 +283,11 @@ acpi_pci_link_get_current ( ...@@ -261,18 +283,11 @@ acpi_pci_link_get_current (
goto end; goto end;
} }
if (!irq) { if (acpi_strict && !irq) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No IRQ resource found\n")); ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
result = -ENODEV; result = -ENODEV;
goto end;
} }
/*
* Note that we don't validate that the current IRQ (_CRS) exists
* within the possible IRQs (_PRS): we blindly assume that whatever
* IRQ a boot-enabled Link device is set to is the correct one.
* (Required to support systems such as the Toshiba 5005-S504.)
*/
link->irq.active = irq; link->irq.active = irq;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
...@@ -281,32 +296,6 @@ acpi_pci_link_get_current ( ...@@ -281,32 +296,6 @@ acpi_pci_link_get_current (
return_VALUE(result); return_VALUE(result);
} }
static int
acpi_pci_link_try_get_current (
struct acpi_pci_link *link,
int irq)
{
int result;
ACPI_FUNCTION_TRACE("acpi_pci_link_try_get_current");
result = acpi_pci_link_get_current(link);
if (result && link->irq.active) {
return_VALUE(result);
}
if (!link->irq.active) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n"));
printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for"
"device (%s [%s]).\n", irq,
acpi_device_name(link->device),
acpi_device_bid(link->device));
link->irq.active = irq;
}
return 0;
}
static int static int
acpi_pci_link_set ( acpi_pci_link_set (
struct acpi_pci_link *link, struct acpi_pci_link *link,
...@@ -321,7 +310,6 @@ acpi_pci_link_set ( ...@@ -321,7 +310,6 @@ acpi_pci_link_set (
struct acpi_buffer buffer = {sizeof(resource)+1, &resource}; struct acpi_buffer buffer = {sizeof(resource)+1, &resource};
int i = 0; int i = 0;
int valid = 0; int valid = 0;
int resource_type = 0;
ACPI_FUNCTION_TRACE("acpi_pci_link_set"); ACPI_FUNCTION_TRACE("acpi_pci_link_set");
...@@ -345,27 +333,9 @@ acpi_pci_link_set ( ...@@ -345,27 +333,9 @@ acpi_pci_link_set (
} }
} }
resource_type = link->irq.resource_type;
if (resource_type != ACPI_RSTYPE_IRQ &&
resource_type != ACPI_RSTYPE_EXT_IRQ){
/* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with
* an extended one */
if (irq <= 15) {
resource_type = ACPI_RSTYPE_IRQ;
} else {
resource_type = ACPI_RSTYPE_EXT_IRQ;
}
}
retry_programming:
memset(&resource, 0, sizeof(resource)); memset(&resource, 0, sizeof(resource));
/* NOTE: PCI interrupts are always level / active_low / shared. But not all switch(link->irq.resource_type) {
interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for
parameters */
switch(resource_type) {
case ACPI_RSTYPE_IRQ: case ACPI_RSTYPE_IRQ:
resource.res.id = ACPI_RSTYPE_IRQ; resource.res.id = ACPI_RSTYPE_IRQ;
resource.res.length = sizeof(struct acpi_resource); resource.res.length = sizeof(struct acpi_resource);
...@@ -393,49 +363,56 @@ acpi_pci_link_set ( ...@@ -393,49 +363,56 @@ acpi_pci_link_set (
resource.res.data.extended_irq.interrupts[0] = irq; resource.res.data.extended_irq.interrupts[0] = irq;
/* ignore resource_source, it's optional */ /* ignore resource_source, it's optional */
break; break;
default:
printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
return_VALUE(-EINVAL);
} }
resource.end.id = ACPI_RSTYPE_END_TAG; resource.end.id = ACPI_RSTYPE_END_TAG;
/* Attempt to set the resource */ /* Attempt to set the resource */
status = acpi_set_current_resources(link->handle, &buffer); status = acpi_set_current_resources(link->handle, &buffer);
/* if we failed and IRQ <= 15, try again with an extended descriptor */
if (ACPI_FAILURE(status) && (resource_type == ACPI_RSTYPE_IRQ)) {
resource_type = ACPI_RSTYPE_EXT_IRQ;
printk(PREFIX "Retrying with extended IRQ descriptor\n");
goto retry_programming;
}
/* check for total failure */ /* check for total failure */
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
/* Make sure the device is enabled. */ /* Query _STA, set device->status */
result = acpi_bus_get_status(link->device); result = acpi_bus_get_status(link->device);
if (result) { if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
return_VALUE(result); return_VALUE(result);
} }
if (!link->device->status.enabled) { if (!link->device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); printk(KERN_WARNING PREFIX
return_VALUE(-ENODEV); "%s [%s] disabled and referenced, BIOS bug.\n",
acpi_device_name(link->device),
acpi_device_bid(link->device));
} }
/* Make sure the active IRQ is the one we requested. */ /* Query _CRS, set link->irq.active */
result = acpi_pci_link_try_get_current(link, irq); result = acpi_pci_link_get_current(link);
if (result) { if (result) {
return_VALUE(result); return_VALUE(result);
} }
/*
* Is current setting not what we set?
* set link->irq.active
*/
if (link->irq.active != irq) { if (link->irq.active != irq) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, /*
"Attempt to enable at IRQ %d resulted in IRQ %d\n", * policy: when _CRS doesn't return what we just _SRS
irq, link->irq.active)); * assume _SRS worked and override _CRS value.
link->irq.active = 0; */
acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL); printk(KERN_WARNING PREFIX
return_VALUE(-ENODEV); "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
acpi_device_name(link->device),
acpi_device_bid(link->device),
link->irq.active, irq);
link->irq.active = irq;
} }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
...@@ -489,7 +466,7 @@ acpi_pci_link_set ( ...@@ -489,7 +466,7 @@ acpi_pci_link_set (
#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
static int acpi_irq_penalty[ACPI_MAX_IRQS] = { static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = {
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
...@@ -562,10 +539,24 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { ...@@ -562,10 +539,24 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
if (link->irq.setonboot) if (link->irq.setonboot)
return_VALUE(0); return_VALUE(0);
if (link->irq.active) { /*
* search for active IRQ in list of possible IRQs.
*/
for (i = 0; i < link->irq.possible_count; ++i) {
if (link->irq.active == link->irq.possible[i])
break;
}
/*
* if active found, use it; else pick entry from end of possible list.
*/
if (i != link->irq.possible_count) {
irq = link->irq.active; irq = link->irq.active;
} else { } else {
irq = link->irq.possible[0]; irq = link->irq.possible[link->irq.possible_count - 1];
if (acpi_strict)
printk(KERN_WARNING PREFIX "_CRS %d not found"
" in _PRS\n", link->irq.active);
} }
if (acpi_irq_balance || !link->irq.active) { if (acpi_irq_balance || !link->irq.active) {
...@@ -581,7 +572,8 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { ...@@ -581,7 +572,8 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
/* Attempt to enable the link device at this IRQ. */ /* Attempt to enable the link device at this IRQ. */
if (acpi_pci_link_set(link, irq)) { if (acpi_pci_link_set(link, irq)) {
printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS). Aborting ACPI-based IRQ routing. Try pci=noacpi or acpi=off\n", printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"
"Try pci=noacpi or acpi=off\n",
acpi_device_name(link->device), acpi_device_name(link->device),
acpi_device_bid(link->device)); acpi_device_bid(link->device));
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
...@@ -633,7 +625,7 @@ acpi_pci_link_get_irq ( ...@@ -633,7 +625,7 @@ acpi_pci_link_get_irq (
return_VALUE(0); return_VALUE(0);
if (!link->irq.active) { if (!link->irq.active) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
return_VALUE(0); return_VALUE(0);
} }
...@@ -679,7 +671,6 @@ acpi_pci_link_add ( ...@@ -679,7 +671,6 @@ acpi_pci_link_add (
/* query and set link->irq.active */ /* query and set link->irq.active */
acpi_pci_link_get_current(link); acpi_pci_link_get_current(link);
//#ifdef CONFIG_ACPI_DEBUG
printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
acpi_device_bid(device)); acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) { for (i = 0; i < link->irq.possible_count; i++) {
...@@ -690,8 +681,16 @@ acpi_pci_link_add ( ...@@ -690,8 +681,16 @@ acpi_pci_link_add (
else else
printk(" %d", link->irq.possible[i]); printk(" %d", link->irq.possible[i]);
} }
printk(")\n");
//#endif /* CONFIG_ACPI_DEBUG */ printk(")");
if (!found)
printk(" *%d", link->irq.active);
if(!link->device->status.enabled)
printk(", disabled.");
printk("\n");
/* TBD: Acquire/release lock */ /* TBD: Acquire/release lock */
list_add_tail(&link->node, &acpi_link.entries); list_add_tail(&link->node, &acpi_link.entries);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment