aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2010-05-08 18:47:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-09 21:35:36 -0400
commit1c6fe0364fa7bf28248488753ee0afb6b759cd04 (patch)
tree8bb0caf5efc652c18354a8694fc1e235f216d6ab
parentf1c448e0a9e99c76f4ece368714fb35a40a8daba (diff)
cpuidle: Fix incorrect optimization
commit 672917dcc78 ("cpuidle: menu governor: reduce latency on exit") added an optimization, where the analysis on the past idle period moved from the end of idle, to the beginning of the new idle. Unfortunately, this optimization had a bug where it zeroed one key variable for new use, that is needed for the analysis. The fix is simple, zero the variable after doing the work from the previous idle. During the audit of the code that found this issue, another issue was also found; the ->measured_us data structure member is never set, a local variable is always used instead. Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Cc: Corrado Zoccolo <czoccolo@gmail.com> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/cpuidle/governors/menu.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 1aea7157d8f..f8e57c6303f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -100,7 +100,6 @@ struct menu_device {
100 int needs_update; 100 int needs_update;
101 101
102 unsigned int expected_us; 102 unsigned int expected_us;
103 unsigned int measured_us;
104 u64 predicted_us; 103 u64 predicted_us;
105 unsigned int exit_us; 104 unsigned int exit_us;
106 unsigned int bucket; 105 unsigned int bucket;
@@ -187,14 +186,14 @@ static int menu_select(struct cpuidle_device *dev)
187 int i; 186 int i;
188 int multiplier; 187 int multiplier;
189 188
190 data->last_state_idx = 0;
191 data->exit_us = 0;
192
193 if (data->needs_update) { 189 if (data->needs_update) {
194 menu_update(dev); 190 menu_update(dev);
195 data->needs_update = 0; 191 data->needs_update = 0;
196 } 192 }
197 193
194 data->last_state_idx = 0;
195 data->exit_us = 0;
196
198 /* Special case when user has set very strict latency requirement */ 197 /* Special case when user has set very strict latency requirement */
199 if (unlikely(latency_req == 0)) 198 if (unlikely(latency_req == 0))
200 return 0; 199 return 0;
@@ -294,7 +293,7 @@ static void menu_update(struct cpuidle_device *dev)
294 new_factor = data->correction_factor[data->bucket] 293 new_factor = data->correction_factor[data->bucket]
295 * (DECAY - 1) / DECAY; 294 * (DECAY - 1) / DECAY;
296 295
297 if (data->expected_us > 0 && data->measured_us < MAX_INTERESTING) 296 if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
298 new_factor += RESOLUTION * measured_us / data->expected_us; 297 new_factor += RESOLUTION * measured_us / data->expected_us;
299 else 298 else
300 /* 299 /*