diff options
author | Lendacky, Thomas <Thomas.Lendacky@amd.com> | 2015-03-20 11:50:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-20 16:33:56 -0400 |
commit | 9ae5eecdba7297725b280e81e905f48f85f9ffe7 (patch) | |
tree | ba768a09585a8044366f9b0fa4f05639ee97dce7 /drivers | |
parent | 65f57cb152ea0ad464793927e79074eb6da0064a (diff) |
amd-xgbe-phy: Provide support for auto-negotiation timeout
Currently, there is no interrupt code that indicates auto-negotiation
has timed out. If the auto-negotiation has timed out then the start of
a new auto-negotiation will begin again with a new base page being
received. The state machine could be in a state that is not expecting
this interrupt code which results in an error during auto-negotiation.
Update the code to timestamp when the auto-negotiation starts. Should
another page received interrupt code occur before auto-negotiation has
completed but after the auto-negotiation timeout, then reset the state
machine to allow the auto-negotiation to continue.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/phy/amd-xgbe-phy.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 4b95caf08aa9..fb276f64cd64 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -78,6 +78,7 @@ #include <linux/bitops.h> #include <linux/property.h> #include <linux/acpi.h> +#include <linux/jiffies.h> MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); MODULE_LICENSE("Dual BSD/GPL"); @@ -100,6 +101,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_SPEED_2500 1 #define XGBE_PHY_SPEED_10000 2 +#define XGBE_AN_MS_TIMEOUT 500 + #define XGBE_AN_INT_CMPLT 0x01 #define XGBE_AN_INC_LINK 0x02 #define XGBE_AN_PG_RCV 0x04 @@ -434,6 +437,7 @@ struct amd_xgbe_phy_priv { unsigned int an_supported; unsigned int parallel_detect; unsigned int fec_ability; + unsigned long an_start; unsigned int lpm_ctrl; /* CTRL1 for resume */ }; @@ -902,8 +906,23 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; enum amd_xgbe_phy_rx *state; + unsigned long an_timeout; int ret; + if (!priv->an_start) { + priv->an_start = jiffies; + } else { + an_timeout = priv->an_start + + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); + if (time_after(jiffies, an_timeout)) { + /* Auto-negotiation timed out, reset state */ + priv->kr_state = AMD_XGBE_RX_BPA; + priv->kx_state = AMD_XGBE_RX_BPA; + + priv->an_start = jiffies; + } + } + state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state : &priv->kx_state; @@ -1078,6 +1097,7 @@ again: priv->an_state = AMD_XGBE_AN_READY; priv->kr_state = AMD_XGBE_RX_BPA; priv->kx_state = AMD_XGBE_RX_BPA; + priv->an_start = 0; } if (cur_state != priv->an_state) |