Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Jan 2015 20:40:08 +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-8@freebsd.org
Subject:   svn commit: r277345 - in stable/8/sys/dev/cxgb: . common
Message-ID:  <201501182040.t0IKe94T038559@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Sun Jan 18 20:40:08 2015
New Revision: 277345
URL: https://svnweb.freebsd.org/changeset/base/277345

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/8/sys/dev/cxgb/common/cxgb_ael1002.c
  stable/8/sys/dev/cxgb/common/cxgb_aq100x.c
  stable/8/sys/dev/cxgb/common/cxgb_common.h
  stable/8/sys/dev/cxgb/common/cxgb_mv88e1xxx.c
  stable/8/sys/dev/cxgb/common/cxgb_t3_hw.c
  stable/8/sys/dev/cxgb/common/cxgb_tn1010.c
  stable/8/sys/dev/cxgb/common/cxgb_vsc8211.c
  stable/8/sys/dev/cxgb/cxgb_main.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/cxgb/   (props changed)

Modified: stable/8/sys/dev/cxgb/common/cxgb_ael1002.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_ael1002.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_ael1002.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_aq100x.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_aq100x.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_aq100x.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_common.h
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_common.h	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_common.h	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_mv88e1xxx.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_mv88e1xxx.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_mv88e1xxx.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_t3_hw.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_t3_hw.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_t3_hw.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_tn1010.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_tn1010.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_tn1010.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/common/cxgb_vsc8211.c
==============================================================================
--- stable/8/sys/dev/cxgb/common/cxgb_vsc8211.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/common/cxgb_vsc8211.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -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/8/sys/dev/cxgb/cxgb_main.c
==============================================================================
--- stable/8/sys/dev/cxgb/cxgb_main.c	Sun Jan 18 20:39:24 2015	(r277344)
+++ stable/8/sys/dev/cxgb/cxgb_main.c	Sun Jan 18 20:40:08 2015	(r277345)
@@ -2293,7 +2293,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?201501182040.t0IKe94T038559>