IB/ipath: Don't count IB symbol and link errors unless link is UP

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>
This commit is contained in:
Dave Olson 2008-12-05 11:13:19 -08:00 committed by Roland Dreier
parent 890fccb242
commit 60e845035a
4 changed files with 155 additions and 3 deletions

View 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;

View 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);

View 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 */

View 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;