When a PHY_HALTED phydev is resumed by phy_start(), it is set to PHY_RESUMING to wait for the link to come up.
However, if the phydev was put to PHY_HALTED (by e.g. phy_stop()) before autonegotiation was ever started by phy_state_machine(), autonegotiation remains unconfigured, i.e. phy_config_aneg() is never called. Fix that by going to PHY_UP instead of PHY_RESUMING if autonegotiation has never been configured. Signed-off-by: Anssi Hannula <anssi.hann...@bitwise.fi> --- This doesn't feel as clean is I'd like to, though. Maybe there is a better way? drivers/net/phy/phy.c | 11 ++++++++++- include/linux/phy.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d46858694db9..7a650cce7599 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -553,6 +553,8 @@ int phy_start_aneg(struct phy_device *phydev) if (err < 0) goto out_unlock; + phydev->autoneg_configured = 1; + if (phydev->state != PHY_HALTED) { if (AUTONEG_ENABLE == phydev->autoneg) { err = phy_check_link_status(phydev); @@ -893,7 +895,14 @@ void phy_start(struct phy_device *phydev) break; } - phydev->state = PHY_RESUMING; + /* if autoneg/forcing was never configured, go back to PHY_UP + * to make that happen + */ + if (!phydev->autoneg_configured) + phydev->state = PHY_UP; + else + phydev->state = PHY_RESUMING; + break; default: break; diff --git a/include/linux/phy.h b/include/linux/phy.h index 8f927246acdb..b306d5ed9d09 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -389,6 +389,8 @@ struct phy_device { unsigned loopback_enabled:1; unsigned autoneg:1; + /* autoneg has been configured at least once */ + unsigned autoneg_configured:1; /* The most recently read link state */ unsigned link:1; -- 2.17.2