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 @@
#include <linux/acpi.h>
#include "pci.h"
extern void eisa_set_level_irq(int irq);
static int acpi_lookup_irq (
struct pci_dev *dev,
int assign)
static int __init pci_acpi_init(void)
{
int result = 0;
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");
if (pcibios_scanned)
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 (acpi_prts.count) {
if (!acpi_pci_irq_init()) {
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
pci_use_acpi_routing = 1;
pci_lookup_irq = acpi_lookup_irq;
pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable;
} else
printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
}
return 0;
}
arch_initcall(pci_acpi_init);
subsys_initcall(pci_acpi_init);
......@@ -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_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
* configuration space.
......@@ -201,6 +207,6 @@ int pcibios_enable_device(struct pci_dev *dev)
if ((err = pcibios_enable_resources(dev)) < 0)
return err;
pcibios_enable_irq(dev);
return 0;
return pcibios_enable_irq(dev);
}
......@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/io_apic.h>
......@@ -22,7 +21,6 @@
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
int pci_use_acpi_routing = 0;
int broken_hp_bios_irq9;
static struct irq_routing_table *pirq_table;
......@@ -46,7 +44,7 @@ struct irq_router {
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.
......@@ -690,7 +688,7 @@ static int __init pcibios_irq_init(void)
{
DBG("PCI: IRQ init\n");
if (pci_lookup_irq)
if (pcibios_enable_irq)
return 0;
pirq_table = pirq_find_routing_table();
......@@ -712,7 +710,9 @@ static int __init pcibios_irq_init(void)
if (io_apic_assign_pci_irqs)
pirq_table = NULL;
}
pci_lookup_irq = pcibios_lookup_irq;
pcibios_enable_irq = pirq_enable_irq;
pcibios_fixup_irqs();
return 0;
}
......@@ -781,7 +781,7 @@ void __init pcibios_fixup_irqs(void)
* Still no IRQ? Try to lookup one...
*/
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)
pirq_penalty[irq] += 100;
}
void pcibios_enable_irq(struct pci_dev *dev)
int pirq_enable_irq(struct pci_dev *dev)
{
u8 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;
if (io_apic_assign_pci_irqs)
msg = " Probably buggy MP table.";
......@@ -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",
'A' + pin - 1, dev->slot_name, msg);
}
return 0;
}
......@@ -42,11 +42,14 @@ static int __init pci_legacy_init(void)
return 0;
}
if (pcibios_scanned++)
return 0;
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0);
if (!pci_use_acpi_routing)
pcibios_fixup_peer_bridges();
pcibios_fixup_peer_bridges();
return 0;
}
......
......@@ -104,6 +104,9 @@ static int __init pci_numa_init(void)
pci_config_read = pci_conf1_read;
pci_config_write = pci_conf1_write;
if (pcibios_scanned++)
return 0;
pci_root_bus = pcibios_scan_root(0);
if (clustered_apic_mode && (numnodes > 1)) {
for (quad = 1; quad < numnodes; ++quad) {
......
......@@ -66,10 +66,10 @@ struct irq_routing_table {
extern unsigned int pcibios_irq_mask;
extern int pci_use_acpi_routing;
extern int pcibios_scanned;
extern spinlock_t pci_config_lock;
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