mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04: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 <[email protected]>
This commit is contained in:
parent
b0dfbcd1e9
commit
a3b03ca553
1 changed files with 18 additions and 5 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2014, 2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2015, 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "cache-hwmon: " fmt
|
||||
|
|
@ -46,7 +46,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 name##_show(struct device *dev, \
|
||||
|
|
@ -171,8 +173,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);
|
||||
|
|
@ -202,6 +208,7 @@ int update_cache_hwmon(struct cache_hwmon *hwmon)
|
|||
|
||||
devfreq_monitor_start(df);
|
||||
|
||||
mutex_unlock(&monitor_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -290,8 +297,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 < 0) {
|
||||
|
|
@ -302,8 +311,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;
|
||||
|
|
@ -318,8 +329,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;
|
||||
|
|
@ -388,13 +401,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…
Reference in a new issue