axgbe: fix some link related issues

By default, axgbe driver does a receiver reset after predefined number
of retries for the link to come up. However, this receiver reset
doesn't always suffice, due to an hardware issue.
In that case, as a workaround, a complete phy reset is necessary.
This patch introduces a sysctl that can be set to 1 to let the driver
reset the phy completely, rather than just doing receiver reset.
The workaround will be removed once the issue is fixed by means
of firmware update.

This patch also fixes the handling of the direct attach cables
properly.

Submitted by:	rajesh1.kumar_amd.com
Differential Revision:	https://reviews.freebsd.org/D28266
This commit is contained in:
Vincenzo Maffione 2021-01-23 13:44:24 +00:00
parent 6c789c55c4
commit bfd75d4557
3 changed files with 25 additions and 6 deletions

View File

@ -213,6 +213,9 @@ enum xgbe_sfp_speed {
#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 @@ struct xgbe_phy_data {
};
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 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
} 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 @@ xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
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 @@ xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
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);

View File

@ -1618,6 +1618,10 @@ axgbe_sysctl_init(struct xgbe_prv_data *pdata)
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",

View File

@ -1302,6 +1302,7 @@ struct xgbe_prv_data {
* This requires a complete restart.
*/
unsigned int sph_enable;
unsigned int link_workaround;
};
struct axgbe_if_softc {