mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
devfreq: nvhost_podgov: Fix NULL dereference issue
When switching the governor to nvhost_pogdov or switching back to other governors, we will need to lock the devfreq lock to prevent triggering DVFS cycle from other paths. The nvhost_pod_target_freq callback will be called when triggering the DVFS cycle. However, the callback expects governor data is already allocated and initialized. We need to synchronize the operations when we switch the governor so that DVFS cycle can only be triggered when governor data is ready. Bug 5354161 Bug 5351714 Change-Id: Iaf8af8291ea09a7c2bfbdc5e1453bb976ee0987b Signed-off-by: Johnny Liu <johnliu@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3392341 Reviewed-by: svcacv <svcacv@nvidia.com> Reviewed-by: Bibek Basu <bbasu@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com> Reviewed-by: Rajesh Devaraj <rdevaraj@nvidia.com> Reviewed-by: Rajkumar Kasirajan <rkasirajan@nvidia.com>
This commit is contained in:
@@ -170,6 +170,17 @@ static int nvhost_pod_target_freq(struct devfreq *df, unsigned long *freq)
|
|||||||
unsigned int down_threshold;
|
unsigned int down_threshold;
|
||||||
int index, err;
|
int index, err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE:
|
||||||
|
* Since "cancel_delayed_work_sync(&devfreq->work)" is not synchronized
|
||||||
|
* by the devfreq->lock mutex lock in the devfreq_monitor_stop function
|
||||||
|
* in the devfreq core, the condition check here is necessary due to
|
||||||
|
* out-of-order execution even though devfreq timer has stopped and the
|
||||||
|
* df->governor_data is already freed in the nvhost_pod_exit handler.
|
||||||
|
*/
|
||||||
|
if (!podgov)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
err = devfreq_update_stats(df);
|
err = devfreq_update_stats(df);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@@ -273,10 +284,6 @@ static int nvhost_pod_init(struct devfreq *df)
|
|||||||
if (err)
|
if (err)
|
||||||
goto unregister_notifier;
|
goto unregister_notifier;
|
||||||
|
|
||||||
if (!pm_runtime_suspended(df->dev.parent)) {
|
|
||||||
devfreq_monitor_start(df);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unregister_notifier:
|
unregister_notifier:
|
||||||
@@ -291,7 +298,6 @@ static void nvhost_pod_exit(struct devfreq *df)
|
|||||||
{
|
{
|
||||||
struct podgov_data *podgov = df->governor_data;
|
struct podgov_data *podgov = df->governor_data;
|
||||||
|
|
||||||
devfreq_monitor_stop(df);
|
|
||||||
sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
|
sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
|
||||||
devfreq_unregister_notifier(df, &podgov->nb, DEVFREQ_TRANSITION_NOTIFIER);
|
devfreq_unregister_notifier(df, &podgov->nb, DEVFREQ_TRANSITION_NOTIFIER);
|
||||||
|
|
||||||
@@ -320,10 +326,16 @@ static int nvhost_pod_event_handler(struct devfreq *df,
|
|||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case DEVFREQ_GOV_START:
|
case DEVFREQ_GOV_START:
|
||||||
|
mutex_lock(&df->lock);
|
||||||
ret = nvhost_pod_init(df);
|
ret = nvhost_pod_init(df);
|
||||||
|
mutex_unlock(&df->lock);
|
||||||
|
devfreq_monitor_start(df);
|
||||||
break;
|
break;
|
||||||
case DEVFREQ_GOV_STOP:
|
case DEVFREQ_GOV_STOP:
|
||||||
|
devfreq_monitor_stop(df);
|
||||||
|
mutex_lock(&df->lock);
|
||||||
nvhost_pod_exit(df);
|
nvhost_pod_exit(df);
|
||||||
|
mutex_unlock(&df->lock);
|
||||||
break;
|
break;
|
||||||
case DEVFREQ_GOV_UPDATE_INTERVAL:
|
case DEVFREQ_GOV_UPDATE_INTERVAL:
|
||||||
devfreq_update_interval(df, (unsigned int *)data);
|
devfreq_update_interval(df, (unsigned int *)data);
|
||||||
|
|||||||
Reference in New Issue
Block a user