Pull ia64-clocksource into release branch
[pandora-kernel.git] / drivers / infiniband / hw / ipath / ipath_intr.c
index f8aac8e..1fd91c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
  * If rewrite is true, and bits are set in the sendbufferror registers,
  * we'll write to the buffer, for error recovery on parity errors.
  */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
@@ -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)
@@ -932,6 +1009,9 @@ irqreturn_t ipath_intr(int irq, void *data)
 
        ipath_stats.sps_ints++;
 
+       if (dd->ipath_int_counter != (u32) -1)
+               dd->ipath_int_counter++;
+
        if (!(dd->ipath_flags & IPATH_PRESENT)) {
                /*
                 * This return value is not great, but we do not want the