amd-xgbe-phy: Properly support the FEC auto-negotiation

Advertise and apply the Forward Error Correction capabilities of the
device based on the FEC ability of the device. Also, remove the use
of some hard coded values related to KR and FEC in preference of some
#defines.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Lendacky, Thomas 2015-01-16 12:47:05 -06:00 committed by David S. Miller
parent c3152d4728
commit cf262527e5
1 changed files with 33 additions and 11 deletions

View File

@ -99,10 +99,21 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define XGBE_PHY_RATECHANGE_COUNT 500 #define XGBE_PHY_RATECHANGE_COUNT 500
#define XGBE_PHY_KR_TRAINING_START 0x01
#define XGBE_PHY_KR_TRAINING_ENABLE 0x02
#define XGBE_PHY_FEC_ENABLE 0x01
#define XGBE_PHY_FEC_FORWARD 0x02
#define XGBE_PHY_FEC_MASK 0x03
#ifndef MDIO_PMA_10GBR_PMD_CTRL #ifndef MDIO_PMA_10GBR_PMD_CTRL
#define MDIO_PMA_10GBR_PMD_CTRL 0x0096 #define MDIO_PMA_10GBR_PMD_CTRL 0x0096
#endif #endif
#ifndef MDIO_PMA_10GBR_FEC_ABILITY
#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa
#endif
#ifndef MDIO_PMA_10GBR_FEC_CTRL #ifndef MDIO_PMA_10GBR_FEC_CTRL
#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
#endif #endif
@ -345,6 +356,7 @@ struct amd_xgbe_phy_priv {
struct workqueue_struct *an_workqueue; struct workqueue_struct *an_workqueue;
unsigned int an_supported; unsigned int an_supported;
unsigned int parallel_detect; unsigned int parallel_detect;
unsigned int fec_ability;
unsigned int lpm_ctrl; /* CTRL1 for resume */ unsigned int lpm_ctrl; /* CTRL1 for resume */
}; };
@ -357,7 +369,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret |= 0x02; ret |= XGBE_PHY_KR_TRAINING_ENABLE;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
return 0; return 0;
@ -371,7 +383,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret &= ~0x02; ret &= ~XGBE_PHY_KR_TRAINING_ENABLE;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
return 0; return 0;
@ -690,10 +702,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
if (ret < 0) if (ret < 0)
return AMD_XGBE_AN_ERROR; return AMD_XGBE_AN_ERROR;
ret &= ~XGBE_PHY_FEC_MASK;
if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
ret |= 0x01; ret |= priv->fec_ability;
else
ret &= ~0x01;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret);
@ -702,12 +713,15 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
if (ret < 0) if (ret < 0)
return AMD_XGBE_AN_ERROR; return AMD_XGBE_AN_ERROR;
XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); if (ret & XGBE_PHY_KR_TRAINING_ENABLE) {
XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
ret |= 0x01; ret |= XGBE_PHY_KR_TRAINING_START;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
ret);
XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
}
return AMD_XGBE_AN_PAGE_RECEIVED; return AMD_XGBE_AN_PAGE_RECEIVED;
} }
@ -1092,12 +1106,16 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev)
priv->an_irq_allocated = 1; priv->an_irq_allocated = 1;
} }
ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY);
if (ret < 0)
return ret;
priv->fec_ability = ret & XGBE_PHY_FEC_MASK;
/* Initialize supported features */ /* Initialize supported features */
phydev->supported = SUPPORTED_Autoneg; phydev->supported = SUPPORTED_Autoneg;
phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
phydev->supported |= SUPPORTED_Backplane; phydev->supported |= SUPPORTED_Backplane;
phydev->supported |= SUPPORTED_10000baseKR_Full | phydev->supported |= SUPPORTED_10000baseKR_Full;
SUPPORTED_10000baseR_FEC;
switch (priv->speed_set) { switch (priv->speed_set) {
case AMD_XGBE_PHY_SPEEDSET_1000_10000: case AMD_XGBE_PHY_SPEEDSET_1000_10000:
phydev->supported |= SUPPORTED_1000baseKX_Full; phydev->supported |= SUPPORTED_1000baseKX_Full;
@ -1106,6 +1124,10 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev)
phydev->supported |= SUPPORTED_2500baseX_Full; phydev->supported |= SUPPORTED_2500baseX_Full;
break; break;
} }
if (priv->fec_ability & XGBE_PHY_FEC_ENABLE)
phydev->supported |= SUPPORTED_10000baseR_FEC;
phydev->advertising = phydev->supported; phydev->advertising = phydev->supported;
/* Set initial mode - call the mode setting routines /* Set initial mode - call the mode setting routines