cpufreq: governor: Replace timers with utilization update callbacks
[cascardo/linux.git] / drivers / cpufreq / cpufreq_ondemand.c
index eae5107..da7f351 100644 (file)
@@ -31,9 +31,7 @@ static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
 
 static struct od_ops od_ops;
 
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
 static struct cpufreq_governor cpufreq_gov_ondemand;
-#endif
 
 static unsigned int default_powersave_bias;
 
@@ -191,7 +189,7 @@ static void od_check_cpu(int cpu, unsigned int load)
        }
 }
 
-static unsigned int od_dbs_timer(struct cpufreq_policy *policy, bool modify_all)
+static unsigned int od_dbs_timer(struct cpufreq_policy *policy)
 {
        struct dbs_data *dbs_data = policy->governor_data;
        unsigned int cpu = policy->cpu;
@@ -200,9 +198,6 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy, bool modify_all)
        struct od_dbs_tuners *od_tuners = dbs_data->tuners;
        int delay = 0, sample_type = dbs_info->sample_type;
 
-       if (!modify_all)
-               goto max_delay;
-
        /* Common NORMAL_SAMPLE setup */
        dbs_info->sample_type = OD_NORMAL_SAMPLE;
        if (sample_type == OD_SUB_SAMPLE) {
@@ -218,7 +213,6 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy, bool modify_all)
                }
        }
 
-max_delay:
        if (!delay)
                delay = delay_for_sampling_rate(od_tuners->sampling_rate
                                * dbs_info->rate_mult);
@@ -264,7 +258,6 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
                struct od_cpu_dbs_info_s *dbs_info;
                struct cpu_dbs_info *cdbs;
                struct cpu_common_dbs_info *shared;
-               unsigned long next_sampling, appointed_at;
 
                dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
                cdbs = &dbs_info->cdbs;
@@ -288,20 +281,28 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
                 * policy will be governed by dbs_data, otherwise there can be
                 * multiple policies that are governed by the same dbs_data.
                 */
-               if (dbs_data != policy->governor_data)
-                       continue;
-
-               /*
-                * Checking this for any CPU should be fine, timers for all of
-                * them are scheduled together.
-                */
-               next_sampling = jiffies + usecs_to_jiffies(new_rate);
-               appointed_at = dbs_info->cdbs.timer.expires;
-
-               if (time_before(next_sampling, appointed_at)) {
-                       gov_cancel_work(shared);
-                       gov_add_timers(policy, usecs_to_jiffies(new_rate));
-
+               if (dbs_data == policy->governor_data) {
+                       mutex_lock(&shared->timer_mutex);
+                       /*
+                        * On 32-bit architectures this may race with the
+                        * sample_delay_ns read in dbs_update_util_handler(),
+                        * but that really doesn't matter.  If the read returns
+                        * a value that's too big, the sample will be skipped,
+                        * but the next invocation of dbs_update_util_handler()
+                        * (when the update has been completed) will take a
+                        * sample.  If the returned value is too small, the
+                        * sample will be taken immediately, but that isn't a
+                        * problem, as we want the new rate to take effect
+                        * immediately anyway.
+                        *
+                        * If this runs in parallel with dbs_work_handler(), we
+                        * may end up overwriting the sample_delay_ns value that
+                        * it has just written, but the difference should not be
+                        * too big and it will be corrected next time a sample
+                        * is taken, so it shouldn't be significant.
+                        */
+                       gov_update_sample_delay(shared, new_rate);
+                       mutex_unlock(&shared->timer_mutex);
                }
        }
 
@@ -554,6 +555,19 @@ static struct common_dbs_data od_dbs_cdata = {
        .mutex = __MUTEX_INITIALIZER(od_dbs_cdata.mutex),
 };
 
+static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
+               unsigned int event)
+{
+       return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
+}
+
+static struct cpufreq_governor cpufreq_gov_ondemand = {
+       .name                   = "ondemand",
+       .governor               = od_cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
+};
+
 static void od_set_powersave_bias(unsigned int powersave_bias)
 {
        struct cpufreq_policy *policy;
@@ -605,22 +619,6 @@ void od_unregister_powersave_bias_handler(void)
 }
 EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
 
-static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
-               unsigned int event)
-{
-       return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
-}
-
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
-static
-#endif
-struct cpufreq_governor cpufreq_gov_ondemand = {
-       .name                   = "ondemand",
-       .governor               = od_cpufreq_governor_dbs,
-       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
-       .owner                  = THIS_MODULE,
-};
-
 static int __init cpufreq_gov_dbs_init(void)
 {
        return cpufreq_register_governor(&cpufreq_gov_ondemand);
@@ -638,6 +636,11 @@ MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
 MODULE_LICENSE("GPL");
 
 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+       return &cpufreq_gov_ondemand;
+}
+
 fs_initcall(cpufreq_gov_dbs_init);
 #else
 module_init(cpufreq_gov_dbs_init);