diff options
Diffstat (limited to 'include/linux/cpufreq.h')
| -rw-r--r-- | include/linux/cpufreq.h | 169 | 
1 files changed, 137 insertions, 32 deletions
| diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index ff88bb3e44fc..1ab29e61b078 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -119,6 +119,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  	 * scaling driver (0, which is the default, means no preference). @@ -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)  { |