aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNathan Bryant <nbryant@optonline.net>2004-08-04 09:06:43 -0400
committerLen Brown <lenb@dhcppc3.>2004-08-04 09:06:43 -0400
commit06df808539357aa5b9c43684cf72eb9ea40496d6 (patch)
tree5ec4dd985d5f60ef9738bf03bcb6f9a97d28568e /drivers
parentb34b79113f292ce1fd2e2a9cebfb4549cd7b567e (diff)
downloadhistory-06df808539357aa5b9c43684cf72eb9ea40496d6.tar.gz
[ACPI] restore PCI Interrupt Link Devices upon resume
* register as as a sys_device so that we can get resume callbacks and restore interrupt routing state. * add acpi_pci_link_resume(), which will be called when resuming from a suspend state that needs IRQ routing to be restored. This fixes issues reported on the mailing lists, e.g.: http://marc.theaimsgroup.com/?l=acpi4linux&m=109142999328643&w=2 * rename setonboot --> initialized * change to test acpi_noirq in init We want to initialize everything on S3 resume in case the BIOS points an interrupt link somewhere we didn't expect. (Doing so avoids "missing interrupt" or "irq x: nobody cared" problems.) According to Len, past experience has shown that it's a good idea to initialize only devices that exist or were explicitly asked for, so we try to initialize only the IRQ's that were previously initialized at some point before suspend, by checking the "initialized" flag. This corresponds to links that have PCI devices attached. Everything else, we leave alone. Assuming the BIOS does the same thing on resume that it did on boot, this will leave all the unused links in the same state that they were on boot. We are registered as a sysdev in order to do this work fairly early during resume, before devices are resumed; some devices may not call pci_device_enable. Previous "setonboot once" behavior is left in place, to be conservative.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/pci_link.c76
1 files changed, 72 insertions, 4 deletions
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 13e9225519d38a..737b0db1f5d5ab 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -29,6 +29,7 @@
* for IRQ management (e.g. start()->_SRS).
*/
+#include <linux/sysdev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -71,7 +72,7 @@ struct acpi_pci_link_irq {
u8 active; /* Current IRQ */
u8 edge_level; /* All IRQs */
u8 active_high_low; /* All IRQs */
- u8 setonboot;
+ u8 initialized;
u8 resource_type;
u8 possible_count;
u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
@@ -517,7 +518,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
- if (link->irq.setonboot)
+ if (link->irq.initialized)
return_VALUE(0);
/*
@@ -571,7 +572,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
acpi_device_bid(link->device), link->irq.active);
}
- link->irq.setonboot = 1;
+ link->irq.initialized = 1;
return_VALUE(0);
}
@@ -695,6 +696,42 @@ end:
static int
+acpi_pci_link_resume (
+ struct acpi_pci_link *link)
+{
+ ACPI_FUNCTION_TRACE("acpi_pci_link_resume");
+
+ if (link->irq.active && link->irq.initialized)
+ return_VALUE(acpi_pci_link_set(link, link->irq.active));
+ else
+ return_VALUE(0);
+}
+
+
+static int
+irqrouter_resume(
+ struct sys_device *dev)
+{
+ struct list_head *node = NULL;
+ struct acpi_pci_link *link = NULL;
+
+ ACPI_FUNCTION_TRACE("irqrouter_resume");
+
+ list_for_each(node, &acpi_link.entries) {
+
+ link = list_entry(node, struct acpi_pci_link, node);
+ if (!link) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+ continue;
+ }
+
+ acpi_pci_link_resume(link);
+ }
+ return_VALUE(0);
+}
+
+
+static int
acpi_pci_link_remove (
struct acpi_device *device,
int type)
@@ -786,11 +823,42 @@ int __init acpi_irq_balance_set(char *str)
__setup("acpi_irq_balance", acpi_irq_balance_set);
+static struct sysdev_class irqrouter_sysdev_class = {
+ set_kset_name("irqrouter"),
+ .resume = irqrouter_resume,
+};
+
+
+static struct sys_device device_irqrouter = {
+ .id = 0,
+ .cls = &irqrouter_sysdev_class,
+};
+
+
+static int __init irqrouter_init_sysfs(void)
+{
+ int error;
+
+ ACPI_FUNCTION_TRACE("irqrouter_init_sysfs");
+
+ if (acpi_disabled || acpi_noirq)
+ return_VALUE(0);
+
+ error = sysdev_class_register(&irqrouter_sysdev_class);
+ if (!error)
+ error = sysdev_register(&device_irqrouter);
+
+ return_VALUE(error);
+}
+
+device_initcall(irqrouter_init_sysfs);
+
+
static int __init acpi_pci_link_init (void)
{
ACPI_FUNCTION_TRACE("acpi_pci_link_init");
- if (acpi_pci_disabled)
+ if (acpi_noirq)
return_VALUE(0);
acpi_link.count = 0;