xref: /openbmc/linux/drivers/cpufreq/freq_table.c (revision 9ac8d3fb)
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 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/cpufreq.h>
16 
17 #define dprintk(msg...) \
18 	cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
19 
20 /*********************************************************************
21  *                     FREQUENCY TABLE HELPERS                       *
22  *********************************************************************/
23 
24 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
25 				    struct cpufreq_frequency_table *table)
26 {
27 	unsigned int min_freq = ~0;
28 	unsigned int max_freq = 0;
29 	unsigned int i;
30 
31 	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
32 		unsigned int freq = table[i].frequency;
33 		if (freq == CPUFREQ_ENTRY_INVALID) {
34 			dprintk("table entry %u is invalid, skipping\n", i);
35 
36 			continue;
37 		}
38 		dprintk("table entry %u: %u kHz, %u index\n",
39 					i, freq, table[i].index);
40 		if (freq < min_freq)
41 			min_freq = freq;
42 		if (freq > max_freq)
43 			max_freq = freq;
44 	}
45 
46 	policy->min = policy->cpuinfo.min_freq = min_freq;
47 	policy->max = policy->cpuinfo.max_freq = max_freq;
48 
49 	if (policy->min == ~0)
50 		return -EINVAL;
51 	else
52 		return 0;
53 }
54 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
55 
56 
57 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
58 				   struct cpufreq_frequency_table *table)
59 {
60 	unsigned int next_larger = ~0;
61 	unsigned int i;
62 	unsigned int count = 0;
63 
64 	dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n",
65 					policy->min, policy->max, policy->cpu);
66 
67 	if (!cpu_online(policy->cpu))
68 		return -EINVAL;
69 
70 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
71 				     policy->cpuinfo.max_freq);
72 
73 	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
74 		unsigned int freq = table[i].frequency;
75 		if (freq == CPUFREQ_ENTRY_INVALID)
76 			continue;
77 		if ((freq >= policy->min) && (freq <= policy->max))
78 			count++;
79 		else if ((next_larger > freq) && (freq > policy->max))
80 			next_larger = freq;
81 	}
82 
83 	if (!count)
84 		policy->max = next_larger;
85 
86 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
87 				     policy->cpuinfo.max_freq);
88 
89 	dprintk("verification lead to (%u - %u kHz) for cpu %u\n",
90 				policy->min, policy->max, policy->cpu);
91 
92 	return 0;
93 }
94 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
95 
96 
97 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
98 				   struct cpufreq_frequency_table *table,
99 				   unsigned int target_freq,
100 				   unsigned int relation,
101 				   unsigned int *index)
102 {
103 	struct cpufreq_frequency_table optimal = {
104 		.index = ~0,
105 		.frequency = 0,
106 	};
107 	struct cpufreq_frequency_table suboptimal = {
108 		.index = ~0,
109 		.frequency = 0,
110 	};
111 	unsigned int i;
112 
113 	dprintk("request for target %u kHz (relation: %u) for cpu %u\n",
114 					target_freq, relation, policy->cpu);
115 
116 	switch (relation) {
117 	case CPUFREQ_RELATION_H:
118 		suboptimal.frequency = ~0;
119 		break;
120 	case CPUFREQ_RELATION_L:
121 		optimal.frequency = ~0;
122 		break;
123 	}
124 
125 	if (!cpu_online(policy->cpu))
126 		return -EINVAL;
127 
128 	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
129 		unsigned int freq = table[i].frequency;
130 		if (freq == CPUFREQ_ENTRY_INVALID)
131 			continue;
132 		if ((freq < policy->min) || (freq > policy->max))
133 			continue;
134 		switch(relation) {
135 		case CPUFREQ_RELATION_H:
136 			if (freq <= target_freq) {
137 				if (freq >= optimal.frequency) {
138 					optimal.frequency = freq;
139 					optimal.index = i;
140 				}
141 			} else {
142 				if (freq <= suboptimal.frequency) {
143 					suboptimal.frequency = freq;
144 					suboptimal.index = i;
145 				}
146 			}
147 			break;
148 		case CPUFREQ_RELATION_L:
149 			if (freq >= target_freq) {
150 				if (freq <= optimal.frequency) {
151 					optimal.frequency = freq;
152 					optimal.index = i;
153 				}
154 			} else {
155 				if (freq >= suboptimal.frequency) {
156 					suboptimal.frequency = freq;
157 					suboptimal.index = i;
158 				}
159 			}
160 			break;
161 		}
162 	}
163 	if (optimal.index > i) {
164 		if (suboptimal.index > i)
165 			return -EINVAL;
166 		*index = suboptimal.index;
167 	} else
168 		*index = optimal.index;
169 
170 	dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
171 		table[*index].index);
172 
173 	return 0;
174 }
175 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
176 
177 static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table);
178 /**
179  * show_available_freqs - show available frequencies for the specified CPU
180  */
181 static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
182 {
183 	unsigned int i = 0;
184 	unsigned int cpu = policy->cpu;
185 	ssize_t count = 0;
186 	struct cpufreq_frequency_table *table;
187 
188 	if (!per_cpu(show_table, cpu))
189 		return -ENODEV;
190 
191 	table = per_cpu(show_table, cpu);
192 
193 	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
194 		if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
195 			continue;
196 		count += sprintf(&buf[count], "%d ", table[i].frequency);
197 	}
198 	count += sprintf(&buf[count], "\n");
199 
200 	return count;
201 
202 }
203 
204 struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
205 	.attr = { .name = "scaling_available_frequencies",
206 		  .mode = 0444,
207 		},
208 	.show = show_available_freqs,
209 };
210 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
211 
212 /*
213  * if you use these, you must assure that the frequency table is valid
214  * all the time between get_attr and put_attr!
215  */
216 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
217 				      unsigned int cpu)
218 {
219 	dprintk("setting show_table for cpu %u to %p\n", cpu, table);
220 	per_cpu(show_table, cpu) = table;
221 }
222 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
223 
224 void cpufreq_frequency_table_put_attr(unsigned int cpu)
225 {
226 	dprintk("clearing show_table for cpu %u\n", cpu);
227 	per_cpu(show_table, cpu) = NULL;
228 }
229 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
230 
231 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
232 {
233 	return per_cpu(show_table, cpu);
234 }
235 EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
236 
237 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
238 MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
239 MODULE_LICENSE ("GPL");
240