eth_phy_of_to_plat() claims the PHY reset GPIO with
gpio_request_by_name() and the PHY reset control with
reset_get_by_index(), but nothing releases either when the device is
removed. When retrying a wedged PHY, any follow-up probes fail because
the reset GPIO is already claimed.

Add a pre_remove hook that frees both.

Signed-off-by: Graeme Smecher <[email protected]>
Acked-by: Michal Simek <[email protected]>
---
This patch was 4/4 of the zynq_gem resource leak series up to v3. As
Michal Simek requested, it is now sent separately so that it can go
through the net tree; the zynq_gem patches continue as their own v4.

Tested on QEMU (xilinx-zynq-a9, xilinx_zynq_virt), with a PHY that
has reset-gpios and a (syscon-reset) resets property: after repeated
unbind/bind of the ethernet controller, the eth-phy device probes
again. Without this patch, the next probe fails because the reset GPIO
is still claimed.

Changes in v4:
- Split out of the zynq_gem series; no code changes
- Rebased onto current main
- Add Acked-by from Michal Simek
- Link to v3: 
https://lore.kernel.org/r/[email protected]

Changes in v3:
- Rebased onto the eth-phy reset control support; also release the
  reset control with reset_free(). Use per-feature DM_GPIO/DM_RESET
  guards, and reword the subject accordingly
---
 drivers/net/eth-phy-uclass.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/eth-phy-uclass.c b/drivers/net/eth-phy-uclass.c
index 
a13e2fc7c50a239bdea4aaeb6d77496cc86b3575..7ac1876f846abbddd23117db235a535eb96d234b
 100644
--- a/drivers/net/eth-phy-uclass.c
+++ b/drivers/net/eth-phy-uclass.c
@@ -191,11 +191,25 @@ static int eth_phy_pre_probe(struct udevice *dev)
        return 0;
 }
 
+static int eth_phy_pre_remove(struct udevice *dev)
+{
+       struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       if (CONFIG_IS_ENABLED(DM_GPIO) && 
dm_gpio_is_valid(&uc_priv->reset_gpio))
+               dm_gpio_free(dev, &uc_priv->reset_gpio);
+
+       if (CONFIG_IS_ENABLED(DM_RESET) && reset_valid(&uc_priv->reset_ctrl))
+               reset_free(&uc_priv->reset_ctrl);
+
+       return 0;
+}
+
 UCLASS_DRIVER(eth_phy_generic) = {
        .id             = UCLASS_ETH_PHY,
        .name           = "eth_phy_generic",
        .per_device_auto        = sizeof(struct eth_phy_device_priv),
        .pre_probe      = eth_phy_pre_probe,
+       .pre_remove     = eth_phy_pre_remove,
 };
 
 U_BOOT_DRIVER(eth_phy_generic_drv) = {

---
base-commit: 709a97a05df66e394f40d249105d0baade46f107
change-id: 20261106-eth-phy-release-reset-0e959156e2c8

Best regards,
-- 
Graeme Smecher <[email protected]>

Reply via email to