Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −2
Original line number Original line Diff line number Diff line
@@ -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[] = {
+19 −6
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	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)
	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[] = {
+14 −3
Original line number Original line Diff line number Diff line
@@ -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)
		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[] = {
+18 −5
Original line number Original line Diff line number Diff line
@@ -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[] = {
+24 −8
Original line number Original line Diff line number Diff line
@@ -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)
Loading