Commit 4203d840 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller
Browse files

net: phy: Ensure state transitions are processed from phy_stop()



In the phy_disconnect() -> phy_stop() path, we will be forcibly setting
the PHY state machine to PHY_HALTED. This invalidates the old_state !=
phydev->state condition in phy_state_machine() such that we will neither
display the state change for debugging, nor will we invoke the
link_change_notify() callback.

Factor the code by introducing phy_process_state_change(), and ensure
that we process the state change from phy_stop() as well.

Fixes: 5c5f626b ("net: phy: improve handling link_change_notify callback")
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 739cb499
Loading
Loading
Loading
Loading
+16 −7
Original line number Diff line number Diff line
@@ -57,6 +57,18 @@ static const char *phy_state_to_str(enum phy_state st)
	return NULL;
}

static void phy_process_state_change(struct phy_device *phydev,
				     enum phy_state old_state)
{
	if (old_state != phydev->state) {
		phydev_dbg(phydev, "PHY state change %s -> %s\n",
			   phy_state_to_str(old_state),
			   phy_state_to_str(phydev->state));
		if (phydev->drv && phydev->drv->link_change_notify)
			phydev->drv->link_change_notify(phydev);
	}
}

static void phy_link_up(struct phy_device *phydev)
{
	phydev->phy_link_change(phydev, true);
@@ -1301,6 +1313,7 @@ EXPORT_SYMBOL(phy_free_interrupt);
void phy_stop(struct phy_device *phydev)
{
	struct net_device *dev = phydev->attached_dev;
	enum phy_state old_state;

	if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) {
		WARN(1, "called from state %s\n",
@@ -1309,6 +1322,7 @@ void phy_stop(struct phy_device *phydev)
	}

	mutex_lock(&phydev->lock);
	old_state = phydev->state;

	if (phydev->state == PHY_CABLETEST) {
		phy_abort_cable_test(phydev);
@@ -1319,6 +1333,7 @@ void phy_stop(struct phy_device *phydev)
		sfp_upstream_stop(phydev->sfp_bus);

	phydev->state = PHY_HALTED;
	phy_process_state_change(phydev, old_state);

	mutex_unlock(&phydev->lock);

@@ -1436,13 +1451,7 @@ void phy_state_machine(struct work_struct *work)
	if (err < 0)
		phy_error(phydev);

	if (old_state != phydev->state) {
		phydev_dbg(phydev, "PHY state change %s -> %s\n",
			   phy_state_to_str(old_state),
			   phy_state_to_str(phydev->state));
		if (phydev->drv && phydev->drv->link_change_notify)
			phydev->drv->link_change_notify(phydev);
	}
	phy_process_state_change(phydev, old_state);

	/* Only re-schedule a PHY state machine change if we are polling the
	 * PHY, if PHY_MAC_INTERRUPT is set, then we will be moving