Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/Documentation/kernel-parameters.txt |    4 +++
 25-akpm/arch/i386/pci/acpi.c                |   30 ++++++++++++++++++-------
 25-akpm/arch/i386/pci/common.c              |    4 +++
 25-akpm/arch/i386/pci/irq.c                 |   16 +++++--------
 25-akpm/arch/ia64/pci/pci.c                 |   33 ++++++++++++++++++++++------
 25-akpm/drivers/atm/idt77252.c              |    4 +--
 25-akpm/drivers/isdn/tpam/tpam_main.c       |    4 +--
 25-akpm/drivers/misc/ibmasm/module.c        |    6 ++---
 25-akpm/drivers/net/tulip/de4x5.c           |    4 +--
 25-akpm/drivers/pci/pci.c                   |   12 ++++++++++
 arch/i386/kernel/acpi/boot.c                |    0 
 11 files changed, 83 insertions(+), 34 deletions(-)

diff -puN arch/i386/kernel/acpi/boot.c~bk-pci arch/i386/kernel/acpi/boot.c
diff -puN arch/i386/pci/acpi.c~bk-pci arch/i386/pci/acpi.c
--- 25/arch/i386/pci/acpi.c~bk-pci	2004-10-28 23:17:33.002273576 -0700
+++ 25-akpm/arch/i386/pci/acpi.c	2004-10-28 23:17:36.446749936 -0700
@@ -15,6 +15,7 @@ struct pci_bus * __devinit pci_acpi_scan
 	return pcibios_scan_root(busnum);
 }
 
+extern int pci_routeirq;
 static int __init pci_acpi_init(void)
 {
 	struct pci_dev *dev = NULL;
@@ -30,14 +31,27 @@ static int __init pci_acpi_init(void)
 	pcibios_scanned++;
 	pcibios_enable_irq = acpi_pci_irq_enable;
 
-	/*
-	 * 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().
-	 */
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-		acpi_pci_irq_enable(dev);
-
+	if (pci_routeirq) {
+		/*
+		 * 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 "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
+		printk(KERN_INFO "** was specified.  If this was required to make a driver work,\n");
+		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
+		printk(KERN_INFO "** so I can fix the driver.\n");
+		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+			acpi_pci_irq_enable(dev);
+	} else {
+		printk(KERN_INFO "** PCI interrupts are no longer routed automatically.  If this\n");
+		printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
+		printk(KERN_INFO "** driver failed to call pci_enable_device().  As a temporary\n");
+		printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
+		printk(KERN_INFO "** behavior.  If this argument makes the device work again,\n");
+		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
+		printk(KERN_INFO "** so I can fix the driver.\n");
+	}
 #ifdef CONFIG_X86_IO_APIC
 	if (acpi_ioapic)
 		print_IO_APIC();
diff -puN arch/i386/pci/common.c~bk-pci arch/i386/pci/common.c
--- 25/arch/i386/pci/common.c~bk-pci	2004-10-28 23:17:33.004273272 -0700
+++ 25-akpm/arch/i386/pci/common.c	2004-10-28 23:17:36.447749784 -0700
@@ -23,6 +23,7 @@ extern  void pcibios_sort(void);
 unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
 				PCI_PROBE_MMCONF;
 
+int pci_routeirq;
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
 struct pci_raw_ops *raw_pci_ops;
@@ -227,6 +228,9 @@ char * __devinit  pcibios_setup(char *st
 	} else if (!strcmp(str, "assign-busses")) {
 		pci_probe |= PCI_ASSIGN_ALL_BUSSES;
 		return NULL;
+	} else if (!strcmp(str, "routeirq")) {
+		pci_routeirq = 1;
+		return NULL;
 	}
 	return str;
 }
diff -puN arch/i386/pci/irq.c~bk-pci arch/i386/pci/irq.c
--- 25/arch/i386/pci/irq.c~bk-pci	2004-10-28 23:17:33.005273120 -0700
+++ 25-akpm/arch/i386/pci/irq.c	2004-10-28 23:17:38.638416752 -0700
@@ -460,21 +460,17 @@ static int pirq_bios_set(struct pci_dev 
 
 #endif
 
-
 static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-	struct pci_dev *dev1, *dev2;
+	static struct pci_device_id pirq_440gx[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) },
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) },
+		{ },
+	};
 
 	/* 440GX has a proprietary PIRQ router -- don't use it */
-	dev1 = pci_get_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82443GX_0, NULL);
-	dev2 = pci_get_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82443GX_2, NULL);
-	if ((dev1 != NULL) || (dev2 != NULL)) {
-		pci_dev_put(dev1);
-		pci_dev_put(dev2);
+	if (pci_dev_present(pirq_440gx))
 		return 0;
-	}
 
 	switch(device)
 	{
diff -puN arch/ia64/pci/pci.c~bk-pci arch/ia64/pci/pci.c
--- 25/arch/ia64/pci/pci.c~bk-pci	2004-10-28 23:17:33.006272968 -0700
+++ 25-akpm/arch/ia64/pci/pci.c	2004-10-28 23:17:38.639416600 -0700
@@ -46,6 +46,8 @@
 #define DBG(x...)
 #endif
 
+static int pci_routeirq;
+
 /*
  * Low-level SAL-based PCI configuration access functions. Note that SAL
  * calls are already serialized (via sal_lock), so we don't need another
@@ -141,13 +143,28 @@ extern acpi_status acpi_map_iosapic (acp
 
 	acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL);
 #endif
-	/*
-	 * 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().
-	 */
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-		acpi_pci_irq_enable(dev);
+
+	if (pci_routeirq) {
+		/*
+		 * 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 "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n");
+		printk(KERN_INFO "** was specified.  If this was required to make a driver work,\n");
+		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
+		printk(KERN_INFO "** so I can fix the driver.\n");
+		while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+			acpi_pci_irq_enable(dev);
+	} else {
+		printk(KERN_INFO "** PCI interrupts are no longer routed automatically.  If this\n");
+		printk(KERN_INFO "** causes a device to stop working, it is probably because the\n");
+		printk(KERN_INFO "** driver failed to call pci_enable_device().  As a temporary\n");
+		printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n");
+		printk(KERN_INFO "** behavior.  If this argument makes the device work again,\n");
+		printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n");
+		printk(KERN_INFO "** so I can fix the driver.\n");
+	}
 
 	return 0;
 }
@@ -443,6 +460,8 @@ pcibios_align_resource (void *data, stru
 char * __init
 pcibios_setup (char *str)
 {
+	if (!strcmp(str, "routeirq"))
+		pci_routeirq = 1;
 	return NULL;
 }
 
diff -puN Documentation/kernel-parameters.txt~bk-pci Documentation/kernel-parameters.txt
--- 25/Documentation/kernel-parameters.txt~bk-pci	2004-10-28 23:17:33.008272664 -0700
+++ 25-akpm/Documentation/kernel-parameters.txt	2004-10-28 23:17:33.029269472 -0700
@@ -921,6 +921,10 @@ running once the system is up.
 					enabled.
 		noacpi			[IA-32] Do not use ACPI for IRQ routing
 					or for PCI scanning.
+		routeirq		Do IRQ routing for all PCI devices.
+					This is normally done in pci_enable_device(),
+					so this option is a temporary workaround
+					for broken drivers that don't call it.
 
 		firmware		[ARM] Do not re-enumerate the bus but
 					instead just use the configuration
diff -puN drivers/atm/idt77252.c~bk-pci drivers/atm/idt77252.c
--- 25/drivers/atm/idt77252.c~bk-pci	2004-10-28 23:17:33.009272512 -0700
+++ 25-akpm/drivers/atm/idt77252.c	2004-10-28 23:17:38.642416144 -0700
@@ -3685,9 +3685,9 @@ idt77252_init_one(struct pci_dev *pcidev
 	int i, err;
 
 
-	if (pci_enable_device(pcidev)) {
+	if ((err = pci_enable_device(pcidev))) {
 		printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev));
-		return -ENODEV;
+		return err;
 	}
 
 	if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) {
diff -puN drivers/isdn/tpam/tpam_main.c~bk-pci drivers/isdn/tpam/tpam_main.c
--- 25/drivers/isdn/tpam/tpam_main.c~bk-pci	2004-10-28 23:17:33.011272208 -0700
+++ 25-akpm/drivers/isdn/tpam/tpam_main.c	2004-10-28 23:17:38.642416144 -0700
@@ -88,10 +88,10 @@ static int __devinit tpam_probe(struct p
 	tpam_card *card, *c;
 	int i, err;
 
-	if (pci_enable_device(dev)) {
+	if ((err = pci_enable_device(dev))) {
 		printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
 			pci_name(dev));
-		return -ENODEV;
+		return err;
 	}
 
 	/* allocate memory for the board structure */
diff -puN drivers/misc/ibmasm/module.c~bk-pci drivers/misc/ibmasm/module.c
--- 25/drivers/misc/ibmasm/module.c~bk-pci	2004-10-28 23:17:33.012272056 -0700
+++ 25-akpm/drivers/misc/ibmasm/module.c	2004-10-28 23:17:38.643415992 -0700
@@ -59,13 +59,13 @@
 
 static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	int result = -ENOMEM;
+	int err, result = -ENOMEM;
 	struct service_processor *sp;
 
-	if (pci_enable_device(pdev)) {
+	if ((err = pci_enable_device(pdev))) {
 		printk(KERN_ERR "%s: can't enable PCI device at %s\n",
 			DRIVER_NAME, pci_name(pdev));
-		return -ENODEV;
+		return err;
 	}
 
 	sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
diff -puN drivers/net/tulip/de4x5.c~bk-pci drivers/net/tulip/de4x5.c
--- 25/drivers/net/tulip/de4x5.c~bk-pci	2004-10-28 23:17:33.014271752 -0700
+++ 25-akpm/drivers/net/tulip/de4x5.c	2004-10-28 23:17:38.647415384 -0700
@@ -2242,8 +2242,8 @@ static int __devinit de4x5_pci_probe (st
 		return -ENODEV;
 
 	/* Ok, the device seems to be for us. */
-	if (pci_enable_device (pdev))
-		return -ENODEV;
+	if ((error = pci_enable_device (pdev)))
+		return error;
 
 	if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) {
 		error = -ENOMEM;
diff -puN drivers/pci/pci.c~bk-pci drivers/pci/pci.c
--- 25/drivers/pci/pci.c~bk-pci	2004-10-28 23:17:33.016271448 -0700
+++ 25-akpm/drivers/pci/pci.c	2004-10-28 23:17:38.649415080 -0700
@@ -375,6 +375,16 @@ pci_enable_device(struct pci_dev *dev)
 }
 
 /**
+ * pcibios_disable_device - disable arch specific PCI resources for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables architecture specific PCI resources for the device. This
+ * is the default implementation. Architecture implementations can
+ * override this.
+ */
+void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+
+/**
  * pci_disable_device - Disable PCI device after use
  * @dev: PCI device to be disabled
  *
@@ -394,6 +404,8 @@ pci_disable_device(struct pci_dev *dev)
 		pci_command &= ~PCI_COMMAND_MASTER;
 		pci_write_config_word(dev, PCI_COMMAND, pci_command);
 	}
+
+	pcibios_disable_device(dev);
 }
 
 /**
_
