]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_iba6110.c
IB/ipath: Fix driver crash (in interrupt or during unload) after chip reset
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_iba6110.c
index bf2455a6d56238024136ba00655df965900e3561..8e0794d316fb69a9fbe7886447af75ef8c92c821 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/htirq.h>
 
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
@@ -207,8 +208,8 @@ static const struct ipath_kregs ipath_ht_kregs = {
        .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
        .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
        /*
-        * These should not be used directly via ipath_read_kreg64(),
-        * use them with ipath_read_kreg64_port(),
+        * These should not be used directly via ipath_write_kreg64(),
+        * use them with ipath_write_kreg64_port(),
         */
        .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
        .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0)
@@ -252,8 +253,8 @@ static const struct ipath_cregs ipath_ht_cregs = {
 };
 
 /* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK 0x1FF
-#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF
+#define INFINIPATH_I_RCVURG_MASK ((1U<<9)-1)
+#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<9)-1)
 
 /* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
 #define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
@@ -283,6 +284,14 @@ static const struct ipath_cregs ipath_ht_cregs = {
 #define INFINIPATH_EXTS_MEMBIST_ENDTEST     0x0000000000004000
 #define INFINIPATH_EXTS_MEMBIST_CORRECT     0x0000000000008000
 
+
+/* TID entries (memory), HT-only */
+#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL        /* 40 bits valid */
+#define INFINIPATH_RT_VALID 0x8000000000000000ULL
+#define INFINIPATH_RT_ADDR_SHIFT 0
+#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
+#define INFINIPATH_RT_BUFSIZE_SHIFT 48
+
 /*
  * masks and bits that are different in different chips, or present only
  * in one
@@ -338,7 +347,7 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
        if (crcbits) {
                u16 ctrl0, ctrl1;
                snprintf(bitsmsg, sizeof bitsmsg,
-                        "[HT%s lane %s CRC (%llx); ignore till reload]",
+                        "[HT%s lane %s CRC (%llx); powercycle to completely clear]",
                         !(crcbits & _IPATH_HTLINK1_CRCBITS) ?
                         "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
                                    ? "1 (B)" : "0+1 (A+B)"),
@@ -389,17 +398,36 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
                                     _IPATH_HTLINK1_CRCBITS)));
 }
 
+/* 6110 specific hardware errors... */
+static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = {
+       INFINIPATH_HWE_MSG(HTCBUSIREQPARITYERR, "HTC Ireq Parity"),
+       INFINIPATH_HWE_MSG(HTCBUSTREQPARITYERR, "HTC Treq Parity"),
+       INFINIPATH_HWE_MSG(HTCBUSTRESPPARITYERR, "HTC Tresp Parity"),
+       INFINIPATH_HWE_MSG(HTCMISCERR5, "HT core Misc5"),
+       INFINIPATH_HWE_MSG(HTCMISCERR6, "HT core Misc6"),
+       INFINIPATH_HWE_MSG(HTCMISCERR7, "HT core Misc7"),
+       INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
+       INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
+};
+
+#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
+                       INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
+                       << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
+#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \
+                         << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)
+
+static int ipath_ht_txe_recover(struct ipath_devdata *);
+
 /**
- * ipath_ht_handle_hwerrors - display hardware errors
+ * ipath_ht_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
  * @msg: the output buffer
  * @msgl: the size of the output buffer
  *
- * Use same msg buffer as regular errors to avoid
- * excessive stack use.  Most hardware errors are catastrophic, but for
- * right now, we'll print them and continue.
- * We reuse the same message buffer as ipath_handle_errors() to avoid
- * excessive stack usage.
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use.  Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue.  We reuse the same message buffer as
+ * ipath_handle_errors() to avoid excessive stack usage.
  */
 static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                                     size_t msgl)
@@ -438,46 +466,39 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
 
        /*
         * make sure we get this much out, unless told to be quiet,
+        * it's a parity error we may recover from,
         * or it's occurred within the last 5 seconds
         */
-       if ((hwerrs & ~dd->ipath_lasthwerror) ||
-           (ipath_debug & __IPATH_VERBDBG))
+       if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY |
+               RXE_EAGER_PARITY)) ||
+               (ipath_debug & __IPATH_VERBDBG))
                dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
                         "(cleared)\n", (unsigned long long) hwerrs);
        dd->ipath_lasthwerror |= hwerrs;
 
-       if (hwerrs & ~infinipath_hwe_bitsextant)
+       if (hwerrs & ~dd->ipath_hwe_bitsextant)
                ipath_dev_err(dd, "hwerror interrupt with unknown errors "
                              "%llx set\n", (unsigned long long)
-                             (hwerrs & ~infinipath_hwe_bitsextant));
+                             (hwerrs & ~dd->ipath_hwe_bitsextant));
 
        ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-       if (ctrl & INFINIPATH_C_FREEZEMODE) {
-               if (hwerrs) {
-                       /*
-                        * if any set that we aren't ignoring; only
-                        * make the complaint once, in case it's stuck
-                        * or recurring, and we get here multiple
-                        * times.
-                        */
-                       if (dd->ipath_flags & IPATH_INITTED) {
-                               ipath_dev_err(dd, "Fatal Hardware Error (freeze "
-                                             "mode), no longer usable, SN %.16s\n",
-                                                 dd->ipath_serial);
-                               isfatal = 1;
-                       }
-                       *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-                       /* mark as having had error */
-                       *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-                       /*
-                        * mark as not usable, at a minimum until driver
-                        * is reloaded, probably until reboot, since no
-                        * other reset is possible.
-                        */
-                       dd->ipath_flags &= ~IPATH_INITTED;
-               } else {
-                       ipath_dbg("Clearing freezemode on ignored hardware "
-                                 "error\n");
+       if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
+               /*
+                * parity errors in send memory are recoverable,
+                * just cancel the send (if indicated in * sendbuffererror),
+                * count the occurrence, unfreeze (if no other handled
+                * hardware error bits are set), and continue. They can
+                * occur if a processor speculative read is done to the PIO
+                * buffer while we are sending a packet, for example.
+                */
+               if ((hwerrs & TXE_PIO_PARITY) && ipath_ht_txe_recover(dd))
+                       hwerrs &= ~TXE_PIO_PARITY;
+               if (hwerrs & RXE_EAGER_PARITY)
+                       ipath_dev_err(dd, "RXE parity, Eager TID error is not "
+                               "recoverable\n");
+               if (!hwerrs) {
+                       ipath_dbg("Clearing freezemode on ignored or "
+                                 "recovered hardware error\n");
                        ctrl &= ~INFINIPATH_C_FREEZEMODE;
                        ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
                                         ctrl);
@@ -499,44 +520,16 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                         bits);
                strlcat(msg, bitsmsg, msgl);
        }
-       if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
-                     << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
-               bits = (u32) ((hwerrs >>
-                              INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
-                             INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
-               snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
-                        bits);
-               strlcat(msg, bitsmsg, msgl);
-       }
-       if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
-                     << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
-               bits = (u32) ((hwerrs >>
-                              INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
-                             INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
-               snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
-                        bits);
-               strlcat(msg, bitsmsg, msgl);
-       }
-       if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
-               strlcat(msg, "[IB2IPATH Parity]", msgl);
-       if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
-               strlcat(msg, "[IPATH2IB Parity]", msgl);
-       if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)
-               strlcat(msg, "[HTC Ireq Parity]", msgl);
-       if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)
-               strlcat(msg, "[HTC Treq Parity]", msgl);
-       if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)
-               strlcat(msg, "[HTC Tresp Parity]", msgl);
+
+       ipath_format_hwerrors(hwerrs,
+                             ipath_6110_hwerror_msgs,
+                             sizeof(ipath_6110_hwerror_msgs) /
+                             sizeof(ipath_6110_hwerror_msgs[0]),
+                             msg, msgl);
 
        if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
                hwerr_crcbits(dd, hwerrs, msg, msgl);
 
-       if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)
-               strlcat(msg, "[HT core Misc5]", msgl);
-       if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)
-               strlcat(msg, "[HT core Misc6]", msgl);
-       if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)
-               strlcat(msg, "[HT core Misc7]", msgl);
        if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
                strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
                        msgl);
@@ -573,12 +566,32 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                                 dd->ipath_hwerrmask);
        }
 
-       if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
-               strlcat(msg, "[Rx Dsync]", msgl);
-       if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
-               strlcat(msg, "[SerDes PLL]", msgl);
-
-       ipath_dev_err(dd, "%s hardware error\n", msg);
+       if (hwerrs) {
+               /*
+                * if any set that we aren't ignoring; only
+                * make the complaint once, in case it's stuck
+                * or recurring, and we get here multiple
+                * times.
+                */
+               ipath_dev_err(dd, "%s hardware error\n", msg);
+               if (dd->ipath_flags & IPATH_INITTED) {
+                       ipath_dev_err(dd, "Fatal Hardware Error (freeze "
+                                         "mode), no longer usable, SN %.16s\n",
+                                         dd->ipath_serial);
+                       isfatal = 1;
+               }
+               *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
+               /* mark as having had error */
+               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
+               /*
+                * mark as not usable, at a minimum until driver
+                * is reloaded, probably until reboot, since no
+                * other reset is possible.
+                */
+               dd->ipath_flags &= ~IPATH_INITTED;
+       }
+       else
+               *msg = 0; /* recovered from all of them */
        if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
                /*
                 * for status file; if no trailing brace is copied,
@@ -649,7 +662,8 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
        if (n)
                snprintf(name, namelen, "%s", n);
 
-       if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
+       if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
+               dd->ipath_minrev > 3)) {
                /*
                 * This version of the driver only supports Rev 3.2 and 3.3
                 */
@@ -742,7 +756,6 @@ static int ipath_setup_ht_reset(struct ipath_devdata *dd)
        return 0;
 }
 
-#define HT_CAPABILITY_ID   0x08        /* HT capabilities not defined in kernel */
 #define HT_INTR_DISC_CONFIG  0x80      /* HT interrupt and discovery cap */
 #define HT_INTR_REG_INDEX    2 /* intconfig requires indirect accesses */
 
@@ -906,49 +919,40 @@ static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev,
        }
 }
 
-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);
 }
 
 /**
@@ -964,16 +968,23 @@ static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
 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.
         */
-       pos = pci_find_capability(pdev, HT_CAPABILITY_ID);
+       pos = pci_find_capability(pdev, PCI_CAP_ID_HT);
        if (!pos) {
                ipath_dev_err(dd, "Couldn't find HyperTransport "
                              "capability; no interrupts\n");
@@ -993,16 +1004,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
                }
                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,
-                                                HT_CAPABILITY_ID)));
-
-       if (!ihandler) {
-               ipath_dev_err(dd, "Couldn't find interrupt handler in "
-                             "config space\n");
-               ret = -ENODEV;
-       }
+                                                PCI_CAP_ID_HT)));
 
 bail:
        return ret;
@@ -1081,21 +1084,21 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
        ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
 }
 
-static void ipath_init_ht_variables(void)
+static void ipath_init_ht_variables(struct ipath_devdata *dd)
 {
-       ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
-       ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
-       ipath_gpio_sda = IPATH_GPIO_SDA;
-       ipath_gpio_scl = IPATH_GPIO_SCL;
+       dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+       dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+       dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+       dd->ipath_gpio_scl = IPATH_GPIO_SCL;
 
-       infinipath_i_bitsextant =
+       dd->ipath_i_bitsextant =
                (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
                (INFINIPATH_I_RCVAVAIL_MASK <<
                 INFINIPATH_I_RCVAVAIL_SHIFT) |
                INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
                INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
 
-       infinipath_e_bitsextant =
+       dd->ipath_e_bitsextant =
                INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
                INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
                INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
@@ -1113,7 +1116,7 @@ static void ipath_init_ht_variables(void)
                INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
                INFINIPATH_E_HARDWARE;
 
-       infinipath_hwe_bitsextant =
+       dd->ipath_hwe_bitsextant =
                (INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
                 INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
                (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
@@ -1142,8 +1145,8 @@ static void ipath_init_ht_variables(void)
                INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
                INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
 
-       infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
-       infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+       dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+       dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
 }
 
 /**
@@ -1165,6 +1168,8 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
 
        if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
                ipath_dev_err(dd, "MemBIST did not complete!\n");
+       if (extsval & INFINIPATH_EXTS_MEMBIST_CORRECT)
+               ipath_dbg("MemBIST corrected\n");
 
        ipath_check_htlink(dd);
 
@@ -1353,25 +1358,6 @@ static void ipath_ht_quiet_serdes(struct ipath_devdata *dd)
        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
@@ -1387,6 +1373,9 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
                             u64 __iomem *tidptr, u32 type,
                             unsigned long pa)
 {
+       if (!dd->ipath_kregbase)
+               return;
+
        if (pa != dd->ipath_tidinvalid) {
                if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {
                        dev_info(&dd->pcidev->dev,
@@ -1403,10 +1392,10 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
                        pa |= lenvalid | INFINIPATH_RT_VALID;
                }
        }
-       if (dd->ipath_kregbase)
-               writeq(pa, tidptr);
+       writeq(pa, tidptr);
 }
 
+
 /**
  * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager
  * @dd: the infinipath device
@@ -1468,7 +1457,7 @@ static void ipath_ht_tidtemplate(struct ipath_devdata *dd)
 static int ipath_ht_early_init(struct ipath_devdata *dd)
 {
        u32 __iomem *piobuf;
-       u32 pioincr, val32, egrsize;
+       u32 pioincr, val32;
        int i;
 
        /*
@@ -1488,7 +1477,6 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
         * errors interrupts if we ever see one).
         */
        dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;
-       egrsize = dd->ipath_rcvegrbufsize;
 
        /*
         * the min() check here is currently a nop, but it may not
@@ -1537,7 +1525,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
                         INFINIPATH_S_ABORT);
 
        ipath_get_eeprom_info(dd);
-       if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
+       if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
                dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
                /*
                 * Later production QHT7040 has same changes as QHT7140, so
@@ -1550,13 +1538,31 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
        return 0;
 }
 
+
+static int ipath_ht_txe_recover(struct ipath_devdata *dd)
+{
+       int cnt = ++ipath_stats.sps_txeparity;
+       if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
+               if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
+                       ipath_dev_err(dd,
+                               "Too many attempts to recover from "
+                               "TXE parity, giving up\n");
+               return 0;
+       }
+       dev_info(&dd->pcidev->dev,
+               "Recovering from TXE PIO parity error\n");
+       ipath_disarm_senderrbufs(dd, 1);
+       return 1;
+}
+
+
 /**
  * ipath_init_ht_get_base_info - set chip-specific flags for user code
  * @dd: the infinipath device
  * @kbase: ipath_base_info pointer
  *
  * We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithims.
+ * HyperTransport can affect some user packet algorithms.
  */
 static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
 {
@@ -1568,6 +1574,14 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
        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
@@ -1591,6 +1605,7 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
        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
@@ -1608,5 +1623,5 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
         * do very early init that is needed before ipath_f_bus is
         * called
         */
-       ipath_init_ht_variables();
+       ipath_init_ht_variables(dd);
 }