Skip to content

Commit

Permalink
cpufreq: Add an interface to mark inefficient frequencies
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Vincent Donnefort authored and intel-lab-lkp committed Aug 26, 2021
1 parent 399dd32 commit ed31a82
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
2 changes: 2 additions & 0 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,8 @@ static int cpufreq_online(unsigned int cpu)
*/
if (cpufreq_driver->register_em)
cpufreq_driver->register_em(policy);

cpufreq_table_update_efficiencies(policy);
}

ret = cpufreq_init_policy(policy);
Expand Down
46 changes: 46 additions & 0 deletions drivers/cpufreq/freq_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,52 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
return set_freq_table_sorted(policy);
}

void cpufreq_table_update_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;
}
}
}

MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("CPUfreq frequency table helpers");
MODULE_LICENSE("GPL");
23 changes: 22 additions & 1 deletion include/linux/cpufreq.h
Original file line number Diff line number Diff line change
Expand Up @@ -664,13 +664,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)
Expand Down Expand Up @@ -1003,6 +1005,20 @@ static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy

return count;
}

static inline void
cpufreq_table_set_inefficient(const struct cpufreq_policy *policy,
unsigned int frequency)
{
struct cpufreq_frequency_table *pos;

cpufreq_for_each_valid_entry(pos, policy->freq_table) {
if (pos->frequency == frequency) {
pos->flags |= CPUFREQ_INEFFICIENT_FREQ;
break;
}
}
}
#else
static inline int cpufreq_boost_trigger_state(int state)
{
Expand All @@ -1022,6 +1038,10 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
{
return false;
}

static inline int
cpufreq_table_set_inefficient(const struct cpufreq_policy *policy,
unsigned int frequency) {}
#endif

#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
Expand Down Expand Up @@ -1049,6 +1069,7 @@ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
extern struct freq_attr *cpufreq_generic_attr[];
int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy);
void cpufreq_table_update_efficiencies(struct cpufreq_policy *policy);

unsigned int cpufreq_generic_get(unsigned int cpu);
void cpufreq_generic_init(struct cpufreq_policy *policy,
Expand Down

0 comments on commit ed31a82

Please sign in to comment.