summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Perry <charles.perry@microchip.com>2026-04-08 06:18:16 -0700
committerJakub Kicinski <kuba@kernel.org>2026-04-12 14:19:19 -0700
commit96aefe3afe0e122a1472967224ffe21c3d51b67b (patch)
tree4af9fe08ea1a9559bb920f26bac908e197dce5a9
parentf76aef980206e7c6bc09933fd3c8e2b8a3479bd2 (diff)
downloadlwn-96aefe3afe0e122a1472967224ffe21c3d51b67b.tar.gz
lwn-96aefe3afe0e122a1472967224ffe21c3d51b67b.zip
net: phy: add a PHY write barrier when disabling interrupts
MDIO bus controllers are not required to wait for write transactions to complete before returning as synchronization is often achieved by polling status bits. This can cause issues when disabling interrupts since an interrupt could fire before the interrupt handler is unregistered and there's no status bit to poll. Add a phy_write_barrier() function and use it in phy_disable_interrupts() to fix this issue. The write barrier just reads an MII register and discards the value, which is enough to guarantee that previous writes have completed. Signed-off-by: Charles Perry <charles.perry@microchip.com> Link: https://patch.msgid.link/20260408131821.1145334-4-charles.perry@microchip.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/phy/phy.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 1f1039084f51..fce9bc7be330 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1369,13 +1369,36 @@ void phy_error(struct phy_device *phydev)
EXPORT_SYMBOL(phy_error);
/**
+ * phy_write_barrier - ensure the last write completed for this PHY device
+ * @phydev: target phy_device struct
+ *
+ * MDIO bus controllers are not required to wait for write transactions to
+ * complete before returning. Calling this function ensures that the previous
+ * write has completed.
+ */
+static void phy_write_barrier(struct phy_device *phydev)
+{
+ if (mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, MII_PHYSID1) ==
+ -EOPNOTSUPP)
+ mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
+ MDIO_MMD_PMAPMD, MII_PHYSID1);
+}
+
+/**
* phy_disable_interrupts - Disable the PHY interrupts from the PHY side
* @phydev: target phy_device struct
*/
int phy_disable_interrupts(struct phy_device *phydev)
{
+ int err;
+
/* Disable PHY interrupts */
- return phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+ err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+ if (err)
+ return err;
+
+ phy_write_barrier(phydev);
+ return 0;
}
/**