Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
[sfrench/cifs-2.6.git] / drivers / infiniband / hw / ipath / ipath_iba6120.c
index 6af89683f7100a6f79067db031703b88c038d326..1b9c30857754e506495cf6291bae5ff938d8437b 100644 (file)
@@ -43,6 +43,8 @@
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
 
+static void ipath_setup_pe_setextled(struct ipath_devdata *, u64, u64);
+
 /*
  * This file contains all the chip-specific register information and
  * access functions for the QLogic InfiniPath PCI-Express chip.
@@ -207,8 +209,8 @@ static const struct ipath_kregs ipath_pe_kregs = {
        .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
 
        /*
-        * 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),
@@ -321,6 +323,12 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
        INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
 };
 
+#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
+                       INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
+                       << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
+
+static int ipath_pe_txe_recover(struct ipath_devdata *);
+
 /**
  * ipath_pe_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
@@ -394,32 +402,21 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                 * occur if a processor speculative read is done to the PIO
                 * buffer while we are sending a packet, for example.
                 */
-               if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
-                              INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
-                             << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
-                       ipath_stats.sps_txeparity++;
-                       ipath_dbg("Recovering from TXE parity error (%llu), "
-                                 "hwerrstatus=%llx\n",
-                                 (unsigned long long) ipath_stats.sps_txeparity,
-                                 (unsigned long long) hwerrs);
-                       ipath_disarm_senderrbufs(dd);
-                       hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
-                                    INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
-                                   << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
-                       if (!hwerrs) { /* else leave in freeze mode */
-                               ipath_write_kreg(dd,
-                                                dd->ipath_kregs->kr_control,
-                                                dd->ipath_control);
-                           return;
-                       }
-               }
+               if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
+                       hwerrs &= ~TXE_PIO_PARITY;
                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
+                        * Force link down, so switch knows, and
+                        * LEDs are turned off
                         */
                        if (dd->ipath_flags & IPATH_INITTED) {
+                               ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
+                               ipath_setup_pe_setextled(dd,
+                                       INFINIPATH_IBCS_L_STATE_DOWN,
+                                       INFINIPATH_IBCS_LT_STATE_DISABLED);
                                ipath_dev_err(dd, "Fatal Hardware Error (freeze "
                                              "mode), no longer usable, SN %.16s\n",
                                                  dd->ipath_serial);
@@ -493,7 +490,8 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                                 dd->ipath_hwerrmask);
        }
 
-       ipath_dev_err(dd, "%s hardware error\n", msg);
+       if (*msg)
+               ipath_dev_err(dd, "%s hardware error\n", msg);
        if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
                /*
                 * for /sys status file ; if no trailing } is copied, we'll
@@ -581,6 +579,8 @@ static void ipath_pe_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_FOUND)
+               ipath_dbg("MemBIST corrected\n");
 
        val = ~0ULL;    /* barring bugs, all hwerrors become interrupts, */
 
@@ -602,7 +602,7 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
  */
 static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
 {
-       u64 val, tmp, config1, prev_val;
+       u64 val, config1, prev_val;
        int ret = 0;
 
        ipath_dbg("Trying to bringup serdes\n");
@@ -633,7 +633,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
                | INFINIPATH_SERDC0_L1PWR_DN;
        ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
        /* be sure chip saw it */
-       tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        udelay(5);              /* need pll reset set at least for a bit */
        /*
         * after PLL is reset, set the per-lane Resets and TxIdle and
@@ -647,7 +647,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
                   "and txidle (%llx)\n", (unsigned long long) val);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
        /* be sure chip saw it */
-       tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
        /* need PLL reset clear for at least 11 usec before lane
         * resets cleared; give it a few more to be sure */
        udelay(15);
@@ -851,12 +851,12 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
        int pos, ret;
 
        dd->ipath_msi_lo = 0;   /* used as a flag during reset processing */
-       dd->ipath_irq = pdev->irq;
        ret = pci_enable_msi(dd->pcidev);
        if (ret)
                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;
@@ -1293,7 +1293,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
  * @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_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
 {
@@ -1330,6 +1330,35 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
        dd->ipath_irq = 0;
 }
 
+/*
+ * On platforms using this chip, and not having ordered WC stores, we
+ * can get TXE parity errors due to speculative reads to the PIO buffers,
+ * and this, due to a chip bug can result in (many) false parity error
+ * reports.  So it's a debug print on those, and an info print on systems
+ * where the speculative reads don't occur.
+ * Because we can get lots of false errors, we have no upper limit
+ * on recovery attempts on those platforms.
+ */
+static int ipath_pe_txe_recover(struct ipath_devdata *dd)
+{
+       if (ipath_unordered_wc())
+               ipath_dbg("Recovering from TXE PIO parity error\n");
+       else {
+               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_iba6120_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device