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>
This commit is contained in:
commit
06e5ba7175
@ -710,6 +710,7 @@ static void phylink_resolve(struct work_struct *w)
|
|||||||
struct phylink_link_state link_state;
|
struct phylink_link_state link_state;
|
||||||
struct net_device *ndev = pl->netdev;
|
struct net_device *ndev = pl->netdev;
|
||||||
bool mac_config = false;
|
bool mac_config = false;
|
||||||
|
bool retrigger = false;
|
||||||
bool cur_link_state;
|
bool cur_link_state;
|
||||||
|
|
||||||
mutex_lock(&pl->state_mutex);
|
mutex_lock(&pl->state_mutex);
|
||||||
@ -723,6 +724,7 @@ static void phylink_resolve(struct work_struct *w)
|
|||||||
link_state.link = false;
|
link_state.link = false;
|
||||||
} else if (pl->mac_link_dropped) {
|
} else if (pl->mac_link_dropped) {
|
||||||
link_state.link = false;
|
link_state.link = false;
|
||||||
|
retrigger = true;
|
||||||
} else {
|
} else {
|
||||||
switch (pl->cur_link_an_mode) {
|
switch (pl->cur_link_an_mode) {
|
||||||
case MLO_AN_PHY:
|
case MLO_AN_PHY:
|
||||||
@ -739,6 +741,19 @@ static void phylink_resolve(struct work_struct *w)
|
|||||||
case MLO_AN_INBAND:
|
case MLO_AN_INBAND:
|
||||||
phylink_mac_pcs_get_state(pl, &link_state);
|
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
|
/* If we have a phy, the "up" state is the union of
|
||||||
* both the PHY and the MAC
|
* 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 */
|
/* Only update if the PHY link is up */
|
||||||
if (pl->phydev && pl->phy_state.link) {
|
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;
|
link_state.interface = pl->phy_state.interface;
|
||||||
|
|
||||||
/* If we have a PHY, we need to update with
|
/* If we have a PHY, we need to update with
|
||||||
@ -789,7 +813,7 @@ static void phylink_resolve(struct work_struct *w)
|
|||||||
else
|
else
|
||||||
phylink_link_up(pl, link_state);
|
phylink_link_up(pl, link_state);
|
||||||
}
|
}
|
||||||
if (!link_state.link && pl->mac_link_dropped) {
|
if (!link_state.link && retrigger) {
|
||||||
pl->mac_link_dropped = false;
|
pl->mac_link_dropped = false;
|
||||||
queue_work(system_power_efficient_wq, &pl->resolve);
|
queue_work(system_power_efficient_wq, &pl->resolve);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user