[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250904154402.300032-13-vladimir.oltean@nxp.com>
Date: Thu, 4 Sep 2025 18:44:00 +0300
From: Vladimir Oltean <vladimir.oltean@....com>
To: linux-phy@...ts.infradead.org
Cc: Ioana Ciornei <ioana.ciornei@....com>,
Vinod Koul <vkoul@...nel.org>,
Kishon Vijay Abraham I <kishon@...nel.org>,
linux-kernel@...r.kernel.org
Subject: [PATCH phy 12/14] phy: lynx-28g: implement phy_exit() operation
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@....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
Powered by blists - more mailing lists