Commit 06e5ba71 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents ddb826c2 dbae3388
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -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);
	}