Blame view

drivers/cpufreq/freq_table.c 7.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   * linux/drivers/cpufreq/freq_table.c
   *
   * Copyright (C) 2002 - 2003 Dominik Brodowski
4f7436942   Dominik Brodowski   [CPUFREQ] clarify...
5
6
7
8
9
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
db7011516   Viresh Kumar   cpufreq: Improve ...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/cpufreq.h>
5ff0a2680   Viresh Kumar   cpufreq: Clean up...
13
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
  /*********************************************************************
   *                     FREQUENCY TABLE HELPERS                       *
   *********************************************************************/
  
  int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
  				    struct cpufreq_frequency_table *table)
  {
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
22
  	struct cpufreq_frequency_table *pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  	unsigned int min_freq = ~0;
  	unsigned int max_freq = 0;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
25
  	unsigned int freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

041526f91   Stratos Karafotis   cpufreq: Use cpuf...
27
28
  	cpufreq_for_each_valid_entry(pos, table) {
  		freq = pos->frequency;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
30
  		if (!cpufreq_boost_enabled()
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
31
  		    && (pos->flags & CPUFREQ_BOOST_FREQ))
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
32
  			continue;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
33
34
  		pr_debug("table entry %u: %u kHz
  ", (int)(pos - table), freq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  		if (freq < min_freq)
  			min_freq = freq;
  		if (freq > max_freq)
  			max_freq = freq;
  	}
  
  	policy->min = policy->cpuinfo.min_freq = min_freq;
  	policy->max = policy->cpuinfo.max_freq = max_freq;
  
  	if (policy->min == ~0)
  		return -EINVAL;
  	else
  		return 0;
  }
  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
  
  
  int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
  				   struct cpufreq_frequency_table *table)
  {
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
55
56
  	struct cpufreq_frequency_table *pos;
  	unsigned int freq, next_larger = ~0;
77db50c4e   Viresh Kumar   cpufreq: Optimize...
57
  	bool found = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
59
60
  	pr_debug("request for verification of policy (%u - %u kHz) for cpu %u
  ",
e08f5f5bb   Gautham R Shenoy   [CPUFREQ] Fix cod...
61
  					policy->min, policy->max, policy->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

be49e3465   Viresh Kumar   cpufreq: add new ...
63
  	cpufreq_verify_within_cpu_limits(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

041526f91   Stratos Karafotis   cpufreq: Use cpuf...
65
66
  	cpufreq_for_each_valid_entry(pos, table) {
  		freq = pos->frequency;
77db50c4e   Viresh Kumar   cpufreq: Optimize...
67
68
69
70
71
72
  		if ((freq >= policy->min) && (freq <= policy->max)) {
  			found = true;
  			break;
  		}
  
  		if ((next_larger > freq) && (freq > policy->max))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  			next_larger = freq;
  	}
77db50c4e   Viresh Kumar   cpufreq: Optimize...
75
  	if (!found) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  		policy->max = next_larger;
be49e3465   Viresh Kumar   cpufreq: add new ...
77
  		cpufreq_verify_within_cpu_limits(policy);
77db50c4e   Viresh Kumar   cpufreq: Optimize...
78
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
80
81
  	pr_debug("verification lead to (%u - %u kHz) for cpu %u
  ",
e08f5f5bb   Gautham R Shenoy   [CPUFREQ] Fix cod...
82
  				policy->min, policy->max, policy->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
184345129   Viresh Kumar   cpufreq: define g...
87
  /*
e0b3165ba   Viresh Kumar   cpufreq: add 'fre...
88
89
   * Generic routine to verify policy & frequency table, requires driver to set
   * policy->freq_table prior to it.
184345129   Viresh Kumar   cpufreq: define g...
90
91
92
93
94
95
96
97
98
99
100
   */
  int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
  {
  	struct cpufreq_frequency_table *table =
  		cpufreq_frequency_get_table(policy->cpu);
  	if (!table)
  		return -ENODEV;
  
  	return cpufreq_frequency_table_verify(policy, table);
  }
  EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
  
  int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
  				   struct cpufreq_frequency_table *table,
  				   unsigned int target_freq,
  				   unsigned int relation,
  				   unsigned int *index)
  {
484944a5b   Dave Jones   [CPUFREQ] Remove ...
108
  	struct cpufreq_frequency_table optimal = {
507015880   Viresh Kumar   cpufreq: rename i...
109
  		.driver_data = ~0,
484944a5b   Dave Jones   [CPUFREQ] Remove ...
110
111
112
  		.frequency = 0,
  	};
  	struct cpufreq_frequency_table suboptimal = {
507015880   Viresh Kumar   cpufreq: rename i...
113
  		.driver_data = ~0,
484944a5b   Dave Jones   [CPUFREQ] Remove ...
114
115
  		.frequency = 0,
  	};
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
116
  	struct cpufreq_frequency_table *pos;
5b0c0b16d   Stratos Karafotis   cpufreq: Introduc...
117
  	unsigned int freq, diff, i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
119
120
  	pr_debug("request for target %u kHz (relation: %u) for cpu %u
  ",
e08f5f5bb   Gautham R Shenoy   [CPUFREQ] Fix cod...
121
  					target_freq, relation, policy->cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
  
  	switch (relation) {
  	case CPUFREQ_RELATION_H:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
  		suboptimal.frequency = ~0;
  		break;
  	case CPUFREQ_RELATION_L:
5b0c0b16d   Stratos Karafotis   cpufreq: Introduc...
128
  	case CPUFREQ_RELATION_C:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  		optimal.frequency = ~0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
  		break;
  	}
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
132
133
134
135
  	cpufreq_for_each_valid_entry(pos, table) {
  		freq = pos->frequency;
  
  		i = pos - table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  		if ((freq < policy->min) || (freq > policy->max))
  			continue;
1e4988563   Stratos Karafotis   cpufreq: Break ou...
138
139
140
141
  		if (freq == target_freq) {
  			optimal.driver_data = i;
  			break;
  		}
97acec55d   Dave Jones   [CPUFREQ] checkpa...
142
  		switch (relation) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  		case CPUFREQ_RELATION_H:
1e4988563   Stratos Karafotis   cpufreq: Break ou...
144
  			if (freq < target_freq) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
  				if (freq >= optimal.frequency) {
  					optimal.frequency = freq;
507015880   Viresh Kumar   cpufreq: rename i...
147
  					optimal.driver_data = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  				}
  			} else {
  				if (freq <= suboptimal.frequency) {
  					suboptimal.frequency = freq;
507015880   Viresh Kumar   cpufreq: rename i...
152
  					suboptimal.driver_data = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  				}
  			}
  			break;
  		case CPUFREQ_RELATION_L:
1e4988563   Stratos Karafotis   cpufreq: Break ou...
157
  			if (freq > target_freq) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  				if (freq <= optimal.frequency) {
  					optimal.frequency = freq;
507015880   Viresh Kumar   cpufreq: rename i...
160
  					optimal.driver_data = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
  				}
  			} else {
  				if (freq >= suboptimal.frequency) {
  					suboptimal.frequency = freq;
507015880   Viresh Kumar   cpufreq: rename i...
165
  					suboptimal.driver_data = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
  				}
  			}
  			break;
5b0c0b16d   Stratos Karafotis   cpufreq: Introduc...
169
170
171
172
173
174
175
176
177
  		case CPUFREQ_RELATION_C:
  			diff = abs(freq - target_freq);
  			if (diff < optimal.frequency ||
  			    (diff == optimal.frequency &&
  			     freq > table[optimal.driver_data].frequency)) {
  				optimal.frequency = diff;
  				optimal.driver_data = i;
  			}
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  		}
  	}
507015880   Viresh Kumar   cpufreq: rename i...
180
181
  	if (optimal.driver_data > i) {
  		if (suboptimal.driver_data > i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  			return -EINVAL;
507015880   Viresh Kumar   cpufreq: rename i...
183
  		*index = suboptimal.driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  	} else
507015880   Viresh Kumar   cpufreq: rename i...
185
  		*index = optimal.driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186

ae87f10f3   Viresh Kumar   cpufreq: don't pr...
187
188
189
  	pr_debug("target index is %u, freq is:%u kHz
  ", *index,
  		 table[*index].frequency);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
d3916691c   Viresh Kumar   cpufreq: Make sur...
194
195
196
  int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
  		unsigned int freq)
  {
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
197
  	struct cpufreq_frequency_table *pos, *table;
d3916691c   Viresh Kumar   cpufreq: Make sur...
198
199
200
201
202
203
204
  
  	table = cpufreq_frequency_get_table(policy->cpu);
  	if (unlikely(!table)) {
  		pr_debug("%s: Unable to find frequency table
  ", __func__);
  		return -ENOENT;
  	}
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
205
206
207
  	cpufreq_for_each_valid_entry(pos, table)
  		if (pos->frequency == freq)
  			return pos - table;
d3916691c   Viresh Kumar   cpufreq: Make sur...
208
209
210
211
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  /**
e32d22f77   Fenghua Yu   [CPUFREQ] fix inc...
213
   * show_available_freqs - show available frequencies for the specified CPU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
   */
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
215
216
  static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
  				    bool show_boost)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	ssize_t count = 0;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
219
  	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

e0b3165ba   Viresh Kumar   cpufreq: add 'fre...
221
  	if (!table)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  		return -ENODEV;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
223
  	cpufreq_for_each_valid_entry(pos, table) {
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
224
225
226
227
228
229
230
231
232
233
234
  		/*
  		 * show_boost = true and driver_data = BOOST freq
  		 * display BOOST freqs
  		 *
  		 * show_boost = false and driver_data = BOOST freq
  		 * show_boost = true and driver_data != BOOST freq
  		 * continue - do not display anything
  		 *
  		 * show_boost = false and driver_data != BOOST freq
  		 * display NON BOOST freqs
  		 */
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
235
  		if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
236
  			continue;
041526f91   Stratos Karafotis   cpufreq: Use cpuf...
237
  		count += sprintf(&buf[count], "%d ", pos->frequency);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
  	}
  	count += sprintf(&buf[count], "
  ");
  
  	return count;
  
  }
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  #define cpufreq_attr_available_freq(_name)	  \
  struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
  __ATTR_RO(_name##_frequencies)
  
  /**
   * show_scaling_available_frequencies - show available normal frequencies for
   * the specified CPU
   */
  static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
  						  char *buf)
  {
  	return show_available_freqs(policy, buf, false);
  }
  cpufreq_attr_available_freq(scaling_available);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
260
261
262
263
264
265
266
267
268
269
270
  /**
   * show_available_boost_freqs - show available boost frequencies for
   * the specified CPU
   */
  static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
  					      char *buf)
  {
  	return show_available_freqs(policy, buf, true);
  }
  cpufreq_attr_available_freq(scaling_boost);
  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
184345129   Viresh Kumar   cpufreq: define g...
271
272
  struct freq_attr *cpufreq_generic_attr[] = {
  	&cpufreq_freq_attr_scaling_available_freqs,
6f19efc0a   Lukasz Majewski   cpufreq: Add boos...
273
274
275
  #ifdef CONFIG_CPU_FREQ_BOOST_SW
  	&cpufreq_freq_attr_scaling_boost_freqs,
  #endif
184345129   Viresh Kumar   cpufreq: define g...
276
277
278
  	NULL,
  };
  EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
27047a603   Viresh Kumar   cpufreq: Add new ...
279
280
281
282
283
284
  int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
  				      struct cpufreq_frequency_table *table)
  {
  	int ret = cpufreq_frequency_table_cpuinfo(policy, table);
  
  	if (!ret)
e0b3165ba   Viresh Kumar   cpufreq: add 'fre...
285
  		policy->freq_table = table;
27047a603   Viresh Kumar   cpufreq: Add new ...
286
287
288
289
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
e0b3165ba   Viresh Kumar   cpufreq: add 'fre...
290
  struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
b8eed8af9   Viresh Kumar   cpufreq: Simplify...
291

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
  {
e0b3165ba   Viresh Kumar   cpufreq: add 'fre...
294
295
  	struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
  	return policy ? policy->freq_table : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
  }
  EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
97acec55d   Dave Jones   [CPUFREQ] checkpa...
298
299
300
  MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
  MODULE_DESCRIPTION("CPUfreq frequency table helpers");
  MODULE_LICENSE("GPL");