]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_intr.c
IB/ipath: Shadow the gpio_mask register
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_intr.c
index d9079ee120308633c49b012988bd0b752df362eb..a90d3b5699c46cc1169faf99ef3c72fbc4a92772 100644 (file)
 #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)
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
@@ -74,8 +103,11 @@ 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 */
        }
 }
@@ -114,7 +146,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)) {
                /*
@@ -403,10 +435,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 +455,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,7 +502,7 @@ 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;
 
@@ -502,6 +542,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 +552,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 +571,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 +637,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
@@ -598,10 +648,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
         * on close
         */
        if (errs & INFINIPATH_E_RRCVHDRFULL) {
-               int any;
                u32 hd, tl;
                ipath_stats.sps_hdrqfull++;
-               for (any = i = 0; i < dd->ipath_cfgports; i++) {
+               for (i = 0; i < dd->ipath_cfgports; i++) {
                        struct ipath_portdata *pd = dd->ipath_pd[i];
                        if (i == 0) {
                                hd = dd->ipath_port0head;
@@ -678,8 +727,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,
@@ -710,14 +764,14 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
                         * linuxbios development work, and it may happen in
                         * the future again.
                         */
-                       if (dd->pcidev && dd->pcidev->irq) {
+                       if (dd->pcidev && dd->ipath_irq) {
                                ipath_dev_err(dd, "Now %u unexpected "
                                              "interrupts, unregistering "
                                              "interrupt handler\n",
                                              *unexpectp);
-                               ipath_dbg("free_irq of irq %x\n",
-                                         dd->pcidev->irq);
-                               free_irq(dd->pcidev->irq, dd);
+                               ipath_dbg("free_irq of irq %d\n",
+                                         dd->ipath_irq);
+                               dd->ipath_f_free_irq(dd);
                        }
                }
                if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
@@ -753,7 +807,7 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
                if (allbits == 2) {
                        ipath_dev_err(dd, "Still bad interrupt status, "
                                      "unregistering interrupt\n");
-                       free_irq(dd->pcidev->irq, dd);
+                       dd->ipath_f_free_irq(dd);
                } else if (allbits > 2) {
                        if ((allbits % 10000) == 0)
                                printk(".");
@@ -820,11 +874,10 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
                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);
+                       clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+                                 &dd->ipath_rcvctrl);
                        wake_up_interruptible(&pd->port_wait);
                        rcvdint = 1;
                }
@@ -1003,7 +1056,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.
@@ -1012,9 +1065,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);