[PATCH v4 5/9] cpufreq: Add an interface to mark inefficient frequencies
From: Vincent Donnefort <hidden>
Date: 2021-07-08 10:09:30
Subsystem:
cpu frequency scaling framework, the rest · Maintainers:
"Rafael J. Wysocki", Viresh Kumar, Linus Torvalds
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 <redacted>
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 67e56cf638ef..d68600b84d93 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c@@ -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>");
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 353969c7acd3..d10784cf7ee4 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h@@ -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)
--
2.7.4