summaryrefslogtreecommitdiff
path: root/drivers/cpufreq/cpufreq_conservative.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-05-18 22:59:49 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-06-02 23:24:39 +0200
commit9a15fb2c797a15524e63eacb10bd6cd68a99e830 (patch)
treec42c85d19058a8632ce0a5fd06ae775d04ca654c /drivers/cpufreq/cpufreq_conservative.c
parentbf2be2de8493dd5f86d6e0f0d4eecb5810ad035b (diff)
cpufreq: Drop the 'initialized' field from struct cpufreq_governor
The 'initialized' field in struct cpufreq_governor is only used by the conservative governor (as a usage counter) and the way that happens is far from straightforward and arguably incorrect. Namely, the value of 'initialized' is checked by cpufreq_dbs_governor_init() and cpufreq_dbs_governor_exit() and the results of those checks are passed (as the second argument) to the ->init() and ->exit() callbacks in struct dbs_governor. Those callbacks are only implemented by the ondemand and conservative governors and ondemand doesn't use their second argument at all. In turn, the conservative governor uses it to decide whether or not to either register or unregister a transition notifier. That whole mechanism is not only unnecessarily convoluted, but also racy, because the 'initialized' field of struct cpufreq_governor is updated in cpufreq_init_governor() and cpufreq_exit_governor() under policy->rwsem which doesn't help if one of these functions is run twice in parallel for different policies (which isn't impossible in principle), for example. Instead of it, add a proper usage counter to the conservative governor and update it from cs_init() and cs_exit() which is guaranteed to be non-racy, as those functions are only called under gov_dbs_data_mutex which is global. With that in place, drop the 'initialized' field from struct cpufreq_governor as it is not used any more. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'drivers/cpufreq/cpufreq_conservative.c')
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 78faa9fbc384..f967ec6c5720 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -127,7 +127,6 @@ static struct notifier_block cs_cpufreq_notifier_block = {
};
/************************** sysfs interface ************************/
-static struct dbs_governor cs_dbs_gov;
static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
const char *buf, size_t count)
@@ -255,6 +254,13 @@ static struct attribute *cs_attributes[] = {
/************************** sysfs end ************************/
+struct cs_governor {
+ struct dbs_governor dbs_gov;
+ unsigned int usage_count;
+};
+
+static struct cs_governor cs_gov;
+
static struct policy_dbs_info *cs_alloc(void)
{
struct cs_policy_dbs_info *dbs_info;
@@ -268,7 +274,7 @@ static void cs_free(struct policy_dbs_info *policy_dbs)
kfree(to_dbs_info(policy_dbs));
}
-static int cs_init(struct dbs_data *dbs_data, bool notify)
+static int cs_init(struct dbs_data *dbs_data)
{
struct cs_dbs_tuners *tuners;
@@ -286,16 +292,22 @@ static int cs_init(struct dbs_data *dbs_data, bool notify)
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
jiffies_to_usecs(10);
- if (notify)
+ /*
+ * This function and cs_exit() are only called under gov_dbs_data_mutex
+ * which is global, so the cs_gov.usage_count accesses are guaranteed
+ * to be serialized.
+ */
+ if (!cs_gov.usage_count++)
cpufreq_register_notifier(&cs_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
return 0;
}
-static void cs_exit(struct dbs_data *dbs_data, bool notify)
+static void cs_exit(struct dbs_data *dbs_data)
{
- if (notify)
+ /* Protected by gov_dbs_data_mutex - see the comment in cs_init(). */
+ if (!--cs_gov.usage_count)
cpufreq_unregister_notifier(&cs_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
@@ -310,18 +322,20 @@ static void cs_start(struct cpufreq_policy *policy)
dbs_info->requested_freq = policy->cur;
}
-static struct dbs_governor cs_dbs_gov = {
- .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
- .kobj_type = { .default_attrs = cs_attributes },
- .gov_dbs_timer = cs_dbs_timer,
- .alloc = cs_alloc,
- .free = cs_free,
- .init = cs_init,
- .exit = cs_exit,
- .start = cs_start,
+static struct cs_governor cs_gov = {
+ .dbs_gov = {
+ .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
+ .kobj_type = { .default_attrs = cs_attributes },
+ .gov_dbs_timer = cs_dbs_timer,
+ .alloc = cs_alloc,
+ .free = cs_free,
+ .init = cs_init,
+ .exit = cs_exit,
+ .start = cs_start,
+ },
};
-#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov)
+#define CPU_FREQ_GOV_CONSERVATIVE (&cs_gov.dbs_gov.gov)
static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)