Merge branch 'merge'
[linux-2.6-microblaze.git] / arch / powerpc / kernel / pci_64.c
index e795a7e..d51be7c 100644 (file)
 #include <linux/mm.h>
 #include <linux/list.h>
 #include <linux/syscalls.h>
+#include <linux/irq.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include <asm/byteorder.h>
-#include <asm/irq.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 
@@ -1254,15 +1254,37 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
 
        DBG("Try to map irq for %s...\n", pci_name(pci_dev));
 
+       /* Try to get a mapping from the device-tree */
        if (of_irq_map_pci(pci_dev, &oirq)) {
-               DBG(" -> failed !\n");
-               return -1;
-       }
+               u8 line, pin;
+
+               /* If that fails, lets fallback to what is in the config
+                * space and map that through the default controller. We
+                * also set the type to level low since that's what PCI
+                * interrupts are. If your platform does differently, then
+                * either provide a proper interrupt tree or don't use this
+                * function.
+                */
+               if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
+                       return -1;
+               if (pin == 0)
+                       return -1;
+               if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
+                   line == 0xff) {
+                       return -1;
+               }
+               DBG(" -> no map ! Using irq line %d from PCI config\n", line);
 
-       DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
-           oirq.size, oirq.specifier[0], oirq.controller->full_name);
+               virq = irq_create_mapping(NULL, line);
+               if (virq != NO_IRQ)
+                       set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+       } else {
+               DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
+                   oirq.size, oirq.specifier[0], oirq.controller->full_name);
 
-       virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size);
+               virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+                                            oirq.size);
+       }
        if(virq == NO_IRQ) {
                DBG(" -> failed to map !\n");
                return -1;