mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-16 05:07:59 +07:00
amd-xgbe: Improve SFP 100Mbps auto-negotiation
After changing speed to 100Mbps as a result of auto-negotiation (AN), some 10/100/1000Mbps SFPs indicate a successful link (no faults or loss of signal), but cannot successfully transmit or receive data. These SFPs required an extra auto-negotiation (AN) after the speed change in order to operate properly. Add a quirk for these SFPs so that if the outcome of the AN actually results in changing to a new speed, re-initiate AN at that new speed. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e722ec8237
commit
76cce0af85
@ -331,13 +331,15 @@ static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
|
||||
xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
|
||||
}
|
||||
|
||||
static void xgbe_set_mode(struct xgbe_prv_data *pdata,
|
||||
static bool xgbe_set_mode(struct xgbe_prv_data *pdata,
|
||||
enum xgbe_mode mode)
|
||||
{
|
||||
if (mode == xgbe_cur_mode(pdata))
|
||||
return;
|
||||
return false;
|
||||
|
||||
xgbe_change_mode(pdata, mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
|
||||
@ -1178,21 +1180,23 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&pdata->an_mutex);
|
||||
|
||||
set_bit(XGBE_LINK_INIT, &pdata->dev_state);
|
||||
pdata->link_check = jiffies;
|
||||
|
||||
ret = pdata->phy_if.phy_impl.an_config(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
if (pdata->phy.autoneg != AUTONEG_ENABLE) {
|
||||
ret = xgbe_phy_config_fixed(pdata);
|
||||
if (ret || !pdata->kr_redrv)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
|
||||
} else {
|
||||
@ -1202,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
/* Disable auto-negotiation interrupt */
|
||||
disable_irq(pdata->an_irq);
|
||||
|
||||
/* Start auto-negotiation in a supported mode */
|
||||
if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KR);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SFI);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_X);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
|
||||
} else {
|
||||
enable_irq(pdata->an_irq);
|
||||
return -EINVAL;
|
||||
if (set_mode) {
|
||||
/* Start auto-negotiation in a supported mode */
|
||||
if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KR);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SFI);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_X);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
|
||||
} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
|
||||
xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
|
||||
} else {
|
||||
enable_irq(pdata->an_irq);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable and stop any in progress auto-negotiation */
|
||||
@ -1239,16 +1246,7 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
xgbe_an_init(pdata);
|
||||
xgbe_an_restart(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&pdata->an_mutex);
|
||||
|
||||
ret = __xgbe_phy_config_aneg(pdata);
|
||||
out:
|
||||
if (ret)
|
||||
set_bit(XGBE_LINK_ERR, &pdata->dev_state);
|
||||
else
|
||||
@ -1259,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
return __xgbe_phy_config_aneg(pdata, true);
|
||||
}
|
||||
|
||||
static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
return __xgbe_phy_config_aneg(pdata, false);
|
||||
}
|
||||
|
||||
static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
return (pdata->an_result == XGBE_AN_COMPLETE);
|
||||
@ -1315,7 +1323,8 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
|
||||
|
||||
pdata->phy.duplex = DUPLEX_FULL;
|
||||
|
||||
xgbe_set_mode(pdata, mode);
|
||||
if (xgbe_set_mode(pdata, mode) && pdata->an_again)
|
||||
xgbe_phy_reconfig_aneg(pdata);
|
||||
}
|
||||
|
||||
static void xgbe_phy_status(struct xgbe_prv_data *pdata)
|
||||
|
@ -902,6 +902,9 @@ static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
|
||||
XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
|
||||
return false;
|
||||
|
||||
/* For Bel-Fuse, use the extra AN flag */
|
||||
pdata->an_again = 1;
|
||||
|
||||
if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
|
||||
XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
|
||||
return false;
|
||||
@ -978,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
|
||||
if (phy_data->phydev)
|
||||
return 0;
|
||||
|
||||
/* Clear the extra AN flag */
|
||||
pdata->an_again = 0;
|
||||
|
||||
/* Check for the use of an external PHY */
|
||||
if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
|
||||
return 0;
|
||||
|
@ -1261,6 +1261,7 @@ struct xgbe_prv_data {
|
||||
enum xgbe_rx kr_state;
|
||||
enum xgbe_rx kx_state;
|
||||
struct work_struct an_work;
|
||||
unsigned int an_again;
|
||||
unsigned int an_supported;
|
||||
unsigned int parallel_detect;
|
||||
unsigned int fec_ability;
|
||||
|
Loading…
Reference in New Issue
Block a user