]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/pci_irq.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
[linux-2.6-omap-h63xx.git] / drivers / acpi / pci_irq.c
index 89022a74faeeda9d9ed9b11f431c2e4c4eecb4d7..bf79d83bdfbbbade9a942a297e90b0223eef5946 100644 (file)
@@ -162,7 +162,7 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
                    !strcmp(prt->source, quirk->source) &&
                    strlen(prt->source) >= strlen(quirk->actual_source)) {
                        printk(KERN_WARNING PREFIX "firmware reports "
-                               "%04x:%02x:%02x[%c] connected to %s; "
+                               "%04x:%02x:%02x PCI INT %c connected to %s; "
                                "changing to %s\n",
                                entry->id.segment, entry->id.bus,
                                entry->id.device, 'A' + entry->pin,
@@ -384,6 +384,27 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry,
        return irq;
 }
 
+#ifdef CONFIG_X86_IO_APIC
+extern int noioapicquirk;
+
+static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
+{
+       struct pci_bus *bus_it;
+
+       for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
+               if (!bus_it->self)
+                       return 0;
+
+               printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor,
+                               bus_it->self->device);
+
+               if (bus_it->self->irq_reroute_variant)
+                       return bus_it->self->irq_reroute_variant;
+       }
+       return 0;
+}
+#endif /* CONFIG_X86_IO_APIC */
+
 /*
  * acpi_pci_irq_lookup
  * success: return IRQ >= 0
@@ -413,6 +434,41 @@ acpi_pci_irq_lookup(struct pci_bus *bus,
        }
 
        ret = func(entry, triggering, polarity, link);
+
+#ifdef CONFIG_X86_IO_APIC
+       /*
+        * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the
+        * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel
+        * does during interrupt handling). When this INTx generation cannot be
+        * disabled, we reroute these interrupts to their legacy equivalent to
+        * get rid of spurious interrupts.
+        */
+        if (!noioapicquirk) {
+               switch (bridge_has_boot_interrupt_variant(bus)) {
+               case 0:
+                       /* no rerouting necessary */
+                       break;
+
+               case INTEL_IRQ_REROUTE_VARIANT:
+                       /*
+                        * Remap according to INTx routing table in 6700PXH
+                        * specs, intel order number 302628-002, section
+                        * 2.15.2. Other chipsets (80332, ...) have the same
+                        * mapping and are handled here as well.
+                        */
+                       printk(KERN_INFO "pci irq %d -> rerouted to legacy "
+                                        "irq %d\n", ret, (ret % 4) + 16);
+                       ret = (ret % 4) + 16;
+                       break;
+
+               default:
+                       printk(KERN_INFO "not rerouting irq %d to legacy irq: "
+                                        "unknown mapping\n", ret);
+                       break;
+               }
+       }
+#endif /* CONFIG_X86_IO_APIC */
+
        return ret;
 }
 
@@ -429,7 +485,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,
 {
        struct pci_dev *bridge = dev;
        int irq = -1;
-       u8 bridge_pin = 0;
+       u8 bridge_pin = 0, orig_pin = pin;
 
 
        if (!dev)
@@ -463,8 +519,8 @@ acpi_pci_irq_derive(struct pci_dev *dev,
        }
 
        if (irq < 0) {
-               printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n",
-                             pci_name(dev));
+               dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
+                        'A' + orig_pin);
                return -1;
        }
 
@@ -487,6 +543,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
        int triggering = ACPI_LEVEL_SENSITIVE;
        int polarity = ACPI_ACTIVE_LOW;
        char *link = NULL;
+       char link_desc[16];
        int rc;
 
 
@@ -503,7 +560,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
        pin--;
 
        if (!dev->bus) {
-               printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n");
+               dev_err(&dev->dev, "invalid (NULL) 'bus' field\n");
                return -ENODEV;
        }
 
@@ -538,8 +595,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
         * driver reported one, then use it. Exit in any case.
         */
        if (irq < 0) {
-               printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
-                      pci_name(dev), ('A' + pin));
+               dev_warn(&dev->dev, "PCI INT %c: no GSI", 'A' + pin);
                /* Interrupt Line values above 0xF are forbidden */
                if (dev->irq > 0 && (dev->irq <= 0xF)) {
                        printk(" - using IRQ %d\n", dev->irq);
@@ -554,21 +610,21 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 
        rc = acpi_register_gsi(irq, triggering, polarity);
        if (rc < 0) {
-               printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed "
-                      "to register GSI\n", pci_name(dev), ('A' + pin));
+               dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
+                        'A' + pin);
                return rc;
        }
        dev->irq = rc;
 
-       printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
-              pci_name(dev), 'A' + pin);
-
        if (link)
-               printk("Link [%s] -> ", link);
+               snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
+       else
+               link_desc[0] = '\0';
 
-       printk("GSI %u (%s, %s) -> IRQ %d\n", irq,
-              (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
-              (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
+       dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
+                'A' + pin, link_desc, irq,
+                (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+                (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
 
        return 0;
 }
@@ -616,10 +672,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
         * (e.g. PCI_UNDEFINED_IRQ).
         */
 
-       printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n",
-              pci_name(dev));
-
+       dev_info(&dev->dev, "PCI INT %c disabled\n", 'A' + pin);
        acpi_unregister_gsi(gsi);
-
-       return;
 }