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