[PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: 2025-09-04 15:44:30
Also in:
lkml
Subsystem:
generic phy framework, lynx serdes phy drivers, the rest · Maintainers:
Vinod Koul, Ioana Ciornei, Vladimir Oltean, Linus Torvalds
Managed lanes are supposed to have power management through phy_power_on() and phy_power_off(). Unmanaged lanes are supposed to be always powered on, because they might have a consumer which doesn't use this SerDes driver, and we don't want to break it. A lane is initially unmanaged, and becomes managed when phy_init() is called on it. It is normal for consumer drivers to call both phy_init() and phy_exit(), in a balanced way. This ensures the phy->init_count from the phy core is brought back to zero, for example during -EPROBE_DEFER in the consumer, the lane temporarily becomes unmanaged and then managed again. Given the above requirement for consumers, it also imposes a requirement for the SerDes driver to implement the exit() operation. Otherwise, a balanced set of phy_init() and phy_exit() calls from the consumer will effectively result in multiple lynx_28g_init() calls as seen by the SerDes and nothing else. That actually doesn't work - the driver can't power down a SerDes lane which is actually powered down, so such a call sequence would hang the kernel. No consumer driver currently uses phy_exit(), so the above problem does not yet trigger, but in preparation for its introduction, it is necessary to add lynx_28g_exit() as the mirror of lynx_28g_init(). Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> --- drivers/phy/freescale/phy-fsl-lynx-28g.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 5055ddba0363..91a3b3928ab4 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c@@ -1129,8 +1129,24 @@ static int lynx_28g_init(struct phy *phy) return 0; } +static int lynx_28g_exit(struct phy *phy) +{ + struct lynx_28g_lane *lane = phy_get_drvdata(phy); + + /* The lane returns to the state where it isn't managed by the + * consumer, so we must treat is as if it isn't initialized, and always + * powered on. + */ + lane->init = false; + lane->powered_up = false; + lynx_28g_power_on(phy); + + return 0; +} + static const struct phy_ops lynx_28g_ops = { .init = lynx_28g_init, + .exit = lynx_28g_exit, .power_on = lynx_28g_power_on, .power_off = lynx_28g_power_off, .set_mode = lynx_28g_set_mode,
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy