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 | 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[] = { |
| @@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) · 270 unmodified lines | |||
| 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) · 14 unmodified lines | |||
| 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) · 12 unmodified lines | |||
| 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) · 20 unmodified lines | |||
| 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[] = { |
| @@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) · 45 unmodified lines | |||
| 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) · 2 unmodified lines | |||
| 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[] = { |
| @@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev) · 63 unmodified lines | |||
| 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[] = { |
| @@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) · 263 unmodified lines | |||
| 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) |
| @@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev) · 980 unmodified lines | |||
| 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[] = { |
| @@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) · 303 unmodified lines | |||
| 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) · 4 unmodified lines | |||
| 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 | } |
| @@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev) · 344 unmodified lines | |||
| 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) · 5 unmodified lines | |||
| 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 = { |
| @@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev) · 106 unmodified lines | |||
| 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 | } |
| @@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev) · 119 unmodified lines | |||
| 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) · 9 unmodified lines | |||
| 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 | } |
| @@ -3416,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev) · 3415 unmodified lines | |||
| 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); |
| @@ -200,7 +200,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, · 199 unmodified lines | |||
| 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) · 99 unmodified lines | |||
| 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) · 16 unmodified lines | |||
| 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) · 49 unmodified lines | |||
| 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 | } |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | |||
| 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); |