aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle.c32
-rw-r--r--drivers/cpuidle/governors/ladder.c13
-rw-r--r--drivers/cpuidle/governors/menu.c7
3 files changed, 34 insertions, 18 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index d4c542372886..88bd12104396 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -62,7 +62,7 @@ int cpuidle_idle_call(void)
62{ 62{
63 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 63 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
64 struct cpuidle_state *target_state; 64 struct cpuidle_state *target_state;
65 int next_state; 65 int next_state, entered_state;
66 66
67 if (off) 67 if (off)
68 return -ENODEV; 68 return -ENODEV;
@@ -102,26 +102,27 @@ int cpuidle_idle_call(void)
102 102
103 target_state = &dev->states[next_state]; 103 target_state = &dev->states[next_state];
104 104
105 /* enter the state and update stats */
106 dev->last_state = target_state;
107
108 trace_power_start(POWER_CSTATE, next_state, dev->cpu); 105 trace_power_start(POWER_CSTATE, next_state, dev->cpu);
109 trace_cpu_idle(next_state, dev->cpu); 106 trace_cpu_idle(next_state, dev->cpu);
110 107
111 dev->last_residency = target_state->enter(dev, target_state); 108 entered_state = target_state->enter(dev, next_state);
112 109
113 trace_power_end(dev->cpu); 110 trace_power_end(dev->cpu);
114 trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); 111 trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
115 112
116 if (dev->last_state) 113 if (entered_state >= 0) {
117 target_state = dev->last_state; 114 /* Update cpuidle counters */
118 115 /* This can be moved to within driver enter routine
119 target_state->time += (unsigned long long)dev->last_residency; 116 * but that results in multiple copies of same code.
120 target_state->usage++; 117 */
118 dev->states[entered_state].time +=
119 (unsigned long long)dev->last_residency;
120 dev->states[entered_state].usage++;
121 }
121 122
122 /* give the governor an opportunity to reflect on the outcome */ 123 /* give the governor an opportunity to reflect on the outcome */
123 if (cpuidle_curr_governor->reflect) 124 if (cpuidle_curr_governor->reflect)
124 cpuidle_curr_governor->reflect(dev); 125 cpuidle_curr_governor->reflect(dev, entered_state);
125 126
126 return 0; 127 return 0;
127} 128}
@@ -172,11 +173,10 @@ void cpuidle_resume_and_unlock(void)
172EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); 173EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
173 174
174#ifdef CONFIG_ARCH_HAS_CPU_RELAX 175#ifdef CONFIG_ARCH_HAS_CPU_RELAX
175static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) 176static int poll_idle(struct cpuidle_device *dev, int index)
176{ 177{
177 ktime_t t1, t2; 178 ktime_t t1, t2;
178 s64 diff; 179 s64 diff;
179 int ret;
180 180
181 t1 = ktime_get(); 181 t1 = ktime_get();
182 local_irq_enable(); 182 local_irq_enable();
@@ -188,8 +188,9 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
188 if (diff > INT_MAX) 188 if (diff > INT_MAX)
189 diff = INT_MAX; 189 diff = INT_MAX;
190 190
191 ret = (int) diff; 191 dev->last_residency = (int) diff;
192 return ret; 192
193 return index;
193} 194}
194 195
195static void poll_idle_init(struct cpuidle_device *dev) 196static void poll_idle_init(struct cpuidle_device *dev)
@@ -248,7 +249,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
248 dev->states[i].time = 0; 249 dev->states[i].time = 0;
249 } 250 }
250 dev->last_residency = 0; 251 dev->last_residency = 0;
251 dev->last_state = NULL;
252 252
253 smp_wmb(); 253 smp_wmb();
254 254
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 12c98900dcf8..6a686a76711f 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -153,11 +153,24 @@ static int ladder_enable_device(struct cpuidle_device *dev)
153 return 0; 153 return 0;
154} 154}
155 155
156/**
157 * ladder_reflect - update the correct last_state_idx
158 * @dev: the CPU
159 * @index: the index of actual state entered
160 */
161static void ladder_reflect(struct cpuidle_device *dev, int index)
162{
163 struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
164 if (index > 0)
165 ldev->last_state_idx = index;
166}
167
156static struct cpuidle_governor ladder_governor = { 168static struct cpuidle_governor ladder_governor = {
157 .name = "ladder", 169 .name = "ladder",
158 .rating = 10, 170 .rating = 10,
159 .enable = ladder_enable_device, 171 .enable = ladder_enable_device,
160 .select = ladder_select_state, 172 .select = ladder_select_state,
173 .reflect = ladder_reflect,
161 .owner = THIS_MODULE, 174 .owner = THIS_MODULE,
162}; 175};
163 176
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c47f3d09c1ee..e4b200c5b441 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -310,14 +310,17 @@ static int menu_select(struct cpuidle_device *dev)
310/** 310/**
311 * menu_reflect - records that data structures need update 311 * menu_reflect - records that data structures need update
312 * @dev: the CPU 312 * @dev: the CPU
313 * @index: the index of actual entered state
313 * 314 *
314 * NOTE: it's important to be fast here because this operation will add to 315 * NOTE: it's important to be fast here because this operation will add to
315 * the overall exit latency. 316 * the overall exit latency.
316 */ 317 */
317static void menu_reflect(struct cpuidle_device *dev) 318static void menu_reflect(struct cpuidle_device *dev, int index)
318{ 319{
319 struct menu_device *data = &__get_cpu_var(menu_devices); 320 struct menu_device *data = &__get_cpu_var(menu_devices);
320 data->needs_update = 1; 321 data->last_state_idx = index;
322 if (index >= 0)
323 data->needs_update = 1;
321} 324}
322 325
323/** 326/**