Skip to content

Commit

Permalink
net: phylink: fix suspend/resume with WoL enabled and link down
Browse files Browse the repository at this point in the history
When WoL is enabled, we update the software state in phylink to
indicate that the link is down, and disable the resolver from
bringing the link back up.

On resume, we attempt to bring the overall state into consistency
by calling the .mac_link_down() method, but this is wrong if the
link was already down, as phylink strictly orders the .mac_link_up()
and .mac_link_down() methods - and this would break that ordering.

Fixes: f974936 ("net: phylink: add suspend/resume support")
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Tested-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1u55Qf-0016RN-PA@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Russell King (Oracle) authored and Jakub Kicinski committed Apr 22, 2025
1 parent c03a49f commit 4c8925c
Showing 1 changed file with 22 additions and 16 deletions.
38 changes: 22 additions & 16 deletions drivers/net/phy/phylink.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct phylink {
unsigned int pcs_state;

bool link_failed;
bool suspend_link_up;
bool major_config_failed;
bool mac_supports_eee_ops;
bool mac_supports_eee;
Expand Down Expand Up @@ -2545,14 +2546,16 @@ void phylink_suspend(struct phylink *pl, bool mac_wol)
/* Stop the resolver bringing the link up */
__set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);

/* Disable the carrier, to prevent transmit timeouts,
* but one would hope all packets have been sent. This
* also means phylink_resolve() will do nothing.
*/
if (pl->netdev)
netif_carrier_off(pl->netdev);
else
pl->suspend_link_up = phylink_link_is_up(pl);
if (pl->suspend_link_up) {
/* Disable the carrier, to prevent transmit timeouts,
* but one would hope all packets have been sent. This
* also means phylink_resolve() will do nothing.
*/
if (pl->netdev)
netif_carrier_off(pl->netdev);
pl->old_link_state = false;
}

/* We do not call mac_link_down() here as we want the
* link to remain up to receive the WoL packets.
Expand Down Expand Up @@ -2603,15 +2606,18 @@ void phylink_resume(struct phylink *pl)
if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) {
/* Wake-on-Lan enabled, MAC handling */

/* Call mac_link_down() so we keep the overall state balanced.
* Do this under the state_mutex lock for consistency. This
* will cause a "Link Down" message to be printed during
* resume, which is harmless - the true link state will be
* printed when we run a resolve.
*/
mutex_lock(&pl->state_mutex);
phylink_link_down(pl);
mutex_unlock(&pl->state_mutex);
if (pl->suspend_link_up) {
/* Call mac_link_down() so we keep the overall state
* balanced. Do this under the state_mutex lock for
* consistency. This will cause a "Link Down" message
* to be printed during resume, which is harmless -
* the true link state will be printed when we run a
* resolve.
*/
mutex_lock(&pl->state_mutex);
phylink_link_down(pl);
mutex_unlock(&pl->state_mutex);
}

/* Re-apply the link parameters so that all the settings get
* restored to the MAC.
Expand Down

0 comments on commit 4c8925c

Please sign in to comment.