}
        addr = pci_resource_start(pdev, 0);
        len = pci_resource_len(pdev, 0);
-       ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %x, vend %x/%x "
+       ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x "
                   "driver_data %lx\n", addr, len, pdev->irq, ent->vendor,
                   ent->device, ent->driver_data);
 
         * check 0 irq after we return from chip-specific bus setup, since
         * that can affect this due to setup
         */
-       if (!pdev->irq)
+       if (!dd->ipath_irq)
                ipath_dev_err(dd, "irq is 0, BIOS error?  Interrupts won't "
                              "work\n");
        else {
-               ret = request_irq(pdev->irq, ipath_intr, IRQF_SHARED,
+               ret = request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED,
                                  IPATH_DRV_NAME, dd);
                if (ret) {
                        ipath_dev_err(dd, "Couldn't setup irq handler, "
-                                     "irq=%u: %d\n", pdev->irq, ret);
+                                     "irq=%d: %d\n", dd->ipath_irq, ret);
                        goto bail_iounmap;
                }
        }
         * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
         * for all versions of the driver, if they were allocated
         */
-       if (pdev->irq) {
-               ipath_cdbg(VERBOSE,
-                          "unit %u free_irq of irq %x\n",
-                          dd->ipath_unit, pdev->irq);
-               free_irq(pdev->irq, dd);
+       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);
        } else
                ipath_dbg("irq is 0, not doing free_irq "
                          "for unit %u\n", dd->ipath_unit);
 
 
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/htirq.h>
 
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
        }
 }
 
-static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
-                           int pos)
+static int ipath_ht_intconfig(struct ipath_devdata *dd)
 {
-       u32 int_handler_addr_lower;
-       u32 int_handler_addr_upper;
-       u64 ihandler;
-       u32 intvec;
+       int ret;
 
-       /* 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);
+       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;
+       }
 
-       ihandler = (u64) int_handler_addr_lower |
-               ((u64) int_handler_addr_upper << 32);
+       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;
 
        /*
-        * 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.
+        * 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.
         */
-       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;
+       if (prev_intconfig)
+               ipath_ht_intconfig(dd);
 }
 
 /**
 static int ipath_setup_ht_config(struct ipath_devdata *dd,
                                 struct pci_dev *pdev)
 {
-       int pos, ret = 0;
-       int ihandler = 0;
+       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;
 
        /*
-        * Read the capability info to find the interrupt info, and also
-        * handle clearing CRC errors in linkctrl register if necessary.  We
+        * 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.
         */
                }
                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;
 }
        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
        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
        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