]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
IB/ipath: Be more cautious about coming out of freeze mode
authorDave Olson <dave.olson@qlogic.com>
Fri, 6 Jul 2007 19:48:33 +0000 (12:48 -0700)
committerRoland Dreier <rolandd@cisco.com>
Tue, 10 Jul 2007 03:12:26 +0000 (20:12 -0700)
We are more careful to be sure that we don't lose information about
changes that occurred while we were in freeze mode, when the chip will
not notify us, and try to avoid false error interrupts while doing
cleanup.  Put all of this logic in a new function ipath_clear_freeze().

Signed-off-by: Dave Olson <dave.olson@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_iba6110.c
drivers/infiniband/hw/ipath/ipath_iba6120.c
drivers/infiniband/hw/ipath/ipath_intr.c
drivers/infiniband/hw/ipath/ipath_kernel.h

index 87b18e928c79982b591cd6d428bbbf0dd2693bca..fdfa95d0dd72b4d4fd1c07d4eedc9af0987af94b 100644 (file)
@@ -509,16 +509,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                if (!hwerrs) {
                        ipath_dbg("Clearing freezemode on ignored or "
                                  "recovered hardware error\n");
-                       /*
-                        * clear all sends, becauase they have may been
-                        * completed by usercode while in freeze mode, and
-                        * therefore would not be sent, and eventually
-                        * might cause the process to run out of bufs
-                        */
-                       ipath_cancel_sends(dd);
-                       ctrl &= ~INFINIPATH_C_FREEZEMODE;
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                                        ctrl);
+                       ipath_clear_freeze(dd);
                }
        }
 
index e67e4a89fcc4fd46bddd0ee3cd2af6888120e023..9868ccda5f26769b66dc76593ef107a53a5630f2 100644 (file)
@@ -435,16 +435,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
                        freeze_cnt++;
                        ipath_dbg("Clearing freezemode on ignored or recovered "
                                  "hardware error (%u)\n", freeze_cnt);
-                       /*
-                        * clear all sends, becauase they have may been
-                        * completed by usercode while in freeze mode, and
-                        * therefore would not be sent, and eventually
-                        * might cause the process to run out of bufs
-                        */
-                       ipath_cancel_sends(dd);
-                       ctrl &= ~INFINIPATH_C_FREEZEMODE;
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                                        dd->ipath_control);
+                       ipath_clear_freeze(dd);
                }
        }
 
index e86a23a05919ba2baa97861e23c3b0367ba10971..ce490235c24fafc154cb6b3aa9ac93089dd07db5 100644 (file)
@@ -132,6 +132,17 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
         INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
         INFINIPATH_E_INVALIDADDR)
 
+/*
+ * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
+ * errors not related to freeze and cancelling buffers.  Can't ignore
+ * armlaunch because could get more while still cleaning up, and need
+ * to cancel those as they happen.
+ */
+#define E_SPKT_ERRS_IGNORE \
+        (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
+        INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SMINPKTLEN | \
+        INFINIPATH_E_SPKTLEN)
+
 /*
  * these are errors that can occur when the link changes state while
  * a packet is being sent or received.  This doesn't cover things
@@ -760,6 +771,72 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
        return chkerrpkts;
 }
 
+
+/*
+ * try to cleanup as much as possible for anything that might have gone
+ * wrong while in freeze mode, such as pio buffers being written by user
+ * processes (causing armlaunch), send errors due to going into freeze mode,
+ * etc., and try to avoid causing extra interrupts while doing so.
+ * Forcibly update the in-memory pioavail register copies after cleanup
+ * because the chip won't do it for anything changing while in freeze mode
+ * (we don't want to wait for the next pio buffer state change).
+ * Make sure that we don't lose any important interrupts by using the chip
+ * feature that says that writing 0 to a bit in *clear that is set in
+ * *status will cause an interrupt to be generated again (if allowed by
+ * the *mask value).
+ */
+void ipath_clear_freeze(struct ipath_devdata *dd)
+{
+       int i, im;
+       __le64 val;
+
+       /* disable error interrupts, to avoid confusion */
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
+
+       /*
+        * clear all sends, because they have may been
+        * completed by usercode while in freeze mode, and
+        * therefore would not be sent, and eventually
+        * might cause the process to run out of bufs
+        */
+       ipath_cancel_sends(dd);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+                        dd->ipath_control);
+
+       /* ensure pio avail updates continue */
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+                dd->ipath_sendctrl & ~IPATH_S_PIOBUFAVAILUPD);
+       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+                dd->ipath_sendctrl);
+
+       /*
+        * We just enabled pioavailupdate, so dma copy is almost certainly
+        * not yet right, so read the registers directly.  Similar to init
+        */
+       for (i = 0; i < dd->ipath_pioavregs; i++) {
+               /* deal with 6110 chip bug */
+               im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
+               val = ipath_read_kreg64(dd, 0x1000+(im*sizeof(u64)));
+               dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
+                       = le64_to_cpu(val);
+       }
+
+       /*
+        * force new interrupt if any hwerr, error or interrupt bits are
+        * still set, and clear "safe" send packet errors related to freeze
+        * and cancelling sends.  Re-enable error interrupts before possible
+        * force of re-interrupt on pending interrupts.
+        */
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
+               E_SPKT_ERRS_IGNORE);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+               ~dd->ipath_maskederrs);
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
+}
+
+
 /* this is separate to allow for better optimization of ipath_intr() */
 
 static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
index f1f812759ee323a335cbbdb9a2d0218175dfbb8a..8bad3e3c555027796e4061d443a937b07788acb5 100644 (file)
@@ -645,6 +645,7 @@ int ipath_enable_wc(struct ipath_devdata *dd);
 void ipath_disable_wc(struct ipath_devdata *dd);
 int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp);
 void ipath_shutdown_device(struct ipath_devdata *);
+void ipath_clear_freeze(struct ipath_devdata *);
 
 struct file_operations;
 int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,