xref: /openbmc/linux/drivers/cpufreq/freq_table.c (revision 8a26af30)
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 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 
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  */
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 
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, 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 		optimal.frequency = ~0;
131 		break;
132 	}
133 
134 	cpufreq_for_each_valid_entry(pos, table) {
135 		freq = pos->frequency;
136 
137 		i = pos - table;
138 		if ((freq < policy->min) || (freq > policy->max))
139 			continue;
140 		if (freq == target_freq) {
141 			optimal.driver_data = i;
142 			break;
143 		}
144 		switch (relation) {
145 		case CPUFREQ_RELATION_H:
146 			if (freq < target_freq) {
147 				if (freq >= optimal.frequency) {
148 					optimal.frequency = freq;
149 					optimal.driver_data = i;
150 				}
151 			} else {
152 				if (freq <= suboptimal.frequency) {
153 					suboptimal.frequency = freq;
154 					suboptimal.driver_data = i;
155 				}
156 			}
157 			break;
158 		case CPUFREQ_RELATION_L:
159 			if (freq > target_freq) {
160 				if (freq <= optimal.frequency) {
161 					optimal.frequency = freq;
162 					optimal.driver_data = i;
163 				}
164 			} else {
165 				if (freq >= suboptimal.frequency) {
166 					suboptimal.frequency = freq;
167 					suboptimal.driver_data = i;
168 				}
169 			}
170 			break;
171 		}
172 	}
173 	if (optimal.driver_data > i) {
174 		if (suboptimal.driver_data > i)
175 			return -EINVAL;
176 		*index = suboptimal.driver_data;
177 	} else
178 		*index = optimal.driver_data;
179 
180 	pr_debug("target index is %u, freq is:%u kHz\n", *index,
181 		 table[*index].frequency);
182 
183 	return 0;
184 }
185 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
186 
187 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
188 		unsigned int freq)
189 {
190 	struct cpufreq_frequency_table *pos, *table;
191 
192 	table = cpufreq_frequency_get_table(policy->cpu);
193 	if (unlikely(!table)) {
194 		pr_debug("%s: Unable to find frequency table\n", __func__);
195 		return -ENOENT;
196 	}
197 
198 	cpufreq_for_each_valid_entry(pos, table)
199 		if (pos->frequency == freq)
200 			return pos - table;
201 
202 	return -EINVAL;
203 }
204 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
205 
206 /**
207  * show_available_freqs - show available frequencies for the specified CPU
208  */
209 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
210 				    bool show_boost)
211 {
212 	ssize_t count = 0;
213 	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
214 
215 	if (!table)
216 		return -ENODEV;
217 
218 	cpufreq_for_each_valid_entry(pos, table) {
219 		/*
220 		 * show_boost = true and driver_data = BOOST freq
221 		 * display BOOST freqs
222 		 *
223 		 * show_boost = false and driver_data = BOOST freq
224 		 * show_boost = true and driver_data != BOOST freq
225 		 * continue - do not display anything
226 		 *
227 		 * show_boost = false and driver_data != BOOST freq
228 		 * display NON BOOST freqs
229 		 */
230 		if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
231 			continue;
232 
233 		count += sprintf(&buf[count], "%d ", pos->frequency);
234 	}
235 	count += sprintf(&buf[count], "\n");
236 
237 	return count;
238 
239 }
240 
241 #define cpufreq_attr_available_freq(_name)	  \
242 struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
243 __ATTR_RO(_name##_frequencies)
244 
245 /**
246  * show_scaling_available_frequencies - show available normal frequencies for
247  * the specified CPU
248  */
249 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
250 						  char *buf)
251 {
252 	return show_available_freqs(policy, buf, false);
253 }
254 cpufreq_attr_available_freq(scaling_available);
255 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
256 
257 /**
258  * show_available_boost_freqs - show available boost frequencies for
259  * the specified CPU
260  */
261 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
262 					      char *buf)
263 {
264 	return show_available_freqs(policy, buf, true);
265 }
266 cpufreq_attr_available_freq(scaling_boost);
267 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
268 
269 struct freq_attr *cpufreq_generic_attr[] = {
270 	&cpufreq_freq_attr_scaling_available_freqs,
271 #ifdef CONFIG_CPU_FREQ_BOOST_SW
272 	&cpufreq_freq_attr_scaling_boost_freqs,
273 #endif
274 	NULL,
275 };
276 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
277 
278 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
279 				      struct cpufreq_frequency_table *table)
280 {
281 	int ret = cpufreq_frequency_table_cpuinfo(policy, table);
282 
283 	if (!ret)
284 		policy->freq_table = table;
285 
286 	return ret;
287 }
288 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
289 
290 struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
291 
292 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
293 {
294 	struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
295 	return policy ? policy->freq_table : NULL;
296 }
297 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
298 
299 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
300 MODULE_DESCRIPTION("CPUfreq frequency table helpers");
301 MODULE_LICENSE("GPL");
302