IB/ipath: HW workaround for case where chip can send but not receive
[safe/jmp/linux-2.6] / drivers / infiniband / hw / ipath / ipath_intr.c
index dde5dfc..ed82ecb 100644 (file)
@@ -366,6 +366,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 +408,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;