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