* [PATCH net v1 0/2] net: phy: fix driver cleanup after probe failure
@ 2026-08-12 12:51 Xuanqiang Luo
2026-08-12 12:51 ` [PATCH net v1 1/2] net: phy: split phy_probe() error paths Xuanqiang Luo
2026-08-12 12:51 ` [PATCH net v1 2/2] net: phy: call driver remove when core initialization fails Xuanqiang Luo
0 siblings, 2 replies; 5+ messages in thread
From: Xuanqiang Luo @ 2026-08-12 12:51 UTC (permalink / raw)
To: netdev
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni,
linux-kernel, Xuanqiang Luo
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
Patch 1 splits the phy_probe() error paths and makes phy_setup_ports()
unwind its own resources.
Patch 2 calls the PHY driver remove callback when phy_probe() fails after
the driver probe callback succeeds.
Xuanqiang Luo (2):
net: phy: split phy_probe() error paths
net: phy: call driver remove when core initialization fails
drivers/net/phy/phy_device.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
base-commit: db2ddb87143519e20a95aa36c60b36107b736a58
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v1 1/2] net: phy: split phy_probe() error paths
2026-08-12 12:51 [PATCH net v1 0/2] net: phy: fix driver cleanup after probe failure Xuanqiang Luo
@ 2026-08-12 12:51 ` Xuanqiang Luo
2026-08-12 13:41 ` Andrew Lunn
2026-08-12 12:51 ` [PATCH net v1 2/2] net: phy: call driver remove when core initialization fails Xuanqiang Luo
1 sibling, 1 reply; 5+ messages in thread
From: Xuanqiang Luo @ 2026-08-12 12:51 UTC (permalink / raw)
To: netdev
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni,
linux-kernel, Xuanqiang Luo
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
phy_probe() uses one cleanup path for failures at every initialization
stage. This runs cleanup for resources that have not been initialized
and leaves phy_setup_ports() relying on its caller to remove an SFP
upstream after a partial failure.
Make phy_setup_ports() unwind the SFP upstream before removing its ports.
Then split the phy_probe() cleanup so each failure path unwinds only the
resources that may have been initialized.
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
---
drivers/net/phy/phy_device.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 0615228459ef4..f8e434daab66e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3556,6 +3556,9 @@ static int phy_setup_ports(struct phy_device *phydev)
return 0;
out:
+ sfp_bus_del_upstream(phydev->sfp_bus);
+ phydev->sfp_bus = NULL;
+
phy_cleanup_ports(phydev);
return ret;
}
@@ -3681,7 +3684,7 @@ static int phy_probe(struct device *dev)
if (phydev->drv->probe) {
err = phydev->drv->probe(phydev);
if (err)
- goto out;
+ goto out_reset;
}
phy_disable_interrupts(phydev);
@@ -3702,7 +3705,7 @@ static int phy_probe(struct device *dev)
err = genphy_read_abilities(phydev);
if (err)
- goto out;
+ goto out_reset;
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
phydev->supported))
@@ -3719,7 +3722,7 @@ static int phy_probe(struct device *dev)
err = phy_setup_ports(phydev);
if (err)
- goto out;
+ goto out_reset;
phy_advertise_supported(phydev);
@@ -3728,7 +3731,7 @@ static int phy_probe(struct device *dev)
*/
err = genphy_c45_read_eee_adv(phydev, phydev->advertising_eee);
if (err)
- goto out;
+ goto out_ports;
/* Get the EEE modes we want to prohibit. */
of_set_phy_eee_broken(phydev);
@@ -3781,20 +3784,22 @@ static int phy_probe(struct device *dev)
if (IS_ENABLED(CONFIG_PHYLIB_LEDS) && !phy_driver_is_genphy(phydev)) {
err = of_phy_leds(phydev);
if (err)
- goto out;
+ goto out_led_triggers;
}
return 0;
-out:
+out_led_triggers:
+ if (!phydev->is_on_sfp_module)
+ phy_led_triggers_unregister(phydev);
+
+out_ports:
sfp_bus_del_upstream(phydev->sfp_bus);
phydev->sfp_bus = NULL;
phy_cleanup_ports(phydev);
- if (!phydev->is_on_sfp_module)
- phy_led_triggers_unregister(phydev);
-
+out_reset:
/* Re-assert the reset signal on error */
phy_device_reset(phydev, 1);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net v1 2/2] net: phy: call driver remove when core initialization fails
2026-08-12 12:51 [PATCH net v1 0/2] net: phy: fix driver cleanup after probe failure Xuanqiang Luo
2026-08-12 12:51 ` [PATCH net v1 1/2] net: phy: split phy_probe() error paths Xuanqiang Luo
@ 2026-08-12 12:51 ` Xuanqiang Luo
1 sibling, 0 replies; 5+ messages in thread
From: Xuanqiang Luo @ 2026-08-12 12:51 UTC (permalink / raw)
To: netdev
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni,
linux-kernel, Xuanqiang Luo
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
phy_probe() may fail while querying features or completing other core
initialization after the PHY driver probe callback has succeeded. The
driver core does not run the remove path after a probe error, so
resources that the PHY driver releases in its remove callback are
leaked.
Call the PHY driver remove callback on these failures.
Fixes: efbdfdc29bdd ("net: phy: Add support for asking the PHY its abilities")
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
---
drivers/net/phy/phy_device.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index f8e434daab66e..be714758360b2 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3705,7 +3705,7 @@ static int phy_probe(struct device *dev)
err = genphy_read_abilities(phydev);
if (err)
- goto out_reset;
+ goto out_remove;
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
phydev->supported))
@@ -3722,7 +3722,7 @@ static int phy_probe(struct device *dev)
err = phy_setup_ports(phydev);
if (err)
- goto out_reset;
+ goto out_remove;
phy_advertise_supported(phydev);
@@ -3799,6 +3799,10 @@ static int phy_probe(struct device *dev)
phy_cleanup_ports(phydev);
+out_remove:
+ if (phydev->drv->remove)
+ phydev->drv->remove(phydev);
+
out_reset:
/* Re-assert the reset signal on error */
phy_device_reset(phydev, 1);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net v1 1/2] net: phy: split phy_probe() error paths
2026-08-12 12:51 ` [PATCH net v1 1/2] net: phy: split phy_probe() error paths Xuanqiang Luo
@ 2026-08-12 13:41 ` Andrew Lunn
2026-08-12 16:05 ` Maxime Chevallier
0 siblings, 1 reply; 5+ messages in thread
From: Andrew Lunn @ 2026-08-12 13:41 UTC (permalink / raw)
To: Xuanqiang Luo
Cc: netdev, hkallweit1, linux, davem, edumazet, kuba, pabeni,
linux-kernel, Xuanqiang Luo
On Wed, Aug 12, 2026 at 08:51:26PM +0800, Xuanqiang Luo wrote:
> From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
>
> phy_probe() uses one cleanup path for failures at every initialization
> stage. This runs cleanup for resources that have not been initialized
> and leaves phy_setup_ports() relying on its caller to remove an SFP
> upstream after a partial failure.
>
> Make phy_setup_ports() unwind the SFP upstream before removing its ports.
> Then split the phy_probe() cleanup so each failure path unwinds only the
> resources that may have been initialized.
>
> Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
> ---
> drivers/net/phy/phy_device.c | 23 ++++++++++++++---------
> 1 file changed, 14 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> index 0615228459ef4..f8e434daab66e 100644
> --- a/drivers/net/phy/phy_device.c
> +++ b/drivers/net/phy/phy_device.c
> @@ -3556,6 +3556,9 @@ static int phy_setup_ports(struct phy_device *phydev)
> return 0;
>
> out:
> + sfp_bus_del_upstream(phydev->sfp_bus);
> + phydev->sfp_bus = NULL;
> +
> phy_cleanup_ports(phydev);
> return ret;
This does not look correct. phy_sfp_probe() may fail, and you then
call sfp_bus_del_upstream() on something which never happened.
Also, it is not obvious that sfp_bus_del_upstream() is the correct
thing to do. You are trying to undo phy_sfp_probe() so i would expect
you to call a function like phy_sfp_release().
It also looks like phy_sfp_probe() does not correctly clean up on
phy_setup_sfp_port() returning an error. But that is a different
issue.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net v1 1/2] net: phy: split phy_probe() error paths
2026-08-12 13:41 ` Andrew Lunn
@ 2026-08-12 16:05 ` Maxime Chevallier
0 siblings, 0 replies; 5+ messages in thread
From: Maxime Chevallier @ 2026-08-12 16:05 UTC (permalink / raw)
To: Andrew Lunn, Xuanqiang Luo
Cc: netdev, hkallweit1, linux, davem, edumazet, kuba, pabeni,
linux-kernel, Xuanqiang Luo
Hi,
On 8/12/26 15:41, Andrew Lunn wrote:
> On Wed, Aug 12, 2026 at 08:51:26PM +0800, Xuanqiang Luo wrote:
>> From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
>>
>> phy_probe() uses one cleanup path for failures at every initialization
>> stage. This runs cleanup for resources that have not been initialized
>> and leaves phy_setup_ports() relying on its caller to remove an SFP
>> upstream after a partial failure.
>>
>> Make phy_setup_ports() unwind the SFP upstream before removing its ports.
>> Then split the phy_probe() cleanup so each failure path unwinds only the
>> resources that may have been initialized.
>>
>> Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
>> ---
>> drivers/net/phy/phy_device.c | 23 ++++++++++++++---------
>> 1 file changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
>> index 0615228459ef4..f8e434daab66e 100644
>> --- a/drivers/net/phy/phy_device.c
>> +++ b/drivers/net/phy/phy_device.c
>> @@ -3556,6 +3556,9 @@ static int phy_setup_ports(struct phy_device *phydev)
>> return 0;
>>
>> out:
>> + sfp_bus_del_upstream(phydev->sfp_bus);
>> + phydev->sfp_bus = NULL;
>> +
>> phy_cleanup_ports(phydev);
>> return ret;
>
> This does not look correct. phy_sfp_probe() may fail, and you then
> call sfp_bus_del_upstream() on something which never happened.
>
> Also, it is not obvious that sfp_bus_del_upstream() is the correct
> thing to do. You are trying to undo phy_sfp_probe() so i would expect
> you to call a function like phy_sfp_release().
I agree with having phy_sfp_release(), we have even more to do with phy SFP
in the future with phy_port, this is less error prone.
>
> It also looks like phy_sfp_probe() does not correctly clean up on
> phy_setup_sfp_port() returning an error. But that is a different
> issue.
In practise, this is cleaned in the phy_probe's "out" failure label,
but indeed this is not pretty.
Maxime
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-12 16:06 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 12:51 [PATCH net v1 0/2] net: phy: fix driver cleanup after probe failure Xuanqiang Luo
2026-08-12 12:51 ` [PATCH net v1 1/2] net: phy: split phy_probe() error paths Xuanqiang Luo
2026-08-12 13:41 ` Andrew Lunn
2026-08-12 16:05 ` Maxime Chevallier
2026-08-12 12:51 ` [PATCH net v1 2/2] net: phy: call driver remove when core initialization fails Xuanqiang Luo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox