@@ -351,6 +351,52 @@ static int set_freq_table_sorted(struct cpufreq_policy *policy)
return 0;
}
+static void set_freq_table_efficiencies(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *pos, *table = policy->freq_table;
+ enum cpufreq_table_sorting sort = policy->freq_table_sorted;
+ int efficient, idx;
+
+ /* Not supported */
+ if (sort == CPUFREQ_TABLE_UNSORTED) {
+ cpufreq_for_each_entry_idx(pos, table, idx)
+ pos->efficient = idx;
+ return;
+ }
+
+ /* The highest frequency is always efficient */
+ cpufreq_for_each_entry_idx(pos, table, idx) {
+ if (pos->frequency == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ efficient = idx;
+
+ if (sort == CPUFREQ_TABLE_SORTED_DESCENDING)
+ break;
+ }
+
+ for (;;) {
+ pos = &table[idx];
+
+ if (pos->frequency != CPUFREQ_ENTRY_INVALID) {
+ if (pos->flags & CPUFREQ_INEFFICIENT_FREQ) {
+ pos->efficient = efficient;
+ } else {
+ pos->efficient = idx;
+ efficient = idx;
+ }
+ }
+
+ if (sort == CPUFREQ_TABLE_SORTED_ASCENDING) {
+ if (--idx < 0)
+ break;
+ } else {
+ if (table[++idx].frequency == CPUFREQ_TABLE_END)
+ break;
+ }
+ }
+}
+
int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
{
int ret;
@@ -362,7 +408,13 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
if (ret)
return ret;
- return set_freq_table_sorted(policy);
+ ret = set_freq_table_sorted(policy);
+ if (ret)
+ return ret;
+
+ set_freq_table_efficiencies(policy);
+
+ return ret;
}
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
@@ -666,13 +666,15 @@ struct governor_attr {
#define CPUFREQ_ENTRY_INVALID ~0u
#define CPUFREQ_TABLE_END ~1u
/* Special Values of .flags field */
-#define CPUFREQ_BOOST_FREQ (1 << 0)
+#define CPUFREQ_BOOST_FREQ (1 << 0)
+#define CPUFREQ_INEFFICIENT_FREQ (1 << 1)
struct cpufreq_frequency_table {
unsigned int flags;
unsigned int driver_data; /* driver specific data, not used by core */
unsigned int frequency; /* kHz - doesn't need to be in ascending
* order */
+ unsigned int efficient; /* idx of an efficient frequency */
};
#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
Some SoCs such as the sd855 have OPPs within the same policy whose cost is higher than others with a higher frequency. Those OPPs are inefficients and it might be interesting for a governor to not use them. Adding a flag, CPUFREQ_INEFFICIENT_FREQ, to mark such OPPs into the frequency table, as well as a new cpufreq_frequency_table member "efficient". This new member allows CPUFreq to resolve an inefficient frequency to an efficient one. Efficient frequencies point to themselves. The efficiency resolution must check it doesn't break the policy maximum. Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>