Commit 52925421 authored by Samuel Holland's avatar Samuel Holland Committed by David S. Miller

net: stmmac: dwmac-sun8i: Balance internal PHY resource references

While stmmac_pltfr_remove calls sun8i_dwmac_exit, the sun8i_dwmac_init
and sun8i_dwmac_exit functions are also called by the stmmac_platform
suspend/resume callbacks. They may be called many times during the
device's lifetime and should not release resources used by the driver.

Furthermore, there was no error handling in case registering the MDIO
mux failed during probe, and the EPHY clock was never released at all.

Fix all of these issues by moving the deinitialization code to a driver
removal callback. Also ensure the EPHY is powered down before removal.

Fixes: 634db83b ("net: stmmac: dwmac-sun8i: Handle integrated/external MDIOs")
Signed-off-by: default avatarSamuel Holland <samuel@sholland.org>
Reviewed-by: default avatarChen-Yu Tsai <wens@csie.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7eeecc4b
...@@ -1004,17 +1004,12 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) ...@@ -1004,17 +1004,12 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
struct sunxi_priv_data *gmac = priv; struct sunxi_priv_data *gmac = priv;
if (gmac->variant->soc_has_internal_phy) { if (gmac->variant->soc_has_internal_phy) {
/* sun8i_dwmac_exit could be called with mdiomux uninit */
if (gmac->mux_handle)
mdio_mux_uninit(gmac->mux_handle);
if (gmac->internal_phy_powered) if (gmac->internal_phy_powered)
sun8i_dwmac_unpower_internal_phy(gmac); sun8i_dwmac_unpower_internal_phy(gmac);
} }
sun8i_dwmac_unset_syscon(gmac); sun8i_dwmac_unset_syscon(gmac);
reset_control_put(gmac->rst_ephy);
clk_disable_unprepare(gmac->tx_clk); clk_disable_unprepare(gmac->tx_clk);
if (gmac->regulator) if (gmac->regulator)
...@@ -1244,6 +1239,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) ...@@ -1244,6 +1239,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
return ret; return ret;
dwmac_mux: dwmac_mux:
reset_control_put(gmac->rst_ephy);
clk_put(gmac->ephy_clk);
sun8i_dwmac_unset_syscon(gmac); sun8i_dwmac_unset_syscon(gmac);
dwmac_remove: dwmac_remove:
stmmac_dvr_remove(&pdev->dev); stmmac_dvr_remove(&pdev->dev);
...@@ -1255,6 +1252,24 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) ...@@ -1255,6 +1252,24 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int sun8i_dwmac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev);
struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
if (gmac->variant->soc_has_internal_phy) {
mdio_mux_uninit(gmac->mux_handle);
sun8i_dwmac_unpower_internal_phy(gmac);
reset_control_put(gmac->rst_ephy);
clk_put(gmac->ephy_clk);
}
stmmac_pltfr_remove(pdev);
return 0;
}
static const struct of_device_id sun8i_dwmac_match[] = { static const struct of_device_id sun8i_dwmac_match[] = {
{ .compatible = "allwinner,sun8i-h3-emac", { .compatible = "allwinner,sun8i-h3-emac",
.data = &emac_variant_h3 }, .data = &emac_variant_h3 },
...@@ -1274,7 +1289,7 @@ MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); ...@@ -1274,7 +1289,7 @@ MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
static struct platform_driver sun8i_dwmac_driver = { static struct platform_driver sun8i_dwmac_driver = {
.probe = sun8i_dwmac_probe, .probe = sun8i_dwmac_probe,
.remove = stmmac_pltfr_remove, .remove = sun8i_dwmac_remove,
.driver = { .driver = {
.name = "dwmac-sun8i", .name = "dwmac-sun8i",
.pm = &stmmac_pltfr_pm_ops, .pm = &stmmac_pltfr_pm_ops,
......
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