Skip to content

Commit f974936

Browse files
Russell King (Oracle)davem330
authored andcommitted
net: phylink: add suspend/resume support
Joakim Zhang reports that Wake-on-Lan with the stmmac ethernet driver broke when moving the incorrect handling of mac link state out of mac_config(). This reason this breaks is because the stmmac's WoL is handled by the MAC rather than the PHY, and phylink doesn't cater for that scenario. This patch adds the necessary phylink code to handle suspend/resume events according to whether the MAC still needs a valid link or not. This is the barest minimum for this support. Reported-by: Joakim Zhang <[email protected]> Tested-by: Joakim Zhang <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]> Signed-off-by: Joakim Zhang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0341d5e commit f974936

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

drivers/net/phy/phylink.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
enum {
3434
PHYLINK_DISABLE_STOPPED,
3535
PHYLINK_DISABLE_LINK,
36+
PHYLINK_DISABLE_MAC_WOL,
3637
};
3738

3839
/**
@@ -1282,6 +1283,9 @@ EXPORT_SYMBOL_GPL(phylink_start);
12821283
* network device driver's &struct net_device_ops ndo_stop() method. The
12831284
* network device's carrier state should not be changed prior to calling this
12841285
* function.
1286+
*
1287+
* This will synchronously bring down the link if the link is not already
1288+
* down (in other words, it will trigger a mac_link_down() method call.)
12851289
*/
12861290
void phylink_stop(struct phylink *pl)
12871291
{
@@ -1301,6 +1305,84 @@ void phylink_stop(struct phylink *pl)
13011305
}
13021306
EXPORT_SYMBOL_GPL(phylink_stop);
13031307

1308+
/**
1309+
* phylink_suspend() - handle a network device suspend event
1310+
* @pl: a pointer to a &struct phylink returned from phylink_create()
1311+
* @mac_wol: true if the MAC needs to receive packets for Wake-on-Lan
1312+
*
1313+
* Handle a network device suspend event. There are several cases:
1314+
* - If Wake-on-Lan is not active, we can bring down the link between
1315+
* the MAC and PHY by calling phylink_stop().
1316+
* - If Wake-on-Lan is active, and being handled only by the PHY, we
1317+
* can also bring down the link between the MAC and PHY.
1318+
* - If Wake-on-Lan is active, but being handled by the MAC, the MAC
1319+
* still needs to receive packets, so we can not bring the link down.
1320+
*/
1321+
void phylink_suspend(struct phylink *pl, bool mac_wol)
1322+
{
1323+
ASSERT_RTNL();
1324+
1325+
if (mac_wol && (!pl->netdev || pl->netdev->wol_enabled)) {
1326+
/* Wake-on-Lan enabled, MAC handling */
1327+
mutex_lock(&pl->state_mutex);
1328+
1329+
/* Stop the resolver bringing the link up */
1330+
__set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
1331+
1332+
/* Disable the carrier, to prevent transmit timeouts,
1333+
* but one would hope all packets have been sent. This
1334+
* also means phylink_resolve() will do nothing.
1335+
*/
1336+
netif_carrier_off(pl->netdev);
1337+
1338+
/* We do not call mac_link_down() here as we want the
1339+
* link to remain up to receive the WoL packets.
1340+
*/
1341+
mutex_unlock(&pl->state_mutex);
1342+
} else {
1343+
phylink_stop(pl);
1344+
}
1345+
}
1346+
EXPORT_SYMBOL_GPL(phylink_suspend);
1347+
1348+
/**
1349+
* phylink_resume() - handle a network device resume event
1350+
* @pl: a pointer to a &struct phylink returned from phylink_create()
1351+
*
1352+
* Undo the effects of phylink_suspend(), returning the link to an
1353+
* operational state.
1354+
*/
1355+
void phylink_resume(struct phylink *pl)
1356+
{
1357+
ASSERT_RTNL();
1358+
1359+
if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) {
1360+
/* Wake-on-Lan enabled, MAC handling */
1361+
1362+
/* Call mac_link_down() so we keep the overall state balanced.
1363+
* Do this under the state_mutex lock for consistency. This
1364+
* will cause a "Link Down" message to be printed during
1365+
* resume, which is harmless - the true link state will be
1366+
* printed when we run a resolve.
1367+
*/
1368+
mutex_lock(&pl->state_mutex);
1369+
phylink_link_down(pl);
1370+
mutex_unlock(&pl->state_mutex);
1371+
1372+
/* Re-apply the link parameters so that all the settings get
1373+
* restored to the MAC.
1374+
*/
1375+
phylink_mac_initial_config(pl, true);
1376+
1377+
/* Re-enable and re-resolve the link parameters */
1378+
clear_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
1379+
phylink_run_resolve(pl);
1380+
} else {
1381+
phylink_start(pl);
1382+
}
1383+
}
1384+
EXPORT_SYMBOL_GPL(phylink_resume);
1385+
13041386
/**
13051387
* phylink_ethtool_get_wol() - get the wake on lan parameters for the PHY
13061388
* @pl: a pointer to a &struct phylink returned from phylink_create()

include/linux/phylink.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,9 @@ void phylink_mac_change(struct phylink *, bool up);
451451
void phylink_start(struct phylink *);
452452
void phylink_stop(struct phylink *);
453453

454+
void phylink_suspend(struct phylink *pl, bool mac_wol);
455+
void phylink_resume(struct phylink *pl);
456+
454457
void phylink_ethtool_get_wol(struct phylink *, struct ethtool_wolinfo *);
455458
int phylink_ethtool_set_wol(struct phylink *, struct ethtool_wolinfo *);
456459

0 commit comments

Comments
 (0)