Commit d262fd12 authored by David S. Miller's avatar David S. Miller

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: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6919756c d2ed0a77
...@@ -50,10 +50,23 @@ static int dwmac_generic_probe(struct platform_device *pdev) ...@@ -50,10 +50,23 @@ static int dwmac_generic_probe(struct platform_device *pdev)
if (plat_dat->init) { if (plat_dat->init) {
ret = plat_dat->init(pdev, plat_dat->bsp_priv); ret = plat_dat->init(pdev, plat_dat->bsp_priv);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
} }
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_exit;
return 0;
err_exit:
if (plat_dat->exit)
plat_dat->exit(pdev, plat_dat->bsp_priv);
err_remove_config_dt:
if (pdev->dev.of_node)
stmmac_remove_config_dt(pdev, plat_dat);
return ret;
} }
static const struct of_device_id dwmac_generic_match[] = { static const struct of_device_id dwmac_generic_match[] = {
......
...@@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) ...@@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
if (!gmac) if (!gmac) {
return -ENOMEM; err = -ENOMEM;
goto err_remove_config_dt;
}
gmac->pdev = pdev; gmac->pdev = pdev;
err = ipq806x_gmac_of_parse(gmac); err = ipq806x_gmac_of_parse(gmac);
if (err) { if (err) {
dev_err(dev, "device tree parsing error\n"); dev_err(dev, "device tree parsing error\n");
return err; goto err_remove_config_dt;
} }
regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
...@@ -300,7 +302,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) ...@@ -300,7 +302,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
default: default:
dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
phy_modes(gmac->phy_mode)); phy_modes(gmac->phy_mode));
return -EINVAL; err = -EINVAL;
goto err_remove_config_dt;
} }
regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
...@@ -319,7 +322,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) ...@@ -319,7 +322,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
default: default:
dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
phy_modes(gmac->phy_mode)); phy_modes(gmac->phy_mode));
return -EINVAL; err = -EINVAL;
goto err_remove_config_dt;
} }
regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
...@@ -346,7 +350,16 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) ...@@ -346,7 +350,16 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
plat_dat->bsp_priv = gmac; plat_dat->bsp_priv = gmac;
plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (err)
goto err_remove_config_dt;
return 0;
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return err;
} }
static const struct of_device_id ipq806x_gmac_dwmac_match[] = { static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
......
...@@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) ...@@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
if (IS_ERR(reg)) { if (IS_ERR(reg)) {
dev_err(&pdev->dev, "syscon lookup failed\n"); dev_err(&pdev->dev, "syscon lookup failed\n");
return PTR_ERR(reg); ret = PTR_ERR(reg);
goto err_remove_config_dt;
} }
if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
...@@ -55,13 +56,23 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) ...@@ -55,13 +56,23 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
} else { } else {
dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
return -EINVAL; ret = -EINVAL;
goto err_remove_config_dt;
} }
regmap_update_bits(reg, LPC18XX_CREG_CREG6, regmap_update_bits(reg, LPC18XX_CREG_CREG6,
LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_remove_config_dt;
return 0;
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret;
} }
static const struct of_device_id lpc18xx_dwmac_match[] = { static const struct of_device_id lpc18xx_dwmac_match[] = {
......
...@@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev) ...@@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac) if (!dwmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
dwmac->reg = devm_ioremap_resource(&pdev->dev, res); dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dwmac->reg)) if (IS_ERR(dwmac->reg)) {
return PTR_ERR(dwmac->reg); ret = PTR_ERR(dwmac->reg);
goto err_remove_config_dt;
}
plat_dat->bsp_priv = dwmac; plat_dat->bsp_priv = dwmac;
plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_remove_config_dt;
return 0;
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret;
} }
static const struct of_device_id meson6_dwmac_match[] = { static const struct of_device_id meson6_dwmac_match[] = {
......
...@@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) ...@@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac) if (!dwmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
dwmac->regs = devm_ioremap_resource(&pdev->dev, res); dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dwmac->regs)) if (IS_ERR(dwmac->regs)) {
return PTR_ERR(dwmac->regs); ret = PTR_ERR(dwmac->regs);
goto err_remove_config_dt;
}
dwmac->pdev = pdev; dwmac->pdev = pdev;
dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
if (dwmac->phy_mode < 0) { if (dwmac->phy_mode < 0) {
dev_err(&pdev->dev, "missing phy-mode property\n"); dev_err(&pdev->dev, "missing phy-mode property\n");
return -EINVAL; ret = -EINVAL;
goto err_remove_config_dt;
} }
ret = meson8b_init_clk(dwmac); ret = meson8b_init_clk(dwmac);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
ret = meson8b_init_prg_eth(dwmac); ret = meson8b_init_prg_eth(dwmac);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
plat_dat->bsp_priv = dwmac; plat_dat->bsp_priv = dwmac;
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_clk_disable;
return 0;
err_clk_disable:
clk_disable_unprepare(dwmac->m25_div_clk);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret;
} }
static int meson8b_dwmac_remove(struct platform_device *pdev) static int meson8b_dwmac_remove(struct platform_device *pdev)
......
...@@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev) ...@@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev)
plat_dat->resume = rk_gmac_resume; plat_dat->resume = rk_gmac_resume;
plat_dat->bsp_priv = rk_gmac_setup(pdev, data); plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
if (IS_ERR(plat_dat->bsp_priv)) if (IS_ERR(plat_dat->bsp_priv)) {
return PTR_ERR(plat_dat->bsp_priv); ret = PTR_ERR(plat_dat->bsp_priv);
goto err_remove_config_dt;
}
ret = rk_gmac_init(pdev, plat_dat->bsp_priv); ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_gmac_exit;
return 0;
err_gmac_exit:
rk_gmac_exit(pdev, plat_dat->bsp_priv);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); return ret;
} }
static const struct of_device_id rk_gmac_dwmac_match[] = { static const struct of_device_id rk_gmac_dwmac_match[] = {
......
...@@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) ...@@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int ret; int ret;
struct socfpga_dwmac *dwmac; struct socfpga_dwmac *dwmac;
struct net_device *ndev;
struct stmmac_priv *stpriv;
ret = stmmac_get_platform_resources(pdev, &stmmac_res); ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret) if (ret)
...@@ -314,32 +316,43 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) ...@@ -314,32 +316,43 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac) if (!dwmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
ret = socfpga_dwmac_parse_data(dwmac, dev); ret = socfpga_dwmac_parse_data(dwmac, dev);
if (ret) { if (ret) {
dev_err(dev, "Unable to parse OF data\n"); dev_err(dev, "Unable to parse OF data\n");
return ret; goto err_remove_config_dt;
} }
plat_dat->bsp_priv = dwmac; plat_dat->bsp_priv = dwmac;
plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_remove_config_dt;
if (!ret) { ndev = platform_get_drvdata(pdev);
struct net_device *ndev = platform_get_drvdata(pdev); stpriv = netdev_priv(ndev);
struct stmmac_priv *stpriv = netdev_priv(ndev);
/* The socfpga driver needs to control the stmmac reset to /* The socfpga driver needs to control the stmmac reset to set the phy
* set the phy mode. Create a copy of the core reset handel * mode. Create a copy of the core reset handle so it can be used by
* so it can be used by the driver later. * the driver later.
*/ */
dwmac->stmmac_rst = stpriv->stmmac_rst; dwmac->stmmac_rst = stpriv->stmmac_rst;
ret = socfpga_dwmac_set_phy_mode(dwmac); ret = socfpga_dwmac_set_phy_mode(dwmac);
} if (ret)
goto err_dvr_remove;
return 0;
err_dvr_remove:
stmmac_dvr_remove(&pdev->dev);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret; return ret;
} }
......
...@@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev) ...@@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac) if (!dwmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
ret = sti_dwmac_parse_data(dwmac, pdev); ret = sti_dwmac_parse_data(dwmac, pdev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Unable to parse OF data\n"); dev_err(&pdev->dev, "Unable to parse OF data\n");
return ret; goto err_remove_config_dt;
} }
dwmac->fix_retime_src = data->fix_retime_src; dwmac->fix_retime_src = data->fix_retime_src;
...@@ -363,9 +365,20 @@ static int sti_dwmac_probe(struct platform_device *pdev) ...@@ -363,9 +365,20 @@ static int sti_dwmac_probe(struct platform_device *pdev)
ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); ret = sti_dwmac_init(pdev, plat_dat->bsp_priv);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
goto err_dwmac_exit;
return 0;
err_dwmac_exit:
sti_dwmac_exit(pdev, plat_dat->bsp_priv);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); return ret;
} }
static const struct sti_dwmac_of_data stih4xx_dwmac_data = { static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
......
...@@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev) ...@@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
if (!dwmac) if (!dwmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
ret = stm32_dwmac_parse_data(dwmac, &pdev->dev); ret = stm32_dwmac_parse_data(dwmac, &pdev->dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Unable to parse OF data\n"); dev_err(&pdev->dev, "Unable to parse OF data\n");
return ret; goto err_remove_config_dt;
} }
plat_dat->bsp_priv = dwmac; plat_dat->bsp_priv = dwmac;
ret = stm32_dwmac_init(plat_dat); ret = stm32_dwmac_init(plat_dat);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret) if (ret)
stm32_dwmac_clk_disable(dwmac); goto err_clk_disable;
return 0;
err_clk_disable:
stm32_dwmac_clk_disable(dwmac);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret; return ret;
} }
......
...@@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev) ...@@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
return PTR_ERR(plat_dat); return PTR_ERR(plat_dat);
gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
if (!gmac) if (!gmac) {
return -ENOMEM; ret = -ENOMEM;
goto err_remove_config_dt;
}
gmac->interface = of_get_phy_mode(dev->of_node); gmac->interface = of_get_phy_mode(dev->of_node);
gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
if (IS_ERR(gmac->tx_clk)) { if (IS_ERR(gmac->tx_clk)) {
dev_err(dev, "could not get tx clock\n"); dev_err(dev, "could not get tx clock\n");
return PTR_ERR(gmac->tx_clk); ret = PTR_ERR(gmac->tx_clk);
goto err_remove_config_dt;
} }
/* Optional regulator for PHY */ /* Optional regulator for PHY */
gmac->regulator = devm_regulator_get_optional(dev, "phy"); gmac->regulator = devm_regulator_get_optional(dev, "phy");
if (IS_ERR(gmac->regulator)) { if (IS_ERR(gmac->regulator)) {
if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) {
return -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto err_remove_config_dt;
}
dev_info(dev, "no regulator found\n"); dev_info(dev, "no regulator found\n");
gmac->regulator = NULL; gmac->regulator = NULL;
} }
...@@ -151,11 +156,18 @@ static int sun7i_gmac_probe(struct platform_device *pdev) ...@@ -151,11 +156,18 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
if (ret) if (ret)
return ret; goto err_remove_config_dt;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret) if (ret)
sun7i_gmac_exit(pdev, plat_dat->bsp_priv); goto err_gmac_exit;
return 0;
err_gmac_exit:
sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
err_remove_config_dt:
stmmac_remove_config_dt(pdev, plat_dat);
return ret; return ret;
} }
......
...@@ -3416,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev) ...@@ -3416,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev)
stmmac_set_mac(priv->ioaddr, false); stmmac_set_mac(priv->ioaddr, false);
netif_carrier_off(ndev); netif_carrier_off(ndev);
unregister_netdev(ndev); unregister_netdev(ndev);
of_node_put(priv->plat->phy_node);
if (priv->stmmac_rst) if (priv->stmmac_rst)
reset_control_assert(priv->stmmac_rst); reset_control_assert(priv->stmmac_rst);
clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->pclk);
......
...@@ -200,7 +200,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, ...@@ -200,7 +200,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
/** /**
* stmmac_probe_config_dt - parse device-tree driver parameters * stmmac_probe_config_dt - parse device-tree driver parameters
* @pdev: platform_device structure * @pdev: platform_device structure
* @plat: driver data platform structure
* @mac: MAC address to use * @mac: MAC address to use
* Description: * Description:
* this function is to read the driver parameters from device-tree and * 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,7 +305,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
GFP_KERNEL); GFP_KERNEL);
if (!dma_cfg) { if (!dma_cfg) {
of_node_put(plat->phy_node); stmmac_remove_config_dt(pdev, plat);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
plat->dma_cfg = dma_cfg; plat->dma_cfg = dma_cfg;
...@@ -329,14 +328,37 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) ...@@ -329,14 +328,37 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
return plat; return plat;
} }
/**
* stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt()
* @pdev: platform_device structure
* @plat: driver data platform structure
*
* Release resources claimed by stmmac_probe_config_dt().
*/
void stmmac_remove_config_dt(struct platform_device *pdev,
struct plat_stmmacenet_data *plat)
{
struct device_node *np = pdev->dev.of_node;
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(plat->phy_node);
}
#else #else
struct plat_stmmacenet_data * struct plat_stmmacenet_data *
stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
void stmmac_remove_config_dt(struct platform_device *pdev,
struct plat_stmmacenet_data *plat)
{
}
#endif /* CONFIG_OF */ #endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
EXPORT_SYMBOL_GPL(stmmac_remove_config_dt);
int stmmac_get_platform_resources(struct platform_device *pdev, int stmmac_get_platform_resources(struct platform_device *pdev,
struct stmmac_resources *stmmac_res) struct stmmac_resources *stmmac_res)
...@@ -392,10 +414,13 @@ int stmmac_pltfr_remove(struct platform_device *pdev) ...@@ -392,10 +414,13 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev); struct stmmac_priv *priv = netdev_priv(ndev);
struct plat_stmmacenet_data *plat = priv->plat;
int ret = stmmac_dvr_remove(&pdev->dev); int ret = stmmac_dvr_remove(&pdev->dev);
if (priv->plat->exit) if (plat->exit)
priv->plat->exit(pdev, priv->plat->bsp_priv); plat->exit(pdev, plat->bsp_priv);
stmmac_remove_config_dt(pdev, plat);
return ret; return ret;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
struct plat_stmmacenet_data * struct plat_stmmacenet_data *
stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
void stmmac_remove_config_dt(struct platform_device *pdev,
struct plat_stmmacenet_data *plat);
int stmmac_get_platform_resources(struct platform_device *pdev, int stmmac_get_platform_resources(struct platform_device *pdev,
struct stmmac_resources *stmmac_res); struct stmmac_resources *stmmac_res);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment