diff options
Diffstat (limited to 'drivers/cpufreq/freq_table.c')
| -rw-r--r-- | drivers/cpufreq/freq_table.c | 202 | 
1 files changed, 132 insertions, 70 deletions
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index f111454a7ae..1632981c4b2 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -21,19 +21,19 @@  int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,  				    struct cpufreq_frequency_table *table)  { +	struct cpufreq_frequency_table *pos;  	unsigned int min_freq = ~0;  	unsigned int max_freq = 0; -	unsigned int i; +	unsigned int freq; -	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -		unsigned int freq = table[i].frequency; -		if (freq == CPUFREQ_ENTRY_INVALID) { -			pr_debug("table entry %u is invalid, skipping\n", i); +	cpufreq_for_each_valid_entry(pos, table) { +		freq = pos->frequency; +		if (!cpufreq_boost_enabled() +		    && (pos->flags & CPUFREQ_BOOST_FREQ))  			continue; -		} -		pr_debug("table entry %u: %u kHz, %u driver_data\n", -					i, freq, table[i].driver_data); + +		pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);  		if (freq < min_freq)  			min_freq = freq;  		if (freq > max_freq) @@ -54,31 +54,31 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);  int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,  				   struct cpufreq_frequency_table *table)  { -	unsigned int next_larger = ~0; -	unsigned int i; -	unsigned int count = 0; +	struct cpufreq_frequency_table *pos; +	unsigned int freq, next_larger = ~0; +	bool found = false;  	pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",  					policy->min, policy->max, policy->cpu); -	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, -				     policy->cpuinfo.max_freq); +	cpufreq_verify_within_cpu_limits(policy); -	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -		unsigned int freq = table[i].frequency; -		if (freq == CPUFREQ_ENTRY_INVALID) -			continue; -		if ((freq >= policy->min) && (freq <= policy->max)) -			count++; -		else if ((next_larger > freq) && (freq > policy->max)) +	cpufreq_for_each_valid_entry(pos, table) { +		freq = pos->frequency; + +		if ((freq >= policy->min) && (freq <= policy->max)) { +			found = true; +			break; +		} + +		if ((next_larger > freq) && (freq > policy->max))  			next_larger = freq;  	} -	if (!count) +	if (!found) {  		policy->max = next_larger; - -	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, -				     policy->cpuinfo.max_freq); +		cpufreq_verify_within_cpu_limits(policy); +	}  	pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",  				policy->min, policy->max, policy->cpu); @@ -87,6 +87,20 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,  }  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); +/* + * Generic routine to verify policy & frequency table, requires driver to set + * policy->freq_table prior to it. + */ +int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) +{ +	struct cpufreq_frequency_table *table = +		cpufreq_frequency_get_table(policy->cpu); +	if (!table) +		return -ENODEV; + +	return cpufreq_frequency_table_verify(policy, table); +} +EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);  int cpufreq_frequency_table_target(struct cpufreq_policy *policy,  				   struct cpufreq_frequency_table *table, @@ -102,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,  		.driver_data = ~0,  		.frequency = 0,  	}; -	unsigned int i; +	struct cpufreq_frequency_table *pos; +	unsigned int freq, i = 0;  	pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",  					target_freq, relation, policy->cpu); @@ -116,15 +131,19 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,  		break;  	} -	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -		unsigned int freq = table[i].frequency; -		if (freq == CPUFREQ_ENTRY_INVALID) -			continue; +	cpufreq_for_each_valid_entry(pos, table) { +		freq = pos->frequency; + +		i = pos - table;  		if ((freq < policy->min) || (freq > policy->max))  			continue; +		if (freq == target_freq) { +			optimal.driver_data = i; +			break; +		}  		switch (relation) {  		case CPUFREQ_RELATION_H: -			if (freq <= target_freq) { +			if (freq < target_freq) {  				if (freq >= optimal.frequency) {  					optimal.frequency = freq;  					optimal.driver_data = i; @@ -137,7 +156,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,  			}  			break;  		case CPUFREQ_RELATION_L: -			if (freq >= target_freq) { +			if (freq > target_freq) {  				if (freq <= optimal.frequency) {  					optimal.frequency = freq;  					optimal.driver_data = i; @@ -158,33 +177,60 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,  	} else  		*index = optimal.driver_data; -	pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, -		table[*index].driver_data); +	pr_debug("target index is %u, freq is:%u kHz\n", *index, +		 table[*index].frequency);  	return 0;  }  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); -static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table); +int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, +		unsigned int freq) +{ +	struct cpufreq_frequency_table *pos, *table; + +	table = cpufreq_frequency_get_table(policy->cpu); +	if (unlikely(!table)) { +		pr_debug("%s: Unable to find frequency table\n", __func__); +		return -ENOENT; +	} + +	cpufreq_for_each_valid_entry(pos, table) +		if (pos->frequency == freq) +			return pos - table; + +	return -EINVAL; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); +  /**   * show_available_freqs - show available frequencies for the specified CPU   */ -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf) +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, +				    bool show_boost)  { -	unsigned int i = 0; -	unsigned int cpu = policy->cpu;  	ssize_t count = 0; -	struct cpufreq_frequency_table *table; +	struct cpufreq_frequency_table *pos, *table = policy->freq_table; -	if (!per_cpu(cpufreq_show_table, cpu)) +	if (!table)  		return -ENODEV; -	table = per_cpu(cpufreq_show_table, cpu); - -	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -		if (table[i].frequency == CPUFREQ_ENTRY_INVALID) +	cpufreq_for_each_valid_entry(pos, table) { +		/* +		 * show_boost = true and driver_data = BOOST freq +		 * display BOOST freqs +		 * +		 * show_boost = false and driver_data = BOOST freq +		 * show_boost = true and driver_data != BOOST freq +		 * continue - do not display anything +		 * +		 * show_boost = false and driver_data != BOOST freq +		 * display NON BOOST freqs +		 */ +		if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))  			continue; -		count += sprintf(&buf[count], "%d ", table[i].frequency); + +		count += sprintf(&buf[count], "%d ", pos->frequency);  	}  	count += sprintf(&buf[count], "\n"); @@ -192,45 +238,61 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)  } -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { -	.attr = { .name = "scaling_available_frequencies", -		  .mode = 0444, -		}, -	.show = show_available_freqs, -}; -EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); +#define cpufreq_attr_available_freq(_name)	  \ +struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \ +__ATTR_RO(_name##_frequencies) -/* - * if you use these, you must assure that the frequency table is valid - * all the time between get_attr and put_attr! +/** + * show_scaling_available_frequencies - show available normal frequencies for + * the specified CPU   */ -void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, -				      unsigned int cpu) +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, +						  char *buf)  { -	pr_debug("setting show_table for cpu %u to %p\n", cpu, table); -	per_cpu(cpufreq_show_table, cpu) = table; +	return show_available_freqs(policy, buf, false);  } -EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); +cpufreq_attr_available_freq(scaling_available); +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); -void cpufreq_frequency_table_put_attr(unsigned int cpu) +/** + * show_available_boost_freqs - show available boost frequencies for + * the specified CPU + */ +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, +					      char *buf)  { -	pr_debug("clearing show_table for cpu %u\n", cpu); -	per_cpu(cpufreq_show_table, cpu) = NULL; +	return show_available_freqs(policy, buf, true);  } -EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); +cpufreq_attr_available_freq(scaling_boost); +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); + +struct freq_attr *cpufreq_generic_attr[] = { +	&cpufreq_freq_attr_scaling_available_freqs, +#ifdef CONFIG_CPU_FREQ_BOOST_SW +	&cpufreq_freq_attr_scaling_boost_freqs, +#endif +	NULL, +}; +EXPORT_SYMBOL_GPL(cpufreq_generic_attr); -void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy) +int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, +				      struct cpufreq_frequency_table *table)  { -	pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n", -			policy->cpu, policy->last_cpu); -	per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table, -			policy->last_cpu); -	per_cpu(cpufreq_show_table, policy->last_cpu) = NULL; +	int ret = cpufreq_frequency_table_cpuinfo(policy, table); + +	if (!ret) +		policy->freq_table = table; + +	return ret;  } +EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); + +struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);  struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)  { -	return per_cpu(cpufreq_show_table, cpu); +	struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); +	return policy ? policy->freq_table : NULL;  }  EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);  | 
