diff options
Diffstat (limited to 'arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c')
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c deleted file mode 100644 index 9b1ff37de46a..000000000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ /dev/null | |||
@@ -1,636 +0,0 @@ | |||
1 | /* | ||
2 | * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium | ||
3 | * M (part of the Centrino chipset). | ||
4 | * | ||
5 | * Since the original Pentium M, most new Intel CPUs support Enhanced | ||
6 | * SpeedStep. | ||
7 | * | ||
8 | * Despite the "SpeedStep" in the name, this is almost entirely unlike | ||
9 | * traditional SpeedStep. | ||
10 | * | ||
11 | * Modelled on speedstep.c | ||
12 | * | ||
13 | * Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org> | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/cpufreq.h> | ||
20 | #include <linux/sched.h> /* current */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/compiler.h> | ||
23 | #include <linux/gfp.h> | ||
24 | |||
25 | #include <asm/msr.h> | ||
26 | #include <asm/processor.h> | ||
27 | #include <asm/cpufeature.h> | ||
28 | |||
29 | #define PFX "speedstep-centrino: " | ||
30 | #define MAINTAINER "cpufreq@vger.kernel.org" | ||
31 | |||
32 | #define dprintk(msg...) \ | ||
33 | cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg) | ||
34 | |||
35 | #define INTEL_MSR_RANGE (0xffff) | ||
36 | |||
37 | struct cpu_id | ||
38 | { | ||
39 | __u8 x86; /* CPU family */ | ||
40 | __u8 x86_model; /* model */ | ||
41 | __u8 x86_mask; /* stepping */ | ||
42 | }; | ||
43 | |||
44 | enum { | ||
45 | CPU_BANIAS, | ||
46 | CPU_DOTHAN_A1, | ||
47 | CPU_DOTHAN_A2, | ||
48 | CPU_DOTHAN_B0, | ||
49 | CPU_MP4HT_D0, | ||
50 | CPU_MP4HT_E0, | ||
51 | }; | ||
52 | |||
53 | static const struct cpu_id cpu_ids[] = { | ||
54 | [CPU_BANIAS] = { 6, 9, 5 }, | ||
55 | [CPU_DOTHAN_A1] = { 6, 13, 1 }, | ||
56 | [CPU_DOTHAN_A2] = { 6, 13, 2 }, | ||
57 | [CPU_DOTHAN_B0] = { 6, 13, 6 }, | ||
58 | [CPU_MP4HT_D0] = {15, 3, 4 }, | ||
59 | [CPU_MP4HT_E0] = {15, 4, 1 }, | ||
60 | }; | ||
61 | #define N_IDS ARRAY_SIZE(cpu_ids) | ||
62 | |||
63 | struct cpu_model | ||
64 | { | ||
65 | const struct cpu_id *cpu_id; | ||
66 | const char *model_name; | ||
67 | unsigned max_freq; /* max clock in kHz */ | ||
68 | |||
69 | struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ | ||
70 | }; | ||
71 | static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, | ||
72 | const struct cpu_id *x); | ||
73 | |||
74 | /* Operating points for current CPU */ | ||
75 | static DEFINE_PER_CPU(struct cpu_model *, centrino_model); | ||
76 | static DEFINE_PER_CPU(const struct cpu_id *, centrino_cpu); | ||
77 | |||
78 | static struct cpufreq_driver centrino_driver; | ||
79 | |||
80 | #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE | ||
81 | |||
82 | /* Computes the correct form for IA32_PERF_CTL MSR for a particular | ||
83 | frequency/voltage operating point; frequency in MHz, volts in mV. | ||
84 | This is stored as "index" in the structure. */ | ||
85 | #define OP(mhz, mv) \ | ||
86 | { \ | ||
87 | .frequency = (mhz) * 1000, \ | ||
88 | .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * These voltage tables were derived from the Intel Pentium M | ||
93 | * datasheet, document 25261202.pdf, Table 5. I have verified they | ||
94 | * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium | ||
95 | * M. | ||
96 | */ | ||
97 | |||
98 | /* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ | ||
99 | static struct cpufreq_frequency_table banias_900[] = | ||
100 | { | ||
101 | OP(600, 844), | ||
102 | OP(800, 988), | ||
103 | OP(900, 1004), | ||
104 | { .frequency = CPUFREQ_TABLE_END } | ||
105 | }; | ||
106 | |||
107 | /* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ | ||
108 | static struct cpufreq_frequency_table banias_1000[] = | ||
109 | { | ||
110 | OP(600, 844), | ||
111 | OP(800, 972), | ||
112 | OP(900, 988), | ||
113 | OP(1000, 1004), | ||
114 | { .frequency = CPUFREQ_TABLE_END } | ||
115 | }; | ||
116 | |||
117 | /* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ | ||
118 | static struct cpufreq_frequency_table banias_1100[] = | ||
119 | { | ||
120 | OP( 600, 956), | ||
121 | OP( 800, 1020), | ||
122 | OP( 900, 1100), | ||
123 | OP(1000, 1164), | ||
124 | OP(1100, 1180), | ||
125 | { .frequency = CPUFREQ_TABLE_END } | ||
126 | }; | ||
127 | |||
128 | |||
129 | /* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ | ||
130 | static struct cpufreq_frequency_table banias_1200[] = | ||
131 | { | ||
132 | OP( 600, 956), | ||
133 | OP( 800, 1004), | ||
134 | OP( 900, 1020), | ||
135 | OP(1000, 1100), | ||
136 | OP(1100, 1164), | ||
137 | OP(1200, 1180), | ||
138 | { .frequency = CPUFREQ_TABLE_END } | ||
139 | }; | ||
140 | |||
141 | /* Intel Pentium M processor 1.30GHz (Banias) */ | ||
142 | static struct cpufreq_frequency_table banias_1300[] = | ||
143 | { | ||
144 | OP( 600, 956), | ||
145 | OP( 800, 1260), | ||
146 | OP(1000, 1292), | ||
147 | OP(1200, 1356), | ||
148 | OP(1300, 1388), | ||
149 | { .frequency = CPUFREQ_TABLE_END } | ||
150 | }; | ||
151 | |||
152 | /* Intel Pentium M processor 1.40GHz (Banias) */ | ||
153 | static struct cpufreq_frequency_table banias_1400[] = | ||
154 | { | ||
155 | OP( 600, 956), | ||
156 | OP( 800, 1180), | ||
157 | OP(1000, 1308), | ||
158 | OP(1200, 1436), | ||
159 | OP(1400, 1484), | ||
160 | { .frequency = CPUFREQ_TABLE_END } | ||
161 | }; | ||
162 | |||
163 | /* Intel Pentium M processor 1.50GHz (Banias) */ | ||
164 | static struct cpufreq_frequency_table banias_1500[] = | ||
165 | { | ||
166 | OP( 600, 956), | ||
167 | OP( 800, 1116), | ||
168 | OP(1000, 1228), | ||
169 | OP(1200, 1356), | ||
170 | OP(1400, 1452), | ||
171 | OP(1500, 1484), | ||
172 | { .frequency = CPUFREQ_TABLE_END } | ||
173 | }; | ||
174 | |||
175 | /* Intel Pentium M processor 1.60GHz (Banias) */ | ||
176 | static struct cpufreq_frequency_table banias_1600[] = | ||
177 | { | ||
178 | OP( 600, 956), | ||
179 | OP( 800, 1036), | ||
180 | OP(1000, 1164), | ||
181 | OP(1200, 1276), | ||
182 | OP(1400, 1420), | ||
183 | OP(1600, 1484), | ||
184 | { .frequency = CPUFREQ_TABLE_END } | ||
185 | }; | ||
186 | |||
187 | /* Intel Pentium M processor 1.70GHz (Banias) */ | ||
188 | static struct cpufreq_frequency_table banias_1700[] = | ||
189 | { | ||
190 | OP( 600, 956), | ||
191 | OP( 800, 1004), | ||
192 | OP(1000, 1116), | ||
193 | OP(1200, 1228), | ||
194 | OP(1400, 1308), | ||
195 | OP(1700, 1484), | ||
196 | { .frequency = CPUFREQ_TABLE_END } | ||
197 | }; | ||
198 | #undef OP | ||
199 | |||
200 | #define _BANIAS(cpuid, max, name) \ | ||
201 | { .cpu_id = cpuid, \ | ||
202 | .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ | ||
203 | .max_freq = (max)*1000, \ | ||
204 | .op_points = banias_##max, \ | ||
205 | } | ||
206 | #define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) | ||
207 | |||
208 | /* CPU models, their operating frequency range, and freq/voltage | ||
209 | operating points */ | ||
210 | static struct cpu_model models[] = | ||
211 | { | ||
212 | _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), | ||
213 | BANIAS(1000), | ||
214 | BANIAS(1100), | ||
215 | BANIAS(1200), | ||
216 | BANIAS(1300), | ||
217 | BANIAS(1400), | ||
218 | BANIAS(1500), | ||
219 | BANIAS(1600), | ||
220 | BANIAS(1700), | ||
221 | |||
222 | /* NULL model_name is a wildcard */ | ||
223 | { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, | ||
224 | { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, | ||
225 | { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, | ||
226 | { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, | ||
227 | { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, | ||
228 | |||
229 | { NULL, } | ||
230 | }; | ||
231 | #undef _BANIAS | ||
232 | #undef BANIAS | ||
233 | |||
234 | static int centrino_cpu_init_table(struct cpufreq_policy *policy) | ||
235 | { | ||
236 | struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); | ||
237 | struct cpu_model *model; | ||
238 | |||
239 | for(model = models; model->cpu_id != NULL; model++) | ||
240 | if (centrino_verify_cpu_id(cpu, model->cpu_id) && | ||
241 | (model->model_name == NULL || | ||
242 | strcmp(cpu->x86_model_id, model->model_name) == 0)) | ||
243 | break; | ||
244 | |||
245 | if (model->cpu_id == NULL) { | ||
246 | /* No match at all */ | ||
247 | dprintk("no support for CPU model \"%s\": " | ||
248 | "send /proc/cpuinfo to " MAINTAINER "\n", | ||
249 | cpu->x86_model_id); | ||
250 | return -ENOENT; | ||
251 | } | ||
252 | |||
253 | if (model->op_points == NULL) { | ||
254 | /* Matched a non-match */ | ||
255 | dprintk("no table support for CPU model \"%s\"\n", | ||
256 | cpu->x86_model_id); | ||
257 | dprintk("try using the acpi-cpufreq driver\n"); | ||
258 | return -ENOENT; | ||
259 | } | ||
260 | |||
261 | per_cpu(centrino_model, policy->cpu) = model; | ||
262 | |||
263 | dprintk("found \"%s\": max frequency: %dkHz\n", | ||
264 | model->model_name, model->max_freq); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | #else | ||
270 | static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) | ||
271 | { | ||
272 | return -ENODEV; | ||
273 | } | ||
274 | #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ | ||
275 | |||
276 | static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, | ||
277 | const struct cpu_id *x) | ||
278 | { | ||
279 | if ((c->x86 == x->x86) && | ||
280 | (c->x86_model == x->x86_model) && | ||
281 | (c->x86_mask == x->x86_mask)) | ||
282 | return 1; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* To be called only after centrino_model is initialized */ | ||
287 | static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) | ||
288 | { | ||
289 | int i; | ||
290 | |||
291 | /* | ||
292 | * Extract clock in kHz from PERF_CTL value | ||
293 | * for centrino, as some DSDTs are buggy. | ||
294 | * Ideally, this can be done using the acpi_data structure. | ||
295 | */ | ||
296 | if ((per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_BANIAS]) || | ||
297 | (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_A1]) || | ||
298 | (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_B0])) { | ||
299 | msr = (msr >> 8) & 0xff; | ||
300 | return msr * 100000; | ||
301 | } | ||
302 | |||
303 | if ((!per_cpu(centrino_model, cpu)) || | ||
304 | (!per_cpu(centrino_model, cpu)->op_points)) | ||
305 | return 0; | ||
306 | |||
307 | msr &= 0xffff; | ||
308 | for (i = 0; | ||
309 | per_cpu(centrino_model, cpu)->op_points[i].frequency | ||
310 | != CPUFREQ_TABLE_END; | ||
311 | i++) { | ||
312 | if (msr == per_cpu(centrino_model, cpu)->op_points[i].index) | ||
313 | return per_cpu(centrino_model, cpu)-> | ||
314 | op_points[i].frequency; | ||
315 | } | ||
316 | if (failsafe) | ||
317 | return per_cpu(centrino_model, cpu)->op_points[i-1].frequency; | ||
318 | else | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* Return the current CPU frequency in kHz */ | ||
323 | static unsigned int get_cur_freq(unsigned int cpu) | ||
324 | { | ||
325 | unsigned l, h; | ||
326 | unsigned clock_freq; | ||
327 | |||
328 | rdmsr_on_cpu(cpu, MSR_IA32_PERF_STATUS, &l, &h); | ||
329 | clock_freq = extract_clock(l, cpu, 0); | ||
330 | |||
331 | if (unlikely(clock_freq == 0)) { | ||
332 | /* | ||
333 | * On some CPUs, we can see transient MSR values (which are | ||
334 | * not present in _PSS), while CPU is doing some automatic | ||
335 | * P-state transition (like TM2). Get the last freq set | ||
336 | * in PERF_CTL. | ||
337 | */ | ||
338 | rdmsr_on_cpu(cpu, MSR_IA32_PERF_CTL, &l, &h); | ||
339 | clock_freq = extract_clock(l, cpu, 1); | ||
340 | } | ||
341 | return clock_freq; | ||
342 | } | ||
343 | |||
344 | |||
345 | static int centrino_cpu_init(struct cpufreq_policy *policy) | ||
346 | { | ||
347 | struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); | ||
348 | unsigned freq; | ||
349 | unsigned l, h; | ||
350 | int ret; | ||
351 | int i; | ||
352 | |||
353 | /* Only Intel makes Enhanced Speedstep-capable CPUs */ | ||
354 | if (cpu->x86_vendor != X86_VENDOR_INTEL || | ||
355 | !cpu_has(cpu, X86_FEATURE_EST)) | ||
356 | return -ENODEV; | ||
357 | |||
358 | if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) | ||
359 | centrino_driver.flags |= CPUFREQ_CONST_LOOPS; | ||
360 | |||
361 | if (policy->cpu != 0) | ||
362 | return -ENODEV; | ||
363 | |||
364 | for (i = 0; i < N_IDS; i++) | ||
365 | if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) | ||
366 | break; | ||
367 | |||
368 | if (i != N_IDS) | ||
369 | per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; | ||
370 | |||
371 | if (!per_cpu(centrino_cpu, policy->cpu)) { | ||
372 | dprintk("found unsupported CPU with " | ||
373 | "Enhanced SpeedStep: send /proc/cpuinfo to " | ||
374 | MAINTAINER "\n"); | ||
375 | return -ENODEV; | ||
376 | } | ||
377 | |||
378 | if (centrino_cpu_init_table(policy)) { | ||
379 | return -ENODEV; | ||
380 | } | ||
381 | |||
382 | /* Check to see if Enhanced SpeedStep is enabled, and try to | ||
383 | enable it if not. */ | ||
384 | rdmsr(MSR_IA32_MISC_ENABLE, l, h); | ||
385 | |||
386 | if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { | ||
387 | l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; | ||
388 | dprintk("trying to enable Enhanced SpeedStep (%x)\n", l); | ||
389 | wrmsr(MSR_IA32_MISC_ENABLE, l, h); | ||
390 | |||
391 | /* check to see if it stuck */ | ||
392 | rdmsr(MSR_IA32_MISC_ENABLE, l, h); | ||
393 | if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { | ||
394 | printk(KERN_INFO PFX | ||
395 | "couldn't enable Enhanced SpeedStep\n"); | ||
396 | return -ENODEV; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | freq = get_cur_freq(policy->cpu); | ||
401 | policy->cpuinfo.transition_latency = 10000; | ||
402 | /* 10uS transition latency */ | ||
403 | policy->cur = freq; | ||
404 | |||
405 | dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); | ||
406 | |||
407 | ret = cpufreq_frequency_table_cpuinfo(policy, | ||
408 | per_cpu(centrino_model, policy->cpu)->op_points); | ||
409 | if (ret) | ||
410 | return (ret); | ||
411 | |||
412 | cpufreq_frequency_table_get_attr( | ||
413 | per_cpu(centrino_model, policy->cpu)->op_points, policy->cpu); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int centrino_cpu_exit(struct cpufreq_policy *policy) | ||
419 | { | ||
420 | unsigned int cpu = policy->cpu; | ||
421 | |||
422 | if (!per_cpu(centrino_model, cpu)) | ||
423 | return -ENODEV; | ||
424 | |||
425 | cpufreq_frequency_table_put_attr(cpu); | ||
426 | |||
427 | per_cpu(centrino_model, cpu) = NULL; | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * centrino_verify - verifies a new CPUFreq policy | ||
434 | * @policy: new policy | ||
435 | * | ||
436 | * Limit must be within this model's frequency range at least one | ||
437 | * border included. | ||
438 | */ | ||
439 | static int centrino_verify (struct cpufreq_policy *policy) | ||
440 | { | ||
441 | return cpufreq_frequency_table_verify(policy, | ||
442 | per_cpu(centrino_model, policy->cpu)->op_points); | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * centrino_setpolicy - set a new CPUFreq policy | ||
447 | * @policy: new policy | ||
448 | * @target_freq: the target frequency | ||
449 | * @relation: how that frequency relates to achieved frequency | ||
450 | * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) | ||
451 | * | ||
452 | * Sets a new CPUFreq policy. | ||
453 | */ | ||
454 | static int centrino_target (struct cpufreq_policy *policy, | ||
455 | unsigned int target_freq, | ||
456 | unsigned int relation) | ||
457 | { | ||
458 | unsigned int newstate = 0; | ||
459 | unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; | ||
460 | struct cpufreq_freqs freqs; | ||
461 | int retval = 0; | ||
462 | unsigned int j, k, first_cpu, tmp; | ||
463 | cpumask_var_t covered_cpus; | ||
464 | |||
465 | if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) | ||
466 | return -ENOMEM; | ||
467 | |||
468 | if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { | ||
469 | retval = -ENODEV; | ||
470 | goto out; | ||
471 | } | ||
472 | |||
473 | if (unlikely(cpufreq_frequency_table_target(policy, | ||
474 | per_cpu(centrino_model, cpu)->op_points, | ||
475 | target_freq, | ||
476 | relation, | ||
477 | &newstate))) { | ||
478 | retval = -EINVAL; | ||
479 | goto out; | ||
480 | } | ||
481 | |||
482 | first_cpu = 1; | ||
483 | for_each_cpu(j, policy->cpus) { | ||
484 | int good_cpu; | ||
485 | |||
486 | /* cpufreq holds the hotplug lock, so we are safe here */ | ||
487 | if (!cpu_online(j)) | ||
488 | continue; | ||
489 | |||
490 | /* | ||
491 | * Support for SMP systems. | ||
492 | * Make sure we are running on CPU that wants to change freq | ||
493 | */ | ||
494 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | ||
495 | good_cpu = cpumask_any_and(policy->cpus, | ||
496 | cpu_online_mask); | ||
497 | else | ||
498 | good_cpu = j; | ||
499 | |||
500 | if (good_cpu >= nr_cpu_ids) { | ||
501 | dprintk("couldn't limit to CPUs in this domain\n"); | ||
502 | retval = -EAGAIN; | ||
503 | if (first_cpu) { | ||
504 | /* We haven't started the transition yet. */ | ||
505 | goto out; | ||
506 | } | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | msr = per_cpu(centrino_model, cpu)->op_points[newstate].index; | ||
511 | |||
512 | if (first_cpu) { | ||
513 | rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); | ||
514 | if (msr == (oldmsr & 0xffff)) { | ||
515 | dprintk("no change needed - msr was and needs " | ||
516 | "to be %x\n", oldmsr); | ||
517 | retval = 0; | ||
518 | goto out; | ||
519 | } | ||
520 | |||
521 | freqs.old = extract_clock(oldmsr, cpu, 0); | ||
522 | freqs.new = extract_clock(msr, cpu, 0); | ||
523 | |||
524 | dprintk("target=%dkHz old=%d new=%d msr=%04x\n", | ||
525 | target_freq, freqs.old, freqs.new, msr); | ||
526 | |||
527 | for_each_cpu(k, policy->cpus) { | ||
528 | if (!cpu_online(k)) | ||
529 | continue; | ||
530 | freqs.cpu = k; | ||
531 | cpufreq_notify_transition(&freqs, | ||
532 | CPUFREQ_PRECHANGE); | ||
533 | } | ||
534 | |||
535 | first_cpu = 0; | ||
536 | /* all but 16 LSB are reserved, treat them with care */ | ||
537 | oldmsr &= ~0xffff; | ||
538 | msr &= 0xffff; | ||
539 | oldmsr |= msr; | ||
540 | } | ||
541 | |||
542 | wrmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, oldmsr, h); | ||
543 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | ||
544 | break; | ||
545 | |||
546 | cpumask_set_cpu(j, covered_cpus); | ||
547 | } | ||
548 | |||
549 | for_each_cpu(k, policy->cpus) { | ||
550 | if (!cpu_online(k)) | ||
551 | continue; | ||
552 | freqs.cpu = k; | ||
553 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
554 | } | ||
555 | |||
556 | if (unlikely(retval)) { | ||
557 | /* | ||
558 | * We have failed halfway through the frequency change. | ||
559 | * We have sent callbacks to policy->cpus and | ||
560 | * MSRs have already been written on coverd_cpus. | ||
561 | * Best effort undo.. | ||
562 | */ | ||
563 | |||
564 | for_each_cpu(j, covered_cpus) | ||
565 | wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); | ||
566 | |||
567 | tmp = freqs.new; | ||
568 | freqs.new = freqs.old; | ||
569 | freqs.old = tmp; | ||
570 | for_each_cpu(j, policy->cpus) { | ||
571 | if (!cpu_online(j)) | ||
572 | continue; | ||
573 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
574 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
575 | } | ||
576 | } | ||
577 | retval = 0; | ||
578 | |||
579 | out: | ||
580 | free_cpumask_var(covered_cpus); | ||
581 | return retval; | ||
582 | } | ||
583 | |||
584 | static struct freq_attr* centrino_attr[] = { | ||
585 | &cpufreq_freq_attr_scaling_available_freqs, | ||
586 | NULL, | ||
587 | }; | ||
588 | |||
589 | static struct cpufreq_driver centrino_driver = { | ||
590 | .name = "centrino", /* should be speedstep-centrino, | ||
591 | but there's a 16 char limit */ | ||
592 | .init = centrino_cpu_init, | ||
593 | .exit = centrino_cpu_exit, | ||
594 | .verify = centrino_verify, | ||
595 | .target = centrino_target, | ||
596 | .get = get_cur_freq, | ||
597 | .attr = centrino_attr, | ||
598 | .owner = THIS_MODULE, | ||
599 | }; | ||
600 | |||
601 | |||
602 | /** | ||
603 | * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver | ||
604 | * | ||
605 | * Initializes the Enhanced SpeedStep support. Returns -ENODEV on | ||
606 | * unsupported devices, -ENOENT if there's no voltage table for this | ||
607 | * particular CPU model, -EINVAL on problems during initiatization, | ||
608 | * and zero on success. | ||
609 | * | ||
610 | * This is quite picky. Not only does the CPU have to advertise the | ||
611 | * "est" flag in the cpuid capability flags, we look for a specific | ||
612 | * CPU model and stepping, and we need to have the exact model name in | ||
613 | * our voltage tables. That is, be paranoid about not releasing | ||
614 | * someone's valuable magic smoke. | ||
615 | */ | ||
616 | static int __init centrino_init(void) | ||
617 | { | ||
618 | struct cpuinfo_x86 *cpu = &cpu_data(0); | ||
619 | |||
620 | if (!cpu_has(cpu, X86_FEATURE_EST)) | ||
621 | return -ENODEV; | ||
622 | |||
623 | return cpufreq_register_driver(¢rino_driver); | ||
624 | } | ||
625 | |||
626 | static void __exit centrino_exit(void) | ||
627 | { | ||
628 | cpufreq_unregister_driver(¢rino_driver); | ||
629 | } | ||
630 | |||
631 | MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); | ||
632 | MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); | ||
633 | MODULE_LICENSE ("GPL"); | ||
634 | |||
635 | late_initcall(centrino_init); | ||
636 | module_exit(centrino_exit); | ||