Date: Sun, 18 Jan 2015 20:38:38 +0000 (UTC) From: Navdeep Parhar <np@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r277343 - in stable/10/sys/dev/cxgb: . common Message-ID: <201501182038.t0IKccCv038071@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: np Date: Sun Jan 18 20:38:38 2015 New Revision: 277343 URL: https://svnweb.freebsd.org/changeset/base/277343 Log: MFC r276959: cxgb: replace r273280 with a more comprehensive fix. Poll for link state when the link is down, even for interrupt capable PHYs. Allow PHYs to report a dubious "partial" link. If this state is seen 3 consecutive times (each check is ~1s apart) then reset the PHY. This is a workaround for a situation where repeatedly toggling the link from the peer gets the AEL2005 PHY into a state where it never establishes a PCS block lock even when everything is in order. Modified: stable/10/sys/dev/cxgb/common/cxgb_ael1002.c stable/10/sys/dev/cxgb/common/cxgb_aq100x.c stable/10/sys/dev/cxgb/common/cxgb_common.h stable/10/sys/dev/cxgb/common/cxgb_mv88e1xxx.c stable/10/sys/dev/cxgb/common/cxgb_t3_hw.c stable/10/sys/dev/cxgb/common/cxgb_tn1010.c stable/10/sys/dev/cxgb/common/cxgb_vsc8211.c stable/10/sys/dev/cxgb/cxgb_main.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/cxgb/common/cxgb_ael1002.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_ael1002.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_ael1002.c Sun Jan 18 20:38:38 2015 (r277343) @@ -283,10 +283,10 @@ static int ael1002_intr_noop(struct cphy /* * Get link status for a 10GBASE-R device. */ -static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, +static int get_link_status_r(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc) { - if (link_ok) { + if (link_state) { unsigned int stat0, stat1, stat2; int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); @@ -296,10 +296,16 @@ static int get_link_status_r(struct cphy err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); if (err) return err; - *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; - if (*link_ok == 0) - return (0); + stat0 &= 1; + stat1 &= 1; + stat2 = (stat2 >> 12) & 1; + if (stat0 & stat1 & stat2) + *link_state = PHY_LINK_UP; + else if (stat0 == 1 && stat1 == 0 && stat2 == 1) + *link_state = PHY_LINK_PARTIAL; + else + *link_state = PHY_LINK_DOWN; } if (speed) *speed = SPEED_10000; @@ -1345,10 +1351,8 @@ static int ael2005_intr_handler(struct c return ret; ret |= cause; - if (!ret) { - (void) ael2005_reset(phy, 0); + if (!ret) ret |= cphy_cause_link_change; - } return ret; } @@ -2156,10 +2160,10 @@ int t3_ael2020_phy_prep(pinfo_t *pinfo, /* * Get link status for a 10GBASE-X device. */ -static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, +static int get_link_status_x(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc) { - if (link_ok) { + if (link_state) { unsigned int stat0, stat1, stat2; int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); @@ -2169,7 +2173,10 @@ static int get_link_status_x(struct cphy err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); if (err) return err; - *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; + if ((stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1) + *link_state = PHY_LINK_UP; + else + *link_state = PHY_LINK_DOWN; } if (speed) *speed = SPEED_10000; @@ -2230,10 +2237,10 @@ static int xaui_direct_reset(struct cphy return 0; } -static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, +static int xaui_direct_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc) { - if (link_ok) { + if (link_state) { unsigned int status; adapter_t *adapter = phy->adapter; @@ -2245,7 +2252,7 @@ static int xaui_direct_get_link_status(s XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | t3_read_reg(adapter, XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); - *link_ok = !(status & F_LOWSIG0); + *link_state = status & F_LOWSIG0 ? PHY_LINK_DOWN : PHY_LINK_UP; } if (speed) *speed = SPEED_10000; Modified: stable/10/sys/dev/cxgb/common/cxgb_aq100x.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_aq100x.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_aq100x.c Sun Jan 18 20:38:38 2015 (r277343) @@ -350,7 +350,7 @@ aq100x_set_speed_duplex(struct cphy *phy } static int -aq100x_get_link_status(struct cphy *phy, int *link_ok, int *speed, int *duplex, +aq100x_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc) { int err; @@ -440,8 +440,8 @@ aq100x_get_link_status(struct cphy *phy, link = 1; done: - if (link_ok) - *link_ok = link; + if (link_state) + *link_state = link ? PHY_LINK_UP : PHY_LINK_DOWN; return (0); } Modified: stable/10/sys/dev/cxgb/common/cxgb_common.h ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_common.h Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_common.h Sun Jan 18 20:38:38 2015 (r277343) @@ -543,6 +543,12 @@ enum { phy_modtype_unknown }; +enum { + PHY_LINK_DOWN = 0, + PHY_LINK_UP, + PHY_LINK_PARTIAL +}; + /* PHY operations */ struct cphy_ops { int (*reset)(struct cphy *phy, int wait); @@ -558,7 +564,7 @@ struct cphy_ops { int (*advertise)(struct cphy *phy, unsigned int advertise_map); int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable); int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); - int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, + int (*get_link_status)(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc); int (*power_down)(struct cphy *phy, int enable); }; @@ -567,6 +573,7 @@ struct cphy_ops { struct cphy { u8 addr; /* PHY address */ u8 modtype; /* PHY module type */ + u8 rst; unsigned int priv; /* scratch pad */ unsigned int caps; /* PHY capabilities */ adapter_t *adapter; /* associated adapter */ Modified: stable/10/sys/dev/cxgb/common/cxgb_mv88e1xxx.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_mv88e1xxx.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_mv88e1xxx.c Sun Jan 18 20:38:38 2015 (r277343) @@ -185,7 +185,7 @@ static int mv88e1xxx_set_loopback(struct on ? BMCR_LOOPBACK : 0); } -static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok, +static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_state, int *speed, int *duplex, int *fc) { u32 status; @@ -206,8 +206,9 @@ static int mv88e1xxx_get_link_status(str else sp = SPEED_1000; } - if (link_ok) - *link_ok = (status & V_PSSR_LINK) != 0; + if (link_state) + *link_state = status & V_PSSR_LINK ? PHY_LINK_UP : + PHY_LINK_DOWN; if (speed) *speed = sp; if (duplex) Modified: stable/10/sys/dev/cxgb/common/cxgb_t3_hw.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_t3_hw.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_t3_hw.c Sun Jan 18 20:38:38 2015 (r277343) @@ -1520,7 +1520,7 @@ static void t3_clear_faults(adapter_t *a */ void t3_link_changed(adapter_t *adapter, int port_id) { - int link_ok, speed, duplex, fc, link_fault; + int link_ok, speed, duplex, fc, link_fault, link_state; struct port_info *pi = adap2pinfo(adapter, port_id); struct cphy *phy = &pi->phy; struct cmac *mac = &pi->mac; @@ -1532,7 +1532,14 @@ void t3_link_changed(adapter_t *adapter, fc = lc->fc; link_fault = 0; - phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + phy->ops->get_link_status(phy, &link_state, &speed, &duplex, &fc); + link_ok = (link_state == PHY_LINK_UP); + if (link_state != PHY_LINK_PARTIAL) + phy->rst = 0; + else if (++phy->rst == 3) { + phy->ops->reset(phy, 0); + phy->rst = 0; + } if (link_ok == 0) pi->link_fault = LF_NO; Modified: stable/10/sys/dev/cxgb/common/cxgb_tn1010.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_tn1010.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_tn1010.c Sun Jan 18 20:38:38 2015 (r277343) @@ -129,7 +129,7 @@ static int tn1010_advertise(struct cphy ADVERTISE_LOOP_TIMING); } -static int tn1010_get_link_status(struct cphy *phy, int *link_ok, +static int tn1010_get_link_status(struct cphy *phy, int *link_state, int *speed, int *duplex, int *fc) { unsigned int status, lpa, adv; @@ -139,8 +139,9 @@ static int tn1010_get_link_status(struct if (err) return err; - if (link_ok) - *link_ok = (status & F_LINK_STAT) != 0; + if (link_state) + *link_state = status & F_LINK_STAT ? PHY_LINK_UP : + PHY_LINK_DOWN; if (G_ANEG_STAT(status) == ANEG_COMPLETE) { sp = (status & F_ANEG_SPEED_1G) ? SPEED_1000 : SPEED_10000; Modified: stable/10/sys/dev/cxgb/common/cxgb_vsc8211.c ============================================================================== --- stable/10/sys/dev/cxgb/common/cxgb_vsc8211.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/common/cxgb_vsc8211.c Sun Jan 18 20:38:38 2015 (r277343) @@ -129,7 +129,7 @@ static int vsc8211_autoneg_restart(struc BMCR_ANRESTART); } -static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, +static int vsc8211_get_link_status(struct cphy *cphy, int *link_state, int *speed, int *duplex, int *fc) { unsigned int bmcr, status, lpa, adv; @@ -141,7 +141,7 @@ static int vsc8211_get_link_status(struc if (err) return err; - if (link_ok) { + if (link_state) { /* * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it * once more to get the current link state. @@ -150,7 +150,8 @@ static int vsc8211_get_link_status(struc err = mdio_read(cphy, 0, MII_BMSR, &status); if (err) return err; - *link_ok = (status & BMSR_LSTATUS) != 0; + *link_state = status & BMSR_LSTATUS ? PHY_LINK_UP : + PHY_LINK_DOWN; } if (!(bmcr & BMCR_ANENABLE)) { dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; @@ -201,7 +202,7 @@ static int vsc8211_get_link_status(struc return 0; } -static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, +static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_state, int *speed, int *duplex, int *fc) { unsigned int bmcr, status, lpa, adv; @@ -213,7 +214,7 @@ static int vsc8211_get_link_status_fiber if (err) return err; - if (link_ok) { + if (link_state) { /* * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it * once more to get the current link state. @@ -222,7 +223,8 @@ static int vsc8211_get_link_status_fiber err = mdio_read(cphy, 0, MII_BMSR, &status); if (err) return err; - *link_ok = (status & BMSR_LSTATUS) != 0; + *link_state = status & BMSR_LSTATUS ? PHY_LINK_UP : + PHY_LINK_DOWN; } if (!(bmcr & BMCR_ANENABLE)) { dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; Modified: stable/10/sys/dev/cxgb/cxgb_main.c ============================================================================== --- stable/10/sys/dev/cxgb/cxgb_main.c Sun Jan 18 20:32:51 2015 (r277342) +++ stable/10/sys/dev/cxgb/cxgb_main.c Sun Jan 18 20:38:38 2015 (r277343) @@ -2226,7 +2226,8 @@ check_link_status(void *arg, int pending t3_link_changed(sc, pi->port_id); - if (pi->link_fault || !(pi->phy.caps & SUPPORTED_LINK_IRQ)) + if (pi->link_fault || !(pi->phy.caps & SUPPORTED_LINK_IRQ) || + pi->link_config.link_ok == 0) callout_reset(&pi->link_check_ch, hz, link_check_callout, pi); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501182038.t0IKccCv038071>