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
21bool 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}
34EXPORT_SYMBOL_GPL(policy_has_boost_freq);
35
36int 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}
66EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
67
68
69int 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}
103EXPORT_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 */
109int 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}
118EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
119
120int 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}
210EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
211
212int 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}
229EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
230
231/**
232 * show_available_freqs - show available frequencies for the specified CPU
233 */
234static 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)	  \
267struct 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 */
274static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
275						  char *buf)
276{
277	return show_available_freqs(policy, buf, false);
278}
279cpufreq_attr_available_freq(scaling_available);
280EXPORT_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 */
286static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
287					      char *buf)
288{
289	return show_available_freqs(policy, buf, true);
290}
291cpufreq_attr_available_freq(scaling_boost);
292EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
293
294struct 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};
301EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
302
303int 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}
313EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
314
315MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
316MODULE_DESCRIPTION("CPUfreq frequency table helpers");
317MODULE_LICENSE("GPL");
318