From ab2a9ae687f2660d551d014d8d3841da15aea2fc Mon Sep 17 00:00:00 2001 From: Dely Sy Date: Sun, 1 Feb 2004 20:19:50 -0800 Subject: [PATCH] [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. --- arch/i386/pci/irq.c | 44 ++++++++++++++++++++++++++++--- drivers/pci/hotplug/cpqphp_ctrl.c | 4 ++- drivers/pci/hotplug/cpqphp_pci.c | 2 ++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 9365627961e62..cff23d2d84957 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -943,12 +943,50 @@ int pirq_enable_irq(struct pci_dev *dev) { u8 pin; extern int interrupt_line_quirk; + struct pci_dev *temp_dev; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { char *msg; - if (io_apic_assign_pci_irqs) - msg = " Probably buggy MP table."; - else if (pci_probe & PCI_BIOS_IRQ_SCAN) + msg = ""; + if (io_apic_assign_pci_irqs) { + 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 = ""; else msg = " Please try using pci=biosirq."; diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index c32a0e12c9e6c..6f7e09cdb958e 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -2446,7 +2446,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f u8 behind_bridge, struct resource_lists * resources) { int cloop; - u8 IRQ; + u8 IRQ = 0; u8 temp_byte; u8 device; u8 class_code; @@ -3021,6 +3021,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f } } // End of base register loop +#if !defined(CONFIG_X86_IO_APIC) // Figure out which interrupt pin this function uses 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 // IRQ Line rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); +#endif if (!behind_bridge) { rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 6af4eb4d9e447..1348fb17a0f33 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -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) { +#if !defined(CONFIG_X86_IO_APIC) int rc; u16 temp_word; struct pci_dev fakedev; @@ -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 outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); +#endif return 0; } -- 2.53.0