[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251025160905.3857885-3-sashal@kernel.org>
Date: Sat, 25 Oct 2025 11:53:54 -0400
From: Sasha Levin <sashal@...nel.org>
To: patches@...ts.linux.dev,
stable@...r.kernel.org
Cc: Heiner Kallweit <hkallweit1@...il.com>,
"Russell King (Oracle)" <rmk+kernel@...linux.org.uk>,
Jakub Kicinski <kuba@...nel.org>,
Sasha Levin <sashal@...nel.org>,
andrew@...n.ch,
olteanv@...il.com,
netdev@...r.kernel.org
Subject: [PATCH AUTOSEL 6.17-6.1] net: phy: fixed_phy: let fixed_phy_unregister free the phy_device
From: Heiner Kallweit <hkallweit1@...il.com>
[ Upstream commit a0f849c1cc6df0db9083b4c81c05a5456b1ed0fb ]
fixed_phy_register() creates and registers the phy_device. To be
symmetric, we should not only unregister, but also free the phy_device
in fixed_phy_unregister(). This allows to simplify code in users.
Note wrt of_phy_deregister_fixed_link():
put_device(&phydev->mdio.dev) and phy_device_free(phydev) are identical.
Signed-off-by: Heiner Kallweit <hkallweit1@...il.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@...linux.org.uk>
Link: https://patch.msgid.link/ad8dda9a-10ed-4060-916b-3f13bdbb899d@gmail.com
Signed-off-by: Jakub Kicinski <kuba@...nel.org>
Signed-off-by: Sasha Levin <sashal@...nel.org>
---
LLM Generated explanations, may be completely bogus:
YES
- Fix rationale and scope
- The change fixes an API asymmetry and a potential memory leak:
`fixed_phy_register()` allocates and registers a `phy_device`, but
pre‑patch `fixed_phy_unregister()` only removed it without freeing.
The commit makes `fixed_phy_unregister()` also free the
`phy_device`, preventing leaks and simplifying callers.
- The change is small and localized to fixed PHY/MDIO code; it does
not alter uAPI or architecture.
- Core change
- `drivers/net/phy/fixed_phy.c:230` now frees the `phy_device` after
removal:
- Calls `phy_device_remove(phy)`, `of_node_put(...)`,
`fixed_phy_del(...)`, and then `phy_device_free(phy)` to drop the
device reference and free when the refcount reaches zero.
- `phy_device_free()` is just a `put_device(&phydev->mdio.dev)`:
- `drivers/net/phy/phy_device.c:212` confirms that
`phy_device_free()` equals a `put_device`, matching the commit
note about identical behavior.
- Callers adjusted to avoid double-free
- `drivers/net/dsa/dsa_loop.c:398` removes the explicit
`phy_device_free(phydevs[i])` after
`fixed_phy_unregister(phydevs[i])`.
- `drivers/net/mdio/of_mdio.c:475` now calls only
`fixed_phy_unregister(phydev)` followed by
`put_device(&phydev->mdio.dev)` at `drivers/net/mdio/of_mdio.c:477`,
which correctly drops the extra reference obtained by
`of_phy_find_device(np)` (see `drivers/net/mdio/of_mdio.c:471`).
This is safe because `fixed_phy_unregister()`’s `phy_device_free()`
and the extra `put_device()` account for two separate refs (the
device’s own and the one grabbed by `of_phy_find_device()`).
- Other in-tree users remain correct and benefit
- Callers which already did not free explicitly remain correct and now
won’t leak:
- Example: `drivers/net/ethernet/faraday/ftgmac100.c:1763` calls
`fixed_phy_unregister(phydev)` (after `phy_disconnect()`), and
does not call `phy_device_free()`.
- `drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c:236` similarly
calls only `fixed_phy_unregister((struct phy_device *)data)`.
- We searched for all in-tree callers of `fixed_phy_unregister()` and
`of_phy_deregister_fixed_link()` and found no remaining explicit
frees which would cause a double free.
- Risk and stable suitability
- Minimal regression risk: change is contained, behavior is well-
defined, and in‑tree callers are updated or already compatible. No
architectural changes; no uAPI impact.
- Positive impact: fixes a likely leak for paths that didn’t free
after unregister (e.g., NCSI fixed PHY path in `ftgmac100`).
- Meets stable criteria: it’s a bug fix (memory management), small and
self-contained, with low risk of regression.
drivers/net/dsa/dsa_loop.c | 9 +++------
drivers/net/mdio/of_mdio.c | 1 -
drivers/net/phy/fixed_phy.c | 1 +
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index d8a35f25a4c82..ad907287a853a 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -386,13 +386,10 @@ static struct mdio_driver dsa_loop_drv = {
static void dsa_loop_phydevs_unregister(void)
{
- unsigned int i;
-
- for (i = 0; i < NUM_FIXED_PHYS; i++)
- if (!IS_ERR(phydevs[i])) {
+ for (int i = 0; i < NUM_FIXED_PHYS; i++) {
+ if (!IS_ERR(phydevs[i]))
fixed_phy_unregister(phydevs[i]);
- phy_device_free(phydevs[i]);
- }
+ }
}
static int __init dsa_loop_init(void)
diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c
index 98f667b121f7d..d8ca63ed87194 100644
--- a/drivers/net/mdio/of_mdio.c
+++ b/drivers/net/mdio/of_mdio.c
@@ -473,6 +473,5 @@ void of_phy_deregister_fixed_link(struct device_node *np)
fixed_phy_unregister(phydev);
put_device(&phydev->mdio.dev); /* of_phy_find_device() */
- phy_device_free(phydev); /* fixed_phy_register() */
}
EXPORT_SYMBOL(of_phy_deregister_fixed_link);
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
index 033656d574b89..b8bec7600ef8e 100644
--- a/drivers/net/phy/fixed_phy.c
+++ b/drivers/net/phy/fixed_phy.c
@@ -309,6 +309,7 @@ void fixed_phy_unregister(struct phy_device *phy)
phy_device_remove(phy);
of_node_put(phy->mdio.dev.of_node);
fixed_phy_del(phy->mdio.addr);
+ phy_device_free(phy);
}
EXPORT_SYMBOL_GPL(fixed_phy_unregister);
--
2.51.0
Powered by blists - more mailing lists