patch-2.4.27 linux-2.4.27/drivers/acpi/pci_link.c
Next file: linux-2.4.27/drivers/acpi/pci_root.c
Previous file: linux-2.4.27/drivers/acpi/pci_irq.c
Back to the patch index
Back to the overall index
- Lines: 401
- Date:
2004-08-07 16:26:04.654346777 -0700
- Orig file:
linux-2.4.26/drivers/acpi/pci_link.c
- Orig date:
2004-04-14 06:05:29.000000000 -0700
diff -urN linux-2.4.26/drivers/acpi/pci_link.c linux-2.4.27/drivers/acpi/pci_link.c
@@ -90,6 +90,9 @@
PCI Link Device Management
-------------------------------------------------------------------------- */
+/*
+ * set context (link) possible list from resource list
+ */
static acpi_status
acpi_pci_link_check_possible (
struct acpi_resource *resource,
@@ -128,7 +131,7 @@
struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Blank IRQ resource\n"));
+ "Blank EXT IRQ resource\n"));
return AE_OK;
}
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
@@ -193,8 +196,12 @@
{
struct acpi_resource_irq *p = &resource->data.irq;
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;
}
*irq = p->interrupts[0];
@@ -204,8 +211,12 @@
{
struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
if (!p || !p->number_of_interrupts) {
+ /*
+ * extended IRQ descriptors must
+ * return at least 1 IRQ
+ */
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Blank IRQ resource\n"));
+ "Blank EXT IRQ resource\n"));
return AE_OK;
}
*irq = p->interrupts[0];
@@ -219,6 +230,13 @@
return AE_CTRL_TERMINATE;
}
+/*
+ * Run _CRS and set link->irq.active
+ *
+ * return value:
+ * 0 - success
+ * !0 - failure
+ */
static int
acpi_pci_link_get_current (
struct acpi_pci_link *link)
@@ -234,15 +252,19 @@
link->irq.active = 0;
- /* Make sure the link is enabled (no use querying if it isn't). */
- result = acpi_bus_get_status(link->device);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
- goto end;
- }
- if (!link->device->status.enabled) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
- return_VALUE(0);
+ /* in practice, status disabled is meaningless, ignore it */
+ if (acpi_strict) {
+ /* Query _STA, set link->device->status */
+ result = acpi_bus_get_status(link->device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+ goto end;
+ }
+
+ if (!link->device->status.enabled) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
+ return_VALUE(0);
+ }
}
/*
@@ -257,18 +279,11 @@
goto end;
}
- if (!irq) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No IRQ resource found\n"));
+ if (acpi_strict && !irq) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
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;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
@@ -278,32 +293,6 @@
}
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
acpi_pci_link_set (
struct acpi_pci_link *link,
int irq)
@@ -315,59 +304,24 @@
struct acpi_resource end;
} resource;
struct acpi_buffer buffer = {sizeof(resource)+1, &resource};
- int i = 0;
- int valid = 0;
- int resource_type = 0;
-
+
ACPI_FUNCTION_TRACE("acpi_pci_link_set");
if (!link || !irq)
return_VALUE(-EINVAL);
- /* We don't check irqs the first time around */
- if (link->irq.setonboot) {
- /* See if we're already at the target IRQ. */
- if (irq == link->irq.active)
- return_VALUE(0);
-
- /* Make sure the target IRQ in the list of possible IRQs. */
- for (i=0; i<link->irq.possible_count; i++) {
- if (irq == link->irq.possible[i])
- valid = 1;
- }
- if (!valid) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq));
- return_VALUE(-EINVAL);
- }
- }
-
- 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));
- /* NOTE: PCI interrupts are always level / active_low / shared. But not all
- interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for
- parameters */
- switch(resource_type) {
+ switch(link->irq.resource_type) {
case ACPI_RSTYPE_IRQ:
resource.res.id = ACPI_RSTYPE_IRQ;
resource.res.length = sizeof(struct acpi_resource);
resource.res.data.irq.edge_level = link->irq.edge_level;
resource.res.data.irq.active_high_low = link->irq.active_high_low;
- resource.res.data.irq.shared_exclusive = ACPI_SHARED;
+ if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+ resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+ else
+ resource.res.data.irq.shared_exclusive = ACPI_SHARED;
resource.res.data.irq.number_of_interrupts = 1;
resource.res.data.irq.interrupts[0] = irq;
break;
@@ -378,55 +332,63 @@
resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER;
resource.res.data.extended_irq.edge_level = link->irq.edge_level;
resource.res.data.extended_irq.active_high_low = link->irq.active_high_low;
- resource.res.data.extended_irq.shared_exclusive = ACPI_SHARED;
+ if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+ resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+ else
+ resource.res.data.irq.shared_exclusive = ACPI_SHARED;
resource.res.data.extended_irq.number_of_interrupts = 1;
resource.res.data.extended_irq.interrupts[0] = irq;
/* ignore resource_source, it's optional */
break;
+ default:
+ printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
+ return_VALUE(-EINVAL);
}
resource.end.id = ACPI_RSTYPE_END_TAG;
/* Attempt to set the resource */
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 */
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
return_VALUE(-ENODEV);
}
- /* Make sure the device is enabled. */
+ /* Query _STA, set device->status */
result = acpi_bus_get_status(link->device);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
return_VALUE(result);
}
if (!link->device->status.enabled) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n"));
- return_VALUE(-ENODEV);
+ printk(KERN_WARNING PREFIX
+ "%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. */
- result = acpi_pci_link_try_get_current(link, irq);
+ /* Query _CRS, set link->irq.active */
+ result = acpi_pci_link_get_current(link);
if (result) {
return_VALUE(result);
}
-
+
+ /*
+ * Is current setting not what we set?
+ * set link->irq.active
+ */
if (link->irq.active != irq) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Attempt to enable at IRQ %d resulted in IRQ %d\n",
- irq, link->irq.active));
- link->irq.active = 0;
- acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL);
- return_VALUE(-ENODEV);
+ /*
+ * policy: when _CRS doesn't return what we just _SRS
+ * assume _SRS worked and override _CRS value.
+ */
+ printk(KERN_WARNING PREFIX
+ "%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));
@@ -480,7 +442,7 @@
#define PIRQ_PENALTY_ISA_USED (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, /* IRQ1 keyboard */
PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
@@ -493,7 +455,7 @@
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */
- PIRQ_PENALTY_ISA_TYPICAL, /* IRQ12 mouse */
+ PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */
PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */
PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */
PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */
@@ -553,10 +515,30 @@
if (link->irq.setonboot)
return_VALUE(0);
+ /*
+ * 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;
+ }
+ /*
+ * forget active IRQ that is not in possible list
+ */
+ if (i == link->irq.possible_count) {
+ if (acpi_strict)
+ printk(KERN_WARNING PREFIX "_CRS %d not found"
+ " in _PRS\n", link->irq.active);
+ link->irq.active = 0;
+ }
+
+ /*
+ * if active found, use it; else pick entry from end of possible list.
+ */
if (link->irq.active) {
irq = link->irq.active;
} else {
- irq = link->irq.possible[0];
+ irq = link->irq.possible[link->irq.possible_count - 1];
}
if (acpi_irq_balance || !link->irq.active) {
@@ -572,7 +554,8 @@
/* Attempt to enable the link device at this 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_bid(link->device));
return_VALUE(-ENODEV);
@@ -624,7 +607,7 @@
return_VALUE(0);
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);
}
@@ -670,7 +653,6 @@
/* query and set link->irq.active */
acpi_pci_link_get_current(link);
-//#ifdef CONFIG_ACPI_DEBUG
printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) {
@@ -681,14 +663,25 @@
else
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 */
list_add_tail(&link->node, &acpi_link.entries);
acpi_link.count++;
end:
+ /* disable all links -- to be activated on use */
+ acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+
if (result)
kfree(link);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)