• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux/drivers/cpufreq/freq_table.c
3  *
4  * Copyright (C) 2002 - 2003 Dominik Brodowski
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11 
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 
14 #include <linux/cpufreq.h>
15 #include <linux/module.h>
16 
17 /*********************************************************************
18  *                     FREQUENCY TABLE HELPERS                       *
19  *********************************************************************/
20 
cpufreq_frequency_table_cpuinfo(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table)21 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
22 				    struct cpufreq_frequency_table *table)
23 {
24 	struct cpufreq_frequency_table *pos;
25 	unsigned int min_freq = ~0;
26 	unsigned int max_freq = 0;
27 	unsigned int freq;
28 
29 	cpufreq_for_each_valid_entry(pos, table) {
30 		freq = pos->frequency;
31 
32 		if (!cpufreq_boost_enabled()
33 		    && (pos->flags & CPUFREQ_BOOST_FREQ))
34 			continue;
35 
36 		pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
37 		if (freq < min_freq)
38 			min_freq = freq;
39 		if (freq > max_freq)
40 			max_freq = freq;
41 	}
42 
43 	policy->min = policy->cpuinfo.min_freq = min_freq;
44 	policy->max = policy->cpuinfo.max_freq = max_freq;
45 
46 	if (policy->min == ~0)
47 		return -EINVAL;
48 	else
49 		return 0;
50 }
51 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
52 
53 
cpufreq_frequency_table_verify(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table)54 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
55 				   struct cpufreq_frequency_table *table)
56 {
57 	struct cpufreq_frequency_table *pos;
58 	unsigned int freq, next_larger = ~0;
59 	bool found = false;
60 
61 	pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
62 					policy->min, policy->max, policy->cpu);
63 
64 	cpufreq_verify_within_cpu_limits(policy);
65 
66 	cpufreq_for_each_valid_entry(pos, table) {
67 		freq = pos->frequency;
68 
69 		if ((freq >= policy->min) && (freq <= policy->max)) {
70 			found = true;
71 			break;
72 		}
73 
74 		if ((next_larger > freq) && (freq > policy->max))
75 			next_larger = freq;
76 	}
77 
78 	if (!found) {
79 		policy->max = next_larger;
80 		cpufreq_verify_within_cpu_limits(policy);
81 	}
82 
83 	pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
84 				policy->min, policy->max, policy->cpu);
85 
86 	return 0;
87 }
88 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
89 
90 /*
91  * Generic routine to verify policy & frequency table, requires driver to set
92  * policy->freq_table prior to it.
93  */
cpufreq_generic_frequency_table_verify(struct cpufreq_policy * policy)94 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
95 {
96 	struct cpufreq_frequency_table *table =
97 		cpufreq_frequency_get_table(policy->cpu);
98 	if (!table)
99 		return -ENODEV;
100 
101 	return cpufreq_frequency_table_verify(policy, table);
102 }
103 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
104 
cpufreq_frequency_table_target(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table,unsigned int target_freq,unsigned int relation,unsigned int * index)105 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
106 				   struct cpufreq_frequency_table *table,
107 				   unsigned int target_freq,
108 				   unsigned int relation,
109 				   unsigned int *index)
110 {
111 	struct cpufreq_frequency_table optimal = {
112 		.driver_data = ~0,
113 		.frequency = 0,
114 	};
115 	struct cpufreq_frequency_table suboptimal = {
116 		.driver_data = ~0,
117 		.frequency = 0,
118 	};
119 	struct cpufreq_frequency_table *pos;
120 	unsigned int freq, diff, i = 0;
121 
122 	pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
123 					target_freq, relation, policy->cpu);
124 
125 	switch (relation) {
126 	case CPUFREQ_RELATION_H:
127 		suboptimal.frequency = ~0;
128 		break;
129 	case CPUFREQ_RELATION_L:
130 	case CPUFREQ_RELATION_C:
131 		optimal.frequency = ~0;
132 		break;
133 	}
134 
135 	cpufreq_for_each_valid_entry(pos, table) {
136 		freq = pos->frequency;
137 
138 		i = pos - table;
139 		if ((freq < policy->min) || (freq > policy->max))
140 			continue;
141 		if (freq == target_freq) {
142 			optimal.driver_data = i;
143 			break;
144 		}
145 		switch (relation) {
146 		case CPUFREQ_RELATION_H:
147 			if (freq < target_freq) {
148 				if (freq >= optimal.frequency) {
149 					optimal.frequency = freq;
150 					optimal.driver_data = i;
151 				}
152 			} else {
153 				if (freq <= suboptimal.frequency) {
154 					suboptimal.frequency = freq;
155 					suboptimal.driver_data = i;
156 				}
157 			}
158 			break;
159 		case CPUFREQ_RELATION_L:
160 			if (freq > target_freq) {
161 				if (freq <= optimal.frequency) {
162 					optimal.frequency = freq;
163 					optimal.driver_data = i;
164 				}
165 			} else {
166 				if (freq >= suboptimal.frequency) {
167 					suboptimal.frequency = freq;
168 					suboptimal.driver_data = i;
169 				}
170 			}
171 			break;
172 		case CPUFREQ_RELATION_C:
173 			diff = abs(freq - target_freq);
174 			if (diff < optimal.frequency ||
175 			    (diff == optimal.frequency &&
176 			     freq > table[optimal.driver_data].frequency)) {
177 				optimal.frequency = diff;
178 				optimal.driver_data = i;
179 			}
180 			break;
181 		}
182 	}
183 	if (optimal.driver_data > i) {
184 		if (suboptimal.driver_data > i)
185 			return -EINVAL;
186 		*index = suboptimal.driver_data;
187 	} else
188 		*index = optimal.driver_data;
189 
190 	pr_debug("target index is %u, freq is:%u kHz\n", *index,
191 		 table[*index].frequency);
192 
193 	return 0;
194 }
195 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
196 
cpufreq_frequency_table_get_index(struct cpufreq_policy * policy,unsigned int freq)197 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
198 		unsigned int freq)
199 {
200 	struct cpufreq_frequency_table *pos, *table;
201 
202 	table = cpufreq_frequency_get_table(policy->cpu);
203 	if (unlikely(!table)) {
204 		pr_debug("%s: Unable to find frequency table\n", __func__);
205 		return -ENOENT;
206 	}
207 
208 	cpufreq_for_each_valid_entry(pos, table)
209 		if (pos->frequency == freq)
210 			return pos - table;
211 
212 	return -EINVAL;
213 }
214 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
215 
216 /**
217  * show_available_freqs - show available frequencies for the specified CPU
218  */
show_available_freqs(struct cpufreq_policy * policy,char * buf,bool show_boost)219 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
220 				    bool show_boost)
221 {
222 	ssize_t count = 0;
223 	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
224 
225 	if (!table)
226 		return -ENODEV;
227 
228 	cpufreq_for_each_valid_entry(pos, table) {
229 		/*
230 		 * show_boost = true and driver_data = BOOST freq
231 		 * display BOOST freqs
232 		 *
233 		 * show_boost = false and driver_data = BOOST freq
234 		 * show_boost = true and driver_data != BOOST freq
235 		 * continue - do not display anything
236 		 *
237 		 * show_boost = false and driver_data != BOOST freq
238 		 * display NON BOOST freqs
239 		 */
240 		if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
241 			continue;
242 
243 		count += sprintf(&buf[count], "%d ", pos->frequency);
244 	}
245 	count += sprintf(&buf[count], "\n");
246 
247 	return count;
248 
249 }
250 
251 #define cpufreq_attr_available_freq(_name)	  \
252 struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
253 __ATTR_RO(_name##_frequencies)
254 
255 /**
256  * show_scaling_available_frequencies - show available normal frequencies for
257  * the specified CPU
258  */
scaling_available_frequencies_show(struct cpufreq_policy * policy,char * buf)259 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
260 						  char *buf)
261 {
262 	return show_available_freqs(policy, buf, false);
263 }
264 cpufreq_attr_available_freq(scaling_available);
265 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
266 
267 /**
268  * show_available_boost_freqs - show available boost frequencies for
269  * the specified CPU
270  */
scaling_boost_frequencies_show(struct cpufreq_policy * policy,char * buf)271 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
272 					      char *buf)
273 {
274 	return show_available_freqs(policy, buf, true);
275 }
276 cpufreq_attr_available_freq(scaling_boost);
277 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
278 
279 struct freq_attr *cpufreq_generic_attr[] = {
280 	&cpufreq_freq_attr_scaling_available_freqs,
281 #ifdef CONFIG_CPU_FREQ_BOOST_SW
282 	&cpufreq_freq_attr_scaling_boost_freqs,
283 #endif
284 	NULL,
285 };
286 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
287 
cpufreq_table_validate_and_show(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table)288 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
289 				      struct cpufreq_frequency_table *table)
290 {
291 	int ret = cpufreq_frequency_table_cpuinfo(policy, table);
292 
293 	if (!ret)
294 		policy->freq_table = table;
295 
296 	return ret;
297 }
298 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
299 
300 struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
301 
cpufreq_frequency_get_table(unsigned int cpu)302 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
303 {
304 	struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
305 	return policy ? policy->freq_table : NULL;
306 }
307 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
308 
309 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
310 MODULE_DESCRIPTION("CPUfreq frequency table helpers");
311 MODULE_LICENSE("GPL");
312