Commit 4c0d2e96 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by David S. Miller

net: phy: consider that suspend2ram may cut off PHY power

Claudiu reported that on his system S2R cuts off power to the PHY and
after resuming certain PHY settings are lost. The PM folks confirmed
that cutting off power to selected components in S2R is a valid case.
Therefore resuming from S2R, same as from hibernation, has to assume
that the PHY has power-on defaults. As a consequence use the restore
callback also as resume callback.
In addition make sure that the interrupt configuration is restored.
Let's do this in phy_init_hw() and ensure that after this call
actual interrupt configuration is in sync with phydev->interrupts.
Currently, if interrupt was enabled before hibernation, we would
resume with interrupt disabled because that's the power-on default.

This fix applies cleanly only after the commit marked as fixed.

I don't have an affected system, therefore change is compile-tested
only.

[0] https://lore.kernel.org/netdev/1610120754-14331-1-git-send-email-claudiu.beznea@microchip.com/

Fixes: 611d779a ("net: phy: fix MDIO bus PM PHY resuming")
Reported-by: default avatarClaudiu Beznea <claudiu.beznea@microchip.com>
Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e12be913
...@@ -300,50 +300,22 @@ static int mdio_bus_phy_resume(struct device *dev) ...@@ -300,50 +300,22 @@ static int mdio_bus_phy_resume(struct device *dev)
phydev->suspended_by_mdio_bus = 0; phydev->suspended_by_mdio_bus = 0;
ret = phy_resume(phydev); ret = phy_init_hw(phydev);
if (ret < 0) if (ret < 0)
return ret; return ret;
no_resume: ret = phy_resume(phydev);
if (phydev->attached_dev && phydev->adjust_link)
phy_start_machine(phydev);
return 0;
}
static int mdio_bus_phy_restore(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
struct net_device *netdev = phydev->attached_dev;
int ret;
if (!netdev)
return 0;
ret = phy_init_hw(phydev);
if (ret < 0) if (ret < 0)
return ret; return ret;
no_resume:
if (phydev->attached_dev && phydev->adjust_link) if (phydev->attached_dev && phydev->adjust_link)
phy_start_machine(phydev); phy_start_machine(phydev);
return 0; return 0;
} }
static const struct dev_pm_ops mdio_bus_phy_pm_ops = { static SIMPLE_DEV_PM_OPS(mdio_bus_phy_pm_ops, mdio_bus_phy_suspend,
.suspend = mdio_bus_phy_suspend, mdio_bus_phy_resume);
.resume = mdio_bus_phy_resume,
.freeze = mdio_bus_phy_suspend,
.thaw = mdio_bus_phy_resume,
.restore = mdio_bus_phy_restore,
};
#define MDIO_BUS_PHY_PM_OPS (&mdio_bus_phy_pm_ops)
#else
#define MDIO_BUS_PHY_PM_OPS NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/** /**
...@@ -554,7 +526,7 @@ static const struct device_type mdio_bus_phy_type = { ...@@ -554,7 +526,7 @@ static const struct device_type mdio_bus_phy_type = {
.name = "PHY", .name = "PHY",
.groups = phy_dev_groups, .groups = phy_dev_groups,
.release = phy_device_release, .release = phy_device_release,
.pm = MDIO_BUS_PHY_PM_OPS, .pm = pm_ptr(&mdio_bus_phy_pm_ops),
}; };
static int phy_request_driver_module(struct phy_device *dev, u32 phy_id) static int phy_request_driver_module(struct phy_device *dev, u32 phy_id)
...@@ -1143,10 +1115,19 @@ int phy_init_hw(struct phy_device *phydev) ...@@ -1143,10 +1115,19 @@ int phy_init_hw(struct phy_device *phydev)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (phydev->drv->config_init) if (phydev->drv->config_init) {
ret = phydev->drv->config_init(phydev); ret = phydev->drv->config_init(phydev);
if (ret < 0)
return ret;
}
return ret; if (phydev->drv->config_intr) {
ret = phydev->drv->config_intr(phydev);
if (ret < 0)
return ret;
}
return 0;
} }
EXPORT_SYMBOL(phy_init_hw); EXPORT_SYMBOL(phy_init_hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment