[PATCH v4 phy 14/16] phy: lynx-28g: improve lynx_28g_probe() sequence

Vladimir Oltean
2025-11-10T09:23:22Z

dev_set_drvdata() is called twice, it is sufficient to do it only once.

devm_of_phy_provider_register() can fail, and if it does, the
&priv->cdr_check work item is queued, but not cancelled, and the device
probing failed, so it will trigger use after free. This is a minor risk
though.

Resource initialization should be done a little earlier, in case we need
to dereference dev_get_drvdata() in lynx_28g_pll_read_configuration() or
in lynx_28g_lane_read_configuration().

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: slight context change due to the introduction of
lynx_28g_probe_lane()
v2->v3: none
v1->v2: patch is new

drivers/phy/freescale/phy-fsl-lynx-28g.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 5d5c94295726..649c5c2fa4ad 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1165,7 +1165,11 @@ static int lynx_28g_probe(struct platform_device *pdev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+
priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+ spin_lock_init(&priv->pcc_lock);
+ INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);

priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -1210,18 +1214,14 @@ static int lynx_28g_probe(struct platform_device *pdev)
}
}

- dev_set_drvdata(dev, priv);
-
- spin_lock_init(&priv->pcc_lock);
- INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
+ provider = devm_of_phy_provider_register(dev, lynx_28g_xlate);
+ if (IS_ERR(provider))
+ return PTR_ERR(provider);

queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
msecs_to_jiffies(1000));

- dev_set_drvdata(dev, priv);
- provider = devm_of_phy_provider_register(dev, lynx_28g_xlate);
-
- return PTR_ERR_OR_ZERO(provider);
+ return 0;
}

static void lynx_28g_remove(struct platform_device *pdev)