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)); |
