vserver 1.9.3
[linux-2.6.git] / drivers / acpi / pci_link.c
index b9ab88f..86e8a0c 100644 (file)
@@ -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];
@@ -308,31 +309,12 @@ acpi_pci_link_set (
                struct acpi_resource    end;
        }                       resource;
        struct acpi_buffer      buffer = {sizeof(resource)+1, &resource};
-       int                     i = 0;
-       int                     valid = 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);
-               }
-       }
-
        memset(&resource, 0, sizeof(resource));
 
        switch(link->irq.resource_type) {
@@ -466,7 +448,7 @@ acpi_pci_link_set (
 #define PIRQ_PENALTY_ISA_USED          (16*16*16*16*16)
 #define PIRQ_PENALTY_ISA_ALWAYS                (16*16*16*16*16*16)
 
-static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = {
+static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ0 timer */
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ1 keyboard */
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ2 cascade */
@@ -479,21 +461,21 @@ static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = {
        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 */
                        /* >IRQ15 */
 };
 
-int
-acpi_pci_link_check (void)
+int __init
+acpi_irq_penalty_init(void)
 {
        struct list_head        *node = NULL;
        struct acpi_pci_link    *link = NULL;
        int                     i = 0;
 
-       ACPI_FUNCTION_TRACE("acpi_pci_link_check");
+       ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
 
        /*
         * Update penalties to facilitate IRQ balancing.
@@ -536,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);
 
        /*
@@ -546,17 +528,23 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
                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 (i != link->irq.possible_count) {
+       if (link->irq.active) {
                irq = link->irq.active;
        } else {
                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) {
@@ -584,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);
 }
@@ -697,6 +685,9 @@ acpi_pci_link_add (
        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);
 
@@ -704,6 +695,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,
@@ -796,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;