cpufreq: Introducing CPUFREQ_RELATION_E
authorVincent Donnefort <vincent.donnefort@arm.com>
Wed, 8 Sep 2021 14:05:28 +0000 (15:05 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 5 Oct 2021 14:33:05 +0000 (16:33 +0200)
This newly introduced flag can be applied by a governor to a CPUFreq
relation, when looking for a frequency within the policy table. The
resolution would then only walk through efficient frequencies.

Even with the flag set, the policy max limit will still be honoured. If no
efficient frequencies can be found within the limits of the policy, an
inefficient one would be returned.

Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/amd_freq_sensitivity.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/s5pv210-cpufreq.c
include/linux/cpufreq.h

index 28467d83c7452d335e356642e0d11a723320acb7..3d514b82d055469fbcc43a6b6694f0f30525794b 100644 (file)
@@ -470,7 +470,8 @@ static unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy,
        if (policy->cached_target_freq == target_freq)
                index = policy->cached_resolved_idx;
        else
-               index = cpufreq_table_find_index_dl(policy, target_freq);
+               index = cpufreq_table_find_index_dl(policy, target_freq,
+                                                   false);
 
        entry = &policy->freq_table[index];
        next_freq = entry->frequency;
index d0b10baf039ab3b54b2b5dc488be9d68aa9ceeaf..6448e03bcf488e9a5bd4e9ef939cfc55a11848a9 100644 (file)
@@ -91,7 +91,8 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
                        unsigned int index;
 
                        index = cpufreq_table_find_index_h(policy,
-                                                          policy->cur - 1);
+                                                          policy->cur - 1,
+                                                          relation & CPUFREQ_RELATION_E);
                        freq_next = policy->freq_table[index].frequency;
                }
 
index 284e940084c613a480f5fbc70bf4f7ba2975c2ba..8069a7bac9efcdf63b24db86282183f7cc05369d 100644 (file)
@@ -2260,8 +2260,16 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
            !(cpufreq_driver->flags & CPUFREQ_NEED_UPDATE_LIMITS))
                return 0;
 
-       if (cpufreq_driver->target)
+       if (cpufreq_driver->target) {
+               /*
+                * If the driver hasn't setup a single inefficient frequency,
+                * it's unlikely it knows how to decode CPUFREQ_RELATION_E.
+                */
+               if (!policy->efficiencies_available)
+                       relation &= ~CPUFREQ_RELATION_E;
+
                return cpufreq_driver->target(policy, target_freq, relation);
+       }
 
        if (!cpufreq_driver->target_index)
                return -EINVAL;
index eb4320b619c9c2e5b195d5475a2bca23fb53aabd..f68cad9abd1162d419fcb7eb1f1a2192e0cfa76c 100644 (file)
@@ -83,9 +83,11 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
        freq_avg = freq_req - freq_reduc;
 
        /* Find freq bounds for freq_avg in freq_table */
-       index = cpufreq_table_find_index_h(policy, freq_avg);
+       index = cpufreq_table_find_index_h(policy, freq_avg,
+                                          relation & CPUFREQ_RELATION_E);
        freq_lo = freq_table[index].frequency;
-       index = cpufreq_table_find_index_l(policy, freq_avg);
+       index = cpufreq_table_find_index_l(policy, freq_avg,
+                                          relation & CPUFREQ_RELATION_E);
        freq_hi = freq_table[index].frequency;
 
        /* Find out how long we have to be in hi and lo freqs */
index 5a2cf5f91ccb0fd54fef316bf1fc5ef0ae4cb852..fddbd1ea163551dc71466f48d3fbf691d1d0a87f 100644 (file)
@@ -934,7 +934,7 @@ static void powernv_cpufreq_work_fn(struct work_struct *work)
                policy = cpufreq_cpu_get(cpu);
                if (!policy)
                        continue;
-               index = cpufreq_table_find_index_c(policy, policy->cur);
+               index = cpufreq_table_find_index_c(policy, policy->cur, false);
                powernv_cpufreq_target_index(policy, index);
                cpumask_andnot(&mask, &mask, policy->cpus);
                cpufreq_cpu_put(policy);
@@ -1022,7 +1022,7 @@ static unsigned int powernv_fast_switch(struct cpufreq_policy *policy,
        int index;
        struct powernv_smp_call_data freq_data;
 
-       index = cpufreq_table_find_index_dl(policy, target_freq);
+       index = cpufreq_table_find_index_dl(policy, target_freq, false);
        freq_data.pstate_id = powernv_freqs[index].driver_data;
        freq_data.gpstate_id = powernv_freqs[index].driver_data;
        set_pstate(&freq_data);
index ad7d4f272ddcb525b8e7abebd8dda1a1bcf2aa39..76c888ed8d160a7de0f68d14498397b631a07825 100644 (file)
@@ -243,7 +243,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
        new_freq = s5pv210_freq_table[index].frequency;
 
        /* Finding current running level index */
-       priv_index = cpufreq_table_find_index_h(policy, old_freq);
+       priv_index = cpufreq_table_find_index_h(policy, old_freq, false);
 
        arm_volt = dvs_conf[index].arm_volt;
        int_volt = dvs_conf[index].int_volt;
index 16997e1ff3fe55f93fafefba813ed7a649f6b332..6d96bd452d55e2c824e0793db085ef37b3efb2e2 100644 (file)
@@ -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;
                }
        }