diff options
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/longhaul.c')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 131 |
1 files changed, 58 insertions, 73 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index c548daad3476..a3db9332d652 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c | |||
@@ -52,6 +52,10 @@ | |||
52 | #define CPU_EZRA_T 4 | 52 | #define CPU_EZRA_T 4 |
53 | #define CPU_NEHEMIAH 5 | 53 | #define CPU_NEHEMIAH 5 |
54 | 54 | ||
55 | /* Flags */ | ||
56 | #define USE_ACPI_C3 (1 << 1) | ||
57 | #define USE_NORTHBRIDGE (1 << 2) | ||
58 | |||
55 | static int cpu_model; | 59 | static int cpu_model; |
56 | static unsigned int numscales=16; | 60 | static unsigned int numscales=16; |
57 | static unsigned int fsb; | 61 | static unsigned int fsb; |
@@ -68,7 +72,7 @@ static unsigned int minmult, maxmult; | |||
68 | static int can_scale_voltage; | 72 | static int can_scale_voltage; |
69 | static struct acpi_processor *pr = NULL; | 73 | static struct acpi_processor *pr = NULL; |
70 | static struct acpi_processor_cx *cx = NULL; | 74 | static struct acpi_processor_cx *cx = NULL; |
71 | static int port22_en; | 75 | static u8 longhaul_flags; |
72 | 76 | ||
73 | /* Module parameters */ | 77 | /* Module parameters */ |
74 | static int scale_voltage; | 78 | static int scale_voltage; |
@@ -80,7 +84,6 @@ static int ignore_latency; | |||
80 | /* Clock ratios multiplied by 10 */ | 84 | /* Clock ratios multiplied by 10 */ |
81 | static int clock_ratio[32]; | 85 | static int clock_ratio[32]; |
82 | static int eblcr_table[32]; | 86 | static int eblcr_table[32]; |
83 | static unsigned int highest_speed, lowest_speed; /* kHz */ | ||
84 | static int longhaul_version; | 87 | static int longhaul_version; |
85 | static struct cpufreq_frequency_table *longhaul_table; | 88 | static struct cpufreq_frequency_table *longhaul_table; |
86 | 89 | ||
@@ -178,7 +181,7 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) | |||
178 | safe_halt(); | 181 | safe_halt(); |
179 | /* Change frequency on next halt or sleep */ | 182 | /* Change frequency on next halt or sleep */ |
180 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); | 183 | wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); |
181 | if (port22_en) { | 184 | if (!cx_address) { |
182 | ACPI_FLUSH_CPU_CACHE(); | 185 | ACPI_FLUSH_CPU_CACHE(); |
183 | /* Invoke C1 */ | 186 | /* Invoke C1 */ |
184 | halt(); | 187 | halt(); |
@@ -187,9 +190,8 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) | |||
187 | /* Invoke C3 */ | 190 | /* Invoke C3 */ |
188 | inb(cx_address); | 191 | inb(cx_address); |
189 | /* Dummy op - must do something useless after P_LVL3 read */ | 192 | /* Dummy op - must do something useless after P_LVL3 read */ |
190 | t = inl(acpi_fadt.xpm_tmr_blk.address); | 193 | t = inl(acpi_gbl_FADT.xpm_timer_block.address); |
191 | } | 194 | } |
192 | |||
193 | /* Disable bus ratio bit */ | 195 | /* Disable bus ratio bit */ |
194 | local_irq_disable(); | 196 | local_irq_disable(); |
195 | longhaul.bits.RevisionKey = longhaul.bits.RevisionID; | 197 | longhaul.bits.RevisionKey = longhaul.bits.RevisionID; |
@@ -243,15 +245,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
243 | outb(0xFF,0xA1); /* Overkill */ | 245 | outb(0xFF,0xA1); /* Overkill */ |
244 | outb(0xFE,0x21); /* TMR0 only */ | 246 | outb(0xFE,0x21); /* TMR0 only */ |
245 | 247 | ||
246 | if (pr->flags.bm_control) { | 248 | if (longhaul_flags & USE_NORTHBRIDGE) { |
247 | /* Disable bus master arbitration */ | ||
248 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, | ||
249 | ACPI_MTX_DO_NOT_LOCK); | ||
250 | } else if (port22_en) { | ||
251 | /* Disable AGP and PCI arbiters */ | 249 | /* Disable AGP and PCI arbiters */ |
252 | outb(3, 0x22); | 250 | outb(3, 0x22); |
251 | } else if ((pr != NULL) && pr->flags.bm_control) { | ||
252 | /* Disable bus master arbitration */ | ||
253 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); | ||
253 | } | 254 | } |
254 | |||
255 | switch (longhaul_version) { | 255 | switch (longhaul_version) { |
256 | 256 | ||
257 | /* | 257 | /* |
@@ -278,22 +278,23 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
278 | * to work in practice. | 278 | * to work in practice. |
279 | */ | 279 | */ |
280 | case TYPE_POWERSAVER: | 280 | case TYPE_POWERSAVER: |
281 | /* Don't allow wakeup */ | 281 | if (longhaul_flags & USE_ACPI_C3) { |
282 | acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, | 282 | /* Don't allow wakeup */ |
283 | ACPI_MTX_DO_NOT_LOCK); | 283 | acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); |
284 | do_powersaver(cx->address, clock_ratio_index); | 284 | do_powersaver(cx->address, clock_ratio_index); |
285 | } else { | ||
286 | do_powersaver(0, clock_ratio_index); | ||
287 | } | ||
285 | break; | 288 | break; |
286 | } | 289 | } |
287 | 290 | ||
288 | if (pr->flags.bm_control) { | 291 | if (longhaul_flags & USE_NORTHBRIDGE) { |
289 | /* Enable bus master arbitration */ | ||
290 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, | ||
291 | ACPI_MTX_DO_NOT_LOCK); | ||
292 | } else if (port22_en) { | ||
293 | /* Enable arbiters */ | 292 | /* Enable arbiters */ |
294 | outb(0, 0x22); | 293 | outb(0, 0x22); |
294 | } else if ((pr != NULL) && pr->flags.bm_control) { | ||
295 | /* Enable bus master arbitration */ | ||
296 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); | ||
295 | } | 297 | } |
296 | |||
297 | outb(pic2_mask,0xA1); /* restore mask */ | 298 | outb(pic2_mask,0xA1); /* restore mask */ |
298 | outb(pic1_mask,0x21); | 299 | outb(pic1_mask,0x21); |
299 | 300 | ||
@@ -314,12 +315,12 @@ static void longhaul_setstate(unsigned int clock_ratio_index) | |||
314 | 315 | ||
315 | #define ROUNDING 0xf | 316 | #define ROUNDING 0xf |
316 | 317 | ||
317 | static int _guess(int guess) | 318 | static int _guess(int guess, int mult) |
318 | { | 319 | { |
319 | int target; | 320 | int target; |
320 | 321 | ||
321 | target = ((maxmult/10)*guess); | 322 | target = ((mult/10)*guess); |
322 | if (maxmult%10 != 0) | 323 | if (mult%10 != 0) |
323 | target += (guess/2); | 324 | target += (guess/2); |
324 | target += ROUNDING/2; | 325 | target += ROUNDING/2; |
325 | target &= ~ROUNDING; | 326 | target &= ~ROUNDING; |
@@ -327,17 +328,17 @@ static int _guess(int guess) | |||
327 | } | 328 | } |
328 | 329 | ||
329 | 330 | ||
330 | static int guess_fsb(void) | 331 | static int guess_fsb(int mult) |
331 | { | 332 | { |
332 | int speed = (cpu_khz/1000); | 333 | int speed = (cpu_khz/1000); |
333 | int i; | 334 | int i; |
334 | int speeds[3] = { 66, 100, 133 }; | 335 | int speeds[] = { 66, 100, 133, 200 }; |
335 | 336 | ||
336 | speed += ROUNDING/2; | 337 | speed += ROUNDING/2; |
337 | speed &= ~ROUNDING; | 338 | speed &= ~ROUNDING; |
338 | 339 | ||
339 | for (i=0; i<3; i++) { | 340 | for (i=0; i<4; i++) { |
340 | if (_guess(speeds[i]) == speed) | 341 | if (_guess(speeds[i], mult) == speed) |
341 | return speeds[i]; | 342 | return speeds[i]; |
342 | } | 343 | } |
343 | return 0; | 344 | return 0; |
@@ -354,9 +355,7 @@ static int __init longhaul_get_ranges(void) | |||
354 | 130, 150, 160, 140, -1, 155, -1, 145 }; | 355 | 130, 150, 160, 140, -1, 155, -1, 145 }; |
355 | unsigned int j, k = 0; | 356 | unsigned int j, k = 0; |
356 | union msr_longhaul longhaul; | 357 | union msr_longhaul longhaul; |
357 | unsigned long lo, hi; | 358 | int mult = 0; |
358 | unsigned int eblcr_fsb_table_v1[] = { 66, 133, 100, -1 }; | ||
359 | unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 }; | ||
360 | 359 | ||
361 | switch (longhaul_version) { | 360 | switch (longhaul_version) { |
362 | case TYPE_LONGHAUL_V1: | 361 | case TYPE_LONGHAUL_V1: |
@@ -364,30 +363,18 @@ static int __init longhaul_get_ranges(void) | |||
364 | /* Ugh, Longhaul v1 didn't have the min/max MSRs. | 363 | /* Ugh, Longhaul v1 didn't have the min/max MSRs. |
365 | Assume min=3.0x & max = whatever we booted at. */ | 364 | Assume min=3.0x & max = whatever we booted at. */ |
366 | minmult = 30; | 365 | minmult = 30; |
367 | maxmult = longhaul_get_cpu_mult(); | 366 | maxmult = mult = longhaul_get_cpu_mult(); |
368 | rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); | ||
369 | invalue = (lo & (1<<18|1<<19)) >>18; | ||
370 | if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2) | ||
371 | fsb = eblcr_fsb_table_v1[invalue]; | ||
372 | else | ||
373 | fsb = guess_fsb(); | ||
374 | break; | 367 | break; |
375 | 368 | ||
376 | case TYPE_POWERSAVER: | 369 | case TYPE_POWERSAVER: |
377 | /* Ezra-T */ | 370 | /* Ezra-T */ |
378 | if (cpu_model==CPU_EZRA_T) { | 371 | if (cpu_model==CPU_EZRA_T) { |
372 | minmult = 30; | ||
379 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); | 373 | rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); |
380 | invalue = longhaul.bits.MaxMHzBR; | 374 | invalue = longhaul.bits.MaxMHzBR; |
381 | if (longhaul.bits.MaxMHzBR4) | 375 | if (longhaul.bits.MaxMHzBR4) |
382 | invalue += 16; | 376 | invalue += 16; |
383 | maxmult=ezra_t_multipliers[invalue]; | 377 | maxmult = mult = ezra_t_multipliers[invalue]; |
384 | |||
385 | invalue = longhaul.bits.MinMHzBR; | ||
386 | if (longhaul.bits.MinMHzBR4 == 1) | ||
387 | minmult = 30; | ||
388 | else | ||
389 | minmult = ezra_t_multipliers[invalue]; | ||
390 | fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; | ||
391 | break; | 378 | break; |
392 | } | 379 | } |
393 | 380 | ||
@@ -407,21 +394,16 @@ static int __init longhaul_get_ranges(void) | |||
407 | * But it works, so we don't grumble. | 394 | * But it works, so we don't grumble. |
408 | */ | 395 | */ |
409 | minmult=40; | 396 | minmult=40; |
410 | maxmult=longhaul_get_cpu_mult(); | 397 | maxmult = mult = longhaul_get_cpu_mult(); |
411 | |||
412 | /* Starting with the 1.2GHz parts, theres a 200MHz bus. */ | ||
413 | if ((cpu_khz/maxmult) > 13400) | ||
414 | fsb = 200; | ||
415 | else | ||
416 | fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; | ||
417 | break; | 398 | break; |
418 | } | 399 | } |
419 | } | 400 | } |
401 | fsb = guess_fsb(mult); | ||
420 | 402 | ||
421 | dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", | 403 | dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", |
422 | minmult/10, minmult%10, maxmult/10, maxmult%10); | 404 | minmult/10, minmult%10, maxmult/10, maxmult%10); |
423 | 405 | ||
424 | if (fsb == -1) { | 406 | if (fsb == 0) { |
425 | printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); | 407 | printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); |
426 | return -EINVAL; | 408 | return -EINVAL; |
427 | } | 409 | } |
@@ -429,7 +411,7 @@ static int __init longhaul_get_ranges(void) | |||
429 | highest_speed = calc_speed(maxmult); | 411 | highest_speed = calc_speed(maxmult); |
430 | lowest_speed = calc_speed(minmult); | 412 | lowest_speed = calc_speed(minmult); |
431 | dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, | 413 | dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, |
432 | print_speed(lowest_speed/1000), | 414 | print_speed(lowest_speed/1000), |
433 | print_speed(highest_speed/1000)); | 415 | print_speed(highest_speed/1000)); |
434 | 416 | ||
435 | if (lowest_speed == highest_speed) { | 417 | if (lowest_speed == highest_speed) { |
@@ -513,7 +495,7 @@ static void __init longhaul_setup_voltagescaling(void) | |||
513 | maxvid.mV/1000, maxvid.mV%1000, | 495 | maxvid.mV/1000, maxvid.mV%1000, |
514 | minvid.mV/1000, minvid.mV%1000, | 496 | minvid.mV/1000, minvid.mV%1000, |
515 | numvscales); | 497 | numvscales); |
516 | 498 | ||
517 | j = 0; | 499 | j = 0; |
518 | while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { | 500 | while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { |
519 | speed = longhaul_table[j].frequency; | 501 | speed = longhaul_table[j].frequency; |
@@ -691,27 +673,32 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
691 | /* Find ACPI data for processor */ | 673 | /* Find ACPI data for processor */ |
692 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | 674 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
693 | &longhaul_walk_callback, NULL, (void *)&pr); | 675 | &longhaul_walk_callback, NULL, (void *)&pr); |
694 | if (pr == NULL) | ||
695 | goto err_acpi; | ||
696 | 676 | ||
697 | if (longhaul_version == TYPE_POWERSAVER) { | 677 | /* Check ACPI support for C3 state */ |
698 | /* Check ACPI support for C3 state */ | 678 | if ((pr != NULL) && (longhaul_version == TYPE_POWERSAVER)) { |
699 | cx = &pr->power.states[ACPI_STATE_C3]; | 679 | cx = &pr->power.states[ACPI_STATE_C3]; |
700 | if (cx->address > 0 && | 680 | if (cx->address > 0 && |
701 | (cx->latency <= 1000 || ignore_latency != 0) ) { | 681 | (cx->latency <= 1000 || ignore_latency != 0) ) { |
682 | longhaul_flags |= USE_ACPI_C3; | ||
702 | goto print_support_type; | 683 | goto print_support_type; |
703 | } | 684 | } |
704 | } | 685 | } |
686 | /* Check if northbridge is friendly */ | ||
687 | if (enable_arbiter_disable()) { | ||
688 | longhaul_flags |= USE_NORTHBRIDGE; | ||
689 | goto print_support_type; | ||
690 | } | ||
691 | |||
692 | /* No ACPI C3 or we can't use it */ | ||
705 | /* Check ACPI support for bus master arbiter disable */ | 693 | /* Check ACPI support for bus master arbiter disable */ |
706 | if (!pr->flags.bm_control) { | 694 | if ((pr == NULL) || !(pr->flags.bm_control)) { |
707 | if (enable_arbiter_disable()) { | 695 | printk(KERN_ERR PFX |
708 | port22_en = 1; | 696 | "No ACPI support. Unsupported northbridge.\n"); |
709 | } else { | 697 | return -ENODEV; |
710 | goto err_acpi; | ||
711 | } | ||
712 | } | 698 | } |
699 | |||
713 | print_support_type: | 700 | print_support_type: |
714 | if (!port22_en) { | 701 | if (!(longhaul_flags & USE_NORTHBRIDGE)) { |
715 | printk (KERN_INFO PFX "Using ACPI support.\n"); | 702 | printk (KERN_INFO PFX "Using ACPI support.\n"); |
716 | } else { | 703 | } else { |
717 | printk (KERN_INFO PFX "Using northbridge support.\n"); | 704 | printk (KERN_INFO PFX "Using northbridge support.\n"); |
@@ -736,10 +723,6 @@ print_support_type: | |||
736 | cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); | 723 | cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); |
737 | 724 | ||
738 | return 0; | 725 | return 0; |
739 | |||
740 | err_acpi: | ||
741 | printk(KERN_ERR PFX "No ACPI support. Unsupported northbridge. Aborting.\n"); | ||
742 | return -ENODEV; | ||
743 | } | 726 | } |
744 | 727 | ||
745 | static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) | 728 | static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) |
@@ -774,8 +757,8 @@ static int __init longhaul_init(void) | |||
774 | 757 | ||
775 | #ifdef CONFIG_SMP | 758 | #ifdef CONFIG_SMP |
776 | if (num_online_cpus() > 1) { | 759 | if (num_online_cpus() > 1) { |
777 | return -ENODEV; | ||
778 | printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); | 760 | printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); |
761 | return -ENODEV; | ||
779 | } | 762 | } |
780 | #endif | 763 | #endif |
781 | #ifdef CONFIG_X86_IO_APIC | 764 | #ifdef CONFIG_X86_IO_APIC |
@@ -787,8 +770,10 @@ static int __init longhaul_init(void) | |||
787 | switch (c->x86_model) { | 770 | switch (c->x86_model) { |
788 | case 6 ... 9: | 771 | case 6 ... 9: |
789 | return cpufreq_register_driver(&longhaul_driver); | 772 | return cpufreq_register_driver(&longhaul_driver); |
773 | case 10: | ||
774 | printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n"); | ||
790 | default: | 775 | default: |
791 | printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n"); | 776 | ;; |
792 | } | 777 | } |
793 | 778 | ||
794 | return -ENODEV; | 779 | return -ENODEV; |