Commit f70fa690 authored by Andy Grover's avatar Andy Grover

Properly (?) handle the multiple people who can find PCI root bridges

parent 6405f55a
...@@ -2,73 +2,23 @@ ...@@ -2,73 +2,23 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include "pci.h" #include "pci.h"
extern void eisa_set_level_irq(int irq); static int __init pci_acpi_init(void)
static int acpi_lookup_irq (
struct pci_dev *dev,
int assign)
{ {
int result = 0; if (pcibios_scanned)
int irq = 0;
u8 pin;
/* TBD: Select IRQ from possible to improve routing performance. */
/* Find IRQ pin */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
DBG(" -> no interrupt pin\n");
return 0; return 0;
}
pin = pin - 1;
result = acpi_prt_get_irq(dev, pin, &irq);
if (!irq)
result = -ENODEV;
if (0 != result) {
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n",
'A'+pin, dev->slot_name);
return result;
}
/* only check for the IRQ */
if (!assign) {
printk(KERN_INFO "PCI: Found IRQ %d for device %s\n",
irq, dev->slot_name);
return 1;
}
dev->irq = irq;
/* also assign an IRQ */
if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
result = acpi_prt_set_irq(dev, pin, irq);
if (0 != result) {
printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name);
return result;
}
eisa_set_level_irq(irq);
printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name);
}
return 1;
}
static int __init pci_acpi_init(void)
{
if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
if (acpi_prts.count) { if (!acpi_pci_irq_init()) {
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n"); printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
pci_use_acpi_routing = 1; pcibios_scanned++;
pci_lookup_irq = acpi_lookup_irq; pcibios_enable_irq = acpi_pci_irq_enable;
} else } else
printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n"); printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
} }
return 0; return 0;
} }
arch_initcall(pci_acpi_init); subsys_initcall(pci_acpi_init);
...@@ -27,6 +27,12 @@ struct pci_ops *pci_root_ops = NULL; ...@@ -27,6 +27,12 @@ struct pci_ops *pci_root_ops = NULL;
int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
/*
* legacy, numa, and acpi all want to call pcibios_scan_root
* from their initcalls. This flag prevents that.
*/
int pcibios_scanned;
/* /*
* This interrupt-safe spinlock protects all accesses to PCI * This interrupt-safe spinlock protects all accesses to PCI
* configuration space. * configuration space.
...@@ -201,6 +207,6 @@ int pcibios_enable_device(struct pci_dev *dev) ...@@ -201,6 +207,6 @@ int pcibios_enable_device(struct pci_dev *dev)
if ((err = pcibios_enable_resources(dev)) < 0) if ((err = pcibios_enable_resources(dev)) < 0)
return err; return err;
pcibios_enable_irq(dev);
return 0; return pcibios_enable_irq(dev);
} }
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/acpi.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
...@@ -22,7 +21,6 @@ ...@@ -22,7 +21,6 @@
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100 #define PIRQ_VERSION 0x0100
int pci_use_acpi_routing = 0;
int broken_hp_bios_irq9; int broken_hp_bios_irq9;
static struct irq_routing_table *pirq_table; static struct irq_routing_table *pirq_table;
...@@ -46,7 +44,7 @@ struct irq_router { ...@@ -46,7 +44,7 @@ struct irq_router {
int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
}; };
int (*pci_lookup_irq)(struct pci_dev * dev, int assign) = NULL; int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
/* /*
* Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
...@@ -690,7 +688,7 @@ static int __init pcibios_irq_init(void) ...@@ -690,7 +688,7 @@ static int __init pcibios_irq_init(void)
{ {
DBG("PCI: IRQ init\n"); DBG("PCI: IRQ init\n");
if (pci_lookup_irq) if (pcibios_enable_irq)
return 0; return 0;
pirq_table = pirq_find_routing_table(); pirq_table = pirq_find_routing_table();
...@@ -712,7 +710,9 @@ static int __init pcibios_irq_init(void) ...@@ -712,7 +710,9 @@ static int __init pcibios_irq_init(void)
if (io_apic_assign_pci_irqs) if (io_apic_assign_pci_irqs)
pirq_table = NULL; pirq_table = NULL;
} }
pci_lookup_irq = pcibios_lookup_irq;
pcibios_enable_irq = pirq_enable_irq;
pcibios_fixup_irqs(); pcibios_fixup_irqs();
return 0; return 0;
} }
...@@ -781,7 +781,7 @@ void __init pcibios_fixup_irqs(void) ...@@ -781,7 +781,7 @@ void __init pcibios_fixup_irqs(void)
* Still no IRQ? Try to lookup one... * Still no IRQ? Try to lookup one...
*/ */
if (pin && !dev->irq) if (pin && !dev->irq)
pci_lookup_irq(dev, 0); pcibios_lookup_irq(dev, 0);
} }
} }
...@@ -794,11 +794,11 @@ void pcibios_penalize_isa_irq(int irq) ...@@ -794,11 +794,11 @@ void pcibios_penalize_isa_irq(int irq)
pirq_penalty[irq] += 100; pirq_penalty[irq] += 100;
} }
void pcibios_enable_irq(struct pci_dev *dev) int pirq_enable_irq(struct pci_dev *dev)
{ {
u8 pin; u8 pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin && !pci_lookup_irq(dev, 1) && !dev->irq) { if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
char *msg; char *msg;
if (io_apic_assign_pci_irqs) if (io_apic_assign_pci_irqs)
msg = " Probably buggy MP table."; msg = " Probably buggy MP table.";
...@@ -809,4 +809,6 @@ void pcibios_enable_irq(struct pci_dev *dev) ...@@ -809,4 +809,6 @@ void pcibios_enable_irq(struct pci_dev *dev)
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
'A' + pin - 1, dev->slot_name, msg); 'A' + pin - 1, dev->slot_name, msg);
} }
return 0;
} }
...@@ -42,11 +42,14 @@ static int __init pci_legacy_init(void) ...@@ -42,11 +42,14 @@ static int __init pci_legacy_init(void)
return 0; return 0;
} }
if (pcibios_scanned++)
return 0;
printk("PCI: Probing PCI hardware\n"); printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0); pci_root_bus = pcibios_scan_root(0);
if (!pci_use_acpi_routing)
pcibios_fixup_peer_bridges(); pcibios_fixup_peer_bridges();
return 0; return 0;
} }
......
...@@ -104,6 +104,9 @@ static int __init pci_numa_init(void) ...@@ -104,6 +104,9 @@ static int __init pci_numa_init(void)
pci_config_read = pci_conf1_read; pci_config_read = pci_conf1_read;
pci_config_write = pci_conf1_write; pci_config_write = pci_conf1_write;
if (pcibios_scanned++)
return 0;
pci_root_bus = pcibios_scan_root(0); pci_root_bus = pcibios_scan_root(0);
if (clustered_apic_mode && (numnodes > 1)) { if (clustered_apic_mode && (numnodes > 1)) {
for (quad = 1; quad < numnodes; ++quad) { for (quad = 1; quad < numnodes; ++quad) {
......
...@@ -66,10 +66,10 @@ struct irq_routing_table { ...@@ -66,10 +66,10 @@ struct irq_routing_table {
extern unsigned int pcibios_irq_mask; extern unsigned int pcibios_irq_mask;
extern int pci_use_acpi_routing; extern int pcibios_scanned;
extern spinlock_t pci_config_lock; extern spinlock_t pci_config_lock;
void pcibios_fixup_irqs(void); void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev); int pirq_enable_irq(struct pci_dev *dev);
extern int (*pci_lookup_irq)(struct pci_dev * dev, int assign); extern int (*pcibios_enable_irq)(struct pci_dev *dev);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment