x86, cpufreq: fix Speedfreq-SMI call that clobbers ECX
I have found that using SMI to change the cpu's frequency on my DELL Latitude L400 clobbers the ECX register in speedstep_set_state, causing unneccessary retries because the "state" variable has changed silently (GCC assumes it is still present in ECX). play safe and avoid gcc caching any register across IO port accesses that trigger SMIs. Signed-off by: <Stephan.Diestelhorst@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
475613b9e3
commit
c6e8256a7b
1 changed files with 24 additions and 15 deletions
|
@ -63,7 +63,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
|
||||||
*/
|
*/
|
||||||
static int speedstep_smi_ownership (void)
|
static int speedstep_smi_ownership (void)
|
||||||
{
|
{
|
||||||
u32 command, result, magic;
|
u32 command, result, magic, dummy;
|
||||||
u32 function = GET_SPEEDSTEP_OWNER;
|
u32 function = GET_SPEEDSTEP_OWNER;
|
||||||
unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
|
unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
|
||||||
|
|
||||||
|
@ -73,8 +73,11 @@ static int speedstep_smi_ownership (void)
|
||||||
dprintk("trying to obtain ownership with command %x at port %x\n", command, smi_port);
|
dprintk("trying to obtain ownership with command %x at port %x\n", command, smi_port);
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
|
"push %%ebp\n"
|
||||||
"out %%al, (%%dx)\n"
|
"out %%al, (%%dx)\n"
|
||||||
: "=D" (result)
|
"pop %%ebp\n"
|
||||||
|
: "=D" (result), "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
|
||||||
|
"=S" (dummy)
|
||||||
: "a" (command), "b" (function), "c" (0), "d" (smi_port),
|
: "a" (command), "b" (function), "c" (0), "d" (smi_port),
|
||||||
"D" (0), "S" (magic)
|
"D" (0), "S" (magic)
|
||||||
: "memory"
|
: "memory"
|
||||||
|
@ -96,7 +99,7 @@ static int speedstep_smi_ownership (void)
|
||||||
*/
|
*/
|
||||||
static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
|
static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
|
||||||
{
|
{
|
||||||
u32 command, result = 0, edi, high_mhz, low_mhz;
|
u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
|
||||||
u32 state=0;
|
u32 state=0;
|
||||||
u32 function = GET_SPEEDSTEP_FREQS;
|
u32 function = GET_SPEEDSTEP_FREQS;
|
||||||
|
|
||||||
|
@ -109,10 +112,12 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
|
||||||
|
|
||||||
dprintk("trying to determine frequencies with command %x at port %x\n", command, smi_port);
|
dprintk("trying to determine frequencies with command %x at port %x\n", command, smi_port);
|
||||||
|
|
||||||
__asm__ __volatile__("movl $0, %%edi\n"
|
__asm__ __volatile__(
|
||||||
|
"push %%ebp\n"
|
||||||
"out %%al, (%%dx)\n"
|
"out %%al, (%%dx)\n"
|
||||||
: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi)
|
"pop %%ebp"
|
||||||
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
|
: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi), "=S" (dummy)
|
||||||
|
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0)
|
||||||
);
|
);
|
||||||
|
|
||||||
dprintk("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz);
|
dprintk("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz);
|
||||||
|
@ -135,16 +140,18 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
|
||||||
static int speedstep_get_state (void)
|
static int speedstep_get_state (void)
|
||||||
{
|
{
|
||||||
u32 function=GET_SPEEDSTEP_STATE;
|
u32 function=GET_SPEEDSTEP_STATE;
|
||||||
u32 result, state, edi, command;
|
u32 result, state, edi, command, dummy;
|
||||||
|
|
||||||
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
|
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
|
||||||
|
|
||||||
dprintk("trying to determine current setting with command %x at port %x\n", command, smi_port);
|
dprintk("trying to determine current setting with command %x at port %x\n", command, smi_port);
|
||||||
|
|
||||||
__asm__ __volatile__("movl $0, %%edi\n"
|
__asm__ __volatile__(
|
||||||
|
"push %%ebp\n"
|
||||||
"out %%al, (%%dx)\n"
|
"out %%al, (%%dx)\n"
|
||||||
: "=a" (result), "=b" (state), "=D" (edi)
|
"pop %%ebp\n"
|
||||||
: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0)
|
: "=a" (result), "=b" (state), "=D" (edi), "=c" (dummy), "=d" (dummy), "=S" (dummy)
|
||||||
|
: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0), "D" (0)
|
||||||
);
|
);
|
||||||
|
|
||||||
dprintk("state is %x, result is %x\n", state, result);
|
dprintk("state is %x, result is %x\n", state, result);
|
||||||
|
@ -160,7 +167,7 @@ static int speedstep_get_state (void)
|
||||||
*/
|
*/
|
||||||
static void speedstep_set_state (unsigned int state)
|
static void speedstep_set_state (unsigned int state)
|
||||||
{
|
{
|
||||||
unsigned int result = 0, command, new_state;
|
unsigned int result = 0, command, new_state, dummy;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int function=SET_SPEEDSTEP_STATE;
|
unsigned int function=SET_SPEEDSTEP_STATE;
|
||||||
unsigned int retry = 0;
|
unsigned int retry = 0;
|
||||||
|
@ -182,10 +189,12 @@ static void speedstep_set_state (unsigned int state)
|
||||||
}
|
}
|
||||||
retry++;
|
retry++;
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"movl $0, %%edi\n"
|
"push %%ebp\n"
|
||||||
"out %%al, (%%dx)\n"
|
"out %%al, (%%dx)\n"
|
||||||
: "=b" (new_state), "=D" (result)
|
"pop %%ebp"
|
||||||
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
|
: "=b" (new_state), "=D" (result), "=c" (dummy), "=a" (dummy),
|
||||||
|
"=d" (dummy), "=S" (dummy)
|
||||||
|
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0)
|
||||||
);
|
);
|
||||||
} while ((new_state != state) && (retry <= SMI_TRIES));
|
} while ((new_state != state) && (retry <= SMI_TRIES));
|
||||||
|
|
||||||
|
@ -195,7 +204,7 @@ static void speedstep_set_state (unsigned int state)
|
||||||
if (new_state == state) {
|
if (new_state == state) {
|
||||||
dprintk("change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result);
|
dprintk("change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result);
|
||||||
} else {
|
} else {
|
||||||
printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result);
|
printk(KERN_ERR "cpufreq: change to state %u failed with new_state %u and result %u\n", state, new_state, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue