Commit ab2a9ae6 authored by Dely Sy's avatar Dely Sy Committed by Greg Kroah-Hartman

[PATCH] PCI: Patch to get cpqphp working with IOAPIC

Here is a patch for to get cpqphp working with IOAPIC.
My earlier statement that a kernel patch is not needed for 2.6 is
true only when ACPI is enabled.  A similar patch is needed in
pcibios_enable_irq() for 2.4 kernel and I will send it out
later.

The fix is in pirq_enable_irq().  This function is called indirectly
by pci_enable_device().  For device present during boot up, it should
get the proper dev->irq for pcibios_fixup_irqs() has been called to
get the dev->irq from MP table. If the value is still zero, then
this is properly caused by "buggy MP table".  For hot-plug device,
its dev->irq is 0 when the pci_enable_device() is called for it hasn't
gone through the fixup.  Therefore, the code (similiar to the code
in pcibios_fixup_irqs) is needed here.
parent 706c39a1
...@@ -943,12 +943,50 @@ int pirq_enable_irq(struct pci_dev *dev) ...@@ -943,12 +943,50 @@ int pirq_enable_irq(struct pci_dev *dev)
{ {
u8 pin; u8 pin;
extern int interrupt_line_quirk; extern int interrupt_line_quirk;
struct pci_dev *temp_dev;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); 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) && !dev->irq) {
char *msg; char *msg;
if (io_apic_assign_pci_irqs) msg = "";
msg = " Probably buggy MP table."; if (io_apic_assign_pci_irqs) {
else if (pci_probe & PCI_BIOS_IRQ_SCAN) int irq;
if (pin) {
pin--; /* interrupt pins are numbered starting from 1 */
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
/*
* 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.
*/
temp_dev = dev;
while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
struct pci_dev * bridge = dev->bus->self;
pin = (pin + PCI_SLOT(dev->devfn)) % 4;
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
PCI_SLOT(bridge->devfn), pin);
if (irq >= 0)
printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n",
bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
dev = bridge;
}
dev = temp_dev;
if (irq >= 0) {
#ifdef CONFIG_PCI_USE_VECTOR
if (!platform_legacy_irq(irq))
irq = IO_APIC_VECTOR(irq);
#endif
printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
dev->irq = irq;
return 0;
} else
msg = " Probably buggy MP table.";
}
} else if (pci_probe & PCI_BIOS_IRQ_SCAN)
msg = ""; msg = "";
else else
msg = " Please try using pci=biosirq."; msg = " Please try using pci=biosirq.";
......
...@@ -2446,7 +2446,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f ...@@ -2446,7 +2446,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f
u8 behind_bridge, struct resource_lists * resources) u8 behind_bridge, struct resource_lists * resources)
{ {
int cloop; int cloop;
u8 IRQ; u8 IRQ = 0;
u8 temp_byte; u8 temp_byte;
u8 device; u8 device;
u8 class_code; u8 class_code;
...@@ -3021,6 +3021,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f ...@@ -3021,6 +3021,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f
} }
} // End of base register loop } // End of base register loop
#if !defined(CONFIG_X86_IO_APIC)
// Figure out which interrupt pin this function uses // Figure out which interrupt pin this function uses
rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte);
...@@ -3045,6 +3046,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f ...@@ -3045,6 +3046,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f
// IRQ Line // IRQ Line
rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
#endif
if (!behind_bridge) { if (!behind_bridge) {
rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
......
...@@ -151,6 +151,7 @@ static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 o ...@@ -151,6 +151,7 @@ static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 o
*/ */
int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
{ {
#if !defined(CONFIG_X86_IO_APIC)
int rc; int rc;
u16 temp_word; u16 temp_word;
struct pci_dev fakedev; struct pci_dev fakedev;
...@@ -175,6 +176,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) ...@@ -175,6 +176,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
// This should only be for x86 as it sets the Edge Level Control Register // This should only be for x86 as it sets the Edge Level Control Register
outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) (temp_word & 0xFF), 0x4d0);
outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
#endif
return 0; return 0;
} }
......
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