Pull ia64-clocksource into release branch
[pandora-kernel.git] / drivers / infiniband / hw / ipath / ipath_intr.c
index 72b9e27..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
 #include "ipath_verbs.h"
 #include "ipath_common.h"
 
+/*
+ * clear (write) a pio buffer, to clear a parity error.   This routine
+ * should only be called when in freeze mode, and the buffer should be
+ * canceled afterwards.
+ */
+static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
+{
+       u32 __iomem *pbuf;
+       u32 dwcnt; /* dword count to write */
+       if (pnum < dd->ipath_piobcnt2k) {
+               pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum *
+                       dd->ipath_palign);
+               dwcnt = dd->ipath_piosize2k >> 2;
+       }
+       else {
+               pbuf = (u32 __iomem *) (dd->ipath_pio4kbase +
+                       (pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign);
+               dwcnt = dd->ipath_piosize4k >> 2;
+       }
+       dev_info(&dd->pcidev->dev,
+               "Rewrite PIO buffer %u, to recover from parity error\n",
+               pnum);
+       *pbuf = dwcnt+1; /* no flush required, since already in freeze */
+       while(--dwcnt)
+               *pbuf++ = 0;
+}
+
 /*
  * Called when we might have an error that is specific to a particular
  * PIO buffer, and may need to cancel that buffer, so it can be re-used.
+ * 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)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
@@ -64,7 +93,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
 
        if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
                int i;
-               if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG)) {
+               if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) &&
+                       dd->ipath_lastcancel > jiffies) {
                        __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
                                          "SendbufErrs %lx %lx", sbuf[0],
                                          sbuf[1]);
@@ -74,9 +104,13 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
                }
 
                for (i = 0; i < piobcnt; i++)
-                       if (test_bit(i, sbuf))
+                       if (test_bit(i, sbuf)) {
+                               if (rewrite)
+                                       ipath_clrpiobuf(dd, i);
                                ipath_disarm_piobufs(dd, i, 1);
-               dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
+                       }
+               /* ignore armlaunch errs for a bit */
+               dd->ipath_lastcancel = jiffies+3;
        }
 }
 
@@ -98,6 +132,17 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
         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
@@ -114,7 +159,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
 {
        u64 ignore_this_time = 0;
 
-       ipath_disarm_senderrbufs(dd);
+       ipath_disarm_senderrbufs(dd, 0);
        if ((errs & E_SUM_LINK_PKTERRS) &&
            !(dd->ipath_flags & IPATH_LINKACTIVE)) {
                /*
@@ -258,12 +303,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                 * Flush all queued sends when link went to DOWN or INIT,
                 * to be sure that they don't block SMA and other MAD packets
                 */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                INFINIPATH_S_ABORT);
-               ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
-                                                       (unsigned)(dd->ipath_piobcnt2k +
-                                       dd->ipath_piobcnt4k) -
-                                       dd->ipath_lastport_piobuf);
+               ipath_cancel_sends(dd);
        }
        else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
            lstate == IPATH_IBSTATE_ACTIVE) {
@@ -403,10 +443,13 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
         * happens so often we never want to count it.
         */
        if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
-               ipath_decode_err(msg, sizeof msg, dd->ipath_lasterror &
-                                ~INFINIPATH_E_IBSTATUSCHANGED);
+               int iserr;
+               iserr = ipath_decode_err(msg, sizeof msg,
+                               dd->ipath_lasterror &
+                               ~INFINIPATH_E_IBSTATUSCHANGED);
                if (dd->ipath_lasterror &
-                   ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
+                       ~(INFINIPATH_E_RRCVEGRFULL |
+                       INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
                        ipath_dev_err(dd, "Suppressed %u messages for "
                                      "fast-repeating errors (%s) (%llx)\n",
                                      supp_msgs, msg,
@@ -420,8 +463,13 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
                         * them. So only complain about these at debug
                         * level.
                         */
-                       ipath_dbg("Suppressed %u messages for %s\n",
-                                 supp_msgs, msg);
+                       if (iserr)
+                               ipath_dbg("Suppressed %u messages for %s\n",
+                                         supp_msgs, msg);
+                       else
+                               ipath_cdbg(ERRPKT,
+                                       "Suppressed %u messages for %s\n",
+                                         supp_msgs, msg);
                }
        }
 }
@@ -462,9 +510,10 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 {
        char msg[512];
        u64 ignore_this_time = 0;
-       int i;
+       int i, iserr = 0;
        int chkerrpkts = 0, noprint = 0;
        unsigned supp_msgs;
+       int log_idx;
 
        supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
 
@@ -478,6 +527,13 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
        if (errs & INFINIPATH_E_HARDWARE) {
                /* reuse same msg buf */
                dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
+       } else {
+               u64 mask;
+               for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx) {
+                       mask = dd->ipath_eep_st_masks[log_idx].errs_to_log;
+                       if (errs & mask)
+                               ipath_inc_eeprom_err(dd, log_idx, 1);
+               }
        }
 
        if (!noprint && (errs & ~dd->ipath_e_bitsextant))
@@ -502,6 +558,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
        }
 
        if (supp_msgs == 250000) {
+               int s_iserr;
                /*
                 * It's not entirely reasonable assuming that the errors set
                 * in the last clear period are all responsible for the
@@ -511,17 +568,17 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
                                 ~dd->ipath_maskederrs);
-               ipath_decode_err(msg, sizeof msg,
+               s_iserr = ipath_decode_err(msg, sizeof msg,
                                 (dd->ipath_maskederrs & ~dd->
                                  ipath_ignorederrs));
 
                if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
-                   ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
-                       ipath_dev_err(dd, "Disabling error(s) %llx because "
-                                     "occurring too frequently (%s)\n",
-                                     (unsigned long long)
-                                     (dd->ipath_maskederrs &
-                                      ~dd->ipath_ignorederrs), msg);
+                       ~(INFINIPATH_E_RRCVEGRFULL |
+                       INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
+                       ipath_dev_err(dd, "Temporarily disabling "
+                           "error(s) %llx reporting; too frequent (%s)\n",
+                               (unsigned long long) (dd->ipath_maskederrs &
+                               ~dd->ipath_ignorederrs), msg);
                else {
                        /*
                         * rcvegrfull and rcvhdrqfull are "normal",
@@ -530,8 +587,15 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                         * processing them.  So only complain about
                         * these at debug level.
                         */
-                       ipath_dbg("Disabling frequent queue full errors "
-                                 "(%s)\n", msg);
+                       if (s_iserr)
+                               ipath_dbg("Temporarily disabling reporting "
+                                   "too frequent queue full errors (%s)\n",
+                                   msg);
+                       else
+                               ipath_cdbg(ERRPKT,
+                                   "Temporarily disabling reporting too"
+                                   " frequent packet errors (%s)\n",
+                                   msg);
                }
 
                /*
@@ -589,6 +653,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                ipath_stats.sps_crcerrs++;
                chkerrpkts = 1;
        }
+       iserr = errs & ~(E_SUM_PKTERRS | INFINIPATH_E_PKTERRS);
+
 
        /*
         * We don't want to print these two as they happen, or we can make
@@ -625,6 +691,17 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                                        chkerrpkts = 1;
                                dd->ipath_lastrcvhdrqtails[i] = tl;
                                pd->port_hdrqfull++;
+                               if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
+                                            &pd->port_flag)) {
+                                       clear_bit(
+                                         IPATH_PORT_WAITING_OVERFLOW,
+                                         &pd->port_flag);
+                                       set_bit(
+                                         IPATH_PORT_WAITING_OVERFLOW,
+                                         &pd->int_flag);
+                                       wake_up_interruptible(
+                                         &pd->port_wait);
+                               }
                        }
                }
        }
@@ -677,8 +754,13 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                *dd->ipath_statusp &= ~IPATH_STATUS_IB_CONF;
        }
 
-       if (!noprint && *msg)
-               ipath_dev_err(dd, "%s error\n", msg);
+       if (!noprint && *msg) {
+               if (iserr)
+                       ipath_dev_err(dd, "%s error\n", msg);
+               else
+                       dev_info(&dd->pcidev->dev, "%s packet problems\n",
+                               msg);
+       }
        if (dd->ipath_state_wanted & dd->ipath_flags) {
                ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, "
                           "waking\n", dd->ipath_state_wanted,
@@ -689,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)
@@ -817,15 +965,25 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
                   dd->ipath_i_rcvurg_mask);
        for (i = 1; i < dd->ipath_cfgports; i++) {
                struct ipath_portdata *pd = dd->ipath_pd[i];
-               if (portr & (1 << i) && pd && pd->port_cnt &&
-                       test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
-                       int rcbit;
-                       clear_bit(IPATH_PORT_WAITING_RCV,
-                                 &pd->port_flag);
-                       rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
-                       clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
-                       wake_up_interruptible(&pd->port_wait);
-                       rcvdint = 1;
+               if (portr & (1 << i) && pd && pd->port_cnt) {
+                       if (test_bit(IPATH_PORT_WAITING_RCV,
+                                    &pd->port_flag)) {
+                               clear_bit(IPATH_PORT_WAITING_RCV,
+                                         &pd->port_flag);
+                               set_bit(IPATH_PORT_WAITING_RCV,
+                                       &pd->int_flag);
+                               clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+                                         &dd->ipath_rcvctrl);
+                               wake_up_interruptible(&pd->port_wait);
+                               rcvdint = 1;
+                       } else if (test_bit(IPATH_PORT_WAITING_URG,
+                                           &pd->port_flag)) {
+                               clear_bit(IPATH_PORT_WAITING_URG,
+                                         &pd->port_flag);
+                               set_bit(IPATH_PORT_WAITING_URG,
+                                       &pd->int_flag);
+                               wake_up_interruptible(&pd->port_wait);
+                       }
                }
        }
        if (rcvdint) {
@@ -851,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
@@ -1002,7 +1163,7 @@ irqreturn_t ipath_intr(int irq, void *data)
                        gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT);
                        chk0rcv = 1;
                }
-               if (unlikely(gpiostatus)) {
+               if (gpiostatus) {
                        /*
                         * Some unexpected bits remain. If they could have
                         * caused the interrupt, complain and clear.
@@ -1011,9 +1172,8 @@ irqreturn_t ipath_intr(int irq, void *data)
                         * GPIO interrupts, possibly on a "three strikes"
                         * basis.
                         */
-                       u32 mask;
-                       mask = ipath_read_kreg32(
-                               dd, dd->ipath_kregs->kr_gpio_mask);
+                       const u32 mask = (u32) dd->ipath_gpio_mask;
+
                        if (mask & gpiostatus) {
                                ipath_dbg("Unexpected GPIO IRQ bits %x\n",
                                  gpiostatus & mask);