Merge tag 'printk-for-5.10-fixup' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / cpufreq / cpufreq.c
index 47aa90f..1877f5e 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;
 
@@ -2056,9 +2060,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 +2731,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 +2809,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);