aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorRobert Lee <rob.lee@linaro.org>2012-03-20 16:22:42 -0400
committerLen Brown <len.brown@intel.com>2012-03-21 01:59:40 -0400
commite1689795a784a7c41ac4cf9032794986b095a133 (patch)
tree19619c24579875e344af337c86c6a604425627b5 /drivers/cpuidle
parentc16fa4f2ad19908a47c63d8fa436a1178438c7e7 (diff)
cpuidle: Add common time keeping and irq enabling
Make necessary changes to implement time keeping and irq enabling in the core cpuidle code. This will allow the removal of these functionalities from various platform cpuidle implementations whose timekeeping and irq enabling follows the form in this common code. Signed-off-by: Robert Lee <rob.lee@linaro.org> Tested-by: Jean Pihet <j-pihet@ti.com> Tested-by: Amit Daniel <amit.kachhap@linaro.org> Tested-by: Robert Lee <rob.lee@linaro.org> Reviewed-by: Kevin Hilman <khilman@ti.com> Reviewed-by: Daniel Lezcano <daniel.lezcano@linaro.org> Reviewed-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> Acked-by: Jean Pihet <j-pihet@ti.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle.c66
1 files changed, 59 insertions, 7 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 59f4261c753a..4869b5500234 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {}
53 53
54static int __cpuidle_register_device(struct cpuidle_device *dev); 54static int __cpuidle_register_device(struct cpuidle_device *dev);
55 55
56static inline int cpuidle_enter(struct cpuidle_device *dev,
57 struct cpuidle_driver *drv, int index)
58{
59 struct cpuidle_state *target_state = &drv->states[index];
60 return target_state->enter(dev, drv, index);
61}
62
63static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
64 struct cpuidle_driver *drv, int index)
65{
66 return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
67}
68
69typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
70 struct cpuidle_driver *drv, int index);
71
72static cpuidle_enter_t cpuidle_enter_ops;
73
56/** 74/**
57 * cpuidle_idle_call - the main idle loop 75 * cpuidle_idle_call - the main idle loop
58 * 76 *
@@ -63,7 +81,6 @@ int cpuidle_idle_call(void)
63{ 81{
64 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 82 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
65 struct cpuidle_driver *drv = cpuidle_get_driver(); 83 struct cpuidle_driver *drv = cpuidle_get_driver();
66 struct cpuidle_state *target_state;
67 int next_state, entered_state; 84 int next_state, entered_state;
68 85
69 if (off) 86 if (off)
@@ -92,12 +109,10 @@ int cpuidle_idle_call(void)
92 return 0; 109 return 0;
93 } 110 }
94 111
95 target_state = &drv->states[next_state];
96
97 trace_power_start(POWER_CSTATE, next_state, dev->cpu); 112 trace_power_start(POWER_CSTATE, next_state, dev->cpu);
98 trace_cpu_idle(next_state, dev->cpu); 113 trace_cpu_idle(next_state, dev->cpu);
99 114
100 entered_state = target_state->enter(dev, drv, next_state); 115 entered_state = cpuidle_enter_ops(dev, drv, next_state);
101 116
102 trace_power_end(dev->cpu); 117 trace_power_end(dev->cpu);
103 trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); 118 trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -110,6 +125,8 @@ int cpuidle_idle_call(void)
110 dev->states_usage[entered_state].time += 125 dev->states_usage[entered_state].time +=
111 (unsigned long long)dev->last_residency; 126 (unsigned long long)dev->last_residency;
112 dev->states_usage[entered_state].usage++; 127 dev->states_usage[entered_state].usage++;
128 } else {
129 dev->last_residency = 0;
113 } 130 }
114 131
115 /* give the governor an opportunity to reflect on the outcome */ 132 /* give the governor an opportunity to reflect on the outcome */
@@ -164,6 +181,37 @@ void cpuidle_resume_and_unlock(void)
164 181
165EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); 182EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
166 183
184/**
185 * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
186 * @dev: pointer to a valid cpuidle_device object
187 * @drv: pointer to a valid cpuidle_driver object
188 * @index: index of the target cpuidle state.
189 */
190int cpuidle_wrap_enter(struct cpuidle_device *dev,
191 struct cpuidle_driver *drv, int index,
192 int (*enter)(struct cpuidle_device *dev,
193 struct cpuidle_driver *drv, int index))
194{
195 ktime_t time_start, time_end;
196 s64 diff;
197
198 time_start = ktime_get();
199
200 index = enter(dev, drv, index);
201
202 time_end = ktime_get();
203
204 local_irq_enable();
205
206 diff = ktime_to_us(ktime_sub(time_end, time_start));
207 if (diff > INT_MAX)
208 diff = INT_MAX;
209
210 dev->last_residency = (int) diff;
211
212 return index;
213}
214
167#ifdef CONFIG_ARCH_HAS_CPU_RELAX 215#ifdef CONFIG_ARCH_HAS_CPU_RELAX
168static int poll_idle(struct cpuidle_device *dev, 216static int poll_idle(struct cpuidle_device *dev,
169 struct cpuidle_driver *drv, int index) 217 struct cpuidle_driver *drv, int index)
@@ -212,10 +260,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
212int cpuidle_enable_device(struct cpuidle_device *dev) 260int cpuidle_enable_device(struct cpuidle_device *dev)
213{ 261{
214 int ret, i; 262 int ret, i;
263 struct cpuidle_driver *drv = cpuidle_get_driver();
215 264
216 if (dev->enabled) 265 if (dev->enabled)
217 return 0; 266 return 0;
218 if (!cpuidle_get_driver() || !cpuidle_curr_governor) 267 if (!drv || !cpuidle_curr_governor)
219 return -EIO; 268 return -EIO;
220 if (!dev->state_count) 269 if (!dev->state_count)
221 return -EINVAL; 270 return -EINVAL;
@@ -226,13 +275,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
226 return ret; 275 return ret;
227 } 276 }
228 277
229 poll_idle_init(cpuidle_get_driver()); 278 cpuidle_enter_ops = drv->en_core_tk_irqen ?
279 cpuidle_enter_tk : cpuidle_enter;
280
281 poll_idle_init(drv);
230 282
231 if ((ret = cpuidle_add_state_sysfs(dev))) 283 if ((ret = cpuidle_add_state_sysfs(dev)))
232 return ret; 284 return ret;
233 285
234 if (cpuidle_curr_governor->enable && 286 if (cpuidle_curr_governor->enable &&
235 (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) 287 (ret = cpuidle_curr_governor->enable(drv, dev)))
236 goto fail_sysfs; 288 goto fail_sysfs;
237 289
238 for (i = 0; i < dev->state_count; i++) { 290 for (i = 0; i < dev->state_count; i++) {