diff options
author | David S. Miller <davem@davemloft.net> | 2016-12-02 10:42:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-02 10:43:23 -0500 |
commit | d262fd12cd03afca40ced117d837fa576a667eab (patch) | |
tree | 38bf52c2e8c80c7ff2b09ebf6943734a9d01336e | |
parent | 6919756caaeaa76dc56287252fb656e3c2d9b4e1 (diff) | |
parent | d2ed0a7755fe14c790f398ae55088d00492ef168 (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.c | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 32 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 33 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h | 2 |
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 | |||
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 | static const struct of_device_id dwmac_generic_match[] = { | 72 | static 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 | |||
359 | err_remove_config_dt: | ||
360 | stmmac_remove_config_dt(pdev, plat_dat); | ||
361 | |||
362 | return err; | ||
350 | } | 363 | } |
351 | 364 | ||
352 | static const struct of_device_id ipq806x_gmac_dwmac_match[] = { | 365 | static 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 | |||
72 | err_remove_config_dt: | ||
73 | stmmac_remove_config_dt(pdev, plat_dat); | ||
74 | |||
75 | return ret; | ||
65 | } | 76 | } |
66 | 77 | ||
67 | static const struct of_device_id lpc18xx_dwmac_match[] = { | 78 | static 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 | |||
88 | err_remove_config_dt: | ||
89 | stmmac_remove_config_dt(pdev, plat_dat); | ||
90 | |||
91 | return ret; | ||
79 | } | 92 | } |
80 | 93 | ||
81 | static const struct of_device_id meson6_dwmac_match[] = { | 94 | static 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 | |||
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 | static int meson8b_dwmac_remove(struct platform_device *pdev) | 311 | static 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 | |||
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 | static const struct of_device_id rk_gmac_dwmac_match[] = { | 1007 | static 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 | |||
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 | 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 | |||
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 | static const struct sti_dwmac_of_data stih4xx_dwmac_data = { | 384 | static 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 | |||
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 | 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 | |||
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 | 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 | */ | ||
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 | #else | 348 | #else |
333 | struct plat_stmmacenet_data * | 349 | struct plat_stmmacenet_data * |
334 | stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) | 350 | stmmac_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 | |||
355 | void stmmac_remove_config_dt(struct platform_device *pdev, | ||
356 | struct plat_stmmacenet_data *plat) | ||
357 | { | ||
358 | } | ||
338 | #endif /* CONFIG_OF */ | 359 | #endif /* CONFIG_OF */ |
339 | EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); | 360 | EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); |
361 | EXPORT_SYMBOL_GPL(stmmac_remove_config_dt); | ||
340 | 362 | ||
341 | int stmmac_get_platform_resources(struct platform_device *pdev, | 363 | int 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 | ||
24 | struct plat_stmmacenet_data * | 24 | struct plat_stmmacenet_data * |
25 | stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); | 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 | int stmmac_get_platform_resources(struct platform_device *pdev, | 29 | int stmmac_get_platform_resources(struct platform_device *pdev, |
28 | struct stmmac_resources *stmmac_res); | 30 | struct stmmac_resources *stmmac_res); |