Support the new resolve_freq cpufreq callback which resolves a target
frequency to a driver-supported frequency without actually setting it.

The target frequency and resolved frequency table entry are cached so
that a subsequent fast_switch operation may avoid the frequency table
walk assuming the requested target frequency is the same.

Suggested-by: Rafael J. Wysocki <rafael.j.wyso...@intel.com>
Signed-off-by: Steve Muckle <smuc...@linaro.org>
---
 drivers/cpufreq/acpi-cpufreq.c | 56 ++++++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 7f38fb55f223..d87962eda1ed 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -66,6 +66,8 @@ enum {
 
 struct acpi_cpufreq_data {
        struct cpufreq_frequency_table *freq_table;
+       unsigned int cached_lookup_freq;
+       struct cpufreq_frequency_table *cached_lookup_entry;
        unsigned int resume;
        unsigned int cpu_feature;
        unsigned int acpi_perf_cpu;
@@ -458,26 +460,53 @@ static int acpi_cpufreq_target(struct cpufreq_policy 
*policy,
        return result;
 }
 
-unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy,
-                                     unsigned int target_freq)
+/*
+ * Find the closest frequency above target_freq.
+ *
+ * The table is sorted in the reverse order with respect to the
+ * frequency and all of the entries are valid (see the initialization).
+ */
+static inline struct cpufreq_frequency_table
+*lookup_freq(struct cpufreq_frequency_table *table, unsigned int target_freq)
 {
-       struct acpi_cpufreq_data *data = policy->driver_data;
-       struct acpi_processor_performance *perf;
-       struct cpufreq_frequency_table *entry;
-       unsigned int next_perf_state, next_freq, freq;
+       struct cpufreq_frequency_table *entry = table;
+       unsigned int freq;
 
-       /*
-        * Find the closest frequency above target_freq.
-        *
-        * The table is sorted in the reverse order with respect to the
-        * frequency and all of the entries are valid (see the initialization).
-        */
-       entry = data->freq_table;
        do {
                entry++;
                freq = entry->frequency;
        } while (freq >= target_freq && freq != CPUFREQ_TABLE_END);
        entry--;
+
+       return entry;
+}
+
+unsigned int acpi_cpufreq_resolve_freq(struct cpufreq_policy *policy,
+                                      unsigned int target_freq)
+{
+       struct acpi_cpufreq_data *data = policy->driver_data;
+       struct cpufreq_frequency_table *entry;
+
+       data->cached_lookup_freq = target_freq;
+       entry = lookup_freq(data->freq_table, target_freq);
+       data->cached_lookup_entry = entry;
+
+       return entry->frequency;
+}
+
+unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy,
+                                     unsigned int target_freq)
+{
+       struct acpi_cpufreq_data *data = policy->driver_data;
+       struct acpi_processor_performance *perf;
+       struct cpufreq_frequency_table *entry;
+       unsigned int next_perf_state, next_freq;
+
+       if (data->cached_lookup_entry &&
+           data->cached_lookup_freq == target_freq)
+               entry = data->cached_lookup_entry;
+       else
+               entry = lookup_freq(data->freq_table, target_freq);
        next_freq = entry->frequency;
        next_perf_state = entry->driver_data;
 
@@ -918,6 +947,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
        .verify         = cpufreq_generic_frequency_table_verify,
        .target_index   = acpi_cpufreq_target,
        .fast_switch    = acpi_cpufreq_fast_switch,
+       .resolve_freq   = acpi_cpufreq_resolve_freq,
        .bios_limit     = acpi_processor_get_bios_limit,
        .init           = acpi_cpufreq_cpu_init,
        .exit           = acpi_cpufreq_cpu_exit,
-- 
2.4.10

Reply via email to