aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-12-02 10:42:47 -0500
committerDavid S. Miller <davem@davemloft.net>2016-12-02 10:43:23 -0500
commitd262fd12cd03afca40ced117d837fa576a667eab (patch)
tree38bf52c2e8c80c7ff2b09ebf6943734a9d01336e
parent6919756caaeaa76dc56287252fb656e3c2d9b4e1 (diff)
parentd2ed0a7755fe14c790f398ae55088d00492ef168 (diff)
Merge branch 'stmmac-probe-error-handling-and-phydev-leaks'
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. ==================== Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c23
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c32
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c23
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c26
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c33
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h2
13 files changed, 215 insertions, 63 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
index b1e5f24708c9..e6e6c2fcc4b7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
@@ -50,10 +50,23 @@ static int dwmac_generic_probe(struct platform_device *pdev)
50 if (plat_dat->init) { 50 if (plat_dat->init) {
51 ret = plat_dat->init(pdev, plat_dat->bsp_priv); 51 ret = plat_dat->init(pdev, plat_dat->bsp_priv);
52 if (ret) 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
62err_exit:
63 if (plat_dat->exit)
64 plat_dat->exit(pdev, plat_dat->bsp_priv);
65err_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
59static const struct of_device_id dwmac_generic_match[] = { 72static const struct of_device_id dwmac_generic_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
index 36d3355f2fb0..866444b6c82f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
271 return PTR_ERR(plat_dat); 271 return PTR_ERR(plat_dat);
272 272
273 gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); 273 gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
274 if (!gmac) 274 if (!gmac) {
275 return -ENOMEM; 275 err = -ENOMEM;
276 goto err_remove_config_dt;
277 }
276 278
277 gmac->pdev = pdev; 279 gmac->pdev = pdev;
278 280
279 err = ipq806x_gmac_of_parse(gmac); 281 err = ipq806x_gmac_of_parse(gmac);
280 if (err) { 282 if (err) {
281 dev_err(dev, "device tree parsing error\n"); 283 dev_err(dev, "device tree parsing error\n");
282 return err; 284 goto err_remove_config_dt;
283 } 285 }
284 286
285 regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, 287 regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
@@ -300,7 +302,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
300 default: 302 default:
301 dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", 303 dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
302 phy_modes(gmac->phy_mode)); 304 phy_modes(gmac->phy_mode));
303 return -EINVAL; 305 err = -EINVAL;
306 goto err_remove_config_dt;
304 } 307 }
305 regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); 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)
319 default: 322 default:
320 dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", 323 dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
321 phy_modes(gmac->phy_mode)); 324 phy_modes(gmac->phy_mode));
322 return -EINVAL; 325 err = -EINVAL;
326 goto err_remove_config_dt;
323 } 327 }
324 regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); 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)
346 plat_dat->bsp_priv = gmac; 350 plat_dat->bsp_priv = gmac;
347 plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; 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
359err_remove_config_dt:
360 stmmac_remove_config_dt(pdev, plat_dat);
361
362 return err;
350} 363}
351 364
352static const struct of_device_id ipq806x_gmac_dwmac_match[] = { 365static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
index 78e9d1861896..3d3f43d91b98 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
@@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
46 reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); 46 reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
47 if (IS_ERR(reg)) { 47 if (IS_ERR(reg)) {
48 dev_err(&pdev->dev, "syscon lookup failed\n"); 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 if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { 53 if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
@@ -55,13 +56,23 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
55 ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; 56 ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
56 } else { 57 } else {
57 dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); 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 regmap_update_bits(reg, LPC18XX_CREG_CREG6, 63 regmap_update_bits(reg, LPC18XX_CREG_CREG6,
62 LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); 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
72err_remove_config_dt:
73 stmmac_remove_config_dt(pdev, plat_dat);
74
75 return ret;
65} 76}
66 77
67static const struct of_device_id lpc18xx_dwmac_match[] = { 78static const struct of_device_id lpc18xx_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index 309d99536a2c..7fdd1760a74c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
64 return PTR_ERR(plat_dat); 64 return PTR_ERR(plat_dat);
65 65
66 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 66 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
67 if (!dwmac) 67 if (!dwmac) {
68 return -ENOMEM; 68 ret = -ENOMEM;
69 goto err_remove_config_dt;
70 }
69 71
70 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 72 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
71 dwmac->reg = devm_ioremap_resource(&pdev->dev, res); 73 dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
72 if (IS_ERR(dwmac->reg)) 74 if (IS_ERR(dwmac->reg)) {
73 return PTR_ERR(dwmac->reg); 75 ret = PTR_ERR(dwmac->reg);
76 goto err_remove_config_dt;
77 }
74 78
75 plat_dat->bsp_priv = dwmac; 79 plat_dat->bsp_priv = dwmac;
76 plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; 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
88err_remove_config_dt:
89 stmmac_remove_config_dt(pdev, plat_dat);
90
91 return ret;
79} 92}
80 93
81static const struct of_device_id meson6_dwmac_match[] = { 94static const struct of_device_id meson6_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 250e4ceafc8d..ffaed1f35efe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
264 return PTR_ERR(plat_dat); 264 return PTR_ERR(plat_dat);
265 265
266 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 266 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
267 if (!dwmac) 267 if (!dwmac) {
268 return -ENOMEM; 268 ret = -ENOMEM;
269 goto err_remove_config_dt;
270 }
269 271
270 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 272 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
271 dwmac->regs = devm_ioremap_resource(&pdev->dev, res); 273 dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
272 if (IS_ERR(dwmac->regs)) 274 if (IS_ERR(dwmac->regs)) {
273 return PTR_ERR(dwmac->regs); 275 ret = PTR_ERR(dwmac->regs);
276 goto err_remove_config_dt;
277 }
274 278
275 dwmac->pdev = pdev; 279 dwmac->pdev = pdev;
276 dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); 280 dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
277 if (dwmac->phy_mode < 0) { 281 if (dwmac->phy_mode < 0) {
278 dev_err(&pdev->dev, "missing phy-mode property\n"); 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 ret = meson8b_init_clk(dwmac); 287 ret = meson8b_init_clk(dwmac);
283 if (ret) 288 if (ret)
284 return ret; 289 goto err_remove_config_dt;
285 290
286 ret = meson8b_init_prg_eth(dwmac); 291 ret = meson8b_init_prg_eth(dwmac);
287 if (ret) 292 if (ret)
288 return ret; 293 goto err_remove_config_dt;
289 294
290 plat_dat->bsp_priv = dwmac; 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
303err_clk_disable:
304 clk_disable_unprepare(dwmac->m25_div_clk);
305err_remove_config_dt:
306 stmmac_remove_config_dt(pdev, plat_dat);
307
308 return ret;
293} 309}
294 310
295static int meson8b_dwmac_remove(struct platform_device *pdev) 311static int meson8b_dwmac_remove(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 3740a4417fa0..d80c88bd2bba 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev)
981 plat_dat->resume = rk_gmac_resume; 981 plat_dat->resume = rk_gmac_resume;
982 982
983 plat_dat->bsp_priv = rk_gmac_setup(pdev, data); 983 plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
984 if (IS_ERR(plat_dat->bsp_priv)) 984 if (IS_ERR(plat_dat->bsp_priv)) {
985 return PTR_ERR(plat_dat->bsp_priv); 985 ret = PTR_ERR(plat_dat->bsp_priv);
986 goto err_remove_config_dt;
987 }
986 988
987 ret = rk_gmac_init(pdev, plat_dat->bsp_priv); 989 ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
988 if (ret) 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
999err_gmac_exit:
1000 rk_gmac_exit(pdev, plat_dat->bsp_priv);
1001err_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
994static const struct of_device_id rk_gmac_dwmac_match[] = { 1007static const struct of_device_id rk_gmac_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index bec6963ac71e..0c420e97de1e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
304 struct device *dev = &pdev->dev; 304 struct device *dev = &pdev->dev;
305 int ret; 305 int ret;
306 struct socfpga_dwmac *dwmac; 306 struct socfpga_dwmac *dwmac;
307 struct net_device *ndev;
308 struct stmmac_priv *stpriv;
307 309
308 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 310 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
309 if (ret) 311 if (ret)
@@ -314,32 +316,43 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
314 return PTR_ERR(plat_dat); 316 return PTR_ERR(plat_dat);
315 317
316 dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); 318 dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
317 if (!dwmac) 319 if (!dwmac) {
318 return -ENOMEM; 320 ret = -ENOMEM;
321 goto err_remove_config_dt;
322 }
319 323
320 ret = socfpga_dwmac_parse_data(dwmac, dev); 324 ret = socfpga_dwmac_parse_data(dwmac, dev);
321 if (ret) { 325 if (ret) {
322 dev_err(dev, "Unable to parse OF data\n"); 326 dev_err(dev, "Unable to parse OF data\n");
323 return ret; 327 goto err_remove_config_dt;
324 } 328 }
325 329
326 plat_dat->bsp_priv = dwmac; 330 plat_dat->bsp_priv = dwmac;
327 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; 331 plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
328 332
329 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 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) { 337 ndev = platform_get_drvdata(pdev);
332 struct net_device *ndev = platform_get_drvdata(pdev); 338 stpriv = netdev_priv(ndev);
333 struct stmmac_priv *stpriv = netdev_priv(ndev);
334 339
335 /* The socfpga driver needs to control the stmmac reset to 340 /* The socfpga driver needs to control the stmmac reset to set the phy
336 * set the phy mode. Create a copy of the core reset handel 341 * mode. Create a copy of the core reset handle so it can be used by
337 * so it can be used by the driver later. 342 * the driver later.
338 */ 343 */
339 dwmac->stmmac_rst = stpriv->stmmac_rst; 344 dwmac->stmmac_rst = stpriv->stmmac_rst;
340 345
341 ret = socfpga_dwmac_set_phy_mode(dwmac); 346 ret = socfpga_dwmac_set_phy_mode(dwmac);
342 } 347 if (ret)
348 goto err_dvr_remove;
349
350 return 0;
351
352err_dvr_remove:
353 stmmac_dvr_remove(&pdev->dev);
354err_remove_config_dt:
355 stmmac_remove_config_dt(pdev, plat_dat);
343 356
344 return ret; 357 return ret;
345} 358}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
index 58c05acc2aab..060b98c37a85 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev)
345 return PTR_ERR(plat_dat); 345 return PTR_ERR(plat_dat);
346 346
347 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 347 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
348 if (!dwmac) 348 if (!dwmac) {
349 return -ENOMEM; 349 ret = -ENOMEM;
350 goto err_remove_config_dt;
351 }
350 352
351 ret = sti_dwmac_parse_data(dwmac, pdev); 353 ret = sti_dwmac_parse_data(dwmac, pdev);
352 if (ret) { 354 if (ret) {
353 dev_err(&pdev->dev, "Unable to parse OF data\n"); 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 dwmac->fix_retime_src = data->fix_retime_src; 359 dwmac->fix_retime_src = data->fix_retime_src;
@@ -363,9 +365,20 @@ static int sti_dwmac_probe(struct platform_device *pdev)
363 365
364 ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); 366 ret = sti_dwmac_init(pdev, plat_dat->bsp_priv);
365 if (ret) 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
376err_dwmac_exit:
377 sti_dwmac_exit(pdev, plat_dat->bsp_priv);
378err_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
371static const struct sti_dwmac_of_data stih4xx_dwmac_data = { 384static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index e5a926b8bee7..61cb24810d10 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
107 return PTR_ERR(plat_dat); 107 return PTR_ERR(plat_dat);
108 108
109 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 109 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
110 if (!dwmac) 110 if (!dwmac) {
111 return -ENOMEM; 111 ret = -ENOMEM;
112 goto err_remove_config_dt;
113 }
112 114
113 ret = stm32_dwmac_parse_data(dwmac, &pdev->dev); 115 ret = stm32_dwmac_parse_data(dwmac, &pdev->dev);
114 if (ret) { 116 if (ret) {
115 dev_err(&pdev->dev, "Unable to parse OF data\n"); 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 plat_dat->bsp_priv = dwmac; 121 plat_dat->bsp_priv = dwmac;
120 122
121 ret = stm32_dwmac_init(plat_dat); 123 ret = stm32_dwmac_init(plat_dat);
122 if (ret) 124 if (ret)
123 return ret; 125 goto err_remove_config_dt;
124 126
125 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 127 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
126 if (ret) 128 if (ret)
127 stm32_dwmac_clk_disable(dwmac); 129 goto err_clk_disable;
130
131 return 0;
132
133err_clk_disable:
134 stm32_dwmac_clk_disable(dwmac);
135err_remove_config_dt:
136 stmmac_remove_config_dt(pdev, plat_dat);
128 137
129 return ret; 138 return ret;
130} 139}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
index adff46375a32..d07520fb969e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
120 return PTR_ERR(plat_dat); 120 return PTR_ERR(plat_dat);
121 121
122 gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); 122 gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
123 if (!gmac) 123 if (!gmac) {
124 return -ENOMEM; 124 ret = -ENOMEM;
125 goto err_remove_config_dt;
126 }
125 127
126 gmac->interface = of_get_phy_mode(dev->of_node); 128 gmac->interface = of_get_phy_mode(dev->of_node);
127 129
128 gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); 130 gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
129 if (IS_ERR(gmac->tx_clk)) { 131 if (IS_ERR(gmac->tx_clk)) {
130 dev_err(dev, "could not get tx clock\n"); 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 /* Optional regulator for PHY */ 137 /* Optional regulator for PHY */
135 gmac->regulator = devm_regulator_get_optional(dev, "phy"); 138 gmac->regulator = devm_regulator_get_optional(dev, "phy");
136 if (IS_ERR(gmac->regulator)) { 139 if (IS_ERR(gmac->regulator)) {
137 if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) 140 if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) {
138 return -EPROBE_DEFER; 141 ret = -EPROBE_DEFER;
142 goto err_remove_config_dt;
143 }
139 dev_info(dev, "no regulator found\n"); 144 dev_info(dev, "no regulator found\n");
140 gmac->regulator = NULL; 145 gmac->regulator = NULL;
141 } 146 }
@@ -151,11 +156,18 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
151 156
152 ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); 157 ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
153 if (ret) 158 if (ret)
154 return ret; 159 goto err_remove_config_dt;
155 160
156 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 161 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
157 if (ret) 162 if (ret)
158 sun7i_gmac_exit(pdev, plat_dat->bsp_priv); 163 goto err_gmac_exit;
164
165 return 0;
166
167err_gmac_exit:
168 sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
169err_remove_config_dt:
170 stmmac_remove_config_dt(pdev, plat_dat);
159 171
160 return ret; 172 return ret;
161} 173}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1f9ec02fa7f8..caf069a465f2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3416,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev)
3416 stmmac_set_mac(priv->ioaddr, false); 3416 stmmac_set_mac(priv->ioaddr, false);
3417 netif_carrier_off(ndev); 3417 netif_carrier_off(ndev);
3418 unregister_netdev(ndev); 3418 unregister_netdev(ndev);
3419 of_node_put(priv->plat->phy_node);
3420 if (priv->stmmac_rst) 3419 if (priv->stmmac_rst)
3421 reset_control_assert(priv->stmmac_rst); 3420 reset_control_assert(priv->stmmac_rst);
3422 clk_disable_unprepare(priv->pclk); 3421 clk_disable_unprepare(priv->pclk);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 0a0d6a86f397..a840818bf4df 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -200,7 +200,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
200/** 200/**
201 * stmmac_probe_config_dt - parse device-tree driver parameters 201 * stmmac_probe_config_dt - parse device-tree driver parameters
202 * @pdev: platform_device structure 202 * @pdev: platform_device structure
203 * @plat: driver data platform structure
204 * @mac: MAC address to use 203 * @mac: MAC address to use
205 * Description: 204 * Description:
206 * this function is to read the driver parameters from device-tree and 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)
306 dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), 305 dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
307 GFP_KERNEL); 306 GFP_KERNEL);
308 if (!dma_cfg) { 307 if (!dma_cfg) {
309 of_node_put(plat->phy_node); 308 stmmac_remove_config_dt(pdev, plat);
310 return ERR_PTR(-ENOMEM); 309 return ERR_PTR(-ENOMEM);
311 } 310 }
312 plat->dma_cfg = dma_cfg; 311 plat->dma_cfg = dma_cfg;
@@ -329,14 +328,37 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
329 328
330 return plat; 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 */
339void 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#else 348#else
333struct plat_stmmacenet_data * 349struct plat_stmmacenet_data *
334stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) 350stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
335{ 351{
336 return ERR_PTR(-ENOSYS); 352 return ERR_PTR(-ENOSYS);
337} 353}
354
355void stmmac_remove_config_dt(struct platform_device *pdev,
356 struct plat_stmmacenet_data *plat)
357{
358}
338#endif /* CONFIG_OF */ 359#endif /* CONFIG_OF */
339EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); 360EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
361EXPORT_SYMBOL_GPL(stmmac_remove_config_dt);
340 362
341int stmmac_get_platform_resources(struct platform_device *pdev, 363int stmmac_get_platform_resources(struct platform_device *pdev,
342 struct stmmac_resources *stmmac_res) 364 struct stmmac_resources *stmmac_res)
@@ -392,10 +414,13 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
392{ 414{
393 struct net_device *ndev = platform_get_drvdata(pdev); 415 struct net_device *ndev = platform_get_drvdata(pdev);
394 struct stmmac_priv *priv = netdev_priv(ndev); 416 struct stmmac_priv *priv = netdev_priv(ndev);
417 struct plat_stmmacenet_data *plat = priv->plat;
395 int ret = stmmac_dvr_remove(&pdev->dev); 418 int ret = stmmac_dvr_remove(&pdev->dev);
396 419
397 if (priv->plat->exit) 420 if (plat->exit)
398 priv->plat->exit(pdev, priv->plat->bsp_priv); 421 plat->exit(pdev, plat->bsp_priv);
422
423 stmmac_remove_config_dt(pdev, plat);
399 424
400 return ret; 425 return ret;
401} 426}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 64e147f53a9c..b72eb0de57b7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -23,6 +23,8 @@
23 23
24struct plat_stmmacenet_data * 24struct plat_stmmacenet_data *
25stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); 25stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
26void stmmac_remove_config_dt(struct platform_device *pdev,
27 struct plat_stmmacenet_data *plat);
26 28
27int stmmac_get_platform_resources(struct platform_device *pdev, 29int stmmac_get_platform_resources(struct platform_device *pdev,
28 struct stmmac_resources *stmmac_res); 30 struct stmmac_resources *stmmac_res);