IB/ipath: Don't count IB symbol and link errors unless link is UP
authorDave Olson <dave.olson@qlogic.com>
Fri, 5 Dec 2008 19:13:19 +0000 (11:13 -0800)
committerRoland Dreier <rolandd@cisco.com>
Fri, 5 Dec 2008 19:13:19 +0000 (11:13 -0800)
Implement the ignoring of ibsymbol errors and linkrecover errors while
the link is at less than INIT (long needed), to get accurate counts.
Particularly an issue when doing non-IBTA DDR negotiation with chips
from vendors that do not support IBTA mode negotiation.  If the driver
is unloaded, and there is a delta, the adjusted counters are written
back to the chip, so they stay adjusted across driver reload.

Signed-off-by: Dave Olson <dave.olson@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_iba6120.c
drivers/infiniband/hw/ipath/ipath_iba7220.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_stats.c

index 421cc2a..fbf8c53 100644 (file)
@@ -721,6 +721,12 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
                                 INFINIPATH_HWE_SERDESPLLFAILED);
        }
 
+       dd->ibdeltainprog = 1;
+       dd->ibsymsnap =
+            ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+       dd->iblnkerrsnap =
+            ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+
        val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
        config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
 
@@ -810,6 +816,36 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
 {
        u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
 
+       if (dd->ibsymdelta || dd->iblnkerrdelta ||
+           dd->ibdeltainprog) {
+               u64 diagc;
+               /* enable counter writes */
+               diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
+               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
+                                diagc | INFINIPATH_DC_COUNTERWREN);
+
+               if (dd->ibsymdelta || dd->ibdeltainprog) {
+                       val = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
+                       if (dd->ibdeltainprog)
+                               val -= val - dd->ibsymsnap;
+                       val -= dd->ibsymdelta;
+                       ipath_write_creg(dd,
+                                 dd->ipath_cregs->cr_ibsymbolerrcnt, val);
+               }
+               if (dd->iblnkerrdelta || dd->ibdeltainprog) {
+                       val = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
+                       if (dd->ibdeltainprog)
+                               val -= val - dd->iblnkerrsnap;
+                       val -= dd->iblnkerrdelta;
+                       ipath_write_creg(dd,
+                                  dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
+            }
+
+            /* and disable counter writes */
+            ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
+       }
        val |= INFINIPATH_SERDC0_TXIDLE;
        ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
                  (unsigned long long) val);
@@ -1749,6 +1785,31 @@ static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
 
 static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
 {
+       if (ibup) {
+               if (dd->ibdeltainprog) {
+                       dd->ibdeltainprog = 0;
+                       dd->ibsymdelta +=
+                               ipath_read_creg32(dd,
+                                 dd->ipath_cregs->cr_ibsymbolerrcnt) -
+                               dd->ibsymsnap;
+                       dd->iblnkerrdelta +=
+                               ipath_read_creg32(dd,
+                                 dd->ipath_cregs->cr_iblinkerrrecovcnt) -
+                               dd->iblnkerrsnap;
+               }
+       } else {
+               dd->ipath_lli_counter = 0;
+               if (!dd->ibdeltainprog) {
+                       dd->ibdeltainprog = 1;
+                       dd->ibsymsnap =
+                               ipath_read_creg32(dd,
+                                 dd->ipath_cregs->cr_ibsymbolerrcnt);
+                       dd->iblnkerrsnap =
+                               ipath_read_creg32(dd,
+                                 dd->ipath_cregs->cr_iblinkerrrecovcnt);
+               }
+       }
+
        ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
                ipath_ib_linktrstate(dd, ibcs));
        return 0;
index 9839e20..3b38bc9 100644 (file)
@@ -951,6 +951,12 @@ static int ipath_7220_bringup_serdes(struct ipath_devdata *dd)
                                 INFINIPATH_HWE_SERDESPLLFAILED);
        }
 
+       dd->ibdeltainprog = 1;
+       dd->ibsymsnap =
+            ipath_read_creg32(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+       dd->iblnkerrsnap =
+            ipath_read_creg32(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+
        if (!dd->ipath_ibcddrctrl) {
                /* not on re-init after reset */
                dd->ipath_ibcddrctrl =
@@ -1084,6 +1090,37 @@ static void ipath_7220_config_jint(struct ipath_devdata *dd,
 static void ipath_7220_quiet_serdes(struct ipath_devdata *dd)
 {
        u64 val;
+       if (dd->ibsymdelta || dd->iblnkerrdelta ||
+           dd->ibdeltainprog) {
+               u64 diagc;
+               /* enable counter writes */
+               diagc = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwdiagctrl);
+               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl,
+                                diagc | INFINIPATH_DC_COUNTERWREN);
+
+               if (dd->ibsymdelta || dd->ibdeltainprog) {
+                       val = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
+                       if (dd->ibdeltainprog)
+                               val -= val - dd->ibsymsnap;
+                       val -= dd->ibsymdelta;
+                       ipath_write_creg(dd,
+                                 dd->ipath_cregs->cr_ibsymbolerrcnt, val);
+               }
+               if (dd->iblnkerrdelta || dd->ibdeltainprog) {
+                       val = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
+                       if (dd->ibdeltainprog)
+                               val -= val - dd->iblnkerrsnap;
+                       val -= dd->iblnkerrdelta;
+                       ipath_write_creg(dd,
+                                  dd->ipath_cregs->cr_iblinkerrrecovcnt, val);
+            }
+
+            /* and disable counter writes */
+            ipath_write_kreg(dd, dd->ipath_kregs->kr_hwdiagctrl, diagc);
+       }
+
        dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG;
        wake_up(&dd->ipath_autoneg_wait);
        cancel_delayed_work(&dd->ipath_autoneg_work);
@@ -2325,7 +2362,7 @@ static void try_auto_neg(struct ipath_devdata *dd)
 
 static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
 {
-       int ret = 0;
+       int ret = 0, symadj = 0;
        u32 ltstate = ipath_ib_linkstate(dd, ibcs);
 
        dd->ipath_link_width_active =
@@ -2368,6 +2405,13 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                        ipath_dbg("DDR negotiation try, %u/%u\n",
                                dd->ipath_autoneg_tries,
                                IPATH_AUTONEG_TRIES);
+                       if (!dd->ibdeltainprog) {
+                               dd->ibdeltainprog = 1;
+                               dd->ibsymsnap = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_ibsymbolerrcnt);
+                               dd->iblnkerrsnap = ipath_read_creg32(dd,
+                                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
+                       }
                        try_auto_neg(dd);
                        ret = 1; /* no other IB status change processing */
                } else if ((dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)
@@ -2388,6 +2432,7 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                                set_speed_fast(dd,
                                        dd->ipath_link_speed_enabled);
                                wake_up(&dd->ipath_autoneg_wait);
+                               symadj = 1;
                        } else if (dd->ipath_flags & IPATH_IB_AUTONEG_FAILED) {
                                /*
                                 * clear autoneg failure flag, and do setup
@@ -2403,6 +2448,7 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                                        IBA7220_IBC_IBTA_1_2_MASK;
                                ipath_write_kreg(dd,
                                        IPATH_KREG_OFFSET(IBNCModeCtrl), 0);
+                               symadj = 1;
                        }
                }
                /*
@@ -2416,9 +2462,13 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                        IB_WIDTH_4X)) == (IB_WIDTH_1X | IB_WIDTH_4X)
                        && dd->ipath_link_width_active == IB_WIDTH_1X
                        && dd->ipath_x1_fix_tries < 3) {
-                       if (++dd->ipath_x1_fix_tries == 3)
+                    if (++dd->ipath_x1_fix_tries == 3) {
                                dev_info(&dd->pcidev->dev,
                                        "IB link is in 1X mode\n");
+                               if (!(dd->ipath_flags &
+                                     IPATH_IB_AUTONEG_INPROG))
+                                       symadj = 1;
+                    }
                        else {
                                ipath_cdbg(VERBOSE, "IB 1X in "
                                        "auto-width, try %u to be "
@@ -2429,7 +2479,8 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                                dd->ipath_f_xgxs_reset(dd);
                                ret = 1; /* skip other processing */
                        }
-               }
+               } else if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG))
+                       symadj = 1;
 
                if (!ret) {
                        dd->delay_mult = rate_to_delay
@@ -2440,6 +2491,25 @@ static int ipath_7220_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
                }
        }
 
+       if (symadj) {
+               if (dd->ibdeltainprog) {
+                       dd->ibdeltainprog = 0;
+                       dd->ibsymdelta += ipath_read_creg32(dd,
+                               dd->ipath_cregs->cr_ibsymbolerrcnt) -
+                               dd->ibsymsnap;
+                       dd->iblnkerrdelta += ipath_read_creg32(dd,
+                               dd->ipath_cregs->cr_iblinkerrrecovcnt) -
+                               dd->iblnkerrsnap;
+               }
+       } else if (!ibup && !dd->ibdeltainprog
+                  && !(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG)) {
+               dd->ibdeltainprog = 1;
+               dd->ibsymsnap = ipath_read_creg32(dd,
+                                    dd->ipath_cregs->cr_ibsymbolerrcnt);
+               dd->iblnkerrsnap = ipath_read_creg32(dd,
+                                    dd->ipath_cregs->cr_iblinkerrrecovcnt);
+       }
+
        if (!ret)
                ipath_setup_7220_setextled(dd, ipath_ib_linkstate(dd, ibcs),
                        ltstate);
index 0bd8bcb..aa84153 100644 (file)
@@ -355,6 +355,19 @@ struct ipath_devdata {
        /* errors masked because they occur too fast */
        ipath_err_t ipath_maskederrs;
        u64 ipath_lastlinkrecov; /* link recoveries at last ACTIVE */
+       /* these 5 fields are used to establish deltas for IB Symbol
+        * errors and linkrecovery errors. They can be reported on
+        * some chips during link negotiation prior to INIT, and with
+        * DDR when faking DDR negotiations with non-IBTA switches.
+        * The chip counters are adjusted at driver unload if there is
+        * a non-zero delta.
+        */
+       u64 ibdeltainprog;
+       u64 ibsymdelta;
+       u64 ibsymsnap;
+       u64 iblnkerrdelta;
+       u64 iblnkerrsnap;
+
        /* time in jiffies at which to re-enable maskederrs */
        unsigned long ipath_unmasktime;
        /* count of egrfull errors, combined for all ports */
index c8e3d65..f63e143 100644 (file)
@@ -112,6 +112,14 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
                        dd->ipath_lastrpkts = val;
                }
                val64 = dd->ipath_rpkts;
+       } else if (creg == dd->ipath_cregs->cr_ibsymbolerrcnt) {
+               if (dd->ibdeltainprog)
+                       val64 -= val64 - dd->ibsymsnap;
+               val64 -= dd->ibsymdelta;
+       } else if (creg == dd->ipath_cregs->cr_iblinkerrrecovcnt) {
+               if (dd->ibdeltainprog)
+                       val64 -= val64 - dd->iblnkerrsnap;
+               val64 -= dd->iblnkerrdelta;
        } else
                val64 = (u64) val;