Merge tag 'xfs-for-linus-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / cpufreq / freq_table.c
index a8f1daffc9bcbfd6773ec50fc765e9fc821d4daa..3bbbf9e6960cdf12d939d3d88c5dc5ba4a89d070 100644 (file)
@@ -63,8 +63,6 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
        else
                return 0;
 }
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
-
 
 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
                                   struct cpufreq_frequency_table *table)
@@ -108,20 +106,16 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
  */
 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
 {
-       struct cpufreq_frequency_table *table =
-               cpufreq_frequency_get_table(policy->cpu);
-       if (!table)
+       if (!policy->freq_table)
                return -ENODEV;
 
-       return cpufreq_frequency_table_verify(policy, table);
+       return cpufreq_frequency_table_verify(policy, policy->freq_table);
 }
 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
 
-int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
-                                  struct cpufreq_frequency_table *table,
-                                  unsigned int target_freq,
-                                  unsigned int relation,
-                                  unsigned int *index)
+int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
+                                unsigned int target_freq,
+                                unsigned int relation)
 {
        struct cpufreq_frequency_table optimal = {
                .driver_data = ~0,
@@ -132,7 +126,9 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                .frequency = 0,
        };
        struct cpufreq_frequency_table *pos;
+       struct cpufreq_frequency_table *table = policy->freq_table;
        unsigned int freq, diff, i = 0;
+       int index;
 
        pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
                                        target_freq, relation, policy->cpu);
@@ -196,25 +192,26 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                }
        }
        if (optimal.driver_data > i) {
-               if (suboptimal.driver_data > i)
-                       return -EINVAL;
-               *index = suboptimal.driver_data;
-       } else
-               *index = optimal.driver_data;
+               if (suboptimal.driver_data > i) {
+                       WARN(1, "Invalid frequency table: %d\n", policy->cpu);
+                       return 0;
+               }
 
-       pr_debug("target index is %u, freq is:%u kHz\n", *index,
-                table[*index].frequency);
+               index = suboptimal.driver_data;
+       } else
+               index = optimal.driver_data;
 
-       return 0;
+       pr_debug("target index is %u, freq is:%u kHz\n", index,
+                table[index].frequency);
+       return index;
 }
-EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
+EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
 
 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
                unsigned int freq)
 {
-       struct cpufreq_frequency_table *pos, *table;
+       struct cpufreq_frequency_table *pos, *table = policy->freq_table;
 
-       table = cpufreq_frequency_get_table(policy->cpu);
        if (unlikely(!table)) {
                pr_debug("%s: Unable to find frequency table\n", __func__);
                return -ENOENT;
@@ -300,15 +297,72 @@ struct freq_attr *cpufreq_generic_attr[] = {
 };
 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
 
+static int set_freq_table_sorted(struct cpufreq_policy *policy)
+{
+       struct cpufreq_frequency_table *pos, *table = policy->freq_table;
+       struct cpufreq_frequency_table *prev = NULL;
+       int ascending = 0;
+
+       policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
+
+       cpufreq_for_each_valid_entry(pos, table) {
+               if (!prev) {
+                       prev = pos;
+                       continue;
+               }
+
+               if (pos->frequency == prev->frequency) {
+                       pr_warn("Duplicate freq-table entries: %u\n",
+                               pos->frequency);
+                       return -EINVAL;
+               }
+
+               /* Frequency increased from prev to pos */
+               if (pos->frequency > prev->frequency) {
+                       /* But frequency was decreasing earlier */
+                       if (ascending < 0) {
+                               pr_debug("Freq table is unsorted\n");
+                               return 0;
+                       }
+
+                       ascending++;
+               } else {
+                       /* Frequency decreased from prev to pos */
+
+                       /* But frequency was increasing earlier */
+                       if (ascending > 0) {
+                               pr_debug("Freq table is unsorted\n");
+                               return 0;
+                       }
+
+                       ascending--;
+               }
+
+               prev = pos;
+       }
+
+       if (ascending > 0)
+               policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
+       else
+               policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
+
+       pr_debug("Freq table is sorted in %s order\n",
+                ascending > 0 ? "ascending" : "descending");
+
+       return 0;
+}
+
 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
                                      struct cpufreq_frequency_table *table)
 {
-       int ret = cpufreq_frequency_table_cpuinfo(policy, table);
+       int ret;
 
-       if (!ret)
-               policy->freq_table = table;
+       ret = cpufreq_frequency_table_cpuinfo(policy, table);
+       if (ret)
+               return ret;
 
-       return ret;
+       policy->freq_table = table;
+       return set_freq_table_sorted(policy);
 }
 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);