diff options
author | Rafał Bilski <rafalbilski@interia.pl> | 2007-01-31 17:42:47 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2007-02-03 17:25:19 -0500 |
commit | 980342a7eb6b4ebcc5feffe6287ad5cda5a68a4b (patch) | |
tree | fa3479ba14b9e627a1f8db975c4c22217ec07bdd | |
parent | 58389a86df48ff927846df9537ea34d9961b5c44 (diff) |
[CPUFREQ] Longhaul - Introduce Nehemiah C
Looks like some time ago I introduced a bug to Longhaul.
I had report that 9x133Mhz CPU is seen as 5x133MHz. So I
changed multipliers table. That was a mistake. According to
documentation table was correct. So only way to avoid 5 or 9
dilema is not use MaxMHzBR for PowerSaver 1.0. One code that
works on all processors. To do it I need also separate flag for
Nehemiah C (min = x4.0) and Nehemiah (min = x5.0).
Signed-off-by: Rafał Bilski <rafalbilski@interia.pl>
Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 73 |
1 files changed, 28 insertions, 45 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index b679aaf0c6b4..849a6dfdfea8 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #define CPU_EZRA 3 | 51 | #define CPU_EZRA 3 |
52 | #define CPU_EZRA_T 4 | 52 | #define CPU_EZRA_T 4 |
53 | #define CPU_NEHEMIAH 5 | 53 | #define CPU_NEHEMIAH 5 |
54 | #define CPU_NEHEMIAH_C 6 | ||
54 | 55 | ||
55 | /* Flags */ | 56 | /* Flags */ |
56 | #define USE_ACPI_C3 (1 << 1) | 57 | #define USE_ACPI_C3 (1 << 1) |
@@ -349,67 +350,47 @@ static int guess_fsb(int mult) | |||
349 | 350 | ||
350 | static int __init longhaul_get_ranges(void) | 351 | static int __init longhaul_get_ranges(void) |
351 | { | 352 | { |
352 | unsigned long invalue; | ||
353 | unsigned int ezra_t_multipliers[32]= { | ||
354 | 90, 30, 40, 100, 55, 35, 45, 95, | ||
355 | 50, 70, 80, 60, 120, 75, 85, 65, | ||
356 | -1, 110, 120, -1, 135, 115, 125, 105, | ||
357 | 130, 150, 160, 140, -1, 155, -1, 145 }; | ||
358 | unsigned int j, k = 0; | 353 | unsigned int j, k = 0; |
359 | union msr_longhaul longhaul; | 354 | int mult; |
360 | int mult = 0; | ||
361 | 355 | ||
356 | /* Get current frequency */ | ||
357 | mult = longhaul_get_cpu_mult(); | ||
358 | if (mult == -1) { | ||
359 | printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | fsb = guess_fsb(mult); | ||
363 | if (fsb == 0) { | ||
364 | printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | /* Get max multiplier - as we always did. | ||
368 | * Longhaul MSR is usefull only when voltage scaling is enabled. | ||
369 | * C3 is booting at max anyway. */ | ||
370 | maxmult = mult; | ||
371 | /* Get min multiplier */ | ||
362 | switch (longhaul_version) { | 372 | switch (longhaul_version) { |
363 | case TYPE_LONGHAUL_V1: | 373 | case TYPE_LONGHAUL_V1: |
364 | case TYPE_LONGHAUL_V2: | 374 | case TYPE_LONGHAUL_V2: |
365 | /* Ugh, Longhaul v1 didn't have the min/max MSRs. | ||
366 | Assume min=3.0x & max = whatever we booted at. */ | ||
367 | minmult = 30; | 375 | minmult = 30; |
368 | maxmult = mult = longhaul_get_cpu_mult(); | ||
369 | break; | 376 | break; |
370 | 377 | ||
371 | case TYPE_POWERSAVER: | 378 | case TYPE_POWERSAVER: |
372 | /* Ezra-T */ | 379 | /* Ezra-T */ |
373 | if (cpu_model==CPU_EZRA_T) { | 380 | if (cpu_model == CPU_EZRA_T) |
374 | minmult = 30; | 381 | minmult = 30; |
375 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); | ||
376 | invalue = longhaul.bits.MaxMHzBR; | ||
377 | if (longhaul.bits.MaxMHzBR4) | ||
378 | invalue += 16; | ||
379 | maxmult = mult = ezra_t_multipliers[invalue]; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | /* Nehemiah */ | 382 | /* Nehemiah */ |
384 | if (cpu_model==CPU_NEHEMIAH) { | 383 | else if (cpu_model == CPU_NEHEMIAH) |
385 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); | 384 | minmult = 50; |
386 | 385 | /* Nehemiah C */ | |
387 | /* | 386 | else if (cpu_model == CPU_NEHEMIAH_C) |
388 | * TODO: This code works, but raises a lot of questions. | 387 | minmult = 40; |
389 | * - Some Nehemiah's seem to have broken Min/MaxMHzBR's. | 388 | break; |
390 | * We get around this by using a hardcoded multiplier of 4.0x | ||
391 | * for the minimimum speed, and the speed we booted up at for the max. | ||
392 | * This is done in longhaul_get_cpu_mult() by reading the EBLCR register. | ||
393 | * - According to some VIA documentation EBLCR is only | ||
394 | * in pre-Nehemiah C3s. How this still works is a mystery. | ||
395 | * We're possibly using something undocumented and unsupported, | ||
396 | * But it works, so we don't grumble. | ||
397 | */ | ||
398 | minmult=40; | ||
399 | maxmult = mult = longhaul_get_cpu_mult(); | ||
400 | break; | ||
401 | } | ||
402 | } | 389 | } |
403 | fsb = guess_fsb(mult); | ||
404 | 390 | ||
405 | dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", | 391 | dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", |
406 | minmult/10, minmult%10, maxmult/10, maxmult%10); | 392 | minmult/10, minmult%10, maxmult/10, maxmult%10); |
407 | 393 | ||
408 | if (fsb == 0) { | ||
409 | printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | highest_speed = calc_speed(maxmult); | 394 | highest_speed = calc_speed(maxmult); |
414 | lowest_speed = calc_speed(minmult); | 395 | lowest_speed = calc_speed(minmult); |
415 | dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, | 396 | dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, |
@@ -634,21 +615,23 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
634 | break; | 615 | break; |
635 | 616 | ||
636 | case 9: | 617 | case 9: |
637 | cpu_model = CPU_NEHEMIAH; | ||
638 | longhaul_version = TYPE_POWERSAVER; | 618 | longhaul_version = TYPE_POWERSAVER; |
639 | numscales=32; | 619 | numscales=32; |
640 | switch (c->x86_mask) { | 620 | switch (c->x86_mask) { |
641 | case 0 ... 1: | 621 | case 0 ... 1: |
622 | cpu_model = CPU_NEHEMIAH; | ||
642 | cpuname = "C3 'Nehemiah A' [C5N]"; | 623 | cpuname = "C3 'Nehemiah A' [C5N]"; |
643 | memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio)); | 624 | memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio)); |
644 | memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr)); | 625 | memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr)); |
645 | break; | 626 | break; |
646 | case 2 ... 4: | 627 | case 2 ... 4: |
628 | cpu_model = CPU_NEHEMIAH; | ||
647 | cpuname = "C3 'Nehemiah B' [C5N]"; | 629 | cpuname = "C3 'Nehemiah B' [C5N]"; |
648 | memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio)); | 630 | memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio)); |
649 | memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr)); | 631 | memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr)); |
650 | break; | 632 | break; |
651 | case 5 ... 15: | 633 | case 5 ... 15: |
634 | cpu_model = CPU_NEHEMIAH_C; | ||
652 | cpuname = "C3 'Nehemiah C' [C5N]"; | 635 | cpuname = "C3 'Nehemiah C' [C5N]"; |
653 | memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio)); | 636 | memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio)); |
654 | memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr)); | 637 | memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr)); |