Johan Hovold says: ==================== net: stmmac: fix probe error handling and phydev leaks This series fixes a number of issues with the stmmac-driver probe error handling, which for example left clocks enabled after probe failures. The final patch fixes a failure to deregister and free any fixed-link PHYs that were registered during probe on probe errors and on driver unbind. It also fixes a related of-node leak on late probe errors. This series depends on the of_phy_deregister_fixed_link() helper that was just merged to net. As mentioned earlier, one staging driver also suffers from a similar leak and can be fixed up once the above mentioned helper hits mainline. Note that these patches have only been compile tested. ====================
Unified · Split
| @@ -50,10 +50,23 @@ static int dwmac_generic_probe(struct platform_device *pdev) · 49 unmodified lines | ||
| 50 | 50 | if (plat_dat->init) { |
| 51 | 51 | ret = plat_dat->init(pdev, plat_dat->bsp_priv); |
| 52 | 52 | if (ret) |
| 53 | − return ret; | |
| 53 | + goto err_remove_config_dt; | |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 56 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 57 | + if (ret) | |
| 58 | + goto err_exit; | |
| 59 | + | |
| 60 | + return 0; | |
| 61 | + | |
| 62 | +err_exit: | |
| 63 | + if (plat_dat->exit) | |
| 64 | + plat_dat->exit(pdev, plat_dat->bsp_priv); | |
| 65 | +err_remove_config_dt: | |
| 66 | + if (pdev->dev.of_node) | |
| 67 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 68 | + | |
| 69 | + return ret; | |
| 57 | 70 | } |
| 58 | 71 | |
| 59 | 72 | static const struct of_device_id dwmac_generic_match[] = { |
| @@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) · 270 unmodified lines | ||
| 271 | 271 | return PTR_ERR(plat_dat); |
| 272 | 272 | |
| 273 | 273 | gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); |
| 274 | − if (!gmac) | |
| 275 | − return -ENOMEM; | |
| 274 | + if (!gmac) { | |
| 275 | + err = -ENOMEM; | |
| 276 | + goto err_remove_config_dt; | |
| 277 | + } | |
| 276 | 278 | |
| 277 | 279 | gmac->pdev = pdev; |
| 278 | 280 | |
| 279 | 281 | err = ipq806x_gmac_of_parse(gmac); |
| 280 | 282 | if (err) { |
| 281 | 283 | dev_err(dev, "device tree parsing error\n"); |
| 282 | − return err; | |
| 284 | + goto err_remove_config_dt; | |
| 283 | 285 | } |
| 284 | 286 | |
| 285 | 287 | regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, |
| @@ -300,7 +302,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) · 14 unmodified lines | ||
| 300 | 302 | default: |
| 301 | 303 | dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", |
| 302 | 304 | phy_modes(gmac->phy_mode)); |
| 303 | − return -EINVAL; | |
| 305 | + err = -EINVAL; | |
| 306 | + goto err_remove_config_dt; | |
| 304 | 307 | } |
| 305 | 308 | regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); |
| 306 | 309 | |
| @@ -319,7 +322,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 319 | 322 | default: |
| 320 | 323 | dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", |
| 321 | 324 | phy_modes(gmac->phy_mode)); |
| 322 | − return -EINVAL; | |
| 325 | + err = -EINVAL; | |
| 326 | + goto err_remove_config_dt; | |
| 323 | 327 | } |
| 324 | 328 | regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); |
| 325 | 329 | |
| @@ -346,7 +350,16 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) · 20 unmodified lines | ||
| 346 | 350 | plat_dat->bsp_priv = gmac; |
| 347 | 351 | plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; |
| 348 | 352 | |
| 349 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 353 | + err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 354 | + if (err) | |
| 355 | + goto err_remove_config_dt; | |
| 356 | + | |
| 357 | + return 0; | |
| 358 | + | |
| 359 | +err_remove_config_dt: | |
| 360 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 361 | + | |
| 362 | + return err; | |
| 350 | 363 | } |
| 351 | 364 | |
| 352 | 365 | static const struct of_device_id ipq806x_gmac_dwmac_match[] = { |
| @@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) · 45 unmodified lines | ||
| 46 | 46 | reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); |
| 47 | 47 | if (IS_ERR(reg)) { |
| 48 | 48 | dev_err(&pdev->dev, "syscon lookup failed\n"); |
| 49 | − return PTR_ERR(reg); | |
| 49 | + ret = PTR_ERR(reg); | |
| 50 | + goto err_remove_config_dt; | |
| 50 | 51 | } |
| 51 | 52 | |
| 52 | 53 | if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { |
| @@ -55,13 +56,23 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 55 | 56 | ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; |
| 56 | 57 | } else { |
| 57 | 58 | dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); |
| 58 | − return -EINVAL; | |
| 59 | + ret = -EINVAL; | |
| 60 | + goto err_remove_config_dt; | |
| 59 | 61 | } |
| 60 | 62 | |
| 61 | 63 | regmap_update_bits(reg, LPC18XX_CREG_CREG6, |
| 62 | 64 | LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); |
| 63 | 65 | |
| 64 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 66 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 67 | + if (ret) | |
| 68 | + goto err_remove_config_dt; | |
| 69 | + | |
| 70 | + return 0; | |
| 71 | + | |
| 72 | +err_remove_config_dt: | |
| 73 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 74 | + | |
| 75 | + return ret; | |
| 65 | 76 | } |
| 66 | 77 | |
| 67 | 78 | static const struct of_device_id lpc18xx_dwmac_match[] = { |
| @@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev) · 63 unmodified lines | ||
| 64 | 64 | return PTR_ERR(plat_dat); |
| 65 | 65 | |
| 66 | 66 | dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); |
| 67 | − if (!dwmac) | |
| 68 | − return -ENOMEM; | |
| 67 | + if (!dwmac) { | |
| 68 | + ret = -ENOMEM; | |
| 69 | + goto err_remove_config_dt; | |
| 70 | + } | |
| 69 | 71 | |
| 70 | 72 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 71 | 73 | dwmac->reg = devm_ioremap_resource(&pdev->dev, res); |
| 72 | − if (IS_ERR(dwmac->reg)) | |
| 73 | − return PTR_ERR(dwmac->reg); | |
| 74 | + if (IS_ERR(dwmac->reg)) { | |
| 75 | + ret = PTR_ERR(dwmac->reg); | |
| 76 | + goto err_remove_config_dt; | |
| 77 | + } | |
| 74 | 78 | |
| 75 | 79 | plat_dat->bsp_priv = dwmac; |
| 76 | 80 | plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; |
| 77 | 81 | |
| 78 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 82 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 83 | + if (ret) | |
| 84 | + goto err_remove_config_dt; | |
| 85 | + | |
| 86 | + return 0; | |
| 87 | + | |
| 88 | +err_remove_config_dt: | |
| 89 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 90 | + | |
| 91 | + return ret; | |
| 79 | 92 | } |
| 80 | 93 | |
| 81 | 94 | static const struct of_device_id meson6_dwmac_match[] = { |
| @@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) · 263 unmodified lines | ||
| 264 | 264 | return PTR_ERR(plat_dat); |
| 265 | 265 | |
| 266 | 266 | dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); |
| 267 | − if (!dwmac) | |
| 268 | − return -ENOMEM; | |
| 267 | + if (!dwmac) { | |
| 268 | + ret = -ENOMEM; | |
| 269 | + goto err_remove_config_dt; | |
| 270 | + } | |
| 269 | 271 | |
| 270 | 272 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 271 | 273 | dwmac->regs = devm_ioremap_resource(&pdev->dev, res); |
| 272 | − if (IS_ERR(dwmac->regs)) | |
| 273 | − return PTR_ERR(dwmac->regs); | |
| 274 | + if (IS_ERR(dwmac->regs)) { | |
| 275 | + ret = PTR_ERR(dwmac->regs); | |
| 276 | + goto err_remove_config_dt; | |
| 277 | + } | |
| 274 | 278 | |
| 275 | 279 | dwmac->pdev = pdev; |
| 276 | 280 | dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); |
| 277 | 281 | if (dwmac->phy_mode < 0) { |
| 278 | 282 | dev_err(&pdev->dev, "missing phy-mode property\n"); |
| 279 | − return -EINVAL; | |
| 283 | + ret = -EINVAL; | |
| 284 | + goto err_remove_config_dt; | |
| 280 | 285 | } |
| 281 | 286 | |
| 282 | 287 | ret = meson8b_init_clk(dwmac); |
| 283 | 288 | if (ret) |
| 284 | − return ret; | |
| 289 | + goto err_remove_config_dt; | |
| 285 | 290 | |
| 286 | 291 | ret = meson8b_init_prg_eth(dwmac); |
| 287 | 292 | if (ret) |
| 288 | − return ret; | |
| 293 | + goto err_remove_config_dt; | |
| 289 | 294 | |
| 290 | 295 | plat_dat->bsp_priv = dwmac; |
| 291 | 296 | |
| 292 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 297 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 298 | + if (ret) | |
| 299 | + goto err_clk_disable; | |
| 300 | + | |
| 301 | + return 0; | |
| 302 | + | |
| 303 | +err_clk_disable: | |
| 304 | + clk_disable_unprepare(dwmac->m25_div_clk); | |
| 305 | +err_remove_config_dt: | |
| 306 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 307 | + | |
| 308 | + return ret; | |
| 293 | 309 | } |
| 294 | 310 | |
| 295 | 311 | static int meson8b_dwmac_remove(struct platform_device *pdev) |
| @@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev) · 980 unmodified lines | ||
| 981 | 981 | plat_dat->resume = rk_gmac_resume; |
| 982 | 982 | |
| 983 | 983 | plat_dat->bsp_priv = rk_gmac_setup(pdev, data); |
| 984 | − if (IS_ERR(plat_dat->bsp_priv)) | |
| 985 | − return PTR_ERR(plat_dat->bsp_priv); | |
| 984 | + if (IS_ERR(plat_dat->bsp_priv)) { | |
| 985 | + ret = PTR_ERR(plat_dat->bsp_priv); | |
| 986 | + goto err_remove_config_dt; | |
| 987 | + } | |
| 986 | 988 | |
| 987 | 989 | ret = rk_gmac_init(pdev, plat_dat->bsp_priv); |
| 988 | 990 | if (ret) |
| 989 | − return ret; | |
| 991 | + goto err_remove_config_dt; | |
| 992 | + | |
| 993 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 994 | + if (ret) | |
| 995 | + goto err_gmac_exit; | |
| 996 | + | |
| 997 | + return 0; | |
| 998 | + | |
| 999 | +err_gmac_exit: | |
| 1000 | + rk_gmac_exit(pdev, plat_dat->bsp_priv); | |
| 1001 | +err_remove_config_dt: | |
| 1002 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 990 | 1003 | |
| 991 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 1004 | + return ret; | |
| 992 | 1005 | } |
| 993 | 1006 | |
| 994 | 1007 | static const struct of_device_id rk_gmac_dwmac_match[] = { |
| @@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) · 303 unmodified lines | ||
| 304 | 304 | struct device *dev = &pdev->dev; |
| 305 | 305 | int ret; |
| 306 | 306 | struct socfpga_dwmac *dwmac; |
| 307 | + struct net_device *ndev; | |
| 308 | + struct stmmac_priv *stpriv; | |
| 307 | 309 | |
| 308 | 310 | ret = stmmac_get_platform_resources(pdev, &stmmac_res); |
| 309 | 311 | if (ret) |
| @@ -314,32 +316,43 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 314 | 316 | return PTR_ERR(plat_dat); |
| 315 | 317 | |
| 316 | 318 | dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); |
| 317 | − if (!dwmac) | |
| 318 | − return -ENOMEM; | |
| 319 | + if (!dwmac) { | |
| 320 | + ret = -ENOMEM; | |
| 321 | + goto err_remove_config_dt; | |
| 322 | + } | |
| 319 | 323 | |
| 320 | 324 | ret = socfpga_dwmac_parse_data(dwmac, dev); |
| 321 | 325 | if (ret) { |
| 322 | 326 | dev_err(dev, "Unable to parse OF data\n"); |
| 323 | − return ret; | |
| 327 | + goto err_remove_config_dt; | |
| 324 | 328 | } |
| 325 | 329 | |
| 326 | 330 | plat_dat->bsp_priv = dwmac; |
| 327 | 331 | plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; |
| 328 | 332 | |
| 329 | 333 | ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); |
| 334 | + if (ret) | |
| 335 | + goto err_remove_config_dt; | |
| 330 | 336 | |
| 331 | − if (!ret) { | |
| 332 | − struct net_device *ndev = platform_get_drvdata(pdev); | |
| 333 | − struct stmmac_priv *stpriv = netdev_priv(ndev); | |
| 337 | + ndev = platform_get_drvdata(pdev); | |
| 338 | + stpriv = netdev_priv(ndev); | |
| 334 | 339 | |
| 335 | − /* The socfpga driver needs to control the stmmac reset to | |
| 336 | − * set the phy mode. Create a copy of the core reset handel | |
| 337 | − * so it can be used by the driver later. | |
| 338 | − */ | |
| 339 | − dwmac->stmmac_rst = stpriv->stmmac_rst; | |
| 340 | + /* The socfpga driver needs to control the stmmac reset to set the phy | |
| 341 | + * mode. Create a copy of the core reset handle so it can be used by | |
| 342 | + * the driver later. | |
| 343 | + */ | |
| 344 | + dwmac->stmmac_rst = stpriv->stmmac_rst; | |
| 340 | 345 | |
| 341 | − ret = socfpga_dwmac_set_phy_mode(dwmac); | |
| 342 | − } | |
| 346 | + ret = socfpga_dwmac_set_phy_mode(dwmac); | |
| 347 | + if (ret) | |
| 348 | + goto err_dvr_remove; | |
| 349 | + | |
| 350 | + return 0; | |
| 351 | + | |
| 352 | +err_dvr_remove: | |
| 353 | + stmmac_dvr_remove(&pdev->dev); | |
| 354 | +err_remove_config_dt: | |
| 355 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 343 | 356 | |
| 344 | 357 | return ret; |
| 345 | 358 | } |
| @@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev) · 344 unmodified lines | ||
| 345 | 345 | return PTR_ERR(plat_dat); |
| 346 | 346 | |
| 347 | 347 | dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); |
| 348 | − if (!dwmac) | |
| 349 | − return -ENOMEM; | |
| 348 | + if (!dwmac) { | |
| 349 | + ret = -ENOMEM; | |
| 350 | + goto err_remove_config_dt; | |
| 351 | + } | |
| 350 | 352 | |
| 351 | 353 | ret = sti_dwmac_parse_data(dwmac, pdev); |
| 352 | 354 | if (ret) { |
| 353 | 355 | dev_err(&pdev->dev, "Unable to parse OF data\n"); |
| 354 | − return ret; | |
| 356 | + goto err_remove_config_dt; | |
| 355 | 357 | } |
| 356 | 358 | |
| 357 | 359 | dwmac->fix_retime_src = data->fix_retime_src; |
| @@ -363,9 +365,20 @@ static int sti_dwmac_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 363 | 365 | |
| 364 | 366 | ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); |
| 365 | 367 | if (ret) |
| 366 | − return ret; | |
| 368 | + goto err_remove_config_dt; | |
| 369 | + | |
| 370 | + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 371 | + if (ret) | |
| 372 | + goto err_dwmac_exit; | |
| 373 | + | |
| 374 | + return 0; | |
| 375 | + | |
| 376 | +err_dwmac_exit: | |
| 377 | + sti_dwmac_exit(pdev, plat_dat->bsp_priv); | |
| 378 | +err_remove_config_dt: | |
| 379 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 367 | 380 | |
| 368 | − return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
| 381 | + return ret; | |
| 369 | 382 | } |
| 370 | 383 | |
| 371 | 384 | static const struct sti_dwmac_of_data stih4xx_dwmac_data = { |
| @@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev) · 106 unmodified lines | ||
| 107 | 107 | return PTR_ERR(plat_dat); |
| 108 | 108 | |
| 109 | 109 | dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); |
| 110 | − if (!dwmac) | |
| 111 | − return -ENOMEM; | |
| 110 | + if (!dwmac) { | |
| 111 | + ret = -ENOMEM; | |
| 112 | + goto err_remove_config_dt; | |
| 113 | + } | |
| 112 | 114 | |
| 113 | 115 | ret = stm32_dwmac_parse_data(dwmac, &pdev->dev); |
| 114 | 116 | if (ret) { |
| 115 | 117 | dev_err(&pdev->dev, "Unable to parse OF data\n"); |
| 116 | − return ret; | |
| 118 | + goto err_remove_config_dt; | |
| 117 | 119 | } |
| 118 | 120 | |
| 119 | 121 | plat_dat->bsp_priv = dwmac; |
| 120 | 122 | |
| 121 | 123 | ret = stm32_dwmac_init(plat_dat); |
| 122 | 124 | if (ret) |
| 123 | − return ret; | |
| 125 | + goto err_remove_config_dt; | |
| 124 | 126 | |
| 125 | 127 | ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); |
| 126 | 128 | if (ret) |
| 127 | − stm32_dwmac_clk_disable(dwmac); | |
| 129 | + goto err_clk_disable; | |
| 130 | + | |
| 131 | + return 0; | |
| 132 | + | |
| 133 | +err_clk_disable: | |
| 134 | + stm32_dwmac_clk_disable(dwmac); | |
| 135 | +err_remove_config_dt: | |
| 136 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 128 | 137 | |
| 129 | 138 | return ret; |
| 130 | 139 | } |
| @@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev) · 119 unmodified lines | ||
| 120 | 120 | return PTR_ERR(plat_dat); |
| 121 | 121 | |
| 122 | 122 | gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); |
| 123 | − if (!gmac) | |
| 124 | − return -ENOMEM; | |
| 123 | + if (!gmac) { | |
| 124 | + ret = -ENOMEM; | |
| 125 | + goto err_remove_config_dt; | |
| 126 | + } | |
| 125 | 127 | |
| 126 | 128 | gmac->interface = of_get_phy_mode(dev->of_node); |
| 127 | 129 | |
| 128 | 130 | gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); |
| 129 | 131 | if (IS_ERR(gmac->tx_clk)) { |
| 130 | 132 | dev_err(dev, "could not get tx clock\n"); |
| 131 | − return PTR_ERR(gmac->tx_clk); | |
| 133 | + ret = PTR_ERR(gmac->tx_clk); | |
| 134 | + goto err_remove_config_dt; | |
| 132 | 135 | } |
| 133 | 136 | |
| 134 | 137 | /* Optional regulator for PHY */ |
| 135 | 138 | gmac->regulator = devm_regulator_get_optional(dev, "phy"); |
| 136 | 139 | if (IS_ERR(gmac->regulator)) { |
| 137 | − if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) | |
| 138 | − return -EPROBE_DEFER; | |
| 140 | + if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) { | |
| 141 | + ret = -EPROBE_DEFER; | |
| 142 | + goto err_remove_config_dt; | |
| 143 | + } | |
| 139 | 144 | dev_info(dev, "no regulator found\n"); |
| 140 | 145 | gmac->regulator = NULL; |
| 141 | 146 | } |
| @@ -151,11 +156,18 @@ static int sun7i_gmac_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 151 | 156 | |
| 152 | 157 | ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); |
| 153 | 158 | if (ret) |
| 154 | − return ret; | |
| 159 | + goto err_remove_config_dt; | |
| 155 | 160 | |
| 156 | 161 | ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); |
| 157 | 162 | if (ret) |
| 158 | − sun7i_gmac_exit(pdev, plat_dat->bsp_priv); | |
| 163 | + goto err_gmac_exit; | |
| 164 | + | |
| 165 | + return 0; | |
| 166 | + | |
| 167 | +err_gmac_exit: | |
| 168 | + sun7i_gmac_exit(pdev, plat_dat->bsp_priv); | |
| 169 | +err_remove_config_dt: | |
| 170 | + stmmac_remove_config_dt(pdev, plat_dat); | |
| 159 | 171 | |
| 160 | 172 | return ret; |
| 161 | 173 | } |
| @@ -3416,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev) · 3415 unmodified lines | ||
| 3416 | 3416 | stmmac_set_mac(priv->ioaddr, false); |
| 3417 | 3417 | netif_carrier_off(ndev); |
| 3418 | 3418 | unregister_netdev(ndev); |
| 3419 | − of_node_put(priv->plat->phy_node); | |
| 3420 | 3419 | if (priv->stmmac_rst) |
| 3421 | 3420 | reset_control_assert(priv->stmmac_rst); |
| 3422 | 3421 | clk_disable_unprepare(priv->pclk); |
| @@ -200,7 +200,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, · 199 unmodified lines | ||
| 200 | 200 | /** |
| 201 | 201 | * stmmac_probe_config_dt - parse device-tree driver parameters |
| 202 | 202 | * @pdev: platform_device structure |
| 203 | − * @plat: driver data platform structure | |
| 204 | 203 | * @mac: MAC address to use |
| 205 | 204 | * Description: |
| 206 | 205 | * this function is to read the driver parameters from device-tree and |
| @@ -306,7 +305,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) · 99 unmodified lines | ||
| 306 | 305 | dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), |
| 307 | 306 | GFP_KERNEL); |
| 308 | 307 | if (!dma_cfg) { |
| 309 | − of_node_put(plat->phy_node); | |
| 308 | + stmmac_remove_config_dt(pdev, plat); | |
| 310 | 309 | return ERR_PTR(-ENOMEM); |
| 311 | 310 | } |
| 312 | 311 | plat->dma_cfg = dma_cfg; |
| @@ -329,14 +328,37 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) · 16 unmodified lines | ||
| 329 | 328 | |
| 330 | 329 | return plat; |
| 331 | 330 | } |
| 331 | + | |
| 332 | +/** | |
| 333 | + * stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt() | |
| 334 | + * @pdev: platform_device structure | |
| 335 | + * @plat: driver data platform structure | |
| 336 | + * | |
| 337 | + * Release resources claimed by stmmac_probe_config_dt(). | |
| 338 | + */ | |
| 339 | +void stmmac_remove_config_dt(struct platform_device *pdev, | |
| 340 | + struct plat_stmmacenet_data *plat) | |
| 341 | +{ | |
| 342 | + struct device_node *np = pdev->dev.of_node; | |
| 343 | + | |
| 344 | + if (of_phy_is_fixed_link(np)) | |
| 345 | + of_phy_deregister_fixed_link(np); | |
| 346 | + of_node_put(plat->phy_node); | |
| 347 | +} | |
| 332 | 348 | #else |
| 333 | 349 | struct plat_stmmacenet_data * |
| 334 | 350 | stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) |
| 335 | 351 | { |
| 336 | 352 | return ERR_PTR(-ENOSYS); |
| 337 | 353 | } |
| 354 | + | |
| 355 | +void stmmac_remove_config_dt(struct platform_device *pdev, | |
| 356 | + struct plat_stmmacenet_data *plat) | |
| 357 | +{ | |
| 358 | +} | |
| 338 | 359 | #endif /* CONFIG_OF */ |
| 339 | 360 | EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); |
| 361 | +EXPORT_SYMBOL_GPL(stmmac_remove_config_dt); | |
| 340 | 362 | |
| 341 | 363 | int stmmac_get_platform_resources(struct platform_device *pdev, |
| 342 | 364 | struct stmmac_resources *stmmac_res) |
| @@ -392,10 +414,13 @@ int stmmac_pltfr_remove(struct platform_device *pdev) · 49 unmodified lines | ||
| 392 | 414 | { |
| 393 | 415 | struct net_device *ndev = platform_get_drvdata(pdev); |
| 394 | 416 | struct stmmac_priv *priv = netdev_priv(ndev); |
| 417 | + struct plat_stmmacenet_data *plat = priv->plat; | |
| 395 | 418 | int ret = stmmac_dvr_remove(&pdev->dev); |
| 396 | 419 | |
| 397 | − if (priv->plat->exit) | |
| 398 | − priv->plat->exit(pdev, priv->plat->bsp_priv); | |
| 420 | + if (plat->exit) | |
| 421 | + plat->exit(pdev, plat->bsp_priv); | |
| 422 | + | |
| 423 | + stmmac_remove_config_dt(pdev, plat); | |
| 399 | 424 | |
| 400 | 425 | return ret; |
| 401 | 426 | } |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | struct plat_stmmacenet_data * |
| 25 | 25 | stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); |
| 26 | +void stmmac_remove_config_dt(struct platform_device *pdev, | |
| 27 | + struct plat_stmmacenet_data *plat); | |
| 26 | 28 | |
| 27 | 29 | int stmmac_get_platform_resources(struct platform_device *pdev, |
| 28 | 30 | struct stmmac_resources *stmmac_res); |