|
|
|
@ -118,6 +118,13 @@ struct cpufreq_policy {
|
|
|
|
|
*/
|
|
|
|
|
bool strict_target;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set if inefficient frequencies were found in the frequency table.
|
|
|
|
|
* This indicates if the relation flag CPUFREQ_RELATION_E can be
|
|
|
|
|
* honored.
|
|
|
|
|
*/
|
|
|
|
|
bool efficiencies_available;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Preferred average time interval between consecutive invocations of
|
|
|
|
|
* the driver to set the frequency for this policy. To be set by the
|
|
|
|
@ -273,6 +280,8 @@ static inline void cpufreq_stats_record_transition(struct cpufreq_policy *policy
|
|
|
|
|
#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */
|
|
|
|
|
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */
|
|
|
|
|
#define CPUFREQ_RELATION_C 2 /* closest frequency to target */
|
|
|
|
|
/* relation flags */
|
|
|
|
|
#define CPUFREQ_RELATION_E BIT(2) /* Get if possible an efficient frequency */
|
|
|
|
|
|
|
|
|
|
struct freq_attr {
|
|
|
|
|
struct attribute attr;
|
|
|
|
@ -741,6 +750,22 @@ static inline void dev_pm_opp_free_cpufreq_table(struct device *dev,
|
|
|
|
|
continue; \
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* cpufreq_for_each_efficient_entry_idx - iterate with index over a cpufreq
|
|
|
|
|
* frequency_table excluding CPUFREQ_ENTRY_INVALID and
|
|
|
|
|
* CPUFREQ_INEFFICIENT_FREQ frequencies.
|
|
|
|
|
* @pos: the &struct cpufreq_frequency_table to use as a loop cursor.
|
|
|
|
|
* @table: the &struct cpufreq_frequency_table to iterate over.
|
|
|
|
|
* @idx: the table entry currently being processed.
|
|
|
|
|
* @efficiencies: set to true to only iterate over efficient frequencies.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) \
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) \
|
|
|
|
|
if (efficiencies && (pos->flags & CPUFREQ_INEFFICIENT_FREQ)) \
|
|
|
|
|
continue; \
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
|
|
|
|
|
struct cpufreq_frequency_table *table);
|
|
|
|
@ -765,14 +790,15 @@ bool policy_has_boost_freq(struct cpufreq_policy *policy);
|
|
|
|
|
|
|
|
|
|
/* Find lowest freq at or above target in a table in ascending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq >= target_freq)
|
|
|
|
@ -786,14 +812,15 @@ static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Find lowest freq at or above target in a table in descending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq == target_freq)
|
|
|
|
@ -816,26 +843,30 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Works only on sorted freq-tables */
|
|
|
|
|
static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
|
|
|
|
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
|
|
|
return cpufreq_table_find_index_al(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_al(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
else
|
|
|
|
|
return cpufreq_table_find_index_dl(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_dl(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find highest freq at or below target in a table in ascending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq == target_freq)
|
|
|
|
@ -858,14 +889,15 @@ static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Find highest freq at or below target in a table in descending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq <= target_freq)
|
|
|
|
@ -879,26 +911,30 @@ static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Works only on sorted freq-tables */
|
|
|
|
|
static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
|
|
|
|
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
|
|
|
return cpufreq_table_find_index_ah(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_ah(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
else
|
|
|
|
|
return cpufreq_table_find_index_dh(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_dh(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find closest freq to target in a table in ascending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq == target_freq)
|
|
|
|
@ -925,14 +961,15 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Find closest freq to target in a table in descending order */
|
|
|
|
|
static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
struct cpufreq_frequency_table *table = policy->freq_table;
|
|
|
|
|
struct cpufreq_frequency_table *pos;
|
|
|
|
|
unsigned int freq;
|
|
|
|
|
int idx, best = -1;
|
|
|
|
|
|
|
|
|
|
cpufreq_for_each_valid_entry_idx(pos, table, idx) {
|
|
|
|
|
cpufreq_for_each_efficient_entry_idx(pos, table, idx, efficiencies) {
|
|
|
|
|
freq = pos->frequency;
|
|
|
|
|
|
|
|
|
|
if (freq == target_freq)
|
|
|
|
@ -959,35 +996,58 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
|
|
|
|
|
|
|
|
|
|
/* Works only on sorted freq-tables */
|
|
|
|
|
static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq)
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
bool efficiencies)
|
|
|
|
|
{
|
|
|
|
|
target_freq = clamp_val(target_freq, policy->min, policy->max);
|
|
|
|
|
|
|
|
|
|
if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
|
|
|
|
|
return cpufreq_table_find_index_ac(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_ac(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
else
|
|
|
|
|
return cpufreq_table_find_index_dc(policy, target_freq);
|
|
|
|
|
return cpufreq_table_find_index_dc(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
|
|
|
|
unsigned int target_freq,
|
|
|
|
|
unsigned int relation)
|
|
|
|
|
{
|
|
|
|
|
bool efficiencies = policy->efficiencies_available &&
|
|
|
|
|
(relation & CPUFREQ_RELATION_E);
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
/* cpufreq_table_index_unsorted() has no use for this flag anyway */
|
|
|
|
|
relation &= ~CPUFREQ_RELATION_E;
|
|
|
|
|
|
|
|
|
|
if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED))
|
|
|
|
|
return cpufreq_table_index_unsorted(policy, target_freq,
|
|
|
|
|
relation);
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
switch (relation) {
|
|
|
|
|
case CPUFREQ_RELATION_L:
|
|
|
|
|
return cpufreq_table_find_index_l(policy, target_freq);
|
|
|
|
|
idx = cpufreq_table_find_index_l(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
break;
|
|
|
|
|
case CPUFREQ_RELATION_H:
|
|
|
|
|
return cpufreq_table_find_index_h(policy, target_freq);
|
|
|
|
|
idx = cpufreq_table_find_index_h(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
break;
|
|
|
|
|
case CPUFREQ_RELATION_C:
|
|
|
|
|
return cpufreq_table_find_index_c(policy, target_freq);
|
|
|
|
|
idx = cpufreq_table_find_index_c(policy, target_freq,
|
|
|
|
|
efficiencies);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx < 0 && efficiencies) {
|
|
|
|
|
efficiencies = false;
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy *policy)
|
|
|
|
@ -1027,6 +1087,7 @@ cpufreq_table_set_inefficient(struct cpufreq_policy *policy,
|
|
|
|
|
cpufreq_for_each_valid_entry(pos, policy->freq_table) {
|
|
|
|
|
if (pos->frequency == frequency) {
|
|
|
|
|
pos->flags |= CPUFREQ_INEFFICIENT_FREQ;
|
|
|
|
|
policy->efficiencies_available = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|