diff --git a/sys/dev/axgbe/xgbe-phy-v2.c b/sys/dev/axgbe/xgbe-phy-v2.c --- a/sys/dev/axgbe/xgbe-phy-v2.c +++ b/sys/dev/axgbe/xgbe-phy-v2.c @@ -213,6 +213,9 @@ #define XGBE_SFP_BASE_EXT_ID 1 #define XGBE_SFP_EXT_ID_SFP 0x04 +#define XGBE_SFP_BASE_CV 2 +#define XGBE_SFP_BASE_CV_CP 0x21 + #define XGBE_SFP_BASE_10GBE_CC 3 #define XGBE_SFP_BASE_10GBE_CC_SR BIT(4) #define XGBE_SFP_BASE_10GBE_CC_LR BIT(5) @@ -380,6 +383,7 @@ }; static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata); +static int xgbe_phy_reset(struct xgbe_prv_data *pdata); static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *i2c_op) @@ -1209,8 +1213,16 @@ } else phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE; - /* Determine the type of SFP */ - if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) + /* + * Determine the type of SFP. Certain 10G SFP+ modules read as + * 1000BASE-CX. To prevent 10G DAC cables to be recognized as + * 1G, we first check if it is a DAC and the bitrate is 10G. + */ + if (((sfp_base[XGBE_SFP_BASE_CV] & XGBE_SFP_BASE_CV_CP) || + (phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE)) && + xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) + phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; + else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_SR) phy_data->sfp_base = XGBE_SFP_BASE_10000_SR; else if (sfp_base[XGBE_SFP_BASE_10GBE_CC] & XGBE_SFP_BASE_10GBE_CC_LR) phy_data->sfp_base = XGBE_SFP_BASE_10000_LR; @@ -1226,9 +1238,6 @@ phy_data->sfp_base = XGBE_SFP_BASE_1000_CX; else if (sfp_base[XGBE_SFP_BASE_1GBE_CC] & XGBE_SFP_BASE_1GBE_CC_T) phy_data->sfp_base = XGBE_SFP_BASE_1000_T; - else if ((phy_data->sfp_cable == XGBE_SFP_CABLE_PASSIVE) && - xgbe_phy_sfp_bit_rate(sfp_eeprom, XGBE_SFP_SPEED_10000)) - phy_data->sfp_base = XGBE_SFP_BASE_10000_CR; switch (phy_data->sfp_base) { case XGBE_SFP_BASE_1000_T: @@ -2879,7 +2888,12 @@ axgbe_printf(1, "ENTERED RRC: rrc_count: %d\n", phy_data->rrc_count); phy_data->rrc_count = 0; - xgbe_phy_rrc(pdata); + if (pdata->link_workaround) { + ret = xgbe_phy_reset(pdata); + if (ret) + axgbe_error("Error resetting phy\n"); + } else + xgbe_phy_rrc(pdata); } return (0); diff --git a/sys/dev/axgbe/xgbe-sysctl.c b/sys/dev/axgbe/xgbe-sysctl.c --- a/sys/dev/axgbe/xgbe-sysctl.c +++ b/sys/dev/axgbe/xgbe-sysctl.c @@ -1618,6 +1618,10 @@ CTLFLAG_RDTUN, &pdata->sph_enable, 1, "shows the split header feature state (1 - enable, 0 - disable"); + SYSCTL_ADD_UINT(clist, top, OID_AUTO, "link_workaround", + CTLFLAG_RWTUN, &pdata->link_workaround, 0, + "enable the workaround for link issue in coming up"); + SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, pdata, 0, sysctl_xgmac_reg_addr_handler, "IU", diff --git a/sys/dev/axgbe/xgbe.h b/sys/dev/axgbe/xgbe.h --- a/sys/dev/axgbe/xgbe.h +++ b/sys/dev/axgbe/xgbe.h @@ -1302,6 +1302,7 @@ * This requires a complete restart. */ unsigned int sph_enable; + unsigned int link_workaround; }; struct axgbe_if_softc {