aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c145
1 files changed, 96 insertions, 49 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index ff4829666472..dde4e3149179 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -29,6 +29,7 @@
29#include <linux/pci.h> 29#include <linux/pci.h>
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/string.h> 31#include <linux/string.h>
32#include <linux/delay.h>
32 33
33#include <asm/msr.h> 34#include <asm/msr.h>
34#include <asm/timex.h> 35#include <asm/timex.h>
@@ -62,11 +63,6 @@ static unsigned int fsb;
62 63
63static const struct mV_pos *vrm_mV_table; 64static const struct mV_pos *vrm_mV_table;
64static const unsigned char *mV_vrm_table; 65static const unsigned char *mV_vrm_table;
65struct f_msr {
66 u8 vrm;
67 u8 pos;
68};
69static struct f_msr f_msr_table[32];
70 66
71static unsigned int highest_speed, lowest_speed; /* kHz */ 67static unsigned int highest_speed, lowest_speed; /* kHz */
72static unsigned int minmult, maxmult; 68static unsigned int minmult, maxmult;
@@ -74,7 +70,7 @@ static int can_scale_voltage;
74static struct acpi_processor *pr = NULL; 70static struct acpi_processor *pr = NULL;
75static struct acpi_processor_cx *cx = NULL; 71static struct acpi_processor_cx *cx = NULL;
76static u8 longhaul_flags; 72static u8 longhaul_flags;
77static u8 longhaul_pos; 73static unsigned int longhaul_index;
78 74
79/* Module parameters */ 75/* Module parameters */
80static int scale_voltage; 76static int scale_voltage;
@@ -87,7 +83,6 @@ static int clock_ratio[32];
87static int eblcr_table[32]; 83static int eblcr_table[32];
88static int longhaul_version; 84static int longhaul_version;
89static struct cpufreq_frequency_table *longhaul_table; 85static struct cpufreq_frequency_table *longhaul_table;
90static unsigned int old_ratio = -1;
91 86
92#ifdef CONFIG_CPU_FREQ_DEBUG 87#ifdef CONFIG_CPU_FREQ_DEBUG
93static char speedbuffer[8]; 88static char speedbuffer[8];
@@ -144,7 +139,7 @@ static void do_longhaul1(unsigned int clock_ratio_index)
144 rdmsrl(MSR_VIA_BCR2, bcr2.val); 139 rdmsrl(MSR_VIA_BCR2, bcr2.val);
145 /* Enable software clock multiplier */ 140 /* Enable software clock multiplier */
146 bcr2.bits.ESOFTBF = 1; 141 bcr2.bits.ESOFTBF = 1;
147 bcr2.bits.CLOCKMUL = clock_ratio_index; 142 bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff;
148 143
149 /* Sync to timer tick */ 144 /* Sync to timer tick */
150 safe_halt(); 145 safe_halt();
@@ -163,14 +158,12 @@ static void do_longhaul1(unsigned int clock_ratio_index)
163 158
164/* For processor with Longhaul MSR */ 159/* For processor with Longhaul MSR */
165 160
166static void do_powersaver(int cx_address, unsigned int clock_ratio_index) 161static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
162 unsigned int dir)
167{ 163{
168 union msr_longhaul longhaul; 164 union msr_longhaul longhaul;
169 u8 dest_pos;
170 u32 t; 165 u32 t;
171 166
172 dest_pos = f_msr_table[clock_ratio_index].pos;
173
174 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); 167 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
175 /* Setup new frequency */ 168 /* Setup new frequency */
176 longhaul.bits.RevisionKey = longhaul.bits.RevisionID; 169 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
@@ -178,11 +171,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
178 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; 171 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
179 /* Setup new voltage */ 172 /* Setup new voltage */
180 if (can_scale_voltage) 173 if (can_scale_voltage)
181 longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; 174 longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f;
182 /* Sync to timer tick */ 175 /* Sync to timer tick */
183 safe_halt(); 176 safe_halt();
184 /* Raise voltage if necessary */ 177 /* Raise voltage if necessary */
185 if (can_scale_voltage && longhaul_pos < dest_pos) { 178 if (can_scale_voltage && dir) {
186 longhaul.bits.EnableSoftVID = 1; 179 longhaul.bits.EnableSoftVID = 1;
187 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 180 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
188 /* Change voltage */ 181 /* Change voltage */
@@ -199,7 +192,6 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
199 } 192 }
200 longhaul.bits.EnableSoftVID = 0; 193 longhaul.bits.EnableSoftVID = 0;
201 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 194 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
202 longhaul_pos = dest_pos;
203 } 195 }
204 196
205 /* Change frequency on next halt or sleep */ 197 /* Change frequency on next halt or sleep */
@@ -220,7 +212,7 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
220 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 212 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
221 213
222 /* Reduce voltage if necessary */ 214 /* Reduce voltage if necessary */
223 if (can_scale_voltage && longhaul_pos > dest_pos) { 215 if (can_scale_voltage && !dir) {
224 longhaul.bits.EnableSoftVID = 1; 216 longhaul.bits.EnableSoftVID = 1;
225 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 217 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
226 /* Change voltage */ 218 /* Change voltage */
@@ -237,7 +229,6 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
237 } 229 }
238 longhaul.bits.EnableSoftVID = 0; 230 longhaul.bits.EnableSoftVID = 0;
239 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 231 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
240 longhaul_pos = dest_pos;
241 } 232 }
242} 233}
243 234
@@ -248,26 +239,28 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
248 * Sets a new clock ratio. 239 * Sets a new clock ratio.
249 */ 240 */
250 241
251static void longhaul_setstate(unsigned int clock_ratio_index) 242static void longhaul_setstate(unsigned int table_index)
252{ 243{
244 unsigned int clock_ratio_index;
253 int speed, mult; 245 int speed, mult;
254 struct cpufreq_freqs freqs; 246 struct cpufreq_freqs freqs;
255 unsigned long flags; 247 unsigned long flags;
256 unsigned int pic1_mask, pic2_mask; 248 unsigned int pic1_mask, pic2_mask;
257 u32 bm_status = 0; 249 u32 bm_status = 0;
258 u32 bm_timeout = 100000; 250 u32 bm_timeout = 100000;
251 unsigned int dir = 0;
259 252
260 if (old_ratio == clock_ratio_index) 253 clock_ratio_index = longhaul_table[table_index].index;
261 return; 254 /* Safety precautions */
262 old_ratio = clock_ratio_index; 255 mult = clock_ratio[clock_ratio_index & 0x1f];
263
264 mult = clock_ratio[clock_ratio_index];
265 if (mult == -1) 256 if (mult == -1)
266 return; 257 return;
267
268 speed = calc_speed(mult); 258 speed = calc_speed(mult);
269 if ((speed > highest_speed) || (speed < lowest_speed)) 259 if ((speed > highest_speed) || (speed < lowest_speed))
270 return; 260 return;
261 /* Voltage transition before frequency transition? */
262 if (can_scale_voltage && longhaul_index < table_index)
263 dir = 1;
271 264
272 freqs.old = calc_speed(longhaul_get_cpu_mult()); 265 freqs.old = calc_speed(longhaul_get_cpu_mult());
273 freqs.new = speed; 266 freqs.new = speed;
@@ -302,7 +295,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
302 /* Disable AGP and PCI arbiters */ 295 /* Disable AGP and PCI arbiters */
303 outb(3, 0x22); 296 outb(3, 0x22);
304 } else if ((pr != NULL) && pr->flags.bm_control) { 297 } else if ((pr != NULL) && pr->flags.bm_control) {
305 /* Disable bus master arbitration */ 298 /* Disable bus master arbitration */
306 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); 299 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
307 } 300 }
308 switch (longhaul_version) { 301 switch (longhaul_version) {
@@ -327,9 +320,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
327 if (longhaul_flags & USE_ACPI_C3) { 320 if (longhaul_flags & USE_ACPI_C3) {
328 /* Don't allow wakeup */ 321 /* Don't allow wakeup */
329 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); 322 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
330 do_powersaver(cx->address, clock_ratio_index); 323 do_powersaver(cx->address, clock_ratio_index, dir);
331 } else { 324 } else {
332 do_powersaver(0, clock_ratio_index); 325 do_powersaver(0, clock_ratio_index, dir);
333 } 326 }
334 break; 327 break;
335 } 328 }
@@ -386,7 +379,8 @@ static int guess_fsb(int mult)
386 379
387static int __init longhaul_get_ranges(void) 380static int __init longhaul_get_ranges(void)
388{ 381{
389 unsigned int j, k = 0; 382 unsigned int i, j, k = 0;
383 unsigned int ratio;
390 int mult; 384 int mult;
391 385
392 /* Get current frequency */ 386 /* Get current frequency */
@@ -440,8 +434,7 @@ static int __init longhaul_get_ranges(void)
440 if(!longhaul_table) 434 if(!longhaul_table)
441 return -ENOMEM; 435 return -ENOMEM;
442 436
443 for (j=0; j < numscales; j++) { 437 for (j = 0; j < numscales; j++) {
444 unsigned int ratio;
445 ratio = clock_ratio[j]; 438 ratio = clock_ratio[j];
446 if (ratio == -1) 439 if (ratio == -1)
447 continue; 440 continue;
@@ -451,13 +444,41 @@ static int __init longhaul_get_ranges(void)
451 longhaul_table[k].index = j; 444 longhaul_table[k].index = j;
452 k++; 445 k++;
453 } 446 }
447 if (k <= 1) {
448 kfree(longhaul_table);
449 return -ENODEV;
450 }
451 /* Sort */
452 for (j = 0; j < k - 1; j++) {
453 unsigned int min_f, min_i;
454 min_f = longhaul_table[j].frequency;
455 min_i = j;
456 for (i = j + 1; i < k; i++) {
457 if (longhaul_table[i].frequency < min_f) {
458 min_f = longhaul_table[i].frequency;
459 min_i = i;
460 }
461 }
462 if (min_i != j) {
463 unsigned int temp;
464 temp = longhaul_table[j].frequency;
465 longhaul_table[j].frequency = longhaul_table[min_i].frequency;
466 longhaul_table[min_i].frequency = temp;
467 temp = longhaul_table[j].index;
468 longhaul_table[j].index = longhaul_table[min_i].index;
469 longhaul_table[min_i].index = temp;
470 }
471 }
454 472
455 longhaul_table[k].frequency = CPUFREQ_TABLE_END; 473 longhaul_table[k].frequency = CPUFREQ_TABLE_END;
456 if (!k) {
457 kfree (longhaul_table);
458 return -EINVAL;
459 }
460 474
475 /* Find index we are running on */
476 for (j = 0; j < k; j++) {
477 if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) {
478 longhaul_index = j;
479 break;
480 }
481 }
461 return 0; 482 return 0;
462} 483}
463 484
@@ -465,7 +486,7 @@ static int __init longhaul_get_ranges(void)
465static void __init longhaul_setup_voltagescaling(void) 486static void __init longhaul_setup_voltagescaling(void)
466{ 487{
467 union msr_longhaul longhaul; 488 union msr_longhaul longhaul;
468 struct mV_pos minvid, maxvid; 489 struct mV_pos minvid, maxvid, vid;
469 unsigned int j, speed, pos, kHz_step, numvscales; 490 unsigned int j, speed, pos, kHz_step, numvscales;
470 int min_vid_speed; 491 int min_vid_speed;
471 492
@@ -476,11 +497,11 @@ static void __init longhaul_setup_voltagescaling(void)
476 } 497 }
477 498
478 if (!longhaul.bits.VRMRev) { 499 if (!longhaul.bits.VRMRev) {
479 printk (KERN_INFO PFX "VRM 8.5\n"); 500 printk(KERN_INFO PFX "VRM 8.5\n");
480 vrm_mV_table = &vrm85_mV[0]; 501 vrm_mV_table = &vrm85_mV[0];
481 mV_vrm_table = &mV_vrm85[0]; 502 mV_vrm_table = &mV_vrm85[0];
482 } else { 503 } else {
483 printk (KERN_INFO PFX "Mobile VRM\n"); 504 printk(KERN_INFO PFX "Mobile VRM\n");
484 if (cpu_model < CPU_NEHEMIAH) 505 if (cpu_model < CPU_NEHEMIAH)
485 return; 506 return;
486 vrm_mV_table = &mobilevrm_mV[0]; 507 vrm_mV_table = &mobilevrm_mV[0];
@@ -540,7 +561,6 @@ static void __init longhaul_setup_voltagescaling(void)
540 /* Calculate kHz for one voltage step */ 561 /* Calculate kHz for one voltage step */
541 kHz_step = (highest_speed - min_vid_speed) / numvscales; 562 kHz_step = (highest_speed - min_vid_speed) / numvscales;
542 563
543
544 j = 0; 564 j = 0;
545 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { 565 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
546 speed = longhaul_table[j].frequency; 566 speed = longhaul_table[j].frequency;
@@ -548,15 +568,14 @@ static void __init longhaul_setup_voltagescaling(void)
548 pos = (speed - min_vid_speed) / kHz_step + minvid.pos; 568 pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
549 else 569 else
550 pos = minvid.pos; 570 pos = minvid.pos;
551 f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos]; 571 longhaul_table[j].index |= mV_vrm_table[pos] << 8;
552 f_msr_table[longhaul_table[j].index].pos = pos; 572 vid = vrm_mV_table[mV_vrm_table[pos]];
573 printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV);
553 j++; 574 j++;
554 } 575 }
555 576
556 longhaul_pos = maxvid.pos;
557 can_scale_voltage = 1; 577 can_scale_voltage = 1;
558 printk(KERN_INFO PFX "Voltage scaling enabled. " 578 printk(KERN_INFO PFX "Voltage scaling enabled.\n");
559 "Use of \"conservative\" governor is highly recommended.\n");
560} 579}
561 580
562 581
@@ -570,15 +589,44 @@ static int longhaul_target(struct cpufreq_policy *policy,
570 unsigned int target_freq, unsigned int relation) 589 unsigned int target_freq, unsigned int relation)
571{ 590{
572 unsigned int table_index = 0; 591 unsigned int table_index = 0;
573 unsigned int new_clock_ratio = 0; 592 unsigned int i;
593 unsigned int dir = 0;
594 u8 vid, current_vid;
574 595
575 if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index)) 596 if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
576 return -EINVAL; 597 return -EINVAL;
577 598
578 new_clock_ratio = longhaul_table[table_index].index & 0xFF; 599 /* Don't set same frequency again */
579 600 if (longhaul_index == table_index)
580 longhaul_setstate(new_clock_ratio); 601 return 0;
581 602
603 if (!can_scale_voltage)
604 longhaul_setstate(table_index);
605 else {
606 /* On test system voltage transitions exceeding single
607 * step up or down were turning motherboard off. Both
608 * "ondemand" and "userspace" are unsafe. C7 is doing
609 * this in hardware, C3 is old and we need to do this
610 * in software. */
611 i = longhaul_index;
612 current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f;
613 if (table_index > longhaul_index)
614 dir = 1;
615 while (i != table_index) {
616 vid = (longhaul_table[i].index >> 8) & 0x1f;
617 if (vid != current_vid) {
618 longhaul_setstate(i);
619 current_vid = vid;
620 msleep(200);
621 }
622 if (dir)
623 i++;
624 else
625 i--;
626 }
627 longhaul_setstate(table_index);
628 }
629 longhaul_index = table_index;
582 return 0; 630 return 0;
583} 631}
584 632
@@ -607,11 +655,10 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
607static int enable_arbiter_disable(void) 655static int enable_arbiter_disable(void)
608{ 656{
609 struct pci_dev *dev; 657 struct pci_dev *dev;
610 int status; 658 int status = 1;
611 int reg; 659 int reg;
612 u8 pci_cmd; 660 u8 pci_cmd;
613 661
614 status = 1;
615 /* Find PLE133 host bridge */ 662 /* Find PLE133 host bridge */
616 reg = 0x78; 663 reg = 0x78;
617 dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, 664 dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,