Commit d395bf12 authored by Venkatesh Pallipadi's avatar Venkatesh Pallipadi Committed by Len Brown

[ACPI] Reduce acpi-cpufreq switching latency by 50%

The acpi-cpufreq driver does a P-state get after a P-state set
to verify whether set went through successfully. This test
is kind of redundant as set goes throught most of the times,
and the test is also expensive as a get of P-states can
take a lot of time (same as a set operation) as it goes
through SMM mode. Effectively, we are doubling the P-state
latency due to this get opertion.

momdule parameter "acpi_pstate_strict" restores orginal paranoia.

http://bugzilla.kernel.org/show_bug.cgi?id=5129Signed-off-by: default avatarVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 60cfff35
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/compiler.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -57,6 +58,8 @@ static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; ...@@ -57,6 +58,8 @@ static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver; static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
static int static int
acpi_processor_write_port( acpi_processor_write_port(
u16 port, u16 port,
...@@ -163,34 +166,44 @@ acpi_processor_set_performance ( ...@@ -163,34 +166,44 @@ acpi_processor_set_performance (
} }
/* /*
* Then we read the 'status_register' and compare the value with the * Assume the write went through when acpi_pstate_strict is not used.
* target state's 'status' to make sure the transition was successful. * As read status_register is an expensive operation and there
* Note that we'll poll for up to 1ms (100 cycles of 10us) before * are no specific error cases where an IO port write will fail.
* giving up.
*/ */
if (acpi_pstate_strict) {
port = data->acpi_data.status_register.address; /* Then we read the 'status_register' and compare the value
bit_width = data->acpi_data.status_register.bit_width; * with the target state's 'status' to make sure the
* transition was successful.
dprintk("Looking for 0x%08x from port 0x%04x\n", * Note that we'll poll for up to 1ms (100 cycles of 10us)
(u32) data->acpi_data.states[state].status, port); * before giving up.
*/
for (i=0; i<100; i++) {
ret = acpi_processor_read_port(port, bit_width, &value); port = data->acpi_data.status_register.address;
if (ret) { bit_width = data->acpi_data.status_register.bit_width;
dprintk("Invalid port width 0x%04x\n", bit_width);
retval = ret; dprintk("Looking for 0x%08x from port 0x%04x\n",
goto migrate_end; (u32) data->acpi_data.states[state].status, port);
for (i=0; i<100; i++) {
ret = acpi_processor_read_port(port, bit_width, &value);
if (ret) {
dprintk("Invalid port width 0x%04x\n", bit_width);
retval = ret;
goto migrate_end;
}
if (value == (u32) data->acpi_data.states[state].status)
break;
udelay(10);
} }
if (value == (u32) data->acpi_data.states[state].status) } else {
break; i = 0;
udelay(10); value = (u32) data->acpi_data.states[state].status;
} }
/* notify cpufreq */ /* notify cpufreq */
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
if (value != (u32) data->acpi_data.states[state].status) { if (unlikely(value != (u32) data->acpi_data.states[state].status)) {
unsigned int tmp = cpufreq_freqs.new; unsigned int tmp = cpufreq_freqs.new;
cpufreq_freqs.new = cpufreq_freqs.old; cpufreq_freqs.new = cpufreq_freqs.old;
cpufreq_freqs.old = tmp; cpufreq_freqs.old = tmp;
...@@ -537,6 +550,8 @@ acpi_cpufreq_exit (void) ...@@ -537,6 +550,8 @@ acpi_cpufreq_exit (void)
return; return;
} }
module_param(acpi_pstate_strict, uint, 0644);
MODULE_PARM_DESC(acpi_pstate_strict, "value 0 or non-zero. non-zero -> strict ACPI checks are performed during frequency changes.");
late_initcall(acpi_cpufreq_init); late_initcall(acpi_cpufreq_init);
module_exit(acpi_cpufreq_exit); module_exit(acpi_cpufreq_exit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment