[PATCH net v4 4/5] net: phy: stop postponing PHY interrupts when a PHY PM callback fails
Igor Velkov via B4 Relay
devnull+iav.iav.lv at kernel.org
Sat Oct 31 01:01:15 PDT 2026
From: Igor Velkov <iav at iav.lv>
When phy_suspend() fails in mdio_bus_phy_suspend(), irq_suspended
stays set and the state machine stays stopped: the PM core does not
resume a device whose suspend callback failed, and the next PHY
interrupt disables the line until the next resume. When phy_init_hw()
or phy_resume() fail, mdio_bus_phy_resume() returns before the rerun,
with irq_suspended set and a postponed interrupt left disabled.
Undo the postponing and restart the state machine when phy_suspend()
fails, and rerun the postponed interrupt when phy_init_hw() or
phy_resume() fail, which gives the line back to the other users of a
shared line. A handler that then cannot read the PHY reports it through
phy_error(), as most PHY drivers do on any MDIO error.
Fixes: 1758bde2e4aa ("net: phy: Don't trigger state machine while in suspend")
Signed-off-by: Igor Velkov <iav at iav.lv>
---
drivers/net/phy/phy_device.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ef5e1cd3a831..390069ec13ca 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -366,6 +366,7 @@ static __maybe_unused void mdio_bus_phy_resume_irq(struct phy_device *phydev)
static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
+ int ret;
if (phydev->mac_managed_pm)
return 0;
@@ -383,9 +384,20 @@ static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
+ ret = phy_suspend(phydev);
+ if (ret) {
+ /* The PM core skips the resume callback of a device whose
+ * suspend callback failed.
+ */
+ mdio_bus_phy_resume_irq(phydev);
+ if (phy_uses_state_machine(phydev))
+ phy_start_machine(phydev);
+ return ret;
+ }
+
phydev->suspended_by_mdio_bus = 1;
- return phy_suspend(phydev);
+ return 0;
}
static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
@@ -411,11 +423,11 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
ret = phy_init_hw(phydev);
if (ret < 0)
- return ret;
+ goto err_resume_irq;
ret = phy_resume(phydev);
if (ret < 0)
- return ret;
+ goto err_resume_irq;
no_resume:
mdio_bus_phy_resume_irq(phydev);
@@ -423,6 +435,10 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
phy_start_machine(phydev);
return 0;
+
+err_resume_irq:
+ mdio_bus_phy_resume_irq(phydev);
+ return ret;
}
static SIMPLE_DEV_PM_OPS(mdio_bus_phy_pm_ops, mdio_bus_phy_suspend,
--
2.43.0
More information about the linux-arm-kernel
mailing list