diff options
author | Jakub Kicinski <kuba@kernel.org> | 2021-11-24 18:40:09 -0800 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2021-11-24 18:40:09 -0800 |
commit | 06e5ba71750861acf65fb1b0cfb8f974159100af (patch) | |
tree | fc745cb9ac180c3db85443ab3baad920eaf7bd66 | |
parent | ddb826c2c92d461f290a7bab89e7c28696191875 (diff) | |
parent | dbae3388ea9ca33bd1d5eabc3b0ef17e69c74677 (diff) | |
download | linux-06e5ba71750861acf65fb1b0cfb8f974159100af.tar.gz |
Merge branch 'phylink-resolve-fixes'
Marek BehĂșn says:
====================
phylink resolve fixes
With information from me and my nagging, Russell has produced two fixes
for phylink, which add code that triggers another phylink_resolve() from
phylink_resolve(), if certain conditions are met:
interface is being changed
or
link is down and previous link was up
These are needed because sometimes the PCS callbacks may provide stale
values if link / speed / ...
====================
Link: https://lore.kernel.org/r/20211123154403.32051-1-kabel@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/phy/phylink.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 3ad7397b81198..5904546acae61 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -710,6 +710,7 @@ static void phylink_resolve(struct work_struct *w) struct phylink_link_state link_state; struct net_device *ndev = pl->netdev; bool mac_config = false; + bool retrigger = false; bool cur_link_state; mutex_lock(&pl->state_mutex); @@ -723,6 +724,7 @@ static void phylink_resolve(struct work_struct *w) link_state.link = false; } else if (pl->mac_link_dropped) { link_state.link = false; + retrigger = true; } else { switch (pl->cur_link_an_mode) { case MLO_AN_PHY: @@ -739,6 +741,19 @@ static void phylink_resolve(struct work_struct *w) case MLO_AN_INBAND: phylink_mac_pcs_get_state(pl, &link_state); + /* The PCS may have a latching link-fail indicator. + * If the link was up, bring the link down and + * re-trigger the resolve. Otherwise, re-read the + * PCS state to get the current status of the link. + */ + if (!link_state.link) { + if (cur_link_state) + retrigger = true; + else + phylink_mac_pcs_get_state(pl, + &link_state); + } + /* If we have a phy, the "up" state is the union of * both the PHY and the MAC */ @@ -747,6 +762,15 @@ static void phylink_resolve(struct work_struct *w) /* Only update if the PHY link is up */ if (pl->phydev && pl->phy_state.link) { + /* If the interface has changed, force a + * link down event if the link isn't already + * down, and re-resolve. + */ + if (link_state.interface != + pl->phy_state.interface) { + retrigger = true; + link_state.link = false; + } link_state.interface = pl->phy_state.interface; /* If we have a PHY, we need to update with @@ -789,7 +813,7 @@ static void phylink_resolve(struct work_struct *w) else phylink_link_up(pl, link_state); } - if (!link_state.link && pl->mac_link_dropped) { + if (!link_state.link && retrigger) { pl->mac_link_dropped = false; queue_work(system_power_efficient_wq, &pl->resolve); } |