]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ipath/ipath_intr.c
IB/ipath: Misc changes to prepare for IB7220 introduction
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ipath / ipath_intr.c
index dde5dfc9fcf5023cfbcee6f0e83287dc19c6bffe..90b972f6a8401b1df97c56e9fd6d6b9fba00792f 100644 (file)
@@ -73,7 +73,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.
  */
-static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
        u32 piobcnt;
        unsigned long sbuf[4];
@@ -87,12 +87,14 @@ static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
                dd, dd->ipath_kregs->kr_sendbuffererror);
        sbuf[1] = ipath_read_kreg64(
                dd, dd->ipath_kregs->kr_sendbuffererror + 1);
-       if (piobcnt > 128) {
+       if (piobcnt > 128)
                sbuf[2] = ipath_read_kreg64(
                        dd, dd->ipath_kregs->kr_sendbuffererror + 2);
+       if (piobcnt > 192)
                sbuf[3] = ipath_read_kreg64(
                        dd, dd->ipath_kregs->kr_sendbuffererror + 3);
-       }
+       else
+               sbuf[3] = 0;
 
        if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
                int i;
@@ -299,6 +301,18 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
        lastlstate = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
        ltstate = ipath_ib_linktrstate(dd, ibcs); /* linktrainingtate */
 
+       /*
+        * Since going into a recovery state causes the link state to go
+        * down and since recovery is transitory, it is better if we "miss"
+        * ever seeing the link training state go into recovery (i.e.,
+        * ignore this transition for link state special handling purposes)
+        * without even updating ipath_lastibcstat.
+        */
+       if ((ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN) ||
+           (ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT) ||
+           (ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERIDLE))
+               goto done;
+
        /*
         * if linkstate transitions into INIT from any of the various down
         * states, or if it transitions from any of the up (INIT or better)
@@ -309,12 +323,14 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                lastlstate == INFINIPATH_IBCS_L_STATE_DOWN) {
                /* transitioned to UP */
                if (dd->ipath_f_ib_updown(dd, 1, ibcs)) {
+                       /* link came up, so we must no longer be disabled */
+                       dd->ipath_flags &= ~IPATH_IB_LINK_DISABLED;
                        ipath_cdbg(LINKVERB, "LinkUp handled, skipped\n");
                        goto skip_ibchange; /* chip-code handled */
                }
        } else if ((lastlstate >= INFINIPATH_IBCS_L_STATE_INIT ||
                (dd->ipath_flags & IPATH_IB_FORCE_NOTIFY)) &&
-               ltstate <= INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE &&
+               ltstate <= INFINIPATH_IBCS_LT_STATE_CFGWAITRMT &&
                ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
                int handled;
                handled = dd->ipath_f_ib_updown(dd, 0, ibcs);
@@ -351,7 +367,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                 */
                if (lastlts == INFINIPATH_IBCS_LT_STATE_POLLACTIVE ||
                    lastlts == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
-                       if (++dd->ipath_ibpollcnt == 40) {
+                       if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) &&
+                            (++dd->ipath_ibpollcnt == 40)) {
                                dd->ipath_flags |= IPATH_NOCABLE;
                                *dd->ipath_statusp |=
                                        IPATH_STATUS_IB_NOCABLE;
@@ -366,6 +383,22 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
        dd->ipath_ibpollcnt = 0; /* not poll*, now */
        ipath_stats.sps_iblink++;
 
+       if (ibstate != init && dd->ipath_lastlinkrecov && ipath_linkrecovery) {
+               u64 linkrecov;
+               linkrecov = ipath_snap_cntr(dd,
+                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
+               if (linkrecov != dd->ipath_lastlinkrecov) {
+                       ipath_dbg("IB linkrecov up %Lx (%s %s) recov %Lu\n",
+                               ibcs, ib_linkstate(dd, ibcs),
+                               ipath_ibcstatus_str[ltstate],
+                               linkrecov);
+                       /* and no more until active again */
+                       dd->ipath_lastlinkrecov = 0;
+                       ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
+                       goto skip_ibchange;
+               }
+       }
+
        if (ibstate == init || ibstate == arm || ibstate == active) {
                *dd->ipath_statusp &= ~IPATH_STATUS_IB_NOCABLE;
                if (ibstate == init || ibstate == arm) {
@@ -392,6 +425,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
                                IPATH_NOCABLE);
                        ipath_hol_down(dd);
                } else {  /* active */
+                       dd->ipath_lastlinkrecov = ipath_snap_cntr(dd,
+                               dd->ipath_cregs->cr_iblinkerrrecovcnt);
                        *dd->ipath_statusp |=
                                IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
                        dd->ipath_flags |= IPATH_LINKACTIVE;
@@ -440,6 +475,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
 
 skip_ibchange:
        dd->ipath_lastibcstat = ibcs;
+done:
+       return;
 }
 
 static void handle_supp_msgs(struct ipath_devdata *dd,
@@ -570,18 +607,19 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                 * ones on this particular interrupt, which also isn't great
                 */
                dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
+
                dd->ipath_errormask &= ~dd->ipath_maskederrs;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-                       dd->ipath_errormask);
+                                dd->ipath_errormask);
                s_iserr = ipath_decode_err(msg, sizeof msg,
-                       dd->ipath_maskederrs);
+                                          dd->ipath_maskederrs);
 
                if (dd->ipath_maskederrs &
-                       ~(INFINIPATH_E_RRCVEGRFULL |
-                       INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
+                   ~(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,
+                               (unsigned long long) dd->ipath_maskederrs,
                                msg);
                else {
                        /*
@@ -674,8 +712,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                        struct ipath_portdata *pd = dd->ipath_pd[i];
                        if (i == 0) {
                                hd = pd->port_head;
-                               tl = (u32) le64_to_cpu(
-                                       *dd->ipath_hdrqtailptr);
+                               tl = ipath_get_hdrqtail(pd);
                        } else if (pd && pd->port_cnt &&
                                   pd->port_rcvhdrtail_kvaddr) {
                                /*
@@ -711,8 +748,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
                 * vs user)
                 */
                ipath_stats.sps_etidfull++;
-               if (pd->port_head !=
-                   (u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
+               if (pd->port_head != ipath_get_hdrqtail(pd))
                        chkerrpkts = 1;
        }
 
@@ -766,7 +802,6 @@ 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
@@ -784,7 +819,6 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 {
        int i, im;
        u64 val;
-       unsigned long flags;
 
        /* disable error interrupts, to avoid confusion */
        ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
@@ -803,14 +837,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
                         dd->ipath_control);
 
        /* ensure pio avail updates continue */
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                        dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+       ipath_force_pio_avail_update(dd);
 
        /*
         * We just enabled pioavailupdate, so dma copy is almost certainly
@@ -822,7 +849,9 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
                        i ^ 1 : i;
                val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
                dd->ipath_pioavailregs_dma[i] = cpu_to_le64(val);
-               dd->ipath_pioavailshadow[i] = val;
+               dd->ipath_pioavailshadow[i] = val |
+                       (~dd->ipath_pioavailkernel[i] <<
+                       INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT);
        }
 
        /*
@@ -938,7 +967,7 @@ set:
  * process was waiting for a packet to arrive, and didn't want
  * to poll
  */
-static void handle_urcv(struct ipath_devdata *dd, u32 istat)
+static void handle_urcv(struct ipath_devdata *dd, u64 istat)
 {
        u64 portr;
        int i;
@@ -954,12 +983,13 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
         * and ipath_poll_next()...
         */
        rmb();
-       portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
-                dd->ipath_i_rcvavail_mask)
-               | ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
-                  dd->ipath_i_rcvurg_mask);
+       portr = ((istat >> dd->ipath_i_rcvavail_shift) &
+                dd->ipath_i_rcvavail_mask) |
+               ((istat >> dd->ipath_i_rcvurg_shift) &
+                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) {
                        if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
                                               &pd->port_flag)) {
@@ -976,7 +1006,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
        }
        if (rcvdint) {
                /* only want to take one interrupt, so turn off the rcv
-                * interrupt for all the ports that we did the wakeup on
+                * interrupt for all the ports that we set the rcv_waiting
                 * (but never for kernel port)
                 */
                ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
@@ -991,8 +1021,7 @@ irqreturn_t ipath_intr(int irq, void *data)
        ipath_err_t estat = 0;
        irqreturn_t ret;
        static unsigned unexpected = 0;
-       static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
-                (1U<<INFINIPATH_I_RCVURG_SHIFT);
+       u64 kportrbits;
 
        ipath_stats.sps_ints++;
 
@@ -1061,9 +1090,7 @@ irqreturn_t ipath_intr(int irq, void *data)
                        ipath_dev_err(dd, "Read of error status failed "
                                      "(all bits set); ignoring\n");
                else
-                       if (handle_errors(dd, estat))
-                               /* force calling ipath_kreceive() */
-                               chk0rcv = 1;
+                       chk0rcv |= handle_errors(dd, estat);
        }
 
        if (istat & INFINIPATH_I_GPIO) {
@@ -1081,8 +1108,7 @@ irqreturn_t ipath_intr(int irq, void *data)
 
                gpiostatus = ipath_read_kreg32(
                        dd, dd->ipath_kregs->kr_gpio_status);
-               /* First the error-counter case.
-                */
+               /* First the error-counter case. */
                if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) &&
                    (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) {
                        /* want to clear the bits we see asserted. */
@@ -1144,7 +1170,6 @@ irqreturn_t ipath_intr(int irq, void *data)
                                        (u64) to_clear);
                }
        }
-       chk0rcv |= istat & port0rbits;
 
        /*
         * Clear the interrupt bits we found set, unless they are receive
@@ -1157,20 +1182,20 @@ irqreturn_t ipath_intr(int irq, void *data)
        ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
 
        /*
-        * handle port0 receive  before checking for pio buffers available,
-        * since receives can overflow; piobuf waiters can afford a few
-        * extra cycles, since they were waiting anyway, and user's waiting
-        * for receive are at the bottom.
+        * Handle kernel receive queues before checking for pio buffers
+        * available since receives can overflow; piobuf waiters can afford
+        * a few extra cycles, since they were waiting anyway, and user's
+        * waiting for receive are at the bottom.
         */
-       if (chk0rcv) {
+       kportrbits = (1ULL << dd->ipath_i_rcvavail_shift) |
+               (1ULL << dd->ipath_i_rcvurg_shift);
+       if (chk0rcv || (istat & kportrbits)) {
+               istat &= ~kportrbits;
                ipath_kreceive(dd->ipath_pd[0]);
-               istat &= ~port0rbits;
        }
 
-       if (istat & ((dd->ipath_i_rcvavail_mask <<
-                     INFINIPATH_I_RCVAVAIL_SHIFT)
-                    | (dd->ipath_i_rcvurg_mask <<
-                       INFINIPATH_I_RCVURG_SHIFT)))
+       if (istat & ((dd->ipath_i_rcvavail_mask << dd->ipath_i_rcvavail_shift) |
+                    (dd->ipath_i_rcvurg_mask << dd->ipath_i_rcvurg_shift)))
                handle_urcv(dd, istat);
 
        if (istat & INFINIPATH_I_SPIOBUFAVAIL) {