]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: stmmac: restructure the error path of stmmac_probe_config_dt()
authorJoe Hattori <joe@pf.is.s.u-tokyo.ac.jp>
Thu, 19 Dec 2024 02:41:19 +0000 (11:41 +0900)
committerJakub Kicinski <kuba@kernel.org>
Mon, 23 Dec 2024 17:52:47 +0000 (09:52 -0800)
Current implementation of stmmac_probe_config_dt() does not release the
OF node reference obtained by of_parse_phandle() in some error paths.
The problem is that some error paths call stmmac_remove_config_dt() to
clean up but others use and unwind ladder.  These two types of error
handling have not kept in sync and have been a recurring source of bugs.
Re-write the error handling in stmmac_probe_config_dt() to use an unwind
ladder. Consequently, stmmac_remove_config_dt() is not needed anymore,
thus remove it.

This bug was found by an experimental verification tool that I am
developing.

Fixes: 4838a5405028 ("net: stmmac: Fix wrapper drivers not detecting PHY")
Signed-off-by: Joe Hattori <joe@pf.is.s.u-tokyo.ac.jp>
Link: https://patch.msgid.link/20241219024119.2017012-1-joe@pf.is.s.u-tokyo.ac.jp
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c

index 3ac32444e492209ee3b7e27b5e18a997be5e4590..dc9884130b912f816c78ac09b44cb706883a8c32 100644 (file)
@@ -405,22 +405,6 @@ static int stmmac_of_get_mac_mode(struct device_node *np)
        return -ENODEV;
 }
 
-/**
- * stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt()
- * @pdev: platform_device structure
- * @plat: driver data platform structure
- *
- * Release resources claimed by stmmac_probe_config_dt().
- */
-static void stmmac_remove_config_dt(struct platform_device *pdev,
-                                   struct plat_stmmacenet_data *plat)
-{
-       clk_disable_unprepare(plat->stmmac_clk);
-       clk_disable_unprepare(plat->pclk);
-       of_node_put(plat->phy_node);
-       of_node_put(plat->mdio_node);
-}
-
 /**
  * stmmac_probe_config_dt - parse device-tree driver parameters
  * @pdev: platform_device structure
@@ -490,8 +474,10 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
                dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
 
        rc = stmmac_mdio_setup(plat, np, &pdev->dev);
-       if (rc)
-               return ERR_PTR(rc);
+       if (rc) {
+               ret = ERR_PTR(rc);
+               goto error_put_phy;
+       }
 
        of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
 
@@ -581,8 +567,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
        dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
                               GFP_KERNEL);
        if (!dma_cfg) {
-               stmmac_remove_config_dt(pdev, plat);
-               return ERR_PTR(-ENOMEM);
+               ret = ERR_PTR(-ENOMEM);
+               goto error_put_mdio;
        }
        plat->dma_cfg = dma_cfg;
 
@@ -610,8 +596,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
 
        rc = stmmac_mtl_setup(pdev, plat);
        if (rc) {
-               stmmac_remove_config_dt(pdev, plat);
-               return ERR_PTR(rc);
+               ret = ERR_PTR(rc);
+               goto error_put_mdio;
        }
 
        /* clock setup */
@@ -663,6 +649,10 @@ error_hw_init:
        clk_disable_unprepare(plat->pclk);
 error_pclk_get:
        clk_disable_unprepare(plat->stmmac_clk);
+error_put_mdio:
+       of_node_put(plat->mdio_node);
+error_put_phy:
+       of_node_put(plat->phy_node);
 
        return ret;
 }
@@ -671,16 +661,17 @@ static void devm_stmmac_remove_config_dt(void *data)
 {
        struct plat_stmmacenet_data *plat = data;
 
-       /* Platform data argument is unused */
-       stmmac_remove_config_dt(NULL, plat);
+       clk_disable_unprepare(plat->stmmac_clk);
+       clk_disable_unprepare(plat->pclk);
+       of_node_put(plat->mdio_node);
+       of_node_put(plat->phy_node);
 }
 
 /**
  * devm_stmmac_probe_config_dt
  * @pdev: platform_device structure
  * @mac: MAC address to use
- * Description: Devres variant of stmmac_probe_config_dt(). Does not require
- * the user to call stmmac_remove_config_dt() at driver detach.
+ * Description: Devres variant of stmmac_probe_config_dt().
  */
 struct plat_stmmacenet_data *
 devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)