platform: tegra: bwmgr: Improve resource management to avoid leak

The previous implementation doesn't release the resource in a few
cases, which can lead to leakage. Improving error handling and resource
cleanup when the driver is removed.

Bug 5483386

Change-Id: I316879075808ea945ebac997728aa51ff8b69488
Signed-off-by: robelin <robelin@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3474021
Reviewed-by: Johnny Liu <johnliu@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Rajkumar Kasirajan <rkasirajan@nvidia.com>
This commit is contained in:
robelin
2025-10-21 19:15:13 +08:00
committed by mobile promotions
parent 9831027796
commit 7f93fd77a5

View File

@@ -189,8 +189,8 @@ static int tegra_bpmp_bwmgr_devfreq_register(struct tegra_bpmp_bwmgr *bwmgr)
bwmgr->devfreq_profile, bwmgr->devfreq_profile,
DEVFREQ_GOV_BWMGR, NULL); DEVFREQ_GOV_BWMGR, NULL);
if (IS_ERR(bwmgr->devfreq)) { if (IS_ERR(bwmgr->devfreq)) {
dev_pm_opp_remove_all_dynamic(bwmgr->dev); ret = PTR_ERR(bwmgr->devfreq);
return PTR_ERR(bwmgr->devfreq); goto devfreq_add_dev_err;
} }
if (!bwmgr->mrq_valid || !bwmgr->enabled) { if (!bwmgr->mrq_valid || !bwmgr->enabled) {
@@ -209,12 +209,16 @@ static int tegra_bpmp_bwmgr_devfreq_register(struct tegra_bpmp_bwmgr *bwmgr)
ret = dev_pm_qos_add_notifier(bwmgr->dev, ret = dev_pm_qos_add_notifier(bwmgr->dev,
&bwmgr->max_freq_nb, &bwmgr->max_freq_nb,
DEV_PM_QOS_MAX_FREQUENCY); DEV_PM_QOS_MAX_FREQUENCY);
if (ret < 0) { if (ret < 0)
devm_devfreq_remove_device(bwmgr->dev, bwmgr->devfreq); goto devfreq_add_notifier_err;
dev_pm_opp_remove_all_dynamic(bwmgr->dev);
return ret;
}
return 0;
devfreq_add_notifier_err:
devm_devfreq_remove_device(bwmgr->dev, bwmgr->devfreq);
devfreq_add_dev_err:
dev_pm_opp_remove_all_dynamic(bwmgr->dev);
kfree(bwmgr->devfreq_profile);
return ret; return ret;
#else #else
return -EOPNOTSUPP; return -EOPNOTSUPP;
@@ -229,6 +233,7 @@ static void tegra_bpmp_bwmgr_devfreq_unregister(struct tegra_bpmp_bwmgr *bwmgr)
DEV_PM_QOS_MAX_FREQUENCY); DEV_PM_QOS_MAX_FREQUENCY);
devm_devfreq_remove_device(bwmgr->dev, bwmgr->devfreq); devm_devfreq_remove_device(bwmgr->dev, bwmgr->devfreq);
dev_pm_opp_remove_all_dynamic(bwmgr->dev); dev_pm_opp_remove_all_dynamic(bwmgr->dev);
kfree(bwmgr->devfreq_profile);
#endif #endif
} }
@@ -245,12 +250,16 @@ static int tegra_bpmp_bwmgr_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
bwmgr->clk = devm_clk_get(&pdev->dev, "emc"); bwmgr->clk = devm_clk_get(&pdev->dev, "emc");
if (IS_ERR(bwmgr->clk)) if (IS_ERR(bwmgr->clk)) {
return PTR_ERR(bwmgr->clk); err = PTR_ERR(bwmgr->clk);
goto devm_clk_get_err;
}
bwmgr->bpmp = tegra_bpmp_get(&pdev->dev); bwmgr->bpmp = tegra_bpmp_get(&pdev->dev);
if (IS_ERR(bwmgr->bpmp)) if (IS_ERR(bwmgr->bpmp)) {
return PTR_ERR(bwmgr->bpmp); err = PTR_ERR(bwmgr->bpmp);
goto bpmp_get_err;
}
bwmgr->mrq_valid = tegra_bpmp_mrq_is_supported(bwmgr->bpmp, MRQ_BWMGR_INT); bwmgr->mrq_valid = tegra_bpmp_mrq_is_supported(bwmgr->bpmp, MRQ_BWMGR_INT);
if (bwmgr->mrq_valid) { if (bwmgr->mrq_valid) {
@@ -285,16 +294,26 @@ static int tegra_bpmp_bwmgr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"fail to register devfreq governor %s: %d\n", "fail to register devfreq governor %s: %d\n",
DEVFREQ_GOV_BWMGR, err); DEVFREQ_GOV_BWMGR, err);
return err; goto add_gov_err;
} }
err = tegra_bpmp_bwmgr_devfreq_register(bwmgr); err = tegra_bpmp_bwmgr_devfreq_register(bwmgr);
if (err) { if (err) {
dev_err(&pdev->dev, "fail to register devfreq device: %d\n", err); dev_err(&pdev->dev, "fail to register devfreq device: %d\n", err);
return err; goto devfreq_register_err;
} }
return 0; return 0;
devfreq_register_err:
devfreq_remove_governor(&devfreq_gov_bwmgr);
add_gov_err:
tegra_bpmp_put(bwmgr->bpmp);
bpmp_get_err:
devm_clk_put(&pdev->dev, bwmgr->clk);
devm_clk_get_err:
kfree(bwmgr);
return err;
} }
static int tegra_bpmp_bwmgr_remove(struct platform_device *pdev) static int tegra_bpmp_bwmgr_remove(struct platform_device *pdev)
@@ -303,6 +322,9 @@ static int tegra_bpmp_bwmgr_remove(struct platform_device *pdev)
tegra_bpmp_bwmgr_devfreq_unregister(bwmgr); tegra_bpmp_bwmgr_devfreq_unregister(bwmgr);
devfreq_remove_governor(&devfreq_gov_bwmgr); devfreq_remove_governor(&devfreq_gov_bwmgr);
tegra_bpmp_put(bwmgr->bpmp);
devm_clk_put(&pdev->dev, bwmgr->clk);
kfree(bwmgr);
return 0; return 0;
} }