cpufreq: governors: Fix CPUFREQ_GOV_POLICY_{INIT|EXIT} notifiers
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 30 Apr 2013 14:32:17 +0000 (14:32 +0000)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sun, 12 May 2013 12:04:16 +0000 (14:04 +0200)
There are two types of INIT/EXIT activities that we need to do for
governors:
 - Done only once per governor (doesn't depend how many instances of
   the governor there are). eg: cpufreq_register_notifier() for
   conservative governor.
 - Done per governor instance, eg: sysfs_{create|remove}_group().

There were some corner cases where current code isn't able to handle
them separately and so failing for some test cases.

We use two separate variables now for keeping track of above two
requirements.
 - governor->initialized for first one
 - dbs_data->usage_count for per governor instance

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h

index 443442df113be73b33173c1a44109b4619508d7a..5af40ad82d231f7fd23bfd862590c30ab7d4b38e 100644 (file)
@@ -255,6 +255,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if (have_governor_per_policy()) {
                        WARN_ON(dbs_data);
                } else if (dbs_data) {
+                       dbs_data->usage_count++;
                        policy->governor_data = dbs_data;
                        return 0;
                }
@@ -266,6 +267,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                }
 
                dbs_data->cdata = cdata;
+               dbs_data->usage_count = 1;
                rc = cdata->init(dbs_data);
                if (rc) {
                        pr_err("%s: POLICY_INIT: init() failed\n", __func__);
@@ -294,7 +296,8 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
                                        latency * LATENCY_MULTIPLIER));
 
-               if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+               if ((cdata->governor == GOV_CONSERVATIVE) &&
+                               (!policy->governor->initialized)) {
                        struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
 
                        cpufreq_register_notifier(cs_ops->notifier_block,
@@ -306,12 +309,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 
                return 0;
        case CPUFREQ_GOV_POLICY_EXIT:
-               if ((policy->governor->initialized == 1) ||
-                               have_governor_per_policy()) {
+               if (!--dbs_data->usage_count) {
                        sysfs_remove_group(get_governor_parent_kobj(policy),
                                        get_sysfs_attr(dbs_data));
 
-                       if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+                       if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) &&
+                               (policy->governor->initialized == 1)) {
                                struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
 
                                cpufreq_unregister_notifier(cs_ops->notifier_block,
index 8ac33538d0bdb4f66cc7572f53db4c463190ae92..e16a96130cb3491d30f376728144cdca92e441cd 100644 (file)
@@ -211,6 +211,7 @@ struct common_dbs_data {
 struct dbs_data {
        struct common_dbs_data *cdata;
        unsigned int min_sampling_rate;
+       int usage_count;
        void *tuners;
 
        /* dbs_mutex protects dbs_enable in governor start/stop */