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

Nick Piggin's USB driver stopped working when I removed the unconditional
PCI ACPI IRQ routing stuff.  He has verified that the attached patch fixes
it.  I sort of hate to add another pass of PCI fixups, so I'm open to
alternate solutions if anybody suggests one.

Add a "pci_fixup_enable" pass of PCI fixups.  These are run at the end of
pci_enable_device() to fix up things like IRQs that are not set up until
then.  Some VIA boards require a fixup after the IRQ is set up.  Found by
Nick Piggin, initial patch by Bjorn Helgaas, reworked to fit into current
-mm by Nick.

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

 25-akpm/drivers/pci/pci.c                 |    7 ++++++-
 25-akpm/drivers/pci/quirks.c              |   15 ++++++++++++---
 25-akpm/include/asm-generic/vmlinux.lds.h |    3 +++
 25-akpm/include/linux/pci.h               |    7 +++++++
 4 files changed, 28 insertions(+), 4 deletions(-)

diff -puN drivers/pci/pci.c~add-pci_fixup_enable-pass drivers/pci/pci.c
--- 25/drivers/pci/pci.c~add-pci_fixup_enable-pass	2004-08-09 22:02:20.830462336 -0700
+++ 25-akpm/drivers/pci/pci.c	2004-08-09 22:02:20.837461272 -0700
@@ -382,8 +382,13 @@ pci_enable_device_bars(struct pci_dev *d
 int
 pci_enable_device(struct pci_dev *dev)
 {
+	int err;
+
 	dev->is_enabled = 1;
-	return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+	if ((err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1)))
+		return err;
+	pci_fixup_device(pci_fixup_enable, dev);
+	return 0;
 }
 
 /**
diff -puN drivers/pci/quirks.c~add-pci_fixup_enable-pass drivers/pci/quirks.c
--- 25/drivers/pci/quirks.c~add-pci_fixup_enable-pass	2004-08-09 22:02:20.831462184 -0700
+++ 25-akpm/drivers/pci/quirks.c	2004-08-09 22:02:20.838461120 -0700
@@ -491,9 +491,9 @@ static void __devinit quirk_via_irqpic(s
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
 	}
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_2,	quirk_via_irqpic );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_5,	quirk_via_irqpic );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_6,	quirk_via_irqpic );
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_2,	quirk_via_irqpic );
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_5,	quirk_via_irqpic );
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_6,	quirk_via_irqpic );
 
 
 /*
@@ -1003,6 +1003,9 @@ extern struct pci_fixup __start_pci_fixu
 extern struct pci_fixup __end_pci_fixups_header[];
 extern struct pci_fixup __start_pci_fixups_final[];
 extern struct pci_fixup __end_pci_fixups_final[];
+extern struct pci_fixup __start_pci_fixups_enable[];
+extern struct pci_fixup __end_pci_fixups_enable[];
+
 
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
 {
@@ -1018,6 +1021,12 @@ void pci_fixup_device(enum pci_fixup_pas
 		start = __start_pci_fixups_final;
 		end = __end_pci_fixups_final;
 		break;
+
+	case pci_fixup_enable:
+		start = __start_pci_fixups_enable;
+		end = __end_pci_fixups_enable;
+		break;
+
 	default:
 		/* stupid compiler warning, you would think with an enum... */
 		return;
diff -puN include/asm-generic/vmlinux.lds.h~add-pci_fixup_enable-pass include/asm-generic/vmlinux.lds.h
--- 25/include/asm-generic/vmlinux.lds.h~add-pci_fixup_enable-pass	2004-08-09 22:02:20.832462032 -0700
+++ 25-akpm/include/asm-generic/vmlinux.lds.h	2004-08-09 22:02:20.839460968 -0700
@@ -24,6 +24,9 @@
 		VMLINUX_SYMBOL(__start_pci_fixups_final) = .;		\
 		*(.pci_fixup_final)					\
 		VMLINUX_SYMBOL(__end_pci_fixups_final) = .;		\
+		VMLINUX_SYMBOL(__start_pci_fixups_enable) = .;		\
+		*(.pci_fixup_enable)					\
+		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
 	}								\
 									\
 	/* Kernel symbol table: Normal symbols */			\
diff -puN include/linux/pci.h~add-pci_fixup_enable-pass include/linux/pci.h
--- 25/include/linux/pci.h~add-pci_fixup_enable-pass	2004-08-09 22:02:20.834461728 -0700
+++ 25-akpm/include/linux/pci.h	2004-08-09 22:02:20.840460816 -0700
@@ -1008,6 +1008,7 @@ struct pci_fixup {
 enum pci_fixup_pass {
 	pci_fixup_header,	/* Called immediately after reading configuration header */
 	pci_fixup_final,	/* Final phase of device fixups */
+	pci_fixup_enable,	/* pci_enable_device() time */
 };
 
 /* Anonymous variables would be nice... */
@@ -1021,6 +1022,12 @@ enum pci_fixup_pass {
 	__attribute__((__section__(".pci_fixup_final"))) = {				\
 		vendor, device, hook };
 
+#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook)				\
+	static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__	\
+	__attribute__((__section__(".pci_fixup_enable"))) = {				\
+		vendor, device, hook };
+
+
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
 
 extern int pci_pci_problems;
_