aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorRafał Bilski <rafalbilski@interia.pl>2007-02-08 12:56:04 -0500
committerDave Jones <davej@redhat.com>2007-02-10 20:05:50 -0500
commit348f31ed2bd18391fe5903aa0ad7bfcda6d8ca0b (patch)
tree1752aedc8f7780cef02688e4df386a93188c700b /arch/i386/kernel
parente57501c15f48d6b7a8fe2b023be8f4779484482d (diff)
[CPUFREQ] Longhaul - Separate frequency and voltage transition
This change should make Longhaul more compatible with both ver. 2 and Powersaver processors. Voltage transitions will be done before or after frequency transition. That depends on direction of change. I don't know how to force conservative governor when voltage scaling is enabled, so there is only a warning for user. Minimal voltage is calculated in different way now because in this way more power is saved at lower multipliers. Signed-off-by: Rafal Bilski <rafalbilski@interia.pl> Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c109
1 files changed, 93 insertions, 16 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index fc9afbb7c1fc..8f40cb47720e 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -65,7 +65,8 @@ static unsigned int fsb;
65static struct mV_pos *vrm_mV_table; 65static struct mV_pos *vrm_mV_table;
66static unsigned char *mV_vrm_table; 66static unsigned char *mV_vrm_table;
67struct f_msr { 67struct f_msr {
68 unsigned char vrm; 68 u8 vrm;
69 u8 pos;
69}; 70};
70static struct f_msr f_msr_table[32]; 71static struct f_msr f_msr_table[32];
71 72
@@ -75,6 +76,7 @@ static int can_scale_voltage;
75static struct acpi_processor *pr = NULL; 76static struct acpi_processor *pr = NULL;
76static struct acpi_processor_cx *cx = NULL; 77static struct acpi_processor_cx *cx = NULL;
77static u8 longhaul_flags; 78static u8 longhaul_flags;
79static u8 longhaul_pos;
78 80
79/* Module parameters */ 81/* Module parameters */
80static int scale_voltage; 82static int scale_voltage;
@@ -165,26 +167,47 @@ static void do_longhaul1(unsigned int clock_ratio_index)
165static void do_powersaver(int cx_address, unsigned int clock_ratio_index) 167static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
166{ 168{
167 union msr_longhaul longhaul; 169 union msr_longhaul longhaul;
170 u8 dest_pos;
168 u32 t; 171 u32 t;
169 172
173 dest_pos = f_msr_table[clock_ratio_index].pos;
174
170 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); 175 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
176 /* Setup new frequency */
171 longhaul.bits.RevisionKey = longhaul.bits.RevisionID; 177 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
172 longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; 178 longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
173 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; 179 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
174 longhaul.bits.EnableSoftBusRatio = 1; 180 /* Setup new voltage */
175 181 if (can_scale_voltage)
176 if (can_scale_voltage) {
177 longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm; 182 longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
183 /* Sync to timer tick */
184 safe_halt();
185 /* Raise voltage if necessary */
186 if (can_scale_voltage && longhaul_pos < dest_pos) {
178 longhaul.bits.EnableSoftVID = 1; 187 longhaul.bits.EnableSoftVID = 1;
188 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
189 /* Change voltage */
190 if (!cx_address) {
191 ACPI_FLUSH_CPU_CACHE();
192 halt();
193 } else {
194 ACPI_FLUSH_CPU_CACHE();
195 /* Invoke C3 */
196 inb(cx_address);
197 /* Dummy op - must do something useless after P_LVL3
198 * read */
199 t = inl(acpi_fadt.xpm_tmr_blk.address);
200 }
201 longhaul.bits.EnableSoftVID = 0;
202 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
203 longhaul_pos = dest_pos;
179 } 204 }
180 205
181 /* Sync to timer tick */
182 safe_halt();
183 /* Change frequency on next halt or sleep */ 206 /* Change frequency on next halt or sleep */
207 longhaul.bits.EnableSoftBusRatio = 1;
184 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 208 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
185 if (!cx_address) { 209 if (!cx_address) {
186 ACPI_FLUSH_CPU_CACHE(); 210 ACPI_FLUSH_CPU_CACHE();
187 /* Invoke C1 */
188 halt(); 211 halt();
189 } else { 212 } else {
190 ACPI_FLUSH_CPU_CACHE(); 213 ACPI_FLUSH_CPU_CACHE();
@@ -194,12 +217,29 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
194 t = inl(acpi_fadt.xpm_tmr_blk.address); 217 t = inl(acpi_fadt.xpm_tmr_blk.address);
195 } 218 }
196 /* Disable bus ratio bit */ 219 /* Disable bus ratio bit */
197 local_irq_disable();
198 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
199 longhaul.bits.EnableSoftBusRatio = 0; 220 longhaul.bits.EnableSoftBusRatio = 0;
200 longhaul.bits.EnableSoftBSEL = 0;
201 longhaul.bits.EnableSoftVID = 0;
202 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 221 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
222
223 /* Reduce voltage if necessary */
224 if (can_scale_voltage && longhaul_pos > dest_pos) {
225 longhaul.bits.EnableSoftVID = 1;
226 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
227 /* Change voltage */
228 if (!cx_address) {
229 ACPI_FLUSH_CPU_CACHE();
230 halt();
231 } else {
232 ACPI_FLUSH_CPU_CACHE();
233 /* Invoke C3 */
234 inb(cx_address);
235 /* Dummy op - must do something useless after P_LVL3
236 * read */
237 t = inl(acpi_fadt.xpm_tmr_blk.address);
238 }
239 longhaul.bits.EnableSoftVID = 0;
240 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
241 longhaul_pos = dest_pos;
242 }
203} 243}
204 244
205/** 245/**
@@ -420,6 +460,7 @@ static void __init longhaul_setup_voltagescaling(void)
420 union msr_longhaul longhaul; 460 union msr_longhaul longhaul;
421 struct mV_pos minvid, maxvid; 461 struct mV_pos minvid, maxvid;
422 unsigned int j, speed, pos, kHz_step, numvscales; 462 unsigned int j, speed, pos, kHz_step, numvscales;
463 int min_vid_speed;
423 464
424 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); 465 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
425 if (!(longhaul.bits.RevisionID & 1)) { 466 if (!(longhaul.bits.RevisionID & 1)) {
@@ -439,8 +480,6 @@ static void __init longhaul_setup_voltagescaling(void)
439 480
440 minvid = vrm_mV_table[longhaul.bits.MinimumVID]; 481 minvid = vrm_mV_table[longhaul.bits.MinimumVID];
441 maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; 482 maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
442 numvscales = maxvid.pos - minvid.pos + 1;
443 kHz_step = (highest_speed - lowest_speed) / numvscales;
444 483
445 if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { 484 if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
446 printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " 485 printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
@@ -456,20 +495,58 @@ static void __init longhaul_setup_voltagescaling(void)
456 return; 495 return;
457 } 496 }
458 497
459 printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n", 498 /* How many voltage steps */
499 numvscales = maxvid.pos - minvid.pos + 1;
500 printk(KERN_INFO PFX
501 "Max VID=%d.%03d "
502 "Min VID=%d.%03d, "
503 "%d possible voltage scales\n",
460 maxvid.mV/1000, maxvid.mV%1000, 504 maxvid.mV/1000, maxvid.mV%1000,
461 minvid.mV/1000, minvid.mV%1000, 505 minvid.mV/1000, minvid.mV%1000,
462 numvscales); 506 numvscales);
463 507
508 /* Calculate max frequency at min voltage */
509 j = longhaul.bits.MinMHzBR;
510 if (longhaul.bits.MinMHzBR4)
511 j += 16;
512 min_vid_speed = eblcr_table[j];
513 if (min_vid_speed == -1)
514 return;
515 switch (longhaul.bits.MinMHzFSB) {
516 case 0:
517 min_vid_speed *= 13333;
518 break;
519 case 1:
520 min_vid_speed *= 10000;
521 break;
522 case 3:
523 min_vid_speed *= 6666;
524 break;
525 default:
526 return;
527 break;
528 }
529 if (min_vid_speed >= highest_speed)
530 return;
531 /* Calculate kHz for one voltage step */
532 kHz_step = (highest_speed - min_vid_speed) / numvscales;
533
464 j = 0; 534 j = 0;
465 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { 535 while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
466 speed = longhaul_table[j].frequency; 536 speed = longhaul_table[j].frequency;
467 pos = (speed - lowest_speed) / kHz_step + minvid.pos; 537 if (speed > min_vid_speed)
538 pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
539 else
540 pos = minvid.pos;
468 f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos]; 541 f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
542 f_msr_table[longhaul_table[j].index].pos = pos;
469 j++; 543 j++;
470 } 544 }
471 545
546 longhaul_pos = maxvid.pos;
472 can_scale_voltage = 1; 547 can_scale_voltage = 1;
548 printk(KERN_INFO PFX "Voltage scaling enabled. "
549 "Use of \"conservative\" governor is highly recommended.\n");
473} 550}
474 551
475 552