aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu/cpufreq/longhaul.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/longhaul.c')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c131
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
55static int cpu_model; 59static int cpu_model;
56static unsigned int numscales=16; 60static unsigned int numscales=16;
57static unsigned int fsb; 61static unsigned int fsb;
@@ -68,7 +72,7 @@ static unsigned int minmult, maxmult;
68static int can_scale_voltage; 72static int can_scale_voltage;
69static struct acpi_processor *pr = NULL; 73static struct acpi_processor *pr = NULL;
70static struct acpi_processor_cx *cx = NULL; 74static struct acpi_processor_cx *cx = NULL;
71static int port22_en; 75static u8 longhaul_flags;
72 76
73/* Module parameters */ 77/* Module parameters */
74static int scale_voltage; 78static int scale_voltage;
@@ -80,7 +84,6 @@ static int ignore_latency;
80/* Clock ratios multiplied by 10 */ 84/* Clock ratios multiplied by 10 */
81static int clock_ratio[32]; 85static int clock_ratio[32];
82static int eblcr_table[32]; 86static int eblcr_table[32];
83static unsigned int highest_speed, lowest_speed; /* kHz */
84static int longhaul_version; 87static int longhaul_version;
85static struct cpufreq_frequency_table *longhaul_table; 88static 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
317static int _guess(int guess) 318static 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
330static int guess_fsb(void) 331static 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
713print_support_type: 700print_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
740err_acpi:
741 printk(KERN_ERR PFX "No ACPI support. Unsupported northbridge. Aborting.\n");
742 return -ENODEV;
743} 726}
744 727
745static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) 728static 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;