diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2023-05-10 22:00:20 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-05-30 12:38:36 +0100 |
commit | d52a0cca591e899d4e5c8ab19e067b4c6b7d104f (patch) | |
tree | 087dbbe416ba60d1faf44c660eee42abe285052c | |
parent | c3627b3e677db850e3ea0ce02f95c158847a2f38 (diff) | |
download | linux-stable-d52a0cca591e899d4e5c8ab19e067b4c6b7d104f.tar.gz linux-stable-d52a0cca591e899d4e5c8ab19e067b4c6b7d104f.tar.bz2 linux-stable-d52a0cca591e899d4e5c8ab19e067b4c6b7d104f.zip |
net: fec: Better handle pm_runtime_get() failing in .remove()
[ Upstream commit f816b9829b19394d318e01953aa3b2721bca040d ]
In the (unlikely) event that pm_runtime_get() (disguised as
pm_runtime_resume_and_get()) fails, the remove callback returned an
error early. The problem with this is that the driver core ignores the
error value and continues removing the device. This results in a
resource leak. Worse the devm allocated resources are freed and so if a
callback of the driver is called later the register mapping is already
gone which probably results in a crash.
Fixes: a31eda65ba21 ("net: fec: fix clock count mis-match")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230510200020.1534610-1-u.kleine-koenig@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index c6fc77a211ea..1085f1d721b0 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3569,7 +3569,9 @@ fec_drv_remove(struct platform_device *pdev) ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; + dev_err(&pdev->dev, + "Failed to resume device in remove callback (%pe)\n", + ERR_PTR(ret)); cancel_work_sync(&fep->tx_timeout_work); fec_ptp_stop(pdev); @@ -3582,8 +3584,13 @@ fec_drv_remove(struct platform_device *pdev) of_phy_deregister_fixed_link(np); of_node_put(fep->phy_node); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); + /* After pm_runtime_get_sync() failed, the clks are still off, so skip + * disabling them again. + */ + if (ret >= 0) { + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); + } pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); |