x86/pci: update pirq_enable_irq() to setup io apic routing

So we can set io apic routing only when enabling the device irq.

This is advantageous for IRQ descriptor allocation affinity: if we set up
the IO-APIC entry later, we have a chance to allocate the IRQ descriptor
later and know which device it is on and can set affinity accordingly.

[ Impact: standardize/enhance irq-enabling sequence for mptable irqs ]

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Len Brown <lenb@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
LKML-Reference: <4A01C46E.8000501@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Yinghai Lu
2009-05-06 10:10:06 -07:00
committed by Ingo Molnar
parent 5ef2183768
commit b9c61b7007
2 changed files with 110 additions and 136 deletions

View File

@@ -889,6 +889,9 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
return 0;
}
if (io_apic_assign_pci_irqs)
return 0;
/* Find IRQ routing entry */
if (!pirq_table)
@@ -1039,63 +1042,15 @@ static void __init pcibios_fixup_irqs(void)
pirq_penalty[dev->irq]++;
}
if (io_apic_assign_pci_irqs)
return;
dev = NULL;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin)
continue;
#ifdef CONFIG_X86_IO_APIC
/*
* Recalculate IRQ numbers if we use the I/O APIC.
*/
if (io_apic_assign_pci_irqs) {
int irq;
int ioapic = -1, ioapic_pin = -1;
int triggering, polarity;
/*
* interrupt pins are numbered starting from 1
*/
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
PCI_SLOT(dev->devfn), pin - 1,
&ioapic, &ioapic_pin,
&triggering, &polarity);
/*
* Busses behind bridges are typically not listed in the
* MP-table. In this case we have to look up the IRQ
* based on the parent bus, parent slot, and pin number.
* The SMP code detects such bridged busses itself so we
* should get into this branch reliably.
*/
if (irq < 0 && dev->bus->parent) {
/* go back to the bridge */
struct pci_dev *bridge = dev->bus->self;
int bus;
pin = pci_swizzle_interrupt_pin(dev, pin);
bus = bridge->bus->number;
irq = IO_APIC_get_PCI_irq_vector(bus,
PCI_SLOT(bridge->devfn),
pin - 1,
&ioapic, &ioapic_pin,
&triggering, &polarity);
if (irq >= 0)
dev_warn(&dev->dev,
"using bridge %s INT %c to "
"get IRQ %d\n",
pci_name(bridge),
'A' + pin - 1, irq);
}
if (irq >= 0) {
dev_info(&dev->dev,
"PCI->APIC IRQ transform: INT %c "
"-> IRQ %d\n",
'A' + pin - 1, irq);
dev->irq = irq;
}
}
#endif
/*
* Still no IRQ? Try to lookup one...
*/
@@ -1190,6 +1145,19 @@ int __init pcibios_irq_init(void)
pcibios_enable_irq = pirq_enable_irq;
pcibios_fixup_irqs();
if (io_apic_assign_pci_irqs && pci_routeirq) {
struct pci_dev *dev = NULL;
/*
* PCI IRQ routing is set up by pci_enable_device(), but we
* also do it here in case there are still broken drivers that
* don't use pci_enable_device().
*/
printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
for_each_pci_dev(dev)
pirq_enable_irq(dev);
}
return 0;
}
@@ -1220,13 +1188,17 @@ void pcibios_penalize_isa_irq(int irq, int active)
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin;
struct pci_dev *temp_dev;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
if (pin && !pcibios_lookup_irq(dev, 1)) {
char *msg = "";
if (!io_apic_assign_pci_irqs && dev->irq)
return 0;
if (io_apic_assign_pci_irqs) {
#ifdef CONFIG_X86_IO_APIC
struct pci_dev *temp_dev;
int irq;
int ioapic = -1, ioapic_pin = -1;
int triggering, polarity;
@@ -1261,12 +1233,16 @@ static int pirq_enable_irq(struct pci_dev *dev)
}
dev = temp_dev;
if (irq >= 0) {
io_apic_set_pci_routing(&dev->dev, ioapic,
ioapic_pin, irq,
triggering, polarity);
dev->irq = irq;
dev_info(&dev->dev, "PCI->APIC IRQ transform: "
"INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
dev->irq = irq;
return 0;
} else
msg = "; probably buggy MP table";
#endif
} else if (pci_probe & PCI_BIOS_IRQ_SCAN)
msg = "";
else