sysctl: add and use base directory declarer and registration helper
[linux-block.git] / include / linux / cpufreq.h
index ff88bb3e44fca1ba7bb58137ca9aea1971a62c9b..1ab29e61b078ed9a45b7ba76444906161163199e 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,12 @@ 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 */
+
+#define CPUFREQ_RELATION_LE (CPUFREQ_RELATION_L | CPUFREQ_RELATION_E)
+#define CPUFREQ_RELATION_HE (CPUFREQ_RELATION_H | CPUFREQ_RELATION_E)
+#define CPUFREQ_RELATION_CE (CPUFREQ_RELATION_C | CPUFREQ_RELATION_E)
 
 struct freq_attr {
        struct attribute attr;
@@ -385,7 +398,7 @@ struct cpufreq_driver {
 /* flags */
 
 /*
- * Set by drivers that need to update internale upper and lower boundaries along
+ * Set by drivers that need to update internal upper and lower boundaries along
  * with the target frequency and so the core and governors should also invoke
  * the diver if the target frequency does not change, but the policy min or max
  * may have changed.
@@ -627,9 +640,11 @@ struct cpufreq_governor *cpufreq_fallback_governor(void);
 static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy)
 {
        if (policy->max < policy->cur)
-               __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
+               __cpufreq_driver_target(policy, policy->max,
+                                       CPUFREQ_RELATION_HE);
        else if (policy->min > policy->cur)
-               __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
+               __cpufreq_driver_target(policy, policy->min,
+                                       CPUFREQ_RELATION_LE);
 }
 
 /* Governor attribute set */
@@ -660,10 +675,11 @@ struct governor_attr {
  *********************************************************************/
 
 /* Special Values of .frequency field */
-#define CPUFREQ_ENTRY_INVALID  ~0u
-#define CPUFREQ_TABLE_END      ~1u
+#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;
@@ -740,6 +756,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);
@@ -764,14 +796,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)
@@ -785,14 +818,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)
@@ -815,26 +849,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)
@@ -857,14 +895,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)
@@ -878,26 +917,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)
@@ -924,14 +967,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)
@@ -958,35 +1002,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)
@@ -1003,6 +1070,37 @@ static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy
        return count;
 }
 
+/**
+ * cpufreq_table_set_inefficient() - Mark a frequency as inefficient
+ * @policy:    the &struct cpufreq_policy containing the inefficient frequency
+ * @frequency: the inefficient frequency
+ *
+ * The &struct cpufreq_policy must use a sorted frequency table
+ *
+ * Return:     %0 on success or a negative errno code
+ */
+
+static inline int
+cpufreq_table_set_inefficient(struct cpufreq_policy *policy,
+                             unsigned int frequency)
+{
+       struct cpufreq_frequency_table *pos;
+
+       /* Not supported */
+       if (policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED)
+               return -EINVAL;
+
+       cpufreq_for_each_valid_entry(pos, policy->freq_table) {
+               if (pos->frequency == frequency) {
+                       pos->flags |= CPUFREQ_INEFFICIENT_FREQ;
+                       policy->efficiencies_available = true;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 static inline int parse_perf_domain(int cpu, const char *list_name,
                                    const char *cell_name)
 {
@@ -1041,7 +1139,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
                if (cpu == pcpu)
                        continue;
 
-               ret = parse_perf_domain(pcpu, list_name, cell_name);
+               ret = parse_perf_domain(cpu, list_name, cell_name);
                if (ret < 0)
                        continue;
 
@@ -1071,6 +1169,13 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
        return false;
 }
 
+static inline int
+cpufreq_table_set_inefficient(struct cpufreq_policy *policy,
+                             unsigned int frequency)
+{
+       return -EINVAL;
+}
+
 static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_name,
                                                     const char *cell_name, struct cpumask *cpumask)
 {