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.c128
1 files changed, 60 insertions, 68 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 7233abe5d695..e940e00b96c9 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();
@@ -189,7 +192,6 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
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_fadt.xpm_tmr_blk.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,14 @@ 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) {
249 /* Disable AGP and PCI arbiters */
250 outb(3, 0x22);
251 } else if ((pr != NULL) && pr->flags.bm_control) {
247 /* Disable bus master arbitration */ 252 /* Disable bus master arbitration */
248 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, 253 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
249 ACPI_MTX_DO_NOT_LOCK); 254 ACPI_MTX_DO_NOT_LOCK);
250 } else if (port22_en) {
251 /* Disable AGP and PCI arbiters */
252 outb(3, 0x22);
253 } 255 }
254
255 switch (longhaul_version) { 256 switch (longhaul_version) {
256 257
257 /* 258 /*
@@ -278,22 +279,25 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
278 * to work in practice. 279 * to work in practice.
279 */ 280 */
280 case TYPE_POWERSAVER: 281 case TYPE_POWERSAVER:
281 /* Don't allow wakeup */ 282 if (longhaul_flags & USE_ACPI_C3) {
282 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, 283 /* Don't allow wakeup */
283 ACPI_MTX_DO_NOT_LOCK); 284 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
284 do_powersaver(cx->address, clock_ratio_index); 285 ACPI_MTX_DO_NOT_LOCK);
286 do_powersaver(cx->address, clock_ratio_index);
287 } else {
288 do_powersaver(0, clock_ratio_index);
289 }
285 break; 290 break;
286 } 291 }
287 292
288 if (pr->flags.bm_control) { 293 if (longhaul_flags & USE_NORTHBRIDGE) {
294 /* Enable arbiters */
295 outb(0, 0x22);
296 } else if ((pr != NULL) && pr->flags.bm_control) {
289 /* Enable bus master arbitration */ 297 /* Enable bus master arbitration */
290 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, 298 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
291 ACPI_MTX_DO_NOT_LOCK); 299 ACPI_MTX_DO_NOT_LOCK);
292 } else if (port22_en) {
293 /* Enable arbiters */
294 outb(0, 0x22);
295 } 300 }
296
297 outb(pic2_mask,0xA1); /* restore mask */ 301 outb(pic2_mask,0xA1); /* restore mask */
298 outb(pic1_mask,0x21); 302 outb(pic1_mask,0x21);
299 303
@@ -314,12 +318,12 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
314 318
315#define ROUNDING 0xf 319#define ROUNDING 0xf
316 320
317static int _guess(int guess) 321static int _guess(int guess, int mult)
318{ 322{
319 int target; 323 int target;
320 324
321 target = ((maxmult/10)*guess); 325 target = ((mult/10)*guess);
322 if (maxmult%10 != 0) 326 if (mult%10 != 0)
323 target += (guess/2); 327 target += (guess/2);
324 target += ROUNDING/2; 328 target += ROUNDING/2;
325 target &= ~ROUNDING; 329 target &= ~ROUNDING;
@@ -327,17 +331,17 @@ static int _guess(int guess)
327} 331}
328 332
329 333
330static int guess_fsb(void) 334static int guess_fsb(int mult)
331{ 335{
332 int speed = (cpu_khz/1000); 336 int speed = (cpu_khz/1000);
333 int i; 337 int i;
334 int speeds[3] = { 66, 100, 133 }; 338 int speeds[] = { 66, 100, 133, 200 };
335 339
336 speed += ROUNDING/2; 340 speed += ROUNDING/2;
337 speed &= ~ROUNDING; 341 speed &= ~ROUNDING;
338 342
339 for (i=0; i<3; i++) { 343 for (i=0; i<4; i++) {
340 if (_guess(speeds[i]) == speed) 344 if (_guess(speeds[i], mult) == speed)
341 return speeds[i]; 345 return speeds[i];
342 } 346 }
343 return 0; 347 return 0;
@@ -354,9 +358,7 @@ static int __init longhaul_get_ranges(void)
354 130, 150, 160, 140, -1, 155, -1, 145 }; 358 130, 150, 160, 140, -1, 155, -1, 145 };
355 unsigned int j, k = 0; 359 unsigned int j, k = 0;
356 union msr_longhaul longhaul; 360 union msr_longhaul longhaul;
357 unsigned long lo, hi; 361 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 362
361 switch (longhaul_version) { 363 switch (longhaul_version) {
362 case TYPE_LONGHAUL_V1: 364 case TYPE_LONGHAUL_V1:
@@ -364,30 +366,18 @@ static int __init longhaul_get_ranges(void)
364 /* Ugh, Longhaul v1 didn't have the min/max MSRs. 366 /* Ugh, Longhaul v1 didn't have the min/max MSRs.
365 Assume min=3.0x & max = whatever we booted at. */ 367 Assume min=3.0x & max = whatever we booted at. */
366 minmult = 30; 368 minmult = 30;
367 maxmult = longhaul_get_cpu_mult(); 369 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; 370 break;
375 371
376 case TYPE_POWERSAVER: 372 case TYPE_POWERSAVER:
377 /* Ezra-T */ 373 /* Ezra-T */
378 if (cpu_model==CPU_EZRA_T) { 374 if (cpu_model==CPU_EZRA_T) {
375 minmult = 30;
379 rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); 376 rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
380 invalue = longhaul.bits.MaxMHzBR; 377 invalue = longhaul.bits.MaxMHzBR;
381 if (longhaul.bits.MaxMHzBR4) 378 if (longhaul.bits.MaxMHzBR4)
382 invalue += 16; 379 invalue += 16;
383 maxmult=ezra_t_multipliers[invalue]; 380 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; 381 break;
392 } 382 }
393 383
@@ -407,21 +397,16 @@ static int __init longhaul_get_ranges(void)
407 * But it works, so we don't grumble. 397 * But it works, so we don't grumble.
408 */ 398 */
409 minmult=40; 399 minmult=40;
410 maxmult=longhaul_get_cpu_mult(); 400 maxmult = mult = longhaul_get_cpu_mult();
411
412 /* Starting with the 1.2GHz parts, theres a 200MHz bus. */
413 if ((cpu_khz/1000) > 1200)
414 fsb = 200;
415 else
416 fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
417 break; 401 break;
418 } 402 }
419 } 403 }
404 fsb = guess_fsb(mult);
420 405
421 dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", 406 dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n",
422 minmult/10, minmult%10, maxmult/10, maxmult%10); 407 minmult/10, minmult%10, maxmult/10, maxmult%10);
423 408
424 if (fsb == -1) { 409 if (fsb == 0) {
425 printk (KERN_INFO PFX "Invalid (reserved) FSB!\n"); 410 printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
426 return -EINVAL; 411 return -EINVAL;
427 } 412 }
@@ -583,6 +568,10 @@ static int enable_arbiter_disable(void)
583 if (dev == NULL) { 568 if (dev == NULL) {
584 reg = 0x76; 569 reg = 0x76;
585 dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL); 570 dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL);
571 /* Find CN400 V-Link host bridge */
572 if (dev == NULL)
573 dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
574
586 } 575 }
587 if (dev != NULL) { 576 if (dev != NULL) {
588 /* Enable access to port 0x22 */ 577 /* Enable access to port 0x22 */
@@ -687,27 +676,32 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
687 /* Find ACPI data for processor */ 676 /* Find ACPI data for processor */
688 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 677 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
689 &longhaul_walk_callback, NULL, (void *)&pr); 678 &longhaul_walk_callback, NULL, (void *)&pr);
690 if (pr == NULL)
691 goto err_acpi;
692 679
693 if (longhaul_version == TYPE_POWERSAVER) { 680 /* Check ACPI support for C3 state */
694 /* Check ACPI support for C3 state */ 681 if ((pr != NULL) && (longhaul_version == TYPE_POWERSAVER)) {
695 cx = &pr->power.states[ACPI_STATE_C3]; 682 cx = &pr->power.states[ACPI_STATE_C3];
696 if (cx->address > 0 && 683 if (cx->address > 0 &&
697 (cx->latency <= 1000 || ignore_latency != 0) ) { 684 (cx->latency <= 1000 || ignore_latency != 0) ) {
685 longhaul_flags |= USE_ACPI_C3;
698 goto print_support_type; 686 goto print_support_type;
699 } 687 }
700 } 688 }
689 /* Check if northbridge is friendly */
690 if (enable_arbiter_disable()) {
691 longhaul_flags |= USE_NORTHBRIDGE;
692 goto print_support_type;
693 }
694
695 /* No ACPI C3 or we can't use it */
701 /* Check ACPI support for bus master arbiter disable */ 696 /* Check ACPI support for bus master arbiter disable */
702 if (!pr->flags.bm_control) { 697 if ((pr == NULL) || !(pr->flags.bm_control)) {
703 if (enable_arbiter_disable()) { 698 printk(KERN_ERR PFX
704 port22_en = 1; 699 "No ACPI support. Unsupported northbridge.\n");
705 } else { 700 return -ENODEV;
706 goto err_acpi;
707 }
708 } 701 }
702
709print_support_type: 703print_support_type:
710 if (!port22_en) { 704 if (!(longhaul_flags & USE_NORTHBRIDGE)) {
711 printk (KERN_INFO PFX "Using ACPI support.\n"); 705 printk (KERN_INFO PFX "Using ACPI support.\n");
712 } else { 706 } else {
713 printk (KERN_INFO PFX "Using northbridge support.\n"); 707 printk (KERN_INFO PFX "Using northbridge support.\n");
@@ -732,10 +726,6 @@ print_support_type:
732 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); 726 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
733 727
734 return 0; 728 return 0;
735
736err_acpi:
737 printk(KERN_ERR PFX "No ACPI support. No VT8601 or VT8623 northbridge. Aborting.\n");
738 return -ENODEV;
739} 729}
740 730
741static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) 731static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
@@ -770,8 +760,8 @@ static int __init longhaul_init(void)
770 760
771#ifdef CONFIG_SMP 761#ifdef CONFIG_SMP
772 if (num_online_cpus() > 1) { 762 if (num_online_cpus() > 1) {
773 return -ENODEV;
774 printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); 763 printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
764 return -ENODEV;
775 } 765 }
776#endif 766#endif
777#ifdef CONFIG_X86_IO_APIC 767#ifdef CONFIG_X86_IO_APIC
@@ -783,8 +773,10 @@ static int __init longhaul_init(void)
783 switch (c->x86_model) { 773 switch (c->x86_model) {
784 case 6 ... 9: 774 case 6 ... 9:
785 return cpufreq_register_driver(&longhaul_driver); 775 return cpufreq_register_driver(&longhaul_driver);
776 case 10:
777 printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n");
786 default: 778 default:
787 printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n"); 779 ;;
788 } 780 }
789 781
790 return -ENODEV; 782 return -ENODEV;