From: "Bjorn Helgaas" <bjorn.helgaas@hp.com>

In PIC mode, some Via devices update IRQ routing when PCI_INTERRUPT_LINE is
written.  So if we've updated the device's IRQ, we also need to update
PCI_INTERRUPT_LINE.

Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/i386/pci/irq.c    |    5 -----
 25-akpm/drivers/acpi/pci_irq.c |    4 ----
 25-akpm/drivers/pci/quirks.c   |   40 +++++++++++++++++++++++++++++++---------
 3 files changed, 31 insertions(+), 18 deletions(-)

diff -puN arch/i386/pci/irq.c~x86-via-workaround arch/i386/pci/irq.c
--- 25/arch/i386/pci/irq.c~x86-via-workaround	Thu Mar 24 16:01:57 2005
+++ 25-akpm/arch/i386/pci/irq.c	Thu Mar 24 16:01:57 2005
@@ -1026,7 +1026,6 @@ void pcibios_penalize_isa_irq(int irq)
 static int pirq_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
-	extern int via_interrupt_line_quirk;
 	struct pci_dev *temp_dev;
 
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
@@ -1081,10 +1080,6 @@ static int pirq_enable_irq(struct pci_de
 		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
 		       'A' + pin, pci_name(dev), msg);
 	}
-	/* VIA bridges use interrupt line for apic/pci steering across
-	   the V-Link */
-	else if (via_interrupt_line_quirk)
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15);
 	return 0;
 }
 
diff -puN drivers/acpi/pci_irq.c~x86-via-workaround drivers/acpi/pci_irq.c
--- 25/drivers/acpi/pci_irq.c~x86-via-workaround	Thu Mar 24 16:01:57 2005
+++ 25-akpm/drivers/acpi/pci_irq.c	Thu Mar 24 16:02:50 2005
@@ -391,7 +391,6 @@ acpi_pci_irq_enable (
 	u8			pin = 0;
 	int			edge_level = ACPI_LEVEL_SENSITIVE;
 	int			active_high_low = ACPI_ACTIVE_LOW;
-	extern int		via_interrupt_line_quirk;
 	char			*link = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
@@ -444,9 +443,6 @@ acpi_pci_irq_enable (
 		}
  	}
 
-	if (via_interrupt_line_quirk)
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15);
-
 	dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
 
 	printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
diff -puN drivers/pci/quirks.c~x86-via-workaround drivers/pci/quirks.c
--- 25/drivers/pci/quirks.c~x86-via-workaround	Thu Mar 24 16:01:57 2005
+++ 25-akpm/drivers/pci/quirks.c	Thu Mar 24 16:01:59 2005
@@ -683,19 +683,41 @@ static void __init quirk_disable_pxb(str
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb );
 
-/*
- *	VIA northbridges care about PCI_INTERRUPT_LINE
- */
-int via_interrupt_line_quirk;
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
 
-static void __devinit quirk_via_bridge(struct pci_dev *pdev)
+static void __devinit quirk_via_irqpic(struct pci_dev *dev)
 {
-	if(pdev->devfn == 0) {
-		printk(KERN_INFO "PCI: Via IRQ fixup\n");
-		via_interrupt_line_quirk = 1;
+	u8 irq, new_irq;
+
+#ifdef CONFIG_X86_IO_APIC
+	if (nr_ioapics && !skip_ioapic_setup)
+		return;
+#endif
+#ifdef CONFIG_ACPI
+	if (acpi_irq_model != ACPI_IRQ_MODEL_PIC)
+		return;
+#endif
+	/*
+	 * Some Via devices make an internal connection to the PIC when the
+	 * PCI_INTERRUPT_LINE register is written.  If we've changed the
+	 * device's IRQ, we need to update this routing.
+	 *
+	 * I suspect this only happens for devices on the same chip as the
+	 * PIC, but I don't know how to identify those without listing them
+	 * all individually, which is a maintenance problem.
+	 */
+	new_irq = dev->irq & 0xf;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	if (new_irq != irq) {
+		printk(KERN_INFO "PCI: Via PIC IRQ fixup for %s, from %d to %d\n",
+			pci_name(dev), irq, new_irq);
+		udelay(15);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
 	}
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_ANY_ID,                     quirk_via_bridge );
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irqpic);
 
 /*
  *	Serverworks CSB5 IDE does not fully support native mode
_