/[pkg-src]/trunk/kernel26-magellan-server/patches-2.6.25-r5/0156-2.6.25-linux-phc-0.3.1-teknohog.patch |
Contents of /trunk/kernel26-magellan-server/patches-2.6.25-r5/0156-2.6.25-linux-phc-0.3.1-teknohog.patch
Parent Directory | Revision Log
Revision 677 -
(show annotations)
(download)
Wed Sep 10 21:27:27 2008 UTC (16 years ago) by niro
File size: 15454 byte(s)
Wed Sep 10 21:27:27 2008 UTC (16 years ago) by niro
File size: 15454 byte(s)
2.6.25-magellan-r5: - updated to linux-2.6.25.17
1 | patch comming from: |
2 | http://hoo.homeunix.net/~teknohog/hacks/linux-phc-kernel-vanilla-2.6.25-teknohog.patch |
3 | |
4 | --- linux-2.6.25/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2008-04-17 05:49:44.000000000 +0300 |
5 | +++ linux-2.6.25-teknohog/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2008-04-21 01:13:12.000000000 +0300 |
6 | @@ -23,10 +23,16 @@ |
7 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
8 | * |
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
10 | */ |
11 | |
12 | +/* This file has been patched with Linux PHC: https://www.dedigentoo.org/trac/linux-phc |
13 | + * Patch version: linux-phc-0.3.1-kernel-vanilla-2.6.23.patch |
14 | + * Updated for Linux 2.6.25 by Risto A. Paju, teknohog at iki.fi |
15 | + */ |
16 | + |
17 | + |
18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> |
20 | #include <linux/init.h> |
21 | #include <linux/smp.h> |
22 | #include <linux/sched.h> |
23 | @@ -57,16 +63,22 @@ |
24 | }; |
25 | |
26 | #define INTEL_MSR_RANGE (0xffff) |
27 | #define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1) |
28 | |
29 | +#define INTEL_MSR_VID_MASK (0x00ff) |
30 | +#define INTEL_MSR_FID_MASK (0xff00) |
31 | +#define INTEL_MSR_FID_SHIFT (0x8) |
32 | +#define PHC_VERSION_STRING "0.3.1:1" |
33 | + |
34 | struct acpi_cpufreq_data { |
35 | struct acpi_processor_performance *acpi_data; |
36 | struct cpufreq_frequency_table *freq_table; |
37 | unsigned int max_freq; |
38 | unsigned int resume; |
39 | unsigned int cpu_feature; |
40 | + acpi_integer *original_controls; |
41 | }; |
42 | |
43 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); |
44 | |
45 | /* acpi_perf_data is a pointer to percpu data. */ |
46 | @@ -102,17 +114,19 @@ |
47 | } |
48 | |
49 | static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) |
50 | { |
51 | int i; |
52 | + u32 fid; |
53 | struct acpi_processor_performance *perf; |
54 | |
55 | - msr &= INTEL_MSR_RANGE; |
56 | + fid = msr & INTEL_MSR_FID_MASK; |
57 | perf = data->acpi_data; |
58 | |
59 | for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
60 | - if (msr == perf->states[data->freq_table[i].index].status) |
61 | + if (fid == (perf->states[data->freq_table[i].index].status & |
62 | + INTEL_MSR_FID_MASK)) |
63 | return data->freq_table[i].frequency; |
64 | } |
65 | return data->freq_table[0].frequency; |
66 | } |
67 | |
68 | @@ -729,10 +743,12 @@ |
69 | if (data) { |
70 | cpufreq_frequency_table_put_attr(policy->cpu); |
71 | per_cpu(drv_data, policy->cpu) = NULL; |
72 | acpi_processor_unregister_performance(data->acpi_data, |
73 | policy->cpu); |
74 | + if (data->original_controls) |
75 | + kfree(data->original_controls); |
76 | kfree(data); |
77 | } |
78 | |
79 | return 0; |
80 | } |
81 | @@ -746,12 +762,452 @@ |
82 | data->resume = 1; |
83 | |
84 | return 0; |
85 | } |
86 | |
87 | + |
88 | + |
89 | + |
90 | +/* sysfs interface to change operating points voltages */ |
91 | + |
92 | +static unsigned int extract_fid_from_control(unsigned int control) |
93 | +{ |
94 | + return ((control & INTEL_MSR_FID_MASK) >> INTEL_MSR_FID_SHIFT); |
95 | +} |
96 | + |
97 | +static unsigned int extract_vid_from_control(unsigned int control) |
98 | +{ |
99 | + return (control & INTEL_MSR_VID_MASK); |
100 | +} |
101 | + |
102 | +static ssize_t check_origial_table (struct acpi_cpufreq_data *data) |
103 | +{ |
104 | + struct acpi_processor_performance *acpi_data; |
105 | + struct cpufreq_frequency_table *freq_table; |
106 | + unsigned int state_index; |
107 | + |
108 | + acpi_data = data->acpi_data; |
109 | + freq_table = data->freq_table; |
110 | + |
111 | + if (data->original_controls == NULL) { |
112 | + // Backup original control values |
113 | + data->original_controls = kcalloc(acpi_data->state_count, |
114 | + sizeof(acpi_integer), GFP_KERNEL); |
115 | + if (data->original_controls == NULL) { |
116 | + printk("failed to allocate memory for original control values\n"); |
117 | + return -ENOMEM; |
118 | + } |
119 | + for (state_index = 0; state_index < acpi_data->state_count; state_index++) { |
120 | + data->original_controls[state_index] = acpi_data->states[state_index].control; |
121 | + } |
122 | + } |
123 | + return 0; |
124 | +} |
125 | + |
126 | +static ssize_t show_freq_attr_vids(struct cpufreq_policy *policy, char *buf) |
127 | +{ |
128 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
129 | + struct acpi_processor_performance *acpi_data; |
130 | + struct cpufreq_frequency_table *freq_table; |
131 | + unsigned int i; |
132 | + unsigned int vid; |
133 | + ssize_t count = 0; |
134 | + |
135 | + if (unlikely(data == NULL || |
136 | + data->acpi_data == NULL || |
137 | + data->freq_table == NULL || |
138 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
139 | + return -ENODEV; |
140 | + } |
141 | + |
142 | + acpi_data = data->acpi_data; |
143 | + freq_table = data->freq_table; |
144 | + |
145 | + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
146 | + vid = extract_vid_from_control(acpi_data->states[freq_table[i].index].control); |
147 | + count += sprintf(&buf[count], "%u ", vid); |
148 | + } |
149 | + count += sprintf(&buf[count], "\n"); |
150 | + |
151 | + return count; |
152 | +} |
153 | + |
154 | +static ssize_t show_freq_attr_default_vids(struct cpufreq_policy *policy, char *buf) |
155 | +{ |
156 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
157 | + struct cpufreq_frequency_table *freq_table; |
158 | + unsigned int i; |
159 | + unsigned int vid; |
160 | + ssize_t count = 0; |
161 | + ssize_t retval; |
162 | + |
163 | + if (unlikely(data == NULL || |
164 | + data->acpi_data == NULL || |
165 | + data->freq_table == NULL || |
166 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
167 | + return -ENODEV; |
168 | + } |
169 | + |
170 | + retval = check_origial_table(data); |
171 | + if (0 != retval) |
172 | + return retval; |
173 | + |
174 | + freq_table = data->freq_table; |
175 | + |
176 | + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
177 | + vid = extract_vid_from_control(data->original_controls[freq_table[i].index]); |
178 | + count += sprintf(&buf[count], "%u ", vid); |
179 | + } |
180 | + count += sprintf(&buf[count], "\n"); |
181 | + |
182 | + return count; |
183 | +} |
184 | + |
185 | +static ssize_t show_freq_attr_fids(struct cpufreq_policy *policy, char *buf) |
186 | +{ |
187 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
188 | + struct acpi_processor_performance *acpi_data; |
189 | + struct cpufreq_frequency_table *freq_table; |
190 | + unsigned int i; |
191 | + unsigned int fid; |
192 | + ssize_t count = 0; |
193 | + |
194 | + if (unlikely(data == NULL || |
195 | + data->acpi_data == NULL || |
196 | + data->freq_table == NULL || |
197 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
198 | + return -ENODEV; |
199 | + } |
200 | + |
201 | + acpi_data = data->acpi_data; |
202 | + freq_table = data->freq_table; |
203 | + |
204 | + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
205 | + fid = extract_fid_from_control(acpi_data->states[freq_table[i].index].control); |
206 | + count += sprintf(&buf[count], "%u ", fid); |
207 | + } |
208 | + count += sprintf(&buf[count], "\n"); |
209 | + |
210 | + return count; |
211 | +} |
212 | + |
213 | +static ssize_t show_freq_attr_controls(struct cpufreq_policy *policy, char *buf) |
214 | +{ |
215 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
216 | + struct acpi_processor_performance *acpi_data; |
217 | + struct cpufreq_frequency_table *freq_table; |
218 | + unsigned int i; |
219 | + unsigned int fid; |
220 | + unsigned int vid; |
221 | + ssize_t count = 0; |
222 | + |
223 | + if (unlikely(data == NULL || |
224 | + data->acpi_data == NULL || |
225 | + data->freq_table == NULL || |
226 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
227 | + return -ENODEV; |
228 | + } |
229 | + |
230 | + acpi_data = data->acpi_data; |
231 | + freq_table = data->freq_table; |
232 | + |
233 | + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
234 | + fid = extract_fid_from_control(acpi_data->states[freq_table[i].index].control); |
235 | + vid = extract_vid_from_control(acpi_data->states[freq_table[i].index].control); |
236 | + count += sprintf(&buf[count], "%u:%u ", fid, vid); |
237 | + } |
238 | + count += sprintf(&buf[count], "\n"); |
239 | + |
240 | + return count; |
241 | +} |
242 | + |
243 | +static ssize_t show_freq_attr_default_controls(struct cpufreq_policy *policy, char *buf) |
244 | +{ |
245 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
246 | + struct cpufreq_frequency_table *freq_table; |
247 | + unsigned int i; |
248 | + unsigned int fid; |
249 | + unsigned int vid; |
250 | + ssize_t count = 0; |
251 | + ssize_t retval; |
252 | + |
253 | + if (unlikely(data == NULL || |
254 | + data->acpi_data == NULL || |
255 | + data->freq_table == NULL || |
256 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
257 | + return -ENODEV; |
258 | + } |
259 | + |
260 | + retval = check_origial_table(data); |
261 | + if (0 != retval) |
262 | + return retval; |
263 | + |
264 | + freq_table = data->freq_table; |
265 | + |
266 | + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { |
267 | + fid = extract_fid_from_control(data->original_controls[freq_table[i].index]); |
268 | + vid = extract_vid_from_control(data->original_controls[freq_table[i].index]); |
269 | + count += sprintf(&buf[count], "%u:%u ", fid, vid); |
270 | + } |
271 | + count += sprintf(&buf[count], "\n"); |
272 | + |
273 | + return count; |
274 | +} |
275 | + |
276 | + |
277 | +static ssize_t store_freq_attr_vids(struct cpufreq_policy *policy, const char *buf, size_t count) |
278 | +{ |
279 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
280 | + struct acpi_processor_performance *acpi_data; |
281 | + struct cpufreq_frequency_table *freq_table; |
282 | + unsigned int freq_index; |
283 | + unsigned int state_index; |
284 | + unsigned int new_vid; |
285 | + unsigned int original_vid; |
286 | + unsigned int new_control; |
287 | + unsigned int original_control; |
288 | + const char *curr_buf = buf; |
289 | + char *next_buf; |
290 | + ssize_t retval; |
291 | + |
292 | + if (unlikely(data == NULL || |
293 | + data->acpi_data == NULL || |
294 | + data->freq_table == NULL || |
295 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
296 | + return -ENODEV; |
297 | + } |
298 | + |
299 | + retval = check_origial_table(data); |
300 | + if (0 != retval) |
301 | + return retval; |
302 | + |
303 | + acpi_data = data->acpi_data; |
304 | + freq_table = data->freq_table; |
305 | + |
306 | + for (freq_index = 0; freq_table[freq_index].frequency != CPUFREQ_TABLE_END; freq_index++) { |
307 | + new_vid = simple_strtoul(curr_buf, &next_buf, 10); |
308 | + if (next_buf == curr_buf) { |
309 | + if ((curr_buf - buf == count - 1) && (*curr_buf == '\n')) { |
310 | + curr_buf++; |
311 | + break; |
312 | + } |
313 | + printk("failed to parse vid value at %i (%s)\n", freq_index, curr_buf); |
314 | + return -EINVAL; |
315 | + } |
316 | + |
317 | + state_index = freq_table[freq_index].index; |
318 | + original_control = data->original_controls[state_index]; |
319 | + original_vid = original_control & INTEL_MSR_VID_MASK; |
320 | + if (new_vid <= original_vid) { |
321 | + new_control = (original_control & ~INTEL_MSR_VID_MASK) | new_vid; |
322 | + dprintk("setting control at %i to %x (default is %x)\n", |
323 | + freq_index, new_control, original_control); |
324 | + acpi_data->states[state_index].control = new_control; |
325 | + |
326 | + } else { |
327 | + printk("skipping vid at %i, %u is greater than default %u\n", |
328 | + freq_index, new_vid, original_vid); |
329 | + } |
330 | + |
331 | + curr_buf = next_buf; |
332 | + while ((curr_buf - buf < count) && ((*curr_buf == ' ') || (*curr_buf == ','))) { |
333 | + curr_buf++; |
334 | + } |
335 | + } |
336 | + |
337 | + /* set new voltage at current frequency */ |
338 | + data->resume = 1; |
339 | + acpi_cpufreq_target(policy, get_cur_freq_on_cpu(policy->cpu), CPUFREQ_RELATION_L); |
340 | + |
341 | + return curr_buf - buf; |
342 | +} |
343 | + |
344 | +static ssize_t store_freq_attr_controls(struct cpufreq_policy *policy, const char *buf, size_t count) |
345 | +{ |
346 | + struct acpi_cpufreq_data *data = per_cpu(drv_data, policy->cpu); |
347 | + struct acpi_processor_performance *acpi_data; |
348 | + struct cpufreq_frequency_table *freq_table; |
349 | + const char *curr_buf; |
350 | + unsigned int op_count; |
351 | + unsigned int state_index; |
352 | + int isok; |
353 | + char *next_buf; |
354 | + ssize_t retval; |
355 | + unsigned int new_vid; |
356 | + unsigned int original_vid; |
357 | + unsigned int new_fid; |
358 | + unsigned int old_fid; |
359 | + unsigned int original_control; |
360 | + unsigned int old_control; |
361 | + unsigned int new_control; |
362 | + int found; |
363 | + |
364 | + if (unlikely(data == NULL || |
365 | + data->acpi_data == NULL || |
366 | + data->freq_table == NULL || |
367 | + data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) { |
368 | + return -ENODEV; |
369 | + } |
370 | + |
371 | + retval = check_origial_table(data); |
372 | + if (0 != retval) |
373 | + return retval; |
374 | + |
375 | + acpi_data = data->acpi_data; |
376 | + freq_table = data->freq_table; |
377 | + |
378 | + op_count = 0; |
379 | + curr_buf = buf; |
380 | + next_buf = NULL; |
381 | + isok = 1; |
382 | + |
383 | + while ( (isok) && (curr_buf != NULL) ) |
384 | + { |
385 | + op_count++; |
386 | + // Parse fid |
387 | + new_fid = simple_strtoul(curr_buf, &next_buf, 10); |
388 | + if ((next_buf != curr_buf) && (next_buf != NULL)) |
389 | + { |
390 | + // Parse separator between frequency and voltage |
391 | + curr_buf = next_buf; |
392 | + next_buf = NULL; |
393 | + if (*curr_buf==':') |
394 | + { |
395 | + curr_buf++; |
396 | + // Parse vid |
397 | + new_vid = simple_strtoul(curr_buf, &next_buf, 10); |
398 | + if ((next_buf != curr_buf) && (next_buf != NULL)) |
399 | + { |
400 | + found = 0; |
401 | + for (state_index = 0; state_index < acpi_data->state_count; state_index++) { |
402 | + old_control = acpi_data->states[state_index].control; |
403 | + old_fid = extract_fid_from_control(old_control); |
404 | + if (new_fid == old_fid) |
405 | + { |
406 | + found = 1; |
407 | + original_control = data->original_controls[state_index]; |
408 | + original_vid = extract_vid_from_control(original_control); |
409 | + if (new_vid <= original_vid) |
410 | + { |
411 | + new_control = (original_control & ~INTEL_MSR_VID_MASK) | new_vid; |
412 | + dprintk("setting control at %i to %x (default is %x)\n", |
413 | + state_index, new_control, original_control); |
414 | + acpi_data->states[state_index].control = new_control; |
415 | + |
416 | + } else { |
417 | + printk("skipping vid at %i, %u is greater than default %u\n", |
418 | + state_index, new_vid, original_vid); |
419 | + } |
420 | + } |
421 | + } |
422 | + |
423 | + if (found == 0) |
424 | + { |
425 | + printk("operating point # %u not found (FID = %u)\n", op_count, new_fid); |
426 | + isok = 0; |
427 | + } |
428 | + |
429 | + // Parse seprator before next operating point, if any |
430 | + curr_buf = next_buf; |
431 | + next_buf = NULL; |
432 | + if ((*curr_buf == ',') || (*curr_buf == ' ')) |
433 | + curr_buf++; |
434 | + else |
435 | + curr_buf = NULL; |
436 | + } |
437 | + else |
438 | + { |
439 | + printk("failed to parse VID of operating point # %u (%s)\n", op_count, curr_buf); |
440 | + isok = 0; |
441 | + } |
442 | + } |
443 | + else |
444 | + { |
445 | + printk("failed to parse operating point # %u (%s)\n", op_count, curr_buf); |
446 | + isok = 0; |
447 | + } |
448 | + } |
449 | + else |
450 | + { |
451 | + printk("failed to parse FID of operating point # %u (%s)\n", op_count, curr_buf); |
452 | + isok = 0; |
453 | + } |
454 | + } |
455 | + |
456 | + if (isok) |
457 | + { |
458 | + retval = count; |
459 | + /* set new voltage at current frequency */ |
460 | + data->resume = 1; |
461 | + acpi_cpufreq_target(policy, get_cur_freq_on_cpu(policy->cpu), CPUFREQ_RELATION_L); |
462 | + } |
463 | + else |
464 | + { |
465 | + retval = -EINVAL; |
466 | + } |
467 | + |
468 | + return retval; |
469 | +} |
470 | + |
471 | +static ssize_t show_freq_attr_phc_version(struct cpufreq_policy *policy, char *buf) |
472 | +{ |
473 | + ssize_t count = 0; |
474 | + count += sprintf(&buf[count], "%s\n", PHC_VERSION_STRING); |
475 | + return count; |
476 | +} |
477 | + |
478 | +static struct freq_attr cpufreq_freq_attr_phc_version = |
479 | +{ |
480 | + .attr = { .name = "phc_version", .mode = 0444, .owner = THIS_MODULE }, |
481 | + .show = show_freq_attr_phc_version, |
482 | + .store = NULL, |
483 | +}; |
484 | + |
485 | +static struct freq_attr cpufreq_freq_attr_vids = |
486 | +{ |
487 | + .attr = { .name = "phc_vids", .mode = 0644, .owner = THIS_MODULE }, |
488 | + .show = show_freq_attr_vids, |
489 | + .store = store_freq_attr_vids, |
490 | +}; |
491 | + |
492 | +static struct freq_attr cpufreq_freq_attr_default_vids = |
493 | +{ |
494 | + .attr = { .name = "phc_default_vids", .mode = 0444, .owner = THIS_MODULE }, |
495 | + .show = show_freq_attr_default_vids, |
496 | + .store = NULL, |
497 | +}; |
498 | + |
499 | +static struct freq_attr cpufreq_freq_attr_fids = |
500 | +{ |
501 | + .attr = { .name = "phc_fids", .mode = 0444, .owner = THIS_MODULE }, |
502 | + .show = show_freq_attr_fids, |
503 | + .store = NULL, |
504 | +}; |
505 | + |
506 | +static struct freq_attr cpufreq_freq_attr_controls = |
507 | +{ |
508 | + .attr = { .name = "phc_controls", .mode = 0644, .owner = THIS_MODULE }, |
509 | + .show = show_freq_attr_controls, |
510 | + .store = store_freq_attr_controls, |
511 | +}; |
512 | + |
513 | +static struct freq_attr cpufreq_freq_attr_default_controls = |
514 | +{ |
515 | + .attr = { .name = "phc_default_controls", .mode = 0444, .owner = THIS_MODULE }, |
516 | + .show = show_freq_attr_default_controls, |
517 | + .store = NULL, |
518 | +}; |
519 | + |
520 | + |
521 | static struct freq_attr *acpi_cpufreq_attr[] = { |
522 | + &cpufreq_freq_attr_phc_version, |
523 | &cpufreq_freq_attr_scaling_available_freqs, |
524 | + &cpufreq_freq_attr_vids, |
525 | + &cpufreq_freq_attr_default_vids, |
526 | + &cpufreq_freq_attr_fids, |
527 | + &cpufreq_freq_attr_controls, |
528 | + &cpufreq_freq_attr_default_controls, |
529 | NULL, |
530 | }; |
531 | |
532 | static struct cpufreq_driver acpi_cpufreq_driver = { |
533 | .verify = acpi_cpufreq_verify, |