1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/init.h>
15#include <linux/cpufreq.h>
16#include <linux/slab.h>
17
18#include <asm/msr.h>
19#include <asm/tsc.h>
20#include "speedstep-lib.h"
21
22#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
23 "speedstep-lib", msg)
24
25#define PFX "speedstep-lib: "
26
27#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
28static int relaxed_check;
29#else
30#define relaxed_check 0
31#endif
32
33
34
35
36
37static unsigned int pentium3_get_frequency(unsigned int processor)
38{
39
40 struct {
41 unsigned int ratio;
42 u8 bitmap;
43
44 } msr_decode_mult[] = {
45 { 30, 0x01 },
46 { 35, 0x05 },
47 { 40, 0x02 },
48 { 45, 0x06 },
49 { 50, 0x00 },
50 { 55, 0x04 },
51 { 60, 0x0b },
52 { 65, 0x0f },
53 { 70, 0x09 },
54 { 75, 0x0d },
55 { 80, 0x0a },
56 { 85, 0x26 },
57 { 90, 0x20 },
58 { 100, 0x2b },
59 { 0, 0xff }
60 };
61
62
63 struct {
64 unsigned int value;
65 u8 bitmap;
66
67 } msr_decode_fsb[] = {
68 { 66, 0x0 },
69 { 100, 0x2 },
70 { 133, 0x1 },
71 { 0, 0xff}
72 };
73
74 u32 msr_lo, msr_tmp;
75 int i = 0, j = 0;
76
77
78 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
79 dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
80 msr_tmp = msr_lo;
81
82
83 msr_tmp &= 0x00c0000;
84 msr_tmp >>= 18;
85 while (msr_tmp != msr_decode_fsb[i].bitmap) {
86 if (msr_decode_fsb[i].bitmap == 0xff)
87 return 0;
88 i++;
89 }
90
91
92 if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
93 dprintk("workaround for early PIIIs\n");
94 msr_lo &= 0x03c00000;
95 } else
96 msr_lo &= 0x0bc00000;
97 msr_lo >>= 22;
98 while (msr_lo != msr_decode_mult[j].bitmap) {
99 if (msr_decode_mult[j].bitmap == 0xff)
100 return 0;
101 j++;
102 }
103
104 dprintk("speed is %u\n",
105 (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
106
107 return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
108}
109
110
111static unsigned int pentiumM_get_frequency(void)
112{
113 u32 msr_lo, msr_tmp;
114
115 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
116 dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
117
118
119 if (msr_lo & 0x00040000) {
120 printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n",
121 msr_lo, msr_tmp);
122 return 0;
123 }
124
125 msr_tmp = (msr_lo >> 22) & 0x1f;
126 dprintk("bits 22-26 are 0x%x, speed is %u\n",
127 msr_tmp, (msr_tmp * 100 * 1000));
128
129 return msr_tmp * 100 * 1000;
130}
131
132static unsigned int pentium_core_get_frequency(void)
133{
134 u32 fsb = 0;
135 u32 msr_lo, msr_tmp;
136 int ret;
137
138 rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
139
140 switch (msr_lo & 0x07) {
141 case 5:
142 fsb = 100000;
143 break;
144 case 1:
145 fsb = 133333;
146 break;
147 case 3:
148 fsb = 166667;
149 break;
150 case 2:
151 fsb = 200000;
152 break;
153 case 0:
154 fsb = 266667;
155 break;
156 case 4:
157 fsb = 333333;
158 break;
159 default:
160 printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value");
161 }
162
163 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
164 dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
165 msr_lo, msr_tmp);
166
167 msr_tmp = (msr_lo >> 22) & 0x1f;
168 dprintk("bits 22-26 are 0x%x, speed is %u\n",
169 msr_tmp, (msr_tmp * fsb));
170
171 ret = (msr_tmp * fsb);
172 return ret;
173}
174
175
176static unsigned int pentium4_get_frequency(void)
177{
178 struct cpuinfo_x86 *c = &boot_cpu_data;
179 u32 msr_lo, msr_hi, mult;
180 unsigned int fsb = 0;
181 unsigned int ret;
182 u8 fsb_code;
183
184
185
186
187
188
189 if (c->x86_model < 2)
190 return cpu_khz;
191
192 rdmsr(0x2c, msr_lo, msr_hi);
193
194 dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
195
196
197
198
199
200
201 fsb_code = (msr_lo >> 16) & 0x7;
202 switch (fsb_code) {
203 case 0:
204 fsb = 100 * 1000;
205 break;
206 case 1:
207 fsb = 13333 * 10;
208 break;
209 case 2:
210 fsb = 200 * 1000;
211 break;
212 }
213
214 if (!fsb)
215 printk(KERN_DEBUG PFX "couldn't detect FSB speed. "
216 "Please send an e-mail to <linux@brodo.de>\n");
217
218
219 mult = msr_lo >> 24;
220
221 dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
222 fsb, mult, (fsb * mult));
223
224 ret = (fsb * mult);
225 return ret;
226}
227
228
229
230unsigned int speedstep_get_frequency(unsigned int processor)
231{
232 switch (processor) {
233 case SPEEDSTEP_CPU_PCORE:
234 return pentium_core_get_frequency();
235 case SPEEDSTEP_CPU_PM:
236 return pentiumM_get_frequency();
237 case SPEEDSTEP_CPU_P4D:
238 case SPEEDSTEP_CPU_P4M:
239 return pentium4_get_frequency();
240 case SPEEDSTEP_CPU_PIII_T:
241 case SPEEDSTEP_CPU_PIII_C:
242 case SPEEDSTEP_CPU_PIII_C_EARLY:
243 return pentium3_get_frequency(processor);
244 default:
245 return 0;
246 };
247 return 0;
248}
249EXPORT_SYMBOL_GPL(speedstep_get_frequency);
250
251
252
253
254
255
256unsigned int speedstep_detect_processor(void)
257{
258 struct cpuinfo_x86 *c = &cpu_data(0);
259 u32 ebx, msr_lo, msr_hi;
260
261 dprintk("x86: %x, model: %x\n", c->x86, c->x86_model);
262
263 if ((c->x86_vendor != X86_VENDOR_INTEL) ||
264 ((c->x86 != 6) && (c->x86 != 0xF)))
265 return 0;
266
267 if (c->x86 == 0xF) {
268
269
270 if (c->x86_model != 2)
271 return 0;
272
273 ebx = cpuid_ebx(0x00000001);
274 ebx &= 0x000000FF;
275
276 dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
277
278 switch (c->x86_mask) {
279 case 4:
280
281
282
283
284 if ((ebx == 0x0e) || (ebx == 0x0f))
285 return SPEEDSTEP_CPU_P4M;
286 break;
287 case 7:
288
289
290
291
292
293
294
295 if (ebx == 0x0e)
296 return SPEEDSTEP_CPU_P4M;
297 break;
298 case 9:
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315 if ((ebx == 0x0e) ||
316 (strstr(c->x86_model_id,
317 "Mobile Intel(R) Pentium(R) 4") != NULL))
318 return SPEEDSTEP_CPU_P4M;
319 break;
320 default:
321 break;
322 }
323 return 0;
324 }
325
326 switch (c->x86_model) {
327 case 0x0B:
328
329
330 ebx = cpuid_ebx(0x00000001);
331 dprintk("ebx is %x\n", ebx);
332
333 ebx &= 0x000000FF;
334
335 if (ebx != 0x06)
336 return 0;
337
338
339
340
341 return SPEEDSTEP_CPU_PIII_T;
342
343 case 0x08:
344
345
346
347 rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
348 dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
349 msr_lo, msr_hi);
350 msr_lo &= 0x00c0000;
351 if (msr_lo != 0x0080000)
352 return 0;
353
354
355
356
357
358
359
360 rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
361 dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
362 msr_lo, msr_hi);
363 if ((msr_hi & (1<<18)) &&
364 (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
365 if (c->x86_mask == 0x01) {
366 dprintk("early PIII version\n");
367 return SPEEDSTEP_CPU_PIII_C_EARLY;
368 } else
369 return SPEEDSTEP_CPU_PIII_C;
370 }
371
372 default:
373 return 0;
374 }
375}
376EXPORT_SYMBOL_GPL(speedstep_detect_processor);
377
378
379
380
381
382
383unsigned int speedstep_get_freqs(unsigned int processor,
384 unsigned int *low_speed,
385 unsigned int *high_speed,
386 unsigned int *transition_latency,
387 void (*set_state) (unsigned int state))
388{
389 unsigned int prev_speed;
390 unsigned int ret = 0;
391 unsigned long flags;
392 struct timeval tv1, tv2;
393
394 if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
395 return -EINVAL;
396
397 dprintk("trying to determine both speeds\n");
398
399
400 prev_speed = speedstep_get_frequency(processor);
401 if (!prev_speed)
402 return -EIO;
403
404 dprintk("previous speed is %u\n", prev_speed);
405
406 local_irq_save(flags);
407
408
409 set_state(SPEEDSTEP_LOW);
410 *low_speed = speedstep_get_frequency(processor);
411 if (!*low_speed) {
412 ret = -EIO;
413 goto out;
414 }
415
416 dprintk("low speed is %u\n", *low_speed);
417
418
419 if (transition_latency)
420 do_gettimeofday(&tv1);
421
422
423 set_state(SPEEDSTEP_HIGH);
424
425
426 if (transition_latency)
427 do_gettimeofday(&tv2);
428
429 *high_speed = speedstep_get_frequency(processor);
430 if (!*high_speed) {
431 ret = -EIO;
432 goto out;
433 }
434
435 dprintk("high speed is %u\n", *high_speed);
436
437 if (*low_speed == *high_speed) {
438 ret = -ENODEV;
439 goto out;
440 }
441
442
443 if (*high_speed != prev_speed)
444 set_state(SPEEDSTEP_LOW);
445
446 if (transition_latency) {
447 *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC +
448 tv2.tv_usec - tv1.tv_usec;
449 dprintk("transition latency is %u uSec\n", *transition_latency);
450
451
452 *transition_latency *= 1200;
453
454
455
456
457 if (*transition_latency > 10000000 ||
458 *transition_latency < 50000) {
459 printk(KERN_WARNING PFX "frequency transition "
460 "measured seems out of range (%u "
461 "nSec), falling back to a safe one of"
462 "%u nSec.\n",
463 *transition_latency, 500000);
464 *transition_latency = 500000;
465 }
466 }
467
468out:
469 local_irq_restore(flags);
470 return ret;
471}
472EXPORT_SYMBOL_GPL(speedstep_get_freqs);
473
474#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
475module_param(relaxed_check, int, 0444);
476MODULE_PARM_DESC(relaxed_check,
477 "Don't do all checks for speedstep capability.");
478#endif
479
480MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
481MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
482MODULE_LICENSE("GPL");
483