mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
[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>
This commit is contained in:
parent
e57501c15f
commit
348f31ed2b
1 changed files with 94 additions and 17 deletions
|
@ -65,7 +65,8 @@ static unsigned int fsb;
|
|||
static struct mV_pos *vrm_mV_table;
|
||||
static unsigned char *mV_vrm_table;
|
||||
struct f_msr {
|
||||
unsigned char vrm;
|
||||
u8 vrm;
|
||||
u8 pos;
|
||||
};
|
||||
static struct f_msr f_msr_table[32];
|
||||
|
||||
|
@ -75,6 +76,7 @@ static int can_scale_voltage;
|
|||
static struct acpi_processor *pr = NULL;
|
||||
static struct acpi_processor_cx *cx = NULL;
|
||||
static u8 longhaul_flags;
|
||||
static u8 longhaul_pos;
|
||||
|
||||
/* Module parameters */
|
||||
static int scale_voltage;
|
||||
|
@ -165,26 +167,47 @@ static void do_longhaul1(unsigned int clock_ratio_index)
|
|||
static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
|
||||
{
|
||||
union msr_longhaul longhaul;
|
||||
u8 dest_pos;
|
||||
u32 t;
|
||||
|
||||
dest_pos = f_msr_table[clock_ratio_index].pos;
|
||||
|
||||
rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
/* Setup new frequency */
|
||||
longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
|
||||
longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
|
||||
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
|
||||
longhaul.bits.EnableSoftBusRatio = 1;
|
||||
|
||||
if (can_scale_voltage) {
|
||||
/* Setup new voltage */
|
||||
if (can_scale_voltage)
|
||||
longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
|
||||
longhaul.bits.EnableSoftVID = 1;
|
||||
}
|
||||
|
||||
/* Sync to timer tick */
|
||||
safe_halt();
|
||||
/* Raise voltage if necessary */
|
||||
if (can_scale_voltage && longhaul_pos < dest_pos) {
|
||||
longhaul.bits.EnableSoftVID = 1;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
/* Change voltage */
|
||||
if (!cx_address) {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
halt();
|
||||
} else {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
/* Invoke C3 */
|
||||
inb(cx_address);
|
||||
/* Dummy op - must do something useless after P_LVL3
|
||||
* read */
|
||||
t = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
}
|
||||
longhaul.bits.EnableSoftVID = 0;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
longhaul_pos = dest_pos;
|
||||
}
|
||||
|
||||
/* Change frequency on next halt or sleep */
|
||||
longhaul.bits.EnableSoftBusRatio = 1;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
if (!cx_address) {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
/* Invoke C1 */
|
||||
halt();
|
||||
} else {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
|
@ -194,12 +217,29 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
|
|||
t = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
}
|
||||
/* Disable bus ratio bit */
|
||||
local_irq_disable();
|
||||
longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
|
||||
longhaul.bits.EnableSoftBusRatio = 0;
|
||||
longhaul.bits.EnableSoftBSEL = 0;
|
||||
longhaul.bits.EnableSoftVID = 0;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
|
||||
/* Reduce voltage if necessary */
|
||||
if (can_scale_voltage && longhaul_pos > dest_pos) {
|
||||
longhaul.bits.EnableSoftVID = 1;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
/* Change voltage */
|
||||
if (!cx_address) {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
halt();
|
||||
} else {
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
/* Invoke C3 */
|
||||
inb(cx_address);
|
||||
/* Dummy op - must do something useless after P_LVL3
|
||||
* read */
|
||||
t = inl(acpi_fadt.xpm_tmr_blk.address);
|
||||
}
|
||||
longhaul.bits.EnableSoftVID = 0;
|
||||
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
longhaul_pos = dest_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,6 +460,7 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
union msr_longhaul longhaul;
|
||||
struct mV_pos minvid, maxvid;
|
||||
unsigned int j, speed, pos, kHz_step, numvscales;
|
||||
int min_vid_speed;
|
||||
|
||||
rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
|
||||
if (!(longhaul.bits.RevisionID & 1)) {
|
||||
|
@ -439,8 +480,6 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
|
||||
minvid = vrm_mV_table[longhaul.bits.MinimumVID];
|
||||
maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
|
||||
numvscales = maxvid.pos - minvid.pos + 1;
|
||||
kHz_step = (highest_speed - lowest_speed) / numvscales;
|
||||
|
||||
if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
|
||||
printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
|
||||
|
@ -456,20 +495,58 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
return;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PFX "Max VID=%d.%03d Min VID=%d.%03d, %d possible voltage scales\n",
|
||||
/* How many voltage steps */
|
||||
numvscales = maxvid.pos - minvid.pos + 1;
|
||||
printk(KERN_INFO PFX
|
||||
"Max VID=%d.%03d "
|
||||
"Min VID=%d.%03d, "
|
||||
"%d possible voltage scales\n",
|
||||
maxvid.mV/1000, maxvid.mV%1000,
|
||||
minvid.mV/1000, minvid.mV%1000,
|
||||
numvscales);
|
||||
|
||||
|
||||
/* Calculate max frequency at min voltage */
|
||||
j = longhaul.bits.MinMHzBR;
|
||||
if (longhaul.bits.MinMHzBR4)
|
||||
j += 16;
|
||||
min_vid_speed = eblcr_table[j];
|
||||
if (min_vid_speed == -1)
|
||||
return;
|
||||
switch (longhaul.bits.MinMHzFSB) {
|
||||
case 0:
|
||||
min_vid_speed *= 13333;
|
||||
break;
|
||||
case 1:
|
||||
min_vid_speed *= 10000;
|
||||
break;
|
||||
case 3:
|
||||
min_vid_speed *= 6666;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (min_vid_speed >= highest_speed)
|
||||
return;
|
||||
/* Calculate kHz for one voltage step */
|
||||
kHz_step = (highest_speed - min_vid_speed) / numvscales;
|
||||
|
||||
j = 0;
|
||||
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
|
||||
speed = longhaul_table[j].frequency;
|
||||
pos = (speed - lowest_speed) / kHz_step + minvid.pos;
|
||||
if (speed > min_vid_speed)
|
||||
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
|
||||
else
|
||||
pos = minvid.pos;
|
||||
f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
|
||||
f_msr_table[longhaul_table[j].index].pos = pos;
|
||||
j++;
|
||||
}
|
||||
|
||||
longhaul_pos = maxvid.pos;
|
||||
can_scale_voltage = 1;
|
||||
printk(KERN_INFO PFX "Voltage scaling enabled. "
|
||||
"Use of \"conservative\" governor is highly recommended.\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue