mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
PM / devfreq: governor_cache_hwmon: Fix race in monitor start/stop
Some cache_hwmon devices can have interrupts firing at any time. The interrupt handler would stop devfreq monitor, update its vote and restart the monitor again. This introduces a race if devfreq_supend/resume() or devfreq_interval_update() is called at the same time. Since devfreq_monitor_start() re-initializes the work, it could cause corruption while the work is being used elsewhere. Protect governor monitor start/stops with a new lock. Change-Id: I143aaaea86494b4c617df46e2c521a19b43861d5 Signed-off-by: Junjie Wu <junjiew@codeaurora.org>
This commit is contained in:
parent
34100a43f3
commit
01bcb7677e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -54,7 +54,9 @@ static LIST_HEAD(cache_hwmon_list);
|
||||
static DEFINE_MUTEX(list_lock);
|
||||
|
||||
static int use_cnt;
|
||||
static DEFINE_MUTEX(state_lock);
|
||||
static DEFINE_MUTEX(register_lock);
|
||||
|
||||
static DEFINE_MUTEX(monitor_lock);
|
||||
|
||||
#define show_attr(name) \
|
||||
static ssize_t show_##name(struct device *dev, \
|
||||
@ -184,8 +186,12 @@ int update_cache_hwmon(struct cache_hwmon *hwmon)
|
||||
node = df->data;
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
if (!node->mon_started)
|
||||
|
||||
mutex_lock(&monitor_lock);
|
||||
if (!node->mon_started) {
|
||||
mutex_unlock(&monitor_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev_dbg(df->dev.parent, "Got update request\n");
|
||||
devfreq_monitor_stop(df);
|
||||
@ -215,6 +221,7 @@ int update_cache_hwmon(struct cache_hwmon *hwmon)
|
||||
|
||||
devfreq_monitor_start(df);
|
||||
|
||||
mutex_unlock(&monitor_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -287,8 +294,10 @@ static int start_monitoring(struct devfreq *df)
|
||||
goto err_start;
|
||||
}
|
||||
|
||||
mutex_lock(&monitor_lock);
|
||||
devfreq_monitor_start(df);
|
||||
node->mon_started = true;
|
||||
mutex_unlock(&monitor_lock);
|
||||
|
||||
ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
|
||||
if (ret) {
|
||||
@ -299,8 +308,10 @@ static int start_monitoring(struct devfreq *df)
|
||||
return 0;
|
||||
|
||||
sysfs_fail:
|
||||
mutex_lock(&monitor_lock);
|
||||
node->mon_started = false;
|
||||
devfreq_monitor_stop(df);
|
||||
mutex_unlock(&monitor_lock);
|
||||
hw->stop_hwmon(hw);
|
||||
err_start:
|
||||
df->data = node->orig_data;
|
||||
@ -315,8 +326,10 @@ static void stop_monitoring(struct devfreq *df)
|
||||
struct cache_hwmon *hw = node->hw;
|
||||
|
||||
sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
|
||||
mutex_lock(&monitor_lock);
|
||||
node->mon_started = false;
|
||||
devfreq_monitor_stop(df);
|
||||
mutex_unlock(&monitor_lock);
|
||||
hw->stop_hwmon(hw);
|
||||
df->data = node->orig_data;
|
||||
node->orig_data = NULL;
|
||||
@ -387,13 +400,13 @@ int register_cache_hwmon(struct device *dev, struct cache_hwmon *hwmon)
|
||||
node->hw = hwmon;
|
||||
node->attr_grp = &dev_attr_group;
|
||||
|
||||
mutex_lock(&state_lock);
|
||||
mutex_lock(®ister_lock);
|
||||
if (!use_cnt) {
|
||||
ret = devfreq_add_governor(&devfreq_cache_hwmon);
|
||||
if (!ret)
|
||||
use_cnt++;
|
||||
}
|
||||
mutex_unlock(&state_lock);
|
||||
mutex_unlock(®ister_lock);
|
||||
|
||||
if (!ret) {
|
||||
dev_info(dev, "Cache HWmon governor registered.\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user