diff options
author | Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 2005-08-25 15:59:00 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-08-26 22:22:33 -0400 |
commit | d395bf12d1ba61437e546eb642f0d7ea666123ff (patch) | |
tree | fbae0f68f62f02803e17309a3d1180619d4fdd31 | |
parent | 60cfff3516580f5c782cef4dc28f2974c4df8ed1 (diff) |
[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=5129
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 60a9e54dd20e..822c8ce9d1f1 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/cpufreq.h> | 31 | #include <linux/cpufreq.h> |
32 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | #include <linux/compiler.h> | ||
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
35 | #include <asm/delay.h> | 36 | #include <asm/delay.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
@@ -57,6 +58,8 @@ static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; | |||
57 | 58 | ||
58 | static struct cpufreq_driver acpi_cpufreq_driver; | 59 | static struct cpufreq_driver acpi_cpufreq_driver; |
59 | 60 | ||
61 | static unsigned int acpi_pstate_strict; | ||
62 | |||
60 | static int | 63 | static int |
61 | acpi_processor_write_port( | 64 | acpi_processor_write_port( |
62 | u16 port, | 65 | u16 port, |
@@ -163,34 +166,44 @@ acpi_processor_set_performance ( | |||
163 | } | 166 | } |
164 | 167 | ||
165 | /* | 168 | /* |
166 | * Then we read the 'status_register' and compare the value with the | 169 | * Assume the write went through when acpi_pstate_strict is not used. |
167 | * target state's 'status' to make sure the transition was successful. | 170 | * As read status_register is an expensive operation and there |
168 | * Note that we'll poll for up to 1ms (100 cycles of 10us) before | 171 | * are no specific error cases where an IO port write will fail. |
169 | * giving up. | ||
170 | */ | 172 | */ |
171 | 173 | if (acpi_pstate_strict) { | |
172 | port = data->acpi_data.status_register.address; | 174 | /* Then we read the 'status_register' and compare the value |
173 | bit_width = data->acpi_data.status_register.bit_width; | 175 | * with the target state's 'status' to make sure the |
174 | 176 | * transition was successful. | |
175 | dprintk("Looking for 0x%08x from port 0x%04x\n", | 177 | * Note that we'll poll for up to 1ms (100 cycles of 10us) |
176 | (u32) data->acpi_data.states[state].status, port); | 178 | * before giving up. |
177 | 179 | */ | |
178 | for (i=0; i<100; i++) { | 180 | |
179 | ret = acpi_processor_read_port(port, bit_width, &value); | 181 | port = data->acpi_data.status_register.address; |
180 | if (ret) { | 182 | bit_width = data->acpi_data.status_register.bit_width; |
181 | dprintk("Invalid port width 0x%04x\n", bit_width); | 183 | |
182 | retval = ret; | 184 | dprintk("Looking for 0x%08x from port 0x%04x\n", |
183 | goto migrate_end; | 185 | (u32) data->acpi_data.states[state].status, port); |
186 | |||
187 | for (i=0; i<100; i++) { | ||
188 | ret = acpi_processor_read_port(port, bit_width, &value); | ||
189 | if (ret) { | ||
190 | dprintk("Invalid port width 0x%04x\n", bit_width); | ||
191 | retval = ret; | ||
192 | goto migrate_end; | ||
193 | } | ||
194 | if (value == (u32) data->acpi_data.states[state].status) | ||
195 | break; | ||
196 | udelay(10); | ||
184 | } | 197 | } |
185 | if (value == (u32) data->acpi_data.states[state].status) | 198 | } else { |
186 | break; | 199 | i = 0; |
187 | udelay(10); | 200 | value = (u32) data->acpi_data.states[state].status; |
188 | } | 201 | } |
189 | 202 | ||
190 | /* notify cpufreq */ | 203 | /* notify cpufreq */ |
191 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); | 204 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); |
192 | 205 | ||
193 | if (value != (u32) data->acpi_data.states[state].status) { | 206 | if (unlikely(value != (u32) data->acpi_data.states[state].status)) { |
194 | unsigned int tmp = cpufreq_freqs.new; | 207 | unsigned int tmp = cpufreq_freqs.new; |
195 | cpufreq_freqs.new = cpufreq_freqs.old; | 208 | cpufreq_freqs.new = cpufreq_freqs.old; |
196 | cpufreq_freqs.old = tmp; | 209 | cpufreq_freqs.old = tmp; |
@@ -537,6 +550,8 @@ acpi_cpufreq_exit (void) | |||
537 | return; | 550 | return; |
538 | } | 551 | } |
539 | 552 | ||
553 | module_param(acpi_pstate_strict, uint, 0644); | ||
554 | MODULE_PARM_DESC(acpi_pstate_strict, "value 0 or non-zero. non-zero -> strict ACPI checks are performed during frequency changes."); | ||
540 | 555 | ||
541 | late_initcall(acpi_cpufreq_init); | 556 | late_initcall(acpi_cpufreq_init); |
542 | module_exit(acpi_cpufreq_exit); | 557 | module_exit(acpi_cpufreq_exit); |