BACKPORT - use old IRQ infrastructure on 2.6.18 and earlier

diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/Kconfig
--- a/drivers/infiniband/hw/ipath/Kconfig	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/Kconfig	Thu Mar 08 14:04:08 2007 -0800
@@ -1,6 +1,6 @@ config INFINIBAND_IPATH
 config INFINIBAND_IPATH
 	tristate "QLogic InfiniPath Driver"
-	depends on (PCI_MSI || HT_IRQ) && 64BIT && INFINIBAND && NET
+	depends on PCI_MSI && 64BIT && INFINIBAND && NET
 	---help---
 	This is a driver for QLogic InfiniPath host channel adapters,
 	including InfiniBand verbs support.  This driver allows these
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/Makefile
--- a/drivers/infiniband/hw/ipath/Makefile	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/Makefile	Thu Mar 08 14:04:08 2007 -0800
@@ -32,7 +32,7 @@ ib_ipath-y := \
 	ipath_verbs_mcast.o \
 	ipath_verbs.o
 
-ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o
+ib_ipath-y += ipath_iba6110.o
 ib_ipath-$(CONFIG_PCI_MSI) += ipath_iba6120.o
 
 ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/ipath_driver.c
--- a/drivers/infiniband/hw/ipath/ipath_driver.c	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c	Thu Mar 08 14:04:08 2007 -0800
@@ -42,6 +42,8 @@
 #include "ipath_verbs.h"
 #include "ipath_common.h"
 
+#define CONFIG_HT_IRQ
+
 static void ipath_update_pio_bufs(struct ipath_devdata *);
 
 const char *ipath_get_unit_name(int unit)
@@ -347,7 +349,7 @@ static int __devinit ipath_init_one(stru
 	}
 	addr = pci_resource_start(pdev, 0);
 	len = pci_resource_len(pdev, 0);
-	ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x "
+	ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %x, vend %x/%x "
 		   "driver_data %lx\n", addr, len, pdev->irq, ent->vendor,
 		   ent->device, ent->driver_data);
 
@@ -530,15 +532,15 @@ static int __devinit ipath_init_one(stru
 	 * check 0 irq after we return from chip-specific bus setup, since
 	 * that can affect this due to setup
 	 */
-	if (!dd->ipath_irq)
+	if (!pdev->irq)
 		ipath_dev_err(dd, "irq is 0, BIOS error?  Interrupts won't "
 			      "work\n");
 	else {
-		ret = request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED,
+		ret = request_irq(pdev->irq, ipath_intr, IRQF_SHARED,
 				  IPATH_DRV_NAME, dd);
 		if (ret) {
 			ipath_dev_err(dd, "Couldn't setup irq handler, "
-				      "irq=%d: %d\n", dd->ipath_irq, ret);
+				      "irq=%d: %d\n", pdev->irq, ret);
 			goto bail_iounmap;
 		}
 	}
@@ -709,10 +711,11 @@ static void __devexit ipath_remove_one(s
 	 * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
 	 * for all versions of the driver, if they were allocated
 	 */
-	if (dd->ipath_irq) {
-		ipath_cdbg(VERBOSE, "unit %u free irq %d\n",
-			   dd->ipath_unit, dd->ipath_irq);
-		dd->ipath_f_free_irq(dd);
+	if (pdev->irq) {
+		ipath_cdbg(VERBOSE,
+			   "unit %u free_irq of irq %x\n",
+			   dd->ipath_unit, pdev->irq);
+		free_irq(pdev->irq, dd);
 	} else
 		ipath_dbg("irq is 0, not doing free_irq "
 			  "for unit %u\n", dd->ipath_unit);
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/ipath_iba6110.c
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c	Thu Mar 08 14:04:08 2007 -0800
@@ -38,7 +38,6 @@
 
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/htirq.h>
 
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
@@ -914,40 +913,49 @@ static void slave_or_pri_blk(struct ipat
 	}
 }
 
-static int ipath_ht_intconfig(struct ipath_devdata *dd)
-{
-	int ret;
-
-	if (dd->ipath_intconfig) {
-		ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig,
-				 dd->ipath_intconfig);	/* interrupt address */
-		ret = 0;
-	} else {
-		ipath_dev_err(dd, "No interrupts enabled, couldn't setup "
-			      "interrupt address\n");
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static void ipath_ht_irq_update(struct pci_dev *dev, int irq,
-				struct ht_irq_msg *msg)
-{
-	struct ipath_devdata *dd = pci_get_drvdata(dev);
-	u64 prev_intconfig = dd->ipath_intconfig;
-
-	dd->ipath_intconfig = msg->address_lo;
-	dd->ipath_intconfig |= ((u64) msg->address_hi) << 32;
-
-	/*
-	 * If the previous value of dd->ipath_intconfig is zero, we're
-	 * getting configured for the first time, and must not program the
-	 * intconfig register here (it will be programmed later, when the
-	 * hardware is ready).  Otherwise, we should.
-	 */
-	if (prev_intconfig)
-		ipath_ht_intconfig(dd);
+static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
+			    int pos)
+{
+	u32 int_handler_addr_lower;
+	u32 int_handler_addr_upper;
+	u64 ihandler;
+	u32 intvec;
+
+	/* use indirection register to get the intr handler */
+	pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10);
+	pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower);
+	pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11);
+	pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper);
+
+	ihandler = (u64) int_handler_addr_lower |
+		((u64) int_handler_addr_upper << 32);
+
+	/*
+	 * kernels with CONFIG_PCI_MSI set the vector in the irq field of
+	 * struct pci_device, so we use that to program the internal
+	 * interrupt register (not config space) with that value. The BIOS
+	 * must still have done the basic MSI setup.
+	 */
+	intvec = pdev->irq;
+	/*
+	 * clear any vector bits there; normally not set but we'll overload
+	 * this for some debug purposes (setting the HTC debug register
+	 * value from software, rather than GPIOs), so it might be set on a
+	 * driver reload.
+	 */
+	ihandler &= ~0xff0000;
+	/* x86 vector goes in intrinfo[23:16] */
+	ihandler |= intvec << 16;
+	ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, "
+		   "interruptconfig %llx\n", int_handler_addr_lower,
+		   int_handler_addr_upper, intvec,
+		   (unsigned long long) ihandler);
+
+	/* can't program yet, so save for interrupt setup */
+	dd->ipath_intconfig = ihandler;
+	/* keep going, so we find link control stuff also */
+
+	return ihandler != 0;
 }
 
 /**
@@ -963,19 +971,12 @@ static int ipath_setup_ht_config(struct 
 static int ipath_setup_ht_config(struct ipath_devdata *dd,
 				 struct pci_dev *pdev)
 {
-	int pos, ret;
-
-	ret = __ht_create_irq(pdev, 0, ipath_ht_irq_update);
-	if (ret < 0) {
-		ipath_dev_err(dd, "Couldn't create interrupt handler: "
-			      "err %d\n", ret);
-		goto bail;
-	}
-	dd->ipath_irq = ret;
-	ret = 0;
-
-	/*
-	 * Handle clearing CRC errors in linkctrl register if necessary.  We
+	int pos, ret = 0;
+	int ihandler = 0;
+
+	/*
+	 * Read the capability info to find the interrupt info, and also
+	 * handle clearing CRC errors in linkctrl register if necessary.  We
 	 * do this early, before we ever enable errors or hardware errors,
 	 * mostly to avoid causing the chip to enter freeze mode.
 	 */
@@ -999,8 +1000,16 @@ static int ipath_setup_ht_config(struct 
 		}
 		if (!(cap_type & 0xE0))
 			slave_or_pri_blk(dd, pdev, pos, cap_type);
+		else if (cap_type == HT_INTR_DISC_CONFIG)
+			ihandler = set_int_handler(dd, pdev, pos);
 	} while ((pos = pci_find_next_capability(pdev, pos,
 						 PCI_CAP_ID_HT)));
+
+	if (!ihandler) {
+		ipath_dev_err(dd, "Couldn't find interrupt handler in "
+			      "config space\n");
+		ret = -ENODEV;
+	}
 
 bail:
 	return ret;
@@ -1351,6 +1360,25 @@ static void ipath_ht_quiet_serdes(struct
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
 }
 
+static int ipath_ht_intconfig(struct ipath_devdata *dd)
+{
+	int ret;
+
+	if (!dd->ipath_intconfig) {
+		ipath_dev_err(dd, "No interrupts enabled, couldn't setup "
+			      "interrupt address\n");
+		ret = 1;
+		goto bail;
+	}
+
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig,
+			 dd->ipath_intconfig);	/* interrupt address */
+	ret = 0;
+
+bail:
+	return ret;
+}
+
 /**
  * ipath_pe_put_tid - write a TID in chip
  * @dd: the infinipath device
@@ -1546,14 +1574,6 @@ static int ipath_ht_get_base_info(struct
 	return 0;
 }
 
-static void ipath_ht_free_irq(struct ipath_devdata *dd)
-{
-	free_irq(dd->ipath_irq, dd);
-	ht_destroy_irq(dd->ipath_irq);
-	dd->ipath_irq = 0;
-	dd->ipath_intconfig = 0;
-}
-
 /**
  * ipath_init_iba6110_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1577,7 +1597,6 @@ void ipath_init_iba6110_funcs(struct ipa
 	dd->ipath_f_cleanup = ipath_setup_ht_cleanup;
 	dd->ipath_f_setextled = ipath_setup_ht_setextled;
 	dd->ipath_f_get_base_info = ipath_ht_get_base_info;
-	dd->ipath_f_free_irq = ipath_ht_free_irq;
 
 	/*
 	 * initialize chip-specific variables
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/ipath_iba6120.c
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c	Thu Mar 08 14:04:08 2007 -0800
@@ -856,7 +856,6 @@ static int ipath_setup_pe_config(struct 
 		ipath_dev_err(dd, "pci_enable_msi failed: %d, "
 			      "interrupts may not work\n", ret);
 	/* continue even if it fails, we may still be OK... */
-	dd->ipath_irq = pdev->irq;
 
 	if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {
 		u16 control;
@@ -1324,12 +1323,6 @@ done:
 	return 0;
 }
 
-static void ipath_pe_free_irq(struct ipath_devdata *dd)
-{
-	free_irq(dd->ipath_irq, dd);
-	dd->ipath_irq = 0;
-}
-
 /**
  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1356,7 +1349,6 @@ void ipath_init_iba6120_funcs(struct ipa
 	dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
 	dd->ipath_f_setextled = ipath_setup_pe_setextled;
 	dd->ipath_f_get_base_info = ipath_pe_get_base_info;
-	dd->ipath_f_free_irq = ipath_pe_free_irq;
 
 	/* initialize chip-specific variables */
 	dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/ipath_intr.c
--- a/drivers/infiniband/hw/ipath/ipath_intr.c	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c	Thu Mar 08 14:04:08 2007 -0800
@@ -732,14 +732,14 @@ static void ipath_bad_intr(struct ipath_
 			 * linuxbios development work, and it may happen in
 			 * the future again.
 			 */
-			if (dd->pcidev && dd->ipath_irq) {
+			if (dd->pcidev && dd->pcidev->irq) {
 				ipath_dev_err(dd, "Now %u unexpected "
 					      "interrupts, unregistering "
 					      "interrupt handler\n",
 					      *unexpectp);
-				ipath_dbg("free_irq of irq %d\n",
-					  dd->ipath_irq);
-				dd->ipath_f_free_irq(dd);
+				ipath_dbg("free_irq of irq %x\n",
+					  dd->pcidev->irq);
+				free_irq(dd->pcidev->irq, dd);
 			}
 		}
 		if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
@@ -775,7 +775,7 @@ static void ipath_bad_regread(struct ipa
 		if (allbits == 2) {
 			ipath_dev_err(dd, "Still bad interrupt status, "
 				      "unregistering interrupt\n");
-			dd->ipath_f_free_irq(dd);
+			free_irq(dd->pcidev->irq, dd);
 		} else if (allbits > 2) {
 			if ((allbits % 10000) == 0)
 				printk(".");
diff -r 0a8c1ca4ad6d drivers/infiniband/hw/ipath/ipath_kernel.h
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h	Thu Mar 08 14:02:44 2007 -0800
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h	Thu Mar 08 14:04:08 2007 -0800
@@ -213,8 +213,6 @@ struct ipath_devdata {
 	void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64);
 	/* fill out chip-specific fields */
 	int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
-	/* free irq */
-	void (*ipath_f_free_irq)(struct ipath_devdata *);
 	struct ipath_ibdev *verbs_dev;
 	struct timer_list verbs_timer;
 	/* total dwords sent (summed from counter) */
@@ -332,8 +330,6 @@ struct ipath_devdata {
 	/* so we can rewrite it after a chip reset */
 	u32 ipath_pcibar1;
 
-	/* interrupt number */
-	int ipath_irq;
 	/* HT/PCI Vendor ID (here for NodeInfo) */
 	u16 ipath_vendorid;
 	/* HT/PCI Device ID (here for NodeInfo) */
