aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorDeepthi Dharwar <deepthi@linux.vnet.ibm.com>2011-10-28 06:50:09 -0400
committerLen Brown <len.brown@intel.com>2011-11-06 21:13:30 -0500
commite978aa7d7d57d04eb5f88a7507c4fb98577def77 (patch)
treed6d6dfe1dba4d4749c7eafe348351aa499c3c5eb /drivers/cpuidle
parentc3b92c8787367a8bb53d57d9789b558f1295cc96 (diff)
cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state
Cpuidle governor only suggests the state to enter using the governor->select() interface, but allows the low level driver to override the recommended state. The actual entered state may be different because of software or hardware demotion. Software demotion is done by the back-end cpuidle driver and can be accounted correctly. Current cpuidle code uses last_state field to capture the actual state entered and based on that updates the statistics for the state entered. Ideally the driver enter routine should update the counters, and it should return the state actually entered rather than the time spent there. The generic cpuidle code should simply handle where the counters live in the sysfs namespace, not updating the counters. Reference: https://lkml.org/lkml/2011/3/25/52 Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com> Tested-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Acked-by: Arjan van de Ven <arjan@linux.intel.com> Acked-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Len Brown <len.brown@intel.com>
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/**