cpufreq: Improve code around unlisted freq check
[linux-2.6-microblaze.git] / drivers / cpufreq / cpufreq.c
index 47aa90f..f4b6066 100644 (file)
@@ -61,6 +61,12 @@ static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
 static DEFINE_RWLOCK(cpufreq_driver_lock);
 
+static DEFINE_STATIC_KEY_FALSE(cpufreq_freq_invariance);
+bool cpufreq_supports_freq_invariance(void)
+{
+       return static_branch_likely(&cpufreq_freq_invariance);
+}
+
 /* Flag to suspend/resume CPUFreq governors */
 static bool cpufreq_suspended;
 
@@ -154,12 +160,6 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
 }
 EXPORT_SYMBOL_GPL(get_cpu_idle_time);
 
-__weak void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
-               unsigned long max_freq)
-{
-}
-EXPORT_SYMBOL_GPL(arch_set_freq_scale);
-
 /*
  * This is a generic cpufreq init() routine which can be used by cpufreq
  * drivers of SMP systems. It will do following:
@@ -446,6 +446,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
 
        cpufreq_notify_post_transition(policy, freqs, transition_failed);
 
+       arch_set_freq_scale(policy->related_cpus,
+                           policy->cur,
+                           policy->cpuinfo.max_freq);
+
        policy->transition_ongoing = false;
        policy->transition_task = NULL;
 
@@ -1450,14 +1454,13 @@ static int cpufreq_online(unsigned int cpu)
         */
        if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK)
            && has_target()) {
+               unsigned int old_freq = policy->cur;
+
                /* Are we running at unknown frequency ? */
-               ret = cpufreq_frequency_table_get_index(policy, policy->cur);
+               ret = cpufreq_frequency_table_get_index(policy, old_freq);
                if (ret == -EINVAL) {
-                       /* Warn user and fix it */
-                       pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n",
-                               __func__, policy->cpu, policy->cur);
-                       ret = __cpufreq_driver_target(policy, policy->cur - 1,
-                               CPUFREQ_RELATION_L);
+                       ret = __cpufreq_driver_target(policy, old_freq - 1,
+                                                     CPUFREQ_RELATION_L);
 
                        /*
                         * Reaching here after boot in a few seconds may not
@@ -1465,8 +1468,8 @@ static int cpufreq_online(unsigned int cpu)
                         * frequency for longer duration. Hence, a BUG_ON().
                         */
                        BUG_ON(ret);
-                       pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n",
-                               __func__, policy->cpu, policy->cur);
+                       pr_info("%s: CPU%d: Running at unlisted initial frequency: %u KHz, changing to: %u KHz\n",
+                               __func__, policy->cpu, old_freq, policy->cur);
                }
        }
 
@@ -2056,9 +2059,26 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
 unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
                                        unsigned int target_freq)
 {
+       unsigned int freq;
+       int cpu;
+
        target_freq = clamp_val(target_freq, policy->min, policy->max);
+       freq = cpufreq_driver->fast_switch(policy, target_freq);
 
-       return cpufreq_driver->fast_switch(policy, target_freq);
+       if (!freq)
+               return 0;
+
+       policy->cur = freq;
+       arch_set_freq_scale(policy->related_cpus, freq,
+                           policy->cpuinfo.max_freq);
+       cpufreq_stats_record_transition(policy, freq);
+
+       if (trace_cpu_frequency_enabled()) {
+               for_each_cpu(cpu, policy->cpus)
+                       trace_cpu_frequency(freq, cpu);
+       }
+
+       return freq;
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
 
@@ -2710,6 +2730,15 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        cpufreq_driver = driver_data;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+       /*
+        * Mark support for the scheduler's frequency invariance engine for
+        * drivers that implement target(), target_index() or fast_switch().
+        */
+       if (!cpufreq_driver->setpolicy) {
+               static_branch_enable_cpuslocked(&cpufreq_freq_invariance);
+               pr_debug("supports frequency invariance");
+       }
+
        if (driver_data->setpolicy)
                driver_data->flags |= CPUFREQ_CONST_LOOPS;
 
@@ -2779,6 +2808,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
        cpus_read_lock();
        subsys_interface_unregister(&cpufreq_interface);
        remove_boost_sysfs_file();
+       static_branch_disable_cpuslocked(&cpufreq_freq_invariance);
        cpuhp_remove_state_nocalls_cpuslocked(hp_online);
 
        write_lock_irqsave(&cpufreq_driver_lock, flags);